ocicrypt

repository·main·Indexed 41 days ago

https://github.com/containers/ocicrypt

An implementation of the OCI image specification for container image encryption. It provides a library for container runtimes and build tools to encrypt and decrypt image layers using functions like EncryptLayer and DecryptLayer. The library supports crypto agility via LayerBlockCipher and KeyWrapper interfaces, and integrates with external Key Management Services (KMS) through a key-provider protocol (binary or gRPC). It also provides experimental PKCS #11 support for Hardware Security Modules (HSM), including IBM CryptoExpress and SoftHSM2.

Tokens
7.7K
Snippets
23
Records
30
Agent score
52%

What's inside ocicrypt

  1. Use the Keyprovider interface for external key services

    main
    The keywrap interface includes a keyprovider implementation. This allows the library to call out to an external binary or a remote service to handle key management tasks, rather than handling keys purely in-process.
  2. Extend cryptographic functions via interfaces

    main

    The library is designed for crypto agility and allows users to extend symmetric and asymmetric encryption implementations through two primary interfaces located in specific sub-packages:

    1. Block Ciphers: Implement the LayerBlockCipher interface in the github.com/containers/ocicrypt/blockcipher package.
    2. Key Wrapping: Implement the KeyWrapper interface in the github.com/containers/ocicrypt/keywrap package.

    Warning: Adding new interfaces outside of the OCI specification is risky and not recommended unless for highly specialized use cases. If you have a general use case, it is preferred to contribute it to the OCI spec.

  3. Use the PKCS #11 key file format in ocicrypt

    main

    While a PKCS #11 URI describes a key, ocicrypt uses a specific YAML-based file format to allow passing additional parameters required by certain drivers (modules), such as module-specific environment variables. This format allows you to bundle the key URI with the environment configuration needed to access the HSM.

    Example format:

    pkcs11:
      uri: <PKCS11_URI>
    module:
      env:
        <MODULE_SPECIFIC_ENV_VAR>: <VALUE>
    pkcs11:
      uri: pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=f21985c5bec65cff;token=ocicrypt-test;id=%2B%74%4C%87%C6%6D%9C%32%C1%E1%82%D5%A3%D0%AC%6C%50%D0%AD%89;object=mykey;type=public?pin-value=1234&module-name=softhsm2
    module:
      env:
        SOFTHSM2_CONF: /home/stefanb/softhsm-config/softhsm2.conf
  4. How the Ocicrypt key-provider protocol works

    main

    Ocicrypt uses a key-provider protocol to enable encryption and decryption of container images using keys retrieved from external Key Management Services (KMS).

    To implement a custom key provider, you can create either:

    1. A binary executable: A local program that is invoked to fetch keys.
    2. A gRPC server: A remote service that provides keys over a network connection.

    During encryption, the provider is responsible for fetching the wrapped key. During decryption, the provider is responsible for fetching the unwrapped key.

  5. Encrypt and decrypt images with skopeo

    main

    Use skopeo copy to handle encrypted image transfers using PKCS #11. Ensure OCICRYPT_CONFIG=internal is set in your environment.

    Encryption

    • Use the --encryption-key flag. You can provide a public key path prefixed with pkcs11: or a PKCS #11 key configuration YAML file prefixed with pkcs11:.

    Decryption

    • Use the --decryption-key flag followed by the path to your PKCS #11 key configuration file.
    # Encrypting with a Public Key
    $ OCICRYPT_CONFIG=internal skopeo copy --encryption-key pkcs11:pubkey.pem oci:alpine:latest oci:alpine_enc_pkcs11pubkey:latest
    
    # Encrypting with a PKCS #11 Key Configuration
    $ OCICRYPT_CONFIG=internal skopeo copy --encryption-key pkcs11:myPkcs11Key.yaml oci:alpine:latest oci:alpine_enc_pkcs11key:latest
    
    # Decrypting
    $ OCICRYPT_CONFIG=internal skopeo copy --decryption-key myPkcs11Key.yaml oci:alpine_enc_pkcs11pubkey:latest oci:alpine_dec_pkcs11pubkey:latest
  6. Encrypt and decrypt OCI images using a key provider

    main

    You can use skopeo to encrypt or decrypt OCI-compliant images by referencing a configured key provider via the OCICRYPT_KEYPROVIDER_CONFIG environment variable and the --encryption-key or --decryption-key flags.

    Key Syntax

    The key identifier follows the format: provider:<provider_name>:<extra_params>.

    Workflow

    1. Prepare an OCI image: Use skopeo copy to pull a docker image into an OCI layout.
    2. Encrypt: Use the --encryption-key flag.
    3. Decrypt: Use the --decryption-key flag.

    Note: Ensure your configuration file is correctly pointed to by the OCICRYPT_KEYPROVIDER_CONFIG environment variable.

    # 1. Prepare an OCI image
    $ skopeo copy docker://docker.io/library/alpine:latest oci:alpine
    
    # 2. Encrypt the image
    $ OCICRYPT_KEYPROVIDER_CONFIG=/home/vagrant/ocicrypt.conf bin/skopeo copy --encryption-key provider:simplecrypt:abc oci:alpine oci:encrypted
    
    # 3. Decrypt the image
    $ OCICRYPT_KEYPROVIDER_CONFIG=/home/vagrant/ocicrypt.conf bin/skopeo copy --decryption-key provider:simplecrypt:extra-params oci:encrypted oci:decrypted
  7. Set up OCIcrypt with IBM CryptoExpress (EP11 mode)

    main

    To use OCIcrypt with IBM CryptoExpress hardware in Enterprise PKCS #11 (EP11) mode, you must configure the hardware, install the necessary software, and register openCryptoki as a module for p11-kit. This setup allows OCIcrypt to leverage hardware security modules (HSM) via the experimental PKCS #11 protocol.

    1. Hardware and OS Requirements

    • Ensure you have an online EP11-Coproc configured in the Support Element/Hardware Management Console.
    • On Linux on IBM Z/LinuxONE, verify hardware using lszcrypt (from s390-tools).
    • Load the appropriate module if necessary: modprobe ap.
    • Administrator certificates and master keys must be configured according to IBM documentation.

    2. Software Installation

    Install the required system packages and the EP11 host library (which must be obtained from IBM software downloads):

    # Install system dependencies
    apt install -y gnutls-bin opencryptoki p11-kit
    
    # Note: You must manually download and install the EP11 host library
    # (e.g., libep11 or ep11-host) using dpkg -i or rpm -i

    3. Configure openCryptoki

    Register openCryptoki as a module for p11-kit by creating a module file. The path to libopencryptoki.so may vary by distribution.

    cat << EOF | sudo tee /etc/pkcs11/modules/opencryptoki.module
    module: /usr/lib/s390x-linux-gnu/pkcs11/libopencryptoki.so
    EOF

    Verify the token is visible using p11tool --list-tokens. You should see an entry with Model: IBM EP11Tok.

    4. Initialize the Token PIN

    All tokens require a PIN. Use the URL provided by p11tool --list-tokens to initialize it:

    p11tool --initialize-pin 'pkcs11:model=IBM%20EP11Tok;manufacturer=IBM%20Corp.;serial=93AAA1XX22347171;token=IBM%20OS%20PKCS%2311'

    Note: The default Security Officer PIN is 87654321.

    apt install -y gnutls-bin opencryptoki p11-kit
    
    cat << EOF | sudo tee /etc/pkcs11/modules/opencryptoki.module
    module: /usr/lib/s390x-linux-gnu/pkcs11/libopencryptoki.so
    EOF
    
    p11tool --initialize-pin 'pkcs11:model=IBM%20EP11Tok;manufacturer=IBM%20Corp.;serial=93AAA1XX22347171;token=IBM%20OS%20PKCS%2311'
  8. Encrypt and decrypt images with containerd imgcrypt (ctr-enc)

    main

    Use the ctr-enc tool from containerd/imgcrypt to perform PKCS #11 encryption and decryption. Note that PKCS #11 support is currently experimental. You must set the OCICRYPT_CONFIG environment variable (e.g., OCICRYPT_CONFIG=internal) for these commands to work.

    Encryption

    • With a Public Key: Use the --recipient flag with the pkcs11: prefix followed by the public key path.
    • With a PKCS #11 Key Configuration: Use the --recipient flag with the pkcs11: prefix followed by the path to your YAML configuration file.

    Decryption

    • Use the --key flag followed by the path to your PKCS #11 key configuration file.
    # Encrypting with a Public Key
    $ OCICRYPT_CONFIG=internal ./bin/ctr-enc images encrypt --recipient pkcs11:pubkey.pem docker.io/library/alpine:latest alpine.enc.pkcs11pubkey:latest
    
    # Encrypting with a PKCS #11 Key Configuration
    $ OCICRYPT_CONFIG=internal ./bin/ctr-enc images encrypt --recipient pkcs11:myPkcs11Key.yaml docker.io/library/alpine:latest alpine.enc.pkcs11key:latest
    
    # Decrypting
    $ OCICRYPT_CONFIG=internal ./bin/ctr-enc images decrypt --key myPkcs11Key.yaml alpine.enc.pkcs11key:latest alpine.dec.pkcs11key:latest
  9. Encrypt and decrypt images with buildah

    main

    Use buildah to push and pull encrypted images using PKCS #11. Ensure OCICRYPT_CONFIG=internal is set in your environment.

    Encryption (Pushing)

    • Use the --encryption-key flag during a push operation. Supports public keys (prefixed with pkcs11:) or PKCS #11 key configuration files (prefixed with pkcs11:).

    Decryption (Pulling)

    • Use the --decryption-key flag during a pull operation, followed by the path to your PKCS #11 key configuration file.
    # Encrypting with a Public Key
    $ OCICRYPT_CONFIG=internal ./bin/buildah push --encryption-key pkcs11:pubkey.pem docker.io/library/alpine:latest oci:alpine_enc_pkcs11pubkey:latest
    
    # Encrypting with a PKCS #11 Key Configuration
    $ OCICRYPT_CONFIG=internal ./bin/buildah push --encryption-key pkcs11:myPkcs11Key.yaml docker.io/library/alpine:latest oci:alpine_enc_pkcs11key:latest
    
    # Decrypting
    $ OCICRYPT_CONFIG=internal ./bin/buildah pull --decryption-key myPkcs11Key.yaml oci:alpine_enc_pkcs11key:latest
  10. Setup SoftHSM for experimental PKCS #11 support

    main

    To use an emulated HSM for testing, follow these steps on Ubuntu:

    1. Install requirements:

      sudo apt install -y softhsm2 p11-kit gnutls-bin
    2. Initialize SoftHSM configuration: Create directories and a configuration file to manage tokens and objects.

      mkdir -p ${HOME}/.config/softhsm2/tokens
      cat > ${HOME}/.config/softhsm2/softhsm2.conf <<EOF
      directories.tokendir = ${HOME}/.config/softhsm2/tokens
      objectstore.backend = file
      log.level = DEBUG
      slots.removable = false
      EOF
    3. Initialize a Token: Set the SOFTHSM2_CONF environment variable and use softhsm2-util to create a token.

      export SOFTHSM2_CONF=${HOME}/.config/softhsm2/softhsm2.conf
      softhsm2-util --init-token --free --label mytoken --pin my-pin --so-pin my-pin
    4. Generate a Private RSA Key: Use p11tool to generate a key pair inside the token. Use the GNUTLS_PIN environment variable to provide the PIN securely.

      export GNUTLS_PIN=my-pin
      # Use the Token URI found via 'p11tool --list-tokens'
      p11tool --login --generate-privkey=rsa --label imagekey 'pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=ee777786c4a769fb;token=mytoken'
    5. Retrieve the Private Key URI: To use the key with ocicrypt, you need the specific URI for the private key object. Find it using:

      p11tool --login --list-privkeys 'pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=ee777786c4a769fb;token=mytoken'

      The resulting URI should be formatted as: pkcs11:<token_uri>;id=<key_id>;object=<label>;type=private?pin-value=<pin>&module-name=<module_name>

    # Example of the final constructed KEY_URI
    pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=ee777786c4a769fb;token=mytoken;id=%A9%8B%58%89%89%C7%A9%01%59%5A%85%9D%5D%6A%FF%C3%E4%57%E2%16;object=imagekey;type=private?pin-value=my-pin&module-name=softhsm2
  11. How key wrapping and encryption work together

    main

    The ocicrypt library uses a two-layer encryption model:

    1. Layer Encryption: The actual content of the OCI layer is encrypted using a symmetric block cipher (defaulting to AES256CTR). The parameters for this encryption (like the symmetric key and the layer digest) are stored in blockcipher.LayerBlockCipherOptions.
    2. Key Wrapping: The symmetric key used for the layer encryption is itself encrypted (wrapped) using one or more KeyWrapper implementations (e.g., pgp, jwe, pkcs7).

    The Lifecycle:

    • Encryption: EncryptLayer generates a symmetric key, encrypts the layer, and then uses registered KeyWrappers to wrap that symmetric key. The wrapped keys and the public encryption options are then returned as annotations to be stored in the OCI descriptor.
    • Decryption: DecryptLayer looks at the annotations in the descriptor, identifies the correct KeyWrapper for the provided private keys, unwraps the symmetric key, and finally uses that key to decrypt the layer content.
  12. Configure PKCS #11 modules via OCICRYPT_CONFIG

    main

    The OCICRYPT_CONFIG environment variable controls how ocicrypt discovers and restricts PKCS #11 modules on the host.

    • If unset: No HSM modules are allowed.
    • If set to internal: Uses a default policy that includes common module search paths for various Linux distributions.
    • If set to a file path: Uses the provided configuration file to define module-directories (where to look for modules) and allowed-module-paths (a whitelist of specific modules that are permitted to run).

    Example configuration file content:

    pkcs11:
      module-directories:
        - /usr/lib64/pkcs11/
        - /usr/lib/pkcs11/
        - /usr/lib/softhsm/
      allowed-module-paths:
        - /usr/lib64/pkcs11/libsofthsm2.so
        - /usr/lib/pkcs11/libsofthsm2.so
        - /usr/lib/softhsm/libsofthsm2.so