Sign Component Versions
On this page
Component versions can be signed to ensure integrity along a transport chain.
Signing requires a key pair, a signature, and, optionally, an issuer, as well as an algorithm and a name for the signature.
A component version can have multiple signatures with different names. A normalization of the component version is used for signing. See Signing Process and Normalization for more details. Currently, only signing according to the RSA PKCS #1 v1.5 signature algorithm is supported.
To follow the examples, one must follow the instructions from the section Create a Component Version.
Create a key pair using the OCM CLI:
ocm create rsakeypair acme.priv
created rsa key pair acme.priv[acme.pub]
This creates two files. One named acme.priv
for the private key and for convenience one named
acme.pub
for the public key.
Use the sign componentversion
command to sign a component version:
ocm sign componentversion --signature acme-sig --private-key=acme.priv ${OCM_REPO}//${COMPONENT}:${VERSION}
applying to version "github.com/acme/helloworld:1.0.0"[github.com/acme/helloworld:1.0.0]...
resource 0: "name"="mychart": digest SHA-256:...[ociArtifactDigest/v1]
resource 1: "name"="image": digest SHA-256:...[ociArtifactDigest/v1]
successfully signed github.com/acme/helloworld:1.0.0 (digest SHA-256:...)
You can also sign a common transport archive before uploading to a component repository:
ocm sign componentversion --signature acme-sig --private-key=acme.priv ${CTF_ARCHIVE}
applying to version "github.com/acme.org/helloworld:1.0.0"[github.com/acme.org/helloworld:1.0.0]...
resource 0: "name"="mychart": digest SHA-256:...[ociArtifactDigest/v1]
resource 1: "name"="image": digest SHA-256:...[ociArtifactDigest/v1]
successfully signed github.com/acme.org/helloworld:1.0.0 (digest SHA-256:...)
What happened?
Digests will be created for all described artifacts and referenced component versions. Then for the top-level component versions, the component-version digests are signed. The signature and digests are stored in the component descriptor(s):
jq . ${CTF_ARCHIVE}/artifact-index.json
{
"schemaVersion": 1,
"artifacts": [
{
"repository": "component-descriptors/github.com/acme.org/helloworld",
"tag": "1.0.0",
"digest": "sha256:02b12782d66fc6504f0003bb11a8e2610ac8f3d616bc1a4545df17a6e9aca5c6"
}
]
}
Beside the digests of the component descriptor layer, nothing has changed:
jq . ${CTF_ARCHIVE}/blobs/sha256.02b12782d66fc6504f0003bb11a8e2610ac8f3d616bc1a4545df17a6e9aca5c6
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.ocm.software.component.config.v1+json",
"digest": "sha256:38ba9898cb8d2c5ad34274549632836b391f5acc96268f0276d6857e87b97141",
"size": 201
},
"layers": [
{
"mediaType": "application/vnd.ocm.software.component-descriptor.v2+yaml+tar",
"digest": "sha256:c9705f0045f91c2cba49ce922dd65da27e66796e3a1fdc7a6fc01058357f2cd4",
"size": 3584
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+tar+gzip",
"digest": "sha256:125cf912d0f67b2b49e4170e684638a05a12f2fcfbdf3571e38a016273620b54",
"size": 16119
}
]
}
tar xvf ${CTF_ARCHIVE}/blobs/sha256.c9705f0045f91c2cba49ce922dd65da27e66796e3a1fdc7a6fc01058357f2cd4 -O - component-descriptor.yaml
meta:
schemaVersion: v2
component:
name: github.com/acme.org/helloworld
version: 1.0.0
provider: acme.org
componentReferences: []
repositoryContexts: []
resources:
- access:
localReference: sha256:125cf912d0f67b2b49e4170e684638a05a12f2fcfbdf3571e38a016273620b54
mediaType: application/vnd.oci.image.manifest.v1+tar+gzip
referenceName: github.com/acme.org/helloworld/podinfo:6.7.0
type: localBlob
digest:
...
name: mychart
relation: local
type: helmChart
version: 1.0.0
- access:
imageReference: gcr.io/google_containers/echoserver:1.10
type: ociArtifact
digest:
...
name: image
relation: external
type: ociArtifact
version: 1.0.0
sources: []
signatures:
- digest:
...
name: acme-sig
signature:
algorithm: RSASSA-PKCS1-V1_5
mediaType: application/vnd.ocm.signature.rsa
value: ...
Signing with Certificates
The public key from the last example cannot be validated. This can be changed by using a certificate instead of a pure public key. The certificate is signed by a CA. This ensures the authenticity of the described public key. Additionally, the common name of the certificate is validated against the issuer attribute of the signature stored in the component descriptor.
The following example creates a CA and signing certificates that are used to sign a component version.
Create the root CA:
ocm create rsakeypair --ca CN=certificate-authority root.priv
created rsa key pair root.priv[root.cert]
Create the CA that is used to create signing certificates:
ocm create rsakeypair --ca CN=acme.org --ca-key root.priv --ca-cert root.cert ca.priv
created rsa key pair ca.priv[ca.cert]
Create signing certificates from the CA:
ocm create rsakeypair CN=acme.org C=DE --ca-key ca.priv --ca-cert ca.cert --root-certs root.cert key.priv
created rsa key pair key.priv[key.cert]
You can use additional attributes of the certificate like O
, OU
or C
. See usage for details.
The certificate can be requested by any official certificate authority instead. It requires the usage types x509.KeyUsageDigitalSignature
and x509.ExtKeyUsageCodeSigning
.
For signing the component version you need to provide the issuer, then run:
ocm sign componentversion ${CTF_ARCHIVE} --private-key key.priv --public-key key.cert --ca-cert root.cert --signature acme.org --issuer CN=acme.org
applying to version "github.com/acme.org/helloworld:1.0.0"[github.com/acme.org/helloworld:1.0.0]...
resource 0: "name"="mychart": digest SHA-256:...[ociArtifactDigest/v1]
resource 1: "name"="image": digest SHA-256:...[ociArtifactDigest/v1]
successfully signed github.com/acme.org/helloworld:1.0.0 (digest SHA-256:...)
Now the issuer will be stored along the signature and will be checked when verifying with the certificate instead of the public key.
Signature Verification
You can verify a signed component version. Therefore, a public key or a certificate provided by the signer is required. If a certificate is provided, it is validated according to its certificate chain. If an official CA is used instead, you need the certificate of the used root CA.
If you followed the previous examples, you can verify the signature of a component version as follows:
ocm verify componentversions --signature acme-sig --public-key=acme.pub ${OCM_REPO}//${COMPONENT}:${VERSION}
applying to version "github.com/acme/helloworld:1.0.0"[github.com/acme/helloworld:1.0.0]...
resource 0: "name"="mychart": digest SHA-256:...[ociArtifactDigest/v1]
resource 1: "name"="image": digest SHA-256:...[ociArtifactDigest/v1]
successfully verified github.com/acme/helloworld:1.0.0 (digest SHA-256:...)
ocm verify component ${CTF_ARCHIVE} --ca-cert root.cert --issuer CN=acme.org
applying to version "github.com/acme.org/helloworld:1.0.0"[github.com/acme.org/helloworld:1.0.0]...
resource 0: "name"="mychart": digest SHA-256:...[ociArtifactDigest/v1]
resource 1: "name"="image": digest SHA-256:...[ociArtifactDigest/v1]
no public key found for signature "acme.org" -> extract key from signature
successfully verified github.com/acme.org/helloworld:1.0.0 (digest SHA-256:...)