Container images – preconfigured blueprints for running containers – have improved the efficiency of the development process, allowing developers to skip the tedious task of building images from scratch. Instead, they can easily pull images from public registries, configure them as needed, and get them up and running quickly.
However, containers, which are replicas of their parent images, also inherit any vulnerabilities or misconfigurations present in those images. This makes container security a critical part of the overall software supply chain. In this article, we’ll explore the role of digital image signing in protecting containers from tampering and man-in-the-middle attacks.
Why is image signing important?
Before we proceed to the main part, let’s briefly revisit what a container image is.
An image is a bundle that contains everything a container needs to run: code, binaries, and libraries. It is immutable, meaning it cannot be altered—any necessary changes require the creation of a new image.
Images are built in layers, with each layer representing a set of file system changes, such as adding, removing, or modifying files. These layers combine to form the container’s complete filesystem. Any configuration settings specific to the container can be applied as additional layers.
Pre-built images are often uploaded to public registries for users to access. However, unsigned images are essentially a black box – it’s difficult to verify what they contain. A cryptographic signature – an encrypted data hash – ensures that the image is exactly what it claims to be: an authentic product as intended by its creator. The signature adds an extra layer of security, guaranteeing:
- Authenticity: Confirming that images come from a trusted source and remain untampered.
- Integrity: Guaranteeing that images have not been changed during transfer or storage, protecting systems from threats like image poisoning.
- Freshness: Verifying that images are up-to-date with the latest security patches, preventing attackers from exploiting outdated or insecure versions.
Images can be signed by developers, organizations, or automated systems, such as a CI/CD pipeline configured to sign built images.
How to verify image legitimacy?
To ensure the legitimacy of an image, you need to validate both its integrity and its provenance from trusted sources. Hashing, also known as a digest, is used to verify the integrity of the image.
Digest
A digest is a cryptographic fingerprint of an image, recorded in its manifest file. The container engine calculates the final image digest by hashing the manifest, which includes the hashes of all image layers. The SHA256 algorithm is used for hashing, generating a unique 32-byte signature based on the image’s content. Any changes to the image or its layers will produce a different digest, indicating a mismatch with the original.
Digital signature
Image signing confirms the image’s origin and creator. Images can be signed using offline keys or through a keyless method.
Signing with offline keys
Cryptographic signatures rely on asymmetric encryption, a method that uses two keys: a private key, which remains confidential, and a public key, which is shared with others. To create a digital signature, the signer first hashes the original image using a hashing algorithm and then signs the resulting hash with their private key. The signed hash, along with the original image and digital certificate, is bundled and uploaded to a registry. This allows consumers to retrieve the signature at any time to verify the publisher’s identity.
On the client side, the consumer hashes the original image using the same algorithm, generating a hash for comparison. Next, they use the public key from the digital certificate to decrypt the signed hash and obtain the original image’s hash. If the two hash values match, the image is verified; any discrepancy indicates that the image has been altered.
Figure 1 illustrates a simplified overview of how image signing works:
Figure 1. Signing with offline keys involves using a private/public key pair to verify the authenticity of a container image.
Keeping your private key secure should be a top priority, as it is essential for maintaining control over your system. If the private key is compromised, malicious actors could create signatures that appear to be yours and use them to sign tampered images. Best practices include using hardware security modules (HSMs) or trusted platform modules (TPMs) for on-premises environments, and Key Management Services (KMS) in cloud environments. These technologies serve as secure vaults, offering strong protection against potential breaches.
Keyless signing
This method uses ephemeral keys and short-lived certificates, valid only at the time of signing. The keys are retained until the image is signed, after which they are discarded. Each signature requires a new certificate from the Certificate Authority, as certificates are single-use. Details about the signature are recorded in a transparency log, an append-only, tamper-resistant data store.
When data is added to the log, the log operator provides a signed receipt, which serves as proof that the data is recorded. The log can be monitored for any unusual activity. The transparency log receipt can be included with the signature as further evidence of its validity.
Verifying signer’s identity
To trust the image, the verifier must check both the signature and the identity of the key pair owner. This identification is achieved through certification that links a specific subject to the signature. The certificate is issued by a Certificate Authority (CA), which verifies the signer’s identity based on the information from one of OpenID Connect (OIDC) providers such as Google, GitHub, or Microsoft.
One key factor to consider is the expiration of certificates. Usually, certificates are no longer trusted once they have expired, meaning that image signatures are only valid up until the certificate’s expiration. Since images often need to last longer than the certificate, having a short-lived signature is not good.
This issue can be addressed by using a Timestamp Authority (TSA). A TSA receives the data, combines it with the current timestamp, and signs the bundle before sending it back. By using a TSA, anyone who trusts the authority can confirm that the data existed at the specified time.
Figure 2 illustrates main steps of the process of verifying a signer’s identity:
Figure 2. Trust policy for verifying the signer’s identity is based on information obtained from an OIDC provider, a Certificate Authority, and a Timestamp Authority.
Image signing technologies
The Update Framework
Popular image signing tools, such as Notary and Cosign, rely on The Update Framework (TUF) as a root of trust – a foundational security component to verify the validity of signing material.
TUF is a security framework designed to protect software update systems from a variety of attacks, such as replay attacks, targeted attacks, and man-in-the-middle attacks. By operating a set of protocols, TUF verifies the authenticity of the update file. In the context of image signing, TUF provides additional layers of security, including:
- Key protection: Rather than relying on a single root key, TUF recommends creating a set of root keys distributed across different systems. A quorum of these keys is used to sign the operational keys that are used daily. These signing keys are then rotated on a regular schedule to enhance security.
- Role delegation: TUF allows for delegating trust to different roles, which can sign and validate container images.
- Versioning and Expiration: TUF can help prevent the use of outdated or compromised images by enforcing strict version control and setting expiration dates on images and metadata.
Docker Content Trust
Docker Content Trust (DCT) is a Docker-native framework for signing images. Built on the Notary Project, it implements key principles from the TUF specification to verify both the integrity of images and the identity of their signers. In DCT, an offline root key is used to generate repository keys for signing image tags. Additionally, a server-managed timestamp key is applied to signed images, ensuring freshness and security for your repository.
Cosign
Cosign is an open-source project by Sigstore, created for signing, verifying, and storing artifacts in OCI repositories. It supports signing methods using both long-lived keys and ephemeral keys.
In keyless signing, Cosign generates ephemeral keys and certificates, which are automatically signed by the Fulcio root certificate authority. Fulcio authenticates the signer’s identity using their OIDC token. The signatures are then stored in the Rekor transparency log, which provides an attestation at the time of creation.
Main take-aways
The importance of images in deploying containerized applications makes image signing critical to overall supply chain security. Ultimately, container image signing involves:
- The creator’s cryptographic signature applied to the image.
- A cryptographic hash, unique to each image, that verifies the image’s authenticity and integrity.
- A signing certificate, often issued by a trusted certificate authority (CA), which includes the public key and confirms the approval of the signing process.
- A private key, securely held by the image creator, used to sign the image and ensure it remains confidential.
Resources
Container Images: Architecture and Best Practices
Container Image Signing: Why and How
Signing Docker Official Images Using OpenPubkey
Container Image Signing: A Practical Guide
What Are Docker Image Layers and How Do They Work?
Signing container images: Comparing Sigstore, Notary, and Docker Content Trust