As @stevenhorsman mentioned in issue#2682 of kata-containers, the function of verifying the container image signature will be added in the PoC of ccv0. It is also mentioned in the proposal that in the long term approach, the attestation-agent (AA for short) will cooperate to complete the verification of the container image signature based on the attestation. This proposal will give specific schemes to support verifying container image signature in AA.
Summary
Based on the red hat simple signing architecture, three contents are required to successfully verify the container image signature: signature, public key and policy.json file. Therefore, how to obtain these three contents has become the key for the confidential containers to support the verification of container image signature. In addition, the usage scenario of the confidential containers requires that the container image must be encrypted (paritial layers containing sensitive info) and signed. Therefore, this scheme needs to organically combine the two mechanisms, rather than treat them as independent and irrelevant features.
We currently envision two options:
Option 1:Boot Image scheme
In this scheme, the signature (or signature store server), public key (or public key server) and policy.json required for signature verification need to be directly built into the boot image by the tenant when building it.
In fact, in this scheme, the process of verifying the signature does not require the participation of AA, ocicrypt-rs can complete all signature verification as long as it supports simple signing. We propose this option only to facilitate comparison with the option 2 scheme introduced later.
Since AA is not required to participate, this scheme is almost indistinguishable from the original red hat simple signing architecture. However, must pay attention to the following two points:
-
To ensure the security of signature, public key and policy.json content, the boot image must be provided by the tenant. In the process of implementing the commercialization of confidential containers, it is optional whether to require tenants to provide boot images, but the scheme of "must provide boot images by tenants" will undoubtedly increase the use and maintenance costs of tenants and reduce the flexibility of the scheme.
-
Although the signature store server and public key server can be configured to obtain from the remote server, this adds additional trustors other than the trusted container registry. In fact, when practicing confidential computing, it is a best practice to reduce the number of trustors as much as possible.
Option 2:Key Broker Service scheme
In order to enhance security, it is not enough to simply configure the signature store server and public key server into the trusted domain controlled by the tenant, because these two communication channels are not attested. At present, the communication between KBS and AA is attested.
In this scheme, the tenant needs to deploy the key broker service (KBS for short) in the trusted domain under his control, and save the signature, public key and policy.json on the KBS side (we still use the word KBS to facilitate description and establish association with the KBS used in the encryption container image scheme). This scheme requires some cooperation from AA, ocicrypt-rs and KBS. We describe the whole process as follows:
- KBS side:
- Manage signing key and assign unique key-id.
- Formulate the policy.json file and save it in the specified local directory.
- Configure the yaml file in the /etc/containers/registries.d local directory and specify the signature store.
- Signing: sign the container image and save the signature in the specified signature store.
- Startup of AA: in the startup phase of AA, connect to KBS through the key broker client (KBC for short) and download the policy.json file through the attested channel.
- Image pulling: the kata-agent in pod pulls the image.
- Signature verification:
- skopeo/image mgmt service calls ocicrypt-rs, and then ocicrypt-rs calls AA to send the manifest digest and docker reference to AA.
- AA uses the informations such as manifest digest and docker reference to obtain the signature and the public key used to verify the signature from KBS and returns them to ocicrypt-rs.
Under this scheme, a best practice on the KBS side is to uniformly manage the signature key and decryption key, and establish a mapping relationship with docker reference/manifest digest. In this way, docker reference/manifest digest becomes the actual "key ID". If this practice is not adopted, KBS needs to separately consider where to place the key ID so that it can be read by AA and sent to itself along with the manifest digest and docker reference.
Since only option 2 requires AA's participation and cooperation, the following text only gives the requirements and design for option 2.
Requirements
KBS scheme requires the cooperation of KBS, ocicrypt-rs and AA. Therefore, the following requirements are proposed for these three components:
ocicrypt-rs
FYI: @arronwy
Attestation Agent
Key Broker Service
If the option2 scheme is finally adopted, we will issue a new proposal for the detailed definitions and standards of the above functions of KBS in the near future, and provide code libs that implement these new functions of KBS in sample KBS of AA's repository in the future(or exists as a separate library project under the CC organization).
Design (Attestation Agent)
We now give the design of the attachment agent supporting container image signature option2 scheme: AA will add a new KBC interface to download the policy.json file, and a new keyprovider grpc API to provide signature and public key to ocicrypt-rs.
KBC Interface
We will add a new interface in KBC interface trait, its name is get_sign_policy_file:
pub trait KbcInterface {
...
fn get_sign_policy_file(&mut self) -> Result<std::fs::File> {
...(default implement)
};
}
This trait will be called immediately after KBC initialization is completed in the startup phase of AA. The functions it realized are: connect to KBS, start an attestation, negotiate the key after attestation, establish an encryption channel, then download the policy.json file from KBS, and then return the file descriptor to the caller.
In order to maintain compatibility with previous KBCs and pre-attestation KBCs, this trait will provide a default implementation (generate the simplest policy.json) to ensure that KBCs that do not implement it can still run normally.
KeyProvider API
We will extend the keyprovider protocol and add a new grpc API:
syntax = "proto3";
package keyprovider;
...
message keyProviderVerifySignatureInput {
bytes KeyProviderVerifySignatureInput = 1;
}
message keyProviderVerifySignatureOutput {
bytes KeyProviderVerifySignatureOutput = 1;
}
service KeyProviderService {
...
rpc VerifySignature(keyProviderVerifySignatureInput) returns (keyProviderVerifySignatureOutput) {};
}
The input and output messages are JSON strings. The format definition is given below:
KeyProviderVerifySignatureInput:
{
"image": {
"manifest-digest": "sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e"
},
"identity": {
"docker-reference": "docker.io/library/busybox:latest"
}
}
"manifest-digest" represents the digest of the image manifest blob of the signed container image, but in the specific implementation, please pay attention to:
-
The image manifest of a single container image may contain the digest value of multiple image manifest using different digest algorithms.
-
If the manifest contained in the container image is signed manifest defined by docker(including image manifest and additional manifest signatures), then this manifest digest field represents the "JSON web signature" part of the manifest signature in the signed manifest, rather than the digest of the image manifest blob in the container image.
"docker-reference" is a way to describe container image. In the currently used red hat simple signaling scheme, only this way is supported.
KeyProviderVerifySignatureOutput:
{
"algorithm": "",
"key-length": "",
"public-key": "<pub-key>",
"signature": "<signature-content>"
}
"algorithm" and "key-length" field indicates the public key length and signature algorithm used to verify the signature. The content of the "public key" field contains the public key required to verify the signature.
"signature" is the signature of the container image, which is embodied as a character stream here. Please refer to here for its specific content format.