containerd imgcrypt

repository·main·Indexed 19 days ago

https://github.com/containerd/imgcrypt

An image encryption library and command-line tool for containerd that provides secure container image encryption and decryption. It includes the ctd-decoder binary for containerd stream processors and the ctr-enc tool for encrypting images and running encrypted containers using RSA keys. Requires containerd 1.3+ (or 1.4+ for Kubernetes).

Tokens
15.2K
Snippets
62
Records
74
Agent score
65%

What's inside imgcrypt

  1. Encrypt container images with ctr-enc

    main

    To encrypt images, follow these steps:

    1. Generate an RSA key pair using OpenSSL:

      openssl genrsa -out mykey.pem
      openssl rsa -in mykey.pem -pubout -out mypubkey.pem
    2. Identify the target image and its platform using ctr-enc (linked to your containerd socket):

      # Set the CTR variable to point to your socket
      CTR="/usr/local/bin/ctr-enc -a /tmp/run/containerd/containerd.sock"
      $CTR images layerinfo --platform linux/amd64 docker.io/library/bash:latest
    3. Encrypt the image using the --recipient flag with the jwe: prefix and your public key:

      $CTR images encrypt --recipient jwe:mypubkey.pem --platform linux/amd64 docker.io/library/bash:latest bash.enc:latest
    4. Verify encryption by checking the layer info of the new image. The ENCRYPTION column should show jwe and RECIPIENTS should show [jwe].

    # 1. Generate keys
    openssl genrsa -out mykey.pem
    openssl rsa -in mykey.pem -pubout -out mypubkey.pem
    
    # 2. Encrypt image
    CTR="/usr/local/bin/ctr-enc -a /tmp/run/containerd/containerd.sock"
    $CTR images encrypt --recipient jwe:mypubkey.pem --platform linux/amd64 docker.io/library/bash:latest bash.enc:latest
  2. Use the ctr CLI to interact with containerd

    main

    The ctr command is a debug and administrative client used to interact with the containerd daemon. Note that ctr is considered unsupported; its commands, options, and operations are not guaranteed to be stable or backward compatible across releases.

    To use ctr, you can specify the containerd GRPC server address, a specific namespace, and debug settings via global flags.

    # Example usage (based on repository overview)
    # Using the ctr-enc tool to pull images
    $ CTR="/usr/local/bin/ctr-enc -a /tmp/run/containerd/containerd.sock"
    $ $CTR images pull --all-platforms docker.io/library/bash:latest
  3. Decrypt and unpack encrypted Windows images

    main
    The NewContainer logic for Windows automatically handles the decryption and unpacking of encrypted images if they are not already unpacked. It uses parsehelpers.CreateDecryptCryptoConfig with arguments parsed from the command line to generate a DecryptConfig. This configuration is then passed to encryption.WithDecryptedUnpack during the image unpack process to ensure the container can be started with the correct decrypted layers.
  4. Format labels and annotations from CLI arguments

    main

    The CLI processes labels and annotations provided as command-line arguments using specific formats.

    Labels

    Labels are passed as key=value pairs. If the value is omitted, it defaults to true. Example: key=value results in {"key": "value"}, while key results in {"key": "true"}.

    Annotations

    Annotations must strictly follow the key=value format. If the = is missing, the command will return an error.

    Note for developers: These parsing behaviors are implemented via LabelArgs and AnnotationArgs functions.

  5. Configure container mounts via CLI

    main

    The run command supports mounting filesystems into the container using the --mount flag. Mounts are specified using a comma-separated key-value format.

    Supported keys in the mount string:

    • type: The type of mount (e.g., tmpfs, bind).
    • source or src: The source path or device.
    • destination or dst: The target path inside the container.
    • options: A colon-separated list of mount options (e.g., rbind:rw).

    Example format: type=bind,source=/host/path,destination=/container/path,options=rbind:rw

  6. Configure containerd to use imgcrypt decoders

    main

    To enable decryption support in containerd, you must configure stream_processors in your config.toml. This maps encrypted media types to the ctd-decoder binary.

    Note: imgcrypt requires containerd 1.3+ (or 1.4+ for Kubernetes). The following configuration example uses /usr/local/bin/ctd-decoder as the path for the decoder.

    version = 2
    # ... other config ...
    
    [stream_processors]
        [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
            accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
            returns = "application/vnd.oci.image.layer.v1.tar+gzip"
            path = "/usr/local/bin/ctd-decoder"
        [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.zstd"]
            accepts = ["application/vnd.oci.image.layer.v1.tar+zstd+encrypted"]
            returns = "application/vnd.oci.image.layer.v1.tar+zstd"
            path = "/usr/local/bin/ctd-decoder"
        [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
            accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
            returns = "application/vnd.oci.image.layer.v1.tar"
            path = "/usr/local/bin/ctd-decoder"
    version = 2
    disabled_plugins = ["io.containerd.grpc.v1.cri"]
    root = "/tmp/var/lib/containerd"
    state = "/tmp/run/containerd"
    [grpc]
      address = "/tmp/run/containerd/containerd.sock"
      uid = 0
      gid = 0
    [stream_processors]
        [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
            accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
            returns = "application/vnd.oci.image.layer.v1.tar+gzip"
            path = "/usr/local/bin/ctd-decoder"
        [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.zstd"]
            accepts = ["application/vnd.oci.image.layer.v1.tar+zstd+encrypted"]
            returns = "application/vnd.oci.image.layer.v1.tar+zstd"
            path = "/usr/local/bin/ctd-decoder"
        [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
            accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
            returns = "application/vnd.oci.image.layer.v1.tar"
            path = "/usr/local/bin/ctd-decoder"
  7. Pushing with the `--local` flag

    main

    When using the --local flag, the push operation is performed by the local client rather than using a transfer service. This mode enables advanced manifest control and specific layer management.

    When --local is not used, the following flags are unsupported and will cause an error if set:

    • --manifest
    • --manifest-type
    • --max-concurrent-uploaded-layers
    • --allow-non-distributable-blobs
    • --skip-verify
    • --tlscacert
    • --tlscert
    • --tlskey
    • --http-dump
    • --http-trace
  8. Run encrypted images with ctr-enc

    main

    When running an encrypted image, you must provide the private key used for encryption via the --key flag, otherwise you will receive an authorization error.

    # This will fail:
    sudo $CTR run --rm localhost:5000/bash.enc:latest test echo 'Hello World!'
    # Error: ctr: you are not authorized to use this image: missing private key needed for decryption
    
    # This will succeed:
    sudo $CTR run --rm --key mykey.pem localhost:5000/bash.enc:latest test echo 'Hello World!'
    # Run with the private key
    sudo $CTR run --rm --key mykey.pem localhost:5000/bash.enc:latest test echo 'Hello World!'
  9. Dump the generated OCI config with `--dump-config`

    main

    You can export the OCI runtime specification generated for a container to a file using the --dump-config flag. This is useful for debugging the exact configuration being passed to the runtime.

    Note: You must provide a filename when using this flag.

    ctr run --dump-config /path/to/config.json docker.io/library/bash:latest my-container
  10. Get image layer Descriptors with GetImageLayerDescriptors

    main

    The GetImageLayerDescriptors function retrieves a list of ocispec.Descriptor objects representing the layers of an image.

    It traverses the image manifest (supporting Docker Schema 2 and OCI formats) and collects descriptors for layers. The returned array contains descriptors grouped by platform: it first includes descriptors for the platform specified in the input descriptor (or the default platform), followed by descriptors for other platforms.

    When processing layers, the function ensures that the descriptor's Platform field is populated using the platform context derived from the parent manifest.

    func GetImageLayerDescriptors(ctx context.Context, cs content.Store, desc ocispec.Descriptor) ([]ocispec.Descriptor, error)
  11. Enable authorization checks with WithAuthorizationCheck

    main

    The WithAuthorizationCheck function returns a containerd.NewContainerOpts function. When used during container creation, it retrieves the image associated with the container and calls CheckAuthorization to verify that the keys used for the encrypted container are authorized. If the image is not found, it allows container creation to proceed without error.

    // dc is an *encconfig.DecryptConfig
    containerOpts := encryption.WithAuthorizationCheck(dc)
    // Use containerOpts when calling containerd client methods to create a container