From d137d5067b72578279a268c93405a8dda5b8bcff Mon Sep 17 00:00:00 2001 From: dervoeti Date: Wed, 10 Jan 2024 21:19:18 +0100 Subject: [PATCH 1/8] wip --- .../verify-signatures/kyverno-policy.yaml | 26 ------------- .../stackable-image-policy.yaml | 15 +++++++ ...ling_verification_of_image_signatures.adoc | 39 ++++++++++++------- 3 files changed, 40 insertions(+), 40 deletions(-) delete mode 100644 modules/tutorials/examples/verify-signatures/kyverno-policy.yaml create mode 100644 modules/tutorials/examples/verify-signatures/stackable-image-policy.yaml diff --git a/modules/tutorials/examples/verify-signatures/kyverno-policy.yaml b/modules/tutorials/examples/verify-signatures/kyverno-policy.yaml deleted file mode 100644 index 808371e45..000000000 --- a/modules/tutorials/examples/verify-signatures/kyverno-policy.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: kyverno.io/v1 -kind: ClusterPolicy -metadata: - name: verify-image-signatures - namespace: default -spec: - validationFailureAction: Enforce - webhookTimeoutSeconds: 30 - failurePolicy: Fail - rules: - - name: verify-stackable-signatures - match: - any: - - resources: - kinds: - - Pod - verifyImages: - - imageReferences: - - docker.stackable.tech/*-operator:23.7.* - attestors: - - entries: - - keyless: - issuer: "https://token.actions.githubusercontent.com" - subject: "https://github.com/stackabletech/*-operator/.github/workflows/build.yml@refs/tags/23.7.*" - rekor: - url: https://rekor.sigstore.dev \ No newline at end of file diff --git a/modules/tutorials/examples/verify-signatures/stackable-image-policy.yaml b/modules/tutorials/examples/verify-signatures/stackable-image-policy.yaml new file mode 100644 index 000000000..b38421206 --- /dev/null +++ b/modules/tutorials/examples/verify-signatures/stackable-image-policy.yaml @@ -0,0 +1,15 @@ +apiVersion: policy.sigstore.dev/v1alpha1 +kind: ClusterImagePolicy +metadata: + name: stackable-image-is-signed-by-github-actions +spec: + images: + - glob: "**.stackable.tech/**" + authorities: + - keyless: + url: https://fulcio.sigstore.dev + identities: + - issuer: https://token.actions.githubusercontent.com + subjectRegExp: "https://github.com/stackabletech/.+/.github/workflows/build.yml@refs.+" + ctlog: + url: https://rekor.sigstore.dev diff --git a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc index 9bf93ae2a..f6044b4ea 100644 --- a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc +++ b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc @@ -1,33 +1,44 @@ = Enabling verification of image signatures -Image signing is a security measure that helps ensure the authenticity and integrity of container images. Starting with SDP 23.7, all our operator images are signed https://docs.sigstore.dev/cosign/openid_signing/["keyless"] (signing of product images and Helm charts will follow). By verifying these signatures, cluster administrators can ensure that the operator images pulled from Stackable's container registry are authentic and have not been tampered with. -Since Kubernetes does not have native support for verifying image signatures yet, we will use a tool called https://kyverno.io/[Kyverno] in this tutorial. +Image signing is a security measure that helps ensure the authenticity and integrity of container images. Starting with SDP 23.7, all our images are signed https://docs.sigstore.dev/cosign/openid_signing/["keyless"]. By verifying these signatures, cluster administrators can ensure that the images pulled from Stackable's container registry are authentic and have not been tampered with. +Since Kubernetes does not have native support for verifying image signatures yet, we will use a Sigstore's https://docs.sigstore.dev/policy-controller/overview/[Policy Controller] in this tutorial. -== Installing Kyverno +IMPORTANT: Releases prior to SDP 23.7 do not have signed images. If you are using an older release and enforce image signature verification, Pods with Stackable images will be prevented from starting. + +== Installing the Policy Controller Kyverno can be easily installed via Helm: [source,bash] ---- -helm repo add kyverno https://kyverno.github.io/kyverno/ +helm repo add sigstore https://sigstore.github.io/helm-charts helm repo update -helm install kyverno kyverno/kyverno -n kyverno --create-namespace +helm install --include-crds policy-controller sigstore/policy-controller ---- -Other installation methods and options to run Kyverno in a highly-available fashion are described in the https://kyverno.io/docs/installation/methods/[Kyverno documentation]. - == Creating a policy to verify image signatures -Now that Kyverno is installed, we can create a policy that verifies that all operator images that are part of the SDP 23.7 releases are signed by Stackable's CI pipeline (Github Actions): +Now that the Policy Controller is installed, we can create a policy that verifies that all images provided by Stackable are signed by Stackable's CI pipeline (Github Actions): [source,yaml] -include::example$verify-signatures/kyverno-policy.yaml[] +include::example$verify-signatures/stackable-image-policy.yaml[] -Apply this policy to the cluster by saving it as `kyverno-policy.yaml` and running: +Apply this policy to the cluster by saving it as `stackable-image-policy.yaml` and running: [source,bash] ---- -kubectl apply -f kyverno-policy.yaml +kubectl apply -f stackable-image-policy.yaml ---- -The policy will be applied to all namespaces in the cluster. It checks all newly created Pods that run any image matching the expression `docker.stackable.tech/+++*+++-operator:23.7.+++*+++` (all Stackable operators version 23.7.+++*+++) and ensures that these images have been signed by a Stackable Github Action from the release 23.7 (`https://github.com/stackabletech/+++*+++-operator/.github/workflows/build.yml@refs/tags/23.7.+++*+++`). If the signature of an operator image is invalid or missing, the policy will deny the pod creation. -For a more detailed explanation of the policy options, please refer to the https://kyverno.io/docs/writing-policies/verify-images/sigstore/#keyless-signing-and-verification[Kyverno documentation]. -If the `subject` field in the policy is changed to something like `https://github.com/test/+++*+++`, the policy will deny the creation of operator pods because the signature is no longer valid. +The policy will be applied to all namespaces in the cluster !!TODO ... that are labeled with ... !!. It checks all newly created Pods that run any image matching the expression `+++*+++.stackable.tech/+++*+++` (all images provided by Stackable) and ensures that these images have been signed by a Stackable Github Action (`https://github.com/stackabletech/.+/.github/workflows/build.yml@refs.+`). If the signature of an image is invalid or missing, the policy will deny the pod creation. +For a more detailed explanation of the policy options, please refer to the https://docs.sigstore.dev/policy-controller/overview/#configuring-image-patterns[Sigstore documentation]. +If the `subjectRegExp` field in the policy is changed to something like `https://github.com/test/.+`, the policy will deny the creation of pods with Stackable images because the signature is no longer valid. + +== Verifying image signatures in an air-gapped environment +As mentioned before, our images and Helm charts for SDP are signed keyless. Keyless signing seems to becoming the standard procedure to sign OCI artifacts, projects like https://kubernetes.io/docs/tasks/administer-cluster/verify-signed-artifacts/#verifying-image-signatures[Kubernetes] use it as well. +Describing the whole flow with all the components is out of scope for this documentation, so we will try to provide a summary of the most important parts instead: To verify that an image has been signed by Stackable, customers check that the image has a valid signature and that this signature is actually from Stackable's CI (Github Actions). More specifically, they check that the identity of the signer (a Github Actions workflow) was confirmed by a trusted authority (github.com in that case). The role of a Sigstore project called https://github.com/sigstore/fulcio[Fulcio] is issuing a certificate for exactly that: "We confirm that this signature is from 'https://github.com/stackabletech/docker-images/.github/workflows/release.yml@refs/tags/23.11.0' and 'https://token.actions.githubusercontent.com' confirmed that identity to us". +By default, the public Fulcio instance hosted by Sigstore is used for this, which is what we do at Stackable as well. + +That means, that customers wanting to verify these image signatures need to trust the Fulcio instance, which issues the certificates that guarantee the identity of the signer. The root of trust for the Sigstore components like the public Fulcio instance is provided by a framework called https://theupdateframework.io/[The Update Framework (TUF)]: +[quote,From the Sigstore documentation, https://docs.sigstore.dev/signing/overview/#root-of-trust] +Sigstore’s root of trust, which includes Fulcio’s root CA certificate and Rekor’s public key, are distributed by The Update Framework (TUF). TUF is a framework to provide secure software and file updates. TUF defines a set of protocols to protect against various types of attacks. + +The problem for air-gapped environments is that expiration of keys is built into TUF. That means, to verify image signatures continuously, customers need to update the root of trust regularly. This can be achieved by running a TUF mirror, if possible, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[here], or by regularly updating a snapshot of the TUF repository, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[here]. You can then refer to the newly created `TrustRoot` in the policy via the `trustRootRef` attribute (as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[here]). From 372dcf7d424df674a23debd4eca609413609d6bf Mon Sep 17 00:00:00 2001 From: dervoeti Date: Fri, 12 Jan 2024 19:47:47 +0100 Subject: [PATCH 2/8] Improved airgap image verification docs --- .../enabling_verification_of_image_signatures.adoc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc index f6044b4ea..0ea64b2ba 100644 --- a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc +++ b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc @@ -33,12 +33,10 @@ For a more detailed explanation of the policy options, please refer to the https If the `subjectRegExp` field in the policy is changed to something like `https://github.com/test/.+`, the policy will deny the creation of pods with Stackable images because the signature is no longer valid. == Verifying image signatures in an air-gapped environment -As mentioned before, our images and Helm charts for SDP are signed keyless. Keyless signing seems to becoming the standard procedure to sign OCI artifacts, projects like https://kubernetes.io/docs/tasks/administer-cluster/verify-signed-artifacts/#verifying-image-signatures[Kubernetes] use it as well. -Describing the whole flow with all the components is out of scope for this documentation, so we will try to provide a summary of the most important parts instead: To verify that an image has been signed by Stackable, customers check that the image has a valid signature and that this signature is actually from Stackable's CI (Github Actions). More specifically, they check that the identity of the signer (a Github Actions workflow) was confirmed by a trusted authority (github.com in that case). The role of a Sigstore project called https://github.com/sigstore/fulcio[Fulcio] is issuing a certificate for exactly that: "We confirm that this signature is from 'https://github.com/stackabletech/docker-images/.github/workflows/release.yml@refs/tags/23.11.0' and 'https://token.actions.githubusercontent.com' confirmed that identity to us". +As mentioned before, our images and Helm charts for SDP are signed keyless. Keyless signing is more complex than "classic" signing with a private and public key, but brings several https://www.chainguard.dev/unchained/benefits-of-keyless-software-signing[benefits]. Projects like https://kubernetes.io/docs/tasks/administer-cluster/verify-signed-artifacts/#verifying-image-signatures[Kubernetes] use it as well. +Describing the whole flow with all the components is out of scope for this documentation, so we will try to provide a summary of the most important parts instead: To verify that an image has been signed by Stackable, customers check that the image has a valid signature and that this signature was created by Stackable's CI (Github Actions). More specifically, they check that the identity of the signer (a Github Actions workflow) was confirmed by a trusted authority (github.com in that case). The role of the Sigstore project https://github.com/sigstore/fulcio[Fulcio] is issuing a certificate for exactly that: "This Fulcio instance confirms that this signature was created by 'https://github.com/stackabletech/docker-images/.github/workflows/release.yml@refs/tags/23.11.0' and 'https://token.actions.githubusercontent.com' confirmed that identity". By default, the public Fulcio instance hosted by Sigstore is used for this, which is what we do at Stackable as well. -That means, that customers wanting to verify these image signatures need to trust the Fulcio instance, which issues the certificates that guarantee the identity of the signer. The root of trust for the Sigstore components like the public Fulcio instance is provided by a framework called https://theupdateframework.io/[The Update Framework (TUF)]: -[quote,From the Sigstore documentation, https://docs.sigstore.dev/signing/overview/#root-of-trust] -Sigstore’s root of trust, which includes Fulcio’s root CA certificate and Rekor’s public key, are distributed by The Update Framework (TUF). TUF is a framework to provide secure software and file updates. TUF defines a set of protocols to protect against various types of attacks. - -The problem for air-gapped environments is that expiration of keys is built into TUF. That means, to verify image signatures continuously, customers need to update the root of trust regularly. This can be achieved by running a TUF mirror, if possible, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[here], or by regularly updating a snapshot of the TUF repository, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[here]. You can then refer to the newly created `TrustRoot` in the policy via the `trustRootRef` attribute (as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[here]). +That means customers wanting to verify these image signatures need to trust the Fulcio instance, which issues the certificates that guarantee the identity of the signer. The root of trust for the Sigstore components like the public Fulcio instance is provided by a framework called https://docs.sigstore.dev/signing/overview/#root-of-trust[The Update Framework (TUF)]. Thankfully, the whole initialization of the root of trust is handled by the policy controller. +The problem for air-gapped environments is that expiration of keys is built into TUF. That means, to verify image signatures continuously, the policy controller needs an up-to-date version of the root of trust. In a environment with internet access, it can just connect to Sigstore's TUF repository and get the latest contents. In an air-gapped environment, this is not possible. It is possible, however, to specify a TUF mirror that is reachable from the air-gapped environment, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[here]. This mirror could for example serve the contents of https://tuf-repo-cdn.sigstore.dev via HTTPS. Another way is to provide a base64 encoded, gzipped tarball of the TUF repository, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[here]. Remember that in both cases the contents of the TUF repository need to be updated regularly. The Sigstore TUF repository is hosted at https://tuf-repo-cdn.sigstore.dev/ and the contents are also available https://github.com/sigstore/root-signing/tree/main/repository/repository[on github]. +You can then refer to the newly created `TrustRoot` (which is configured to use the TUF mirror) in the policy via the `trustRootRef` attribute, as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[in the policy controller's documentation]. From ed90c5372604e8a9ec45aab552f9c60916756142 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Fri, 12 Jan 2024 20:06:12 +0100 Subject: [PATCH 3/8] Fixes and wording improvements --- ...ling_verification_of_image_signatures.adoc | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc index 0ea64b2ba..43a7c82e6 100644 --- a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc +++ b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc @@ -6,15 +6,18 @@ Since Kubernetes does not have native support for verifying image signatures yet IMPORTANT: Releases prior to SDP 23.7 do not have signed images. If you are using an older release and enforce image signature verification, Pods with Stackable images will be prevented from starting. == Installing the Policy Controller -Kyverno can be easily installed via Helm: +The Policy Controller can be easily installed via Helm: [source,bash] ---- helm repo add sigstore https://sigstore.github.io/helm-charts helm repo update -helm install --include-crds policy-controller sigstore/policy-controller +helm install policy-controller sigstore/policy-controller ---- +The default settings might not be appropriate for your environment, please refer to the https://artifacthub.io/packages/helm/sigstore/policy-controller[configurable values] for more information. + + == Creating a policy to verify image signatures Now that the Policy Controller is installed, we can create a policy that verifies that all images provided by Stackable are signed by Stackable's CI pipeline (Github Actions): @@ -28,15 +31,22 @@ Apply this policy to the cluster by saving it as `stackable-image-policy.yaml` a kubectl apply -f stackable-image-policy.yaml ---- -The policy will be applied to all namespaces in the cluster !!TODO ... that are labeled with ... !!. It checks all newly created Pods that run any image matching the expression `+++*+++.stackable.tech/+++*+++` (all images provided by Stackable) and ensures that these images have been signed by a Stackable Github Action (`https://github.com/stackabletech/.+/.github/workflows/build.yml@refs.+`). If the signature of an image is invalid or missing, the policy will deny the pod creation. +If you used the default values for the Helm chart, policies will only be applied to namespaces labeled with `policy.sigstore.dev/include: "true"`. +Add a label for the namespace where you deployed SDP: +[source,bash] +---- +kubectl label namespace stackable policy.sigstore.dev/include=true +---- + +The Policy Controller checks all newly created Pods in that namespace which run any image matching `+++**+++.stackable.tech/+++**+++` (all images provided by Stackable) and ensures that these images have been signed by a Stackable Github Action (`https://github.com/stackabletech/.+/.github/workflows/build.yml@refs.+`). If the signature of an image is invalid or missing, the policy will deny the pod creation. For a more detailed explanation of the policy options, please refer to the https://docs.sigstore.dev/policy-controller/overview/#configuring-image-patterns[Sigstore documentation]. -If the `subjectRegExp` field in the policy is changed to something like `https://github.com/test/.+`, the policy will deny the creation of pods with Stackable images because the signature is no longer valid. +If the `subjectRegExp` field in the policy is changed to something like `https://github.com/test/.+`, the policy will deny the creation of pods with Stackable images because the identity of the subject that signed the image will no longer match. == Verifying image signatures in an air-gapped environment As mentioned before, our images and Helm charts for SDP are signed keyless. Keyless signing is more complex than "classic" signing with a private and public key, but brings several https://www.chainguard.dev/unchained/benefits-of-keyless-software-signing[benefits]. Projects like https://kubernetes.io/docs/tasks/administer-cluster/verify-signed-artifacts/#verifying-image-signatures[Kubernetes] use it as well. Describing the whole flow with all the components is out of scope for this documentation, so we will try to provide a summary of the most important parts instead: To verify that an image has been signed by Stackable, customers check that the image has a valid signature and that this signature was created by Stackable's CI (Github Actions). More specifically, they check that the identity of the signer (a Github Actions workflow) was confirmed by a trusted authority (github.com in that case). The role of the Sigstore project https://github.com/sigstore/fulcio[Fulcio] is issuing a certificate for exactly that: "This Fulcio instance confirms that this signature was created by 'https://github.com/stackabletech/docker-images/.github/workflows/release.yml@refs/tags/23.11.0' and 'https://token.actions.githubusercontent.com' confirmed that identity". By default, the public Fulcio instance hosted by Sigstore is used for this, which is what we do at Stackable as well. -That means customers wanting to verify these image signatures need to trust the Fulcio instance, which issues the certificates that guarantee the identity of the signer. The root of trust for the Sigstore components like the public Fulcio instance is provided by a framework called https://docs.sigstore.dev/signing/overview/#root-of-trust[The Update Framework (TUF)]. Thankfully, the whole initialization of the root of trust is handled by the policy controller. -The problem for air-gapped environments is that expiration of keys is built into TUF. That means, to verify image signatures continuously, the policy controller needs an up-to-date version of the root of trust. In a environment with internet access, it can just connect to Sigstore's TUF repository and get the latest contents. In an air-gapped environment, this is not possible. It is possible, however, to specify a TUF mirror that is reachable from the air-gapped environment, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[here]. This mirror could for example serve the contents of https://tuf-repo-cdn.sigstore.dev via HTTPS. Another way is to provide a base64 encoded, gzipped tarball of the TUF repository, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[here]. Remember that in both cases the contents of the TUF repository need to be updated regularly. The Sigstore TUF repository is hosted at https://tuf-repo-cdn.sigstore.dev/ and the contents are also available https://github.com/sigstore/root-signing/tree/main/repository/repository[on github]. -You can then refer to the newly created `TrustRoot` (which is configured to use the TUF mirror) in the policy via the `trustRootRef` attribute, as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[in the policy controller's documentation]. +That means customers wanting to verify these image signatures need to trust the Fulcio instance, which issues the certificates that guarantee the identity of the signer. The root of trust for the Sigstore components like the public Fulcio instance is provided by a framework called https://docs.sigstore.dev/signing/overview/#root-of-trust[The Update Framework (TUF)]. Thankfully, the whole initialization of the root of trust is handled by the Policy Controller. +The problem for air-gapped environments is that expiration of keys is built into TUF. That means, to verify image signatures continuously, the Policy Controller needs an up-to-date version of the root of trust. In a environment with internet access, it can just connect to Sigstore's TUF repository and get the latest contents. In an air-gapped environment, this is not possible. It is possible, however, to specify a TUF mirror that is reachable from the air-gapped environment, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[here]. This mirror could for example serve the contents of https://tuf-repo-cdn.sigstore.dev via HTTPS. Another way is to provide a base64 encoded, gzipped tarball of the TUF repository, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[here]. Remember that in both cases the contents of the TUF repository need to be updated regularly. The Sigstore TUF repository is hosted at https://tuf-repo-cdn.sigstore.dev/ and the contents are also available https://github.com/sigstore/root-signing/tree/main/repository/repository[on github]. +You can then refer to the newly created `TrustRoot` (which is configured to use the TUF mirror) in the policy via the `trustRootRef` attribute, as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[in the Policy Controller's documentation]. From 25f5b5a1cf5dcbbdbe133c5eb90706d6a33f3216 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Mon, 15 Jan 2024 14:45:07 +0100 Subject: [PATCH 4/8] Rewording / improved formatting --- ...ling_verification_of_image_signatures.adoc | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc index 43a7c82e6..145909a11 100644 --- a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc +++ b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc @@ -1,9 +1,9 @@ = Enabling verification of image signatures -Image signing is a security measure that helps ensure the authenticity and integrity of container images. Starting with SDP 23.7, all our images are signed https://docs.sigstore.dev/cosign/openid_signing/["keyless"]. By verifying these signatures, cluster administrators can ensure that the images pulled from Stackable's container registry are authentic and have not been tampered with. -Since Kubernetes does not have native support for verifying image signatures yet, we will use a Sigstore's https://docs.sigstore.dev/policy-controller/overview/[Policy Controller] in this tutorial. +Image signing is a security measure that helps ensure the authenticity and integrity of container images. Starting with SDP 23.11, all our images are signed https://docs.sigstore.dev/cosign/openid_signing/["keyless"]. By verifying these signatures, cluster administrators can ensure that the images pulled from Stackable's container registry are authentic and have not been tampered with. +Since Kubernetes does not have native support for verifying image signatures yet, we will use Sigstore's https://docs.sigstore.dev/policy-controller/overview/[Policy Controller] in this tutorial. -IMPORTANT: Releases prior to SDP 23.7 do not have signed images. If you are using an older release and enforce image signature verification, Pods with Stackable images will be prevented from starting. +IMPORTANT: Releases prior to SDP 23.11 do not have signed images. If you are using an older release and enforce image signature verification, Pods with Stackable images will be prevented from starting. == Installing the Policy Controller The Policy Controller can be easily installed via Helm: @@ -15,7 +15,7 @@ helm repo update helm install policy-controller sigstore/policy-controller ---- -The default settings might not be appropriate for your environment, please refer to the https://artifacthub.io/packages/helm/sigstore/policy-controller[configurable values] for more information. +The default settings might not be appropriate for your environment, please refer to the https://artifacthub.io/packages/helm/sigstore/policy-controller[configurable values for the Helm chart] for more information. == Creating a policy to verify image signatures @@ -38,15 +38,21 @@ Add a label for the namespace where you deployed SDP: kubectl label namespace stackable policy.sigstore.dev/include=true ---- -The Policy Controller checks all newly created Pods in that namespace which run any image matching `+++**+++.stackable.tech/+++**+++` (all images provided by Stackable) and ensures that these images have been signed by a Stackable Github Action (`https://github.com/stackabletech/.+/.github/workflows/build.yml@refs.+`). If the signature of an image is invalid or missing, the policy will deny the pod creation. +The Policy Controller checks all newly created Pods in this namespace that run any image matching `+++**+++.stackable.tech/+++**+++` (this matches images provided by Stackable) and ensures that these images have been signed by a Stackable Github Action. If the signature of an image is invalid or missing, the policy will deny the pod creation. For a more detailed explanation of the policy options, please refer to the https://docs.sigstore.dev/policy-controller/overview/#configuring-image-patterns[Sigstore documentation]. -If the `subjectRegExp` field in the policy is changed to something like `https://github.com/test/.+`, the policy will deny the creation of pods with Stackable images because the identity of the subject that signed the image will no longer match. +If the `subjectRegExp` field in the policy is changed to something like `https://github.com/test/.+`, the policy will deny the creation of pods with Stackable images because the identity of the subject that signed the image (a Stackable Github Action Workflow) will no longer match the expression specified in the policy. == Verifying image signatures in an air-gapped environment -As mentioned before, our images and Helm charts for SDP are signed keyless. Keyless signing is more complex than "classic" signing with a private and public key, but brings several https://www.chainguard.dev/unchained/benefits-of-keyless-software-signing[benefits]. Projects like https://kubernetes.io/docs/tasks/administer-cluster/verify-signed-artifacts/#verifying-image-signatures[Kubernetes] use it as well. -Describing the whole flow with all the components is out of scope for this documentation, so we will try to provide a summary of the most important parts instead: To verify that an image has been signed by Stackable, customers check that the image has a valid signature and that this signature was created by Stackable's CI (Github Actions). More specifically, they check that the identity of the signer (a Github Actions workflow) was confirmed by a trusted authority (github.com in that case). The role of the Sigstore project https://github.com/sigstore/fulcio[Fulcio] is issuing a certificate for exactly that: "This Fulcio instance confirms that this signature was created by 'https://github.com/stackabletech/docker-images/.github/workflows/release.yml@refs/tags/23.11.0' and 'https://token.actions.githubusercontent.com' confirmed that identity". +As mentioned before, our images and Helm charts for SDP are signed keyless. Keyless signing is more complex than "classic" signing with a private and public key, but brings several https://www.chainguard.dev/unchained/benefits-of-keyless-software-signing[benefits]. It's also in line with Kubernetes, https://kubernetes.io/docs/tasks/administer-cluster/verify-signed-artifacts/[which uses keyless signing as well]. + +Describing the whole flow with all the components is out of scope for this documentation, so we will try to provide a summary of the most important parts instead: + +To verify that an image has been signed by Stackable, customers check that the image has a valid signature and that this signature was created by Stackable's CI (Github Actions). More specifically, they check that the identity of the signer is one of Stackable's Github Actions workflows and that this identity has been confirmed by a trusted authority (Github in that case). The role of the Sigstore project https://github.com/sigstore/fulcio[Fulcio] is to issue a certificate for exactly that: + +"This Fulcio instance confirms that this signature was created by `https://github.com/stackabletech/docker-images/.github/workflows/release.yml@refs/tags/23.11.0` and `https://token.actions.githubusercontent.com` confirmed that identity". + By default, the public Fulcio instance hosted by Sigstore is used for this, which is what we do at Stackable as well. -That means customers wanting to verify these image signatures need to trust the Fulcio instance, which issues the certificates that guarantee the identity of the signer. The root of trust for the Sigstore components like the public Fulcio instance is provided by a framework called https://docs.sigstore.dev/signing/overview/#root-of-trust[The Update Framework (TUF)]. Thankfully, the whole initialization of the root of trust is handled by the Policy Controller. +That means customers wanting to verify these image signatures need to trust the Fulcio instance, which issues the certificates that attest the identity of the signer. The root of trust for Sigstore components like the public Fulcio instance is distributed by a framework called https://docs.sigstore.dev/signing/overview/#root-of-trust[The Update Framework (TUF)]. Thankfully, the whole initialization of the root of trust via TUF is handled by the Policy Controller. + The problem for air-gapped environments is that expiration of keys is built into TUF. That means, to verify image signatures continuously, the Policy Controller needs an up-to-date version of the root of trust. In a environment with internet access, it can just connect to Sigstore's TUF repository and get the latest contents. In an air-gapped environment, this is not possible. It is possible, however, to specify a TUF mirror that is reachable from the air-gapped environment, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[here]. This mirror could for example serve the contents of https://tuf-repo-cdn.sigstore.dev via HTTPS. Another way is to provide a base64 encoded, gzipped tarball of the TUF repository, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[here]. Remember that in both cases the contents of the TUF repository need to be updated regularly. The Sigstore TUF repository is hosted at https://tuf-repo-cdn.sigstore.dev/ and the contents are also available https://github.com/sigstore/root-signing/tree/main/repository/repository[on github]. + You can then refer to the newly created `TrustRoot` (which is configured to use the TUF mirror) in the policy via the `trustRootRef` attribute, as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[in the Policy Controller's documentation]. From 846fd19ee59c565c6c92d85625f37dc661fb7279 Mon Sep 17 00:00:00 2001 From: Felix Hennig Date: Tue, 16 Jan 2024 14:24:58 +0100 Subject: [PATCH 5/8] reformulate --- ...ling_verification_of_image_signatures.adoc | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc index 145909a11..7dbf47982 100644 --- a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc +++ b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc @@ -43,8 +43,50 @@ For a more detailed explanation of the policy options, please refer to the https If the `subjectRegExp` field in the policy is changed to something like `https://github.com/test/.+`, the policy will deny the creation of pods with Stackable images because the identity of the subject that signed the image (a Stackable Github Action Workflow) will no longer match the expression specified in the policy. == Verifying image signatures in an air-gapped environment + +// intro As mentioned before, our images and Helm charts for SDP are signed keyless. Keyless signing is more complex than "classic" signing with a private and public key, but brings several https://www.chainguard.dev/unchained/benefits-of-keyless-software-signing[benefits]. It's also in line with Kubernetes, https://kubernetes.io/docs/tasks/administer-cluster/verify-signed-artifacts/[which uses keyless signing as well]. +=== The general setup + +The Policy Controller needs an up-to-date version of the root of trust, this is distributed as a collection of files and in an online setting it is automatically fetched from the https://tuf-repo-cdn.sigstore.dev/[Sigstore TUF Repo CDN]. + +NOTE: https://theupdateframework.io/[The Update Framework (TUF)] is the mechanism used by the Policy Controller to update the root of trust. + +In an air-gapped environment, the CDN is not available, and so instead you have to provide the root of trust files yourself. +There are multiple ways to do this, and you should pick the way that works best for your air-gapped environment. + +The files hosted in the CDN are available also on https://github.com/sigstore/root-signing/tree/main/repository/repository[GitHub]. +This is the source where you need to get the files. +Then there are two ways to provide these files to the Policy Controller inside of your air-gapped Kubernetes. +Either by hosting them with a HTTP server that is reachable by the Policy Controller, or by zipping the files, serializing them and putting them directly into a custom resource. +For both options we refer to the Sigstore documentation: https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[configuring a mirror] or https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[serializing the files into a custom resource]. + +Both options yield you a TrustRoot custom resource which you then need to configure in your ClusterImagePolicy. +This is done via the `trustRootRef` attribute, as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[in the Policy Controller's documentation]. + +=== Updating + +The problem for air-gapped environments is that expiration of keys is built into TUF. +That means, to verify image signatures continuously, the Policy Controller needs an up-to-date version of the root of trust. + +Depending on which way you are providing the root of trust (mirror or direct files), you need to update that accordingly. +If your cluster has access to for example a bastion host that in turn has limited internet access, configuring a mirror might be the easier way to go for you. +You might even be able to simply configure a reverse proxy to https://tuf-repo-cdn.sigstore.dev/ to avoid manually updating files periodically. + +If your setup is completely air-gapped, you will have to do periodic manual updates of the files that you deployed earlier. +It is not clear how often the root of trust needs to be updated (TODO: research if we can find out more) + +Either refresh your mirror or periodically supply the files directly via other methods into your airgapped system. + +The Policy Controller does not need to be restarted. (TODO verify) + +== Further reading + +... + +=== Background: How it usually works online with Fulcio + Describing the whole flow with all the components is out of scope for this documentation, so we will try to provide a summary of the most important parts instead: + To verify that an image has been signed by Stackable, customers check that the image has a valid signature and that this signature was created by Stackable's CI (Github Actions). More specifically, they check that the identity of the signer is one of Stackable's Github Actions workflows and that this identity has been confirmed by a trusted authority (Github in that case). The role of the Sigstore project https://github.com/sigstore/fulcio[Fulcio] is to issue a certificate for exactly that: + "This Fulcio instance confirms that this signature was created by `https://github.com/stackabletech/docker-images/.github/workflows/release.yml@refs/tags/23.11.0` and `https://token.actions.githubusercontent.com` confirmed that identity". @@ -52,7 +94,3 @@ To verify that an image has been signed by Stackable, customers check that the i By default, the public Fulcio instance hosted by Sigstore is used for this, which is what we do at Stackable as well. That means customers wanting to verify these image signatures need to trust the Fulcio instance, which issues the certificates that attest the identity of the signer. The root of trust for Sigstore components like the public Fulcio instance is distributed by a framework called https://docs.sigstore.dev/signing/overview/#root-of-trust[The Update Framework (TUF)]. Thankfully, the whole initialization of the root of trust via TUF is handled by the Policy Controller. - -The problem for air-gapped environments is that expiration of keys is built into TUF. That means, to verify image signatures continuously, the Policy Controller needs an up-to-date version of the root of trust. In a environment with internet access, it can just connect to Sigstore's TUF repository and get the latest contents. In an air-gapped environment, this is not possible. It is possible, however, to specify a TUF mirror that is reachable from the air-gapped environment, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[here]. This mirror could for example serve the contents of https://tuf-repo-cdn.sigstore.dev via HTTPS. Another way is to provide a base64 encoded, gzipped tarball of the TUF repository, as explained https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[here]. Remember that in both cases the contents of the TUF repository need to be updated regularly. The Sigstore TUF repository is hosted at https://tuf-repo-cdn.sigstore.dev/ and the contents are also available https://github.com/sigstore/root-signing/tree/main/repository/repository[on github]. - -You can then refer to the newly created `TrustRoot` (which is configured to use the TUF mirror) in the policy via the `trustRootRef` attribute, as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[in the Policy Controller's documentation]. From 3801cf132dbbb49e7cfae904f5581e568432670f Mon Sep 17 00:00:00 2001 From: dervoeti Date: Tue, 16 Jan 2024 16:18:00 +0100 Subject: [PATCH 6/8] Rewording / More explanations --- ...ling_verification_of_image_signatures.adoc | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc index 7dbf47982..65243ba08 100644 --- a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc +++ b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc @@ -44,25 +44,34 @@ If the `subjectRegExp` field in the policy is changed to something like `https:/ == Verifying image signatures in an air-gapped environment -// intro -As mentioned before, our images and Helm charts for SDP are signed keyless. Keyless signing is more complex than "classic" signing with a private and public key, but brings several https://www.chainguard.dev/unchained/benefits-of-keyless-software-signing[benefits]. It's also in line with Kubernetes, https://kubernetes.io/docs/tasks/administer-cluster/verify-signed-artifacts/[which uses keyless signing as well]. +As mentioned before, our images and Helm charts for SDP are signed keyless. Keyless signing is more complex than "classic" signing with a private and public key, especially when you want to verify signatures in an air-gapped environment. However, it brings several https://www.chainguard.dev/unchained/benefits-of-keyless-software-signing[benefits] and by signing our images keyless, we're also in line with Kubernetes, https://kubernetes.io/docs/tasks/administer-cluster/verify-signed-artifacts/[which uses keyless signing as well]. === The general setup -The Policy Controller needs an up-to-date version of the root of trust, this is distributed as a collection of files and in an online setting it is automatically fetched from the https://tuf-repo-cdn.sigstore.dev/[Sigstore TUF Repo CDN]. +To verify keyless signatures, the Policy Controller needs an up-to-date version of the root of trust, which is distributed as a collection of files (to put it simply). In an online setting, these files are automatically fetched from a CDN, by default the https://tuf-repo-cdn.sigstore.dev/[Sigstore TUF Repo CDN]. -NOTE: https://theupdateframework.io/[The Update Framework (TUF)] is the mechanism used by the Policy Controller to update the root of trust. +NOTE: https://docs.sigstore.dev/signing/overview/#root-of-trust[The Update Framework (TUF)] is the mechanism used by the Policy Controller to initialize and update the root of trust. -In an air-gapped environment, the CDN is not available, and so instead you have to provide the root of trust files yourself. -There are multiple ways to do this, and you should pick the way that works best for your air-gapped environment. +In an air-gapped environment, this CDN is not reachable, so instead you have to provide those files yourself. You can get these files from https://github.com/sigstore/root-signing/tree/main/repository/repository[GitHub]. +There two multiple ways how you can provide these files to the Policy Controller, please pick the one that works best for your air-gapped environment: -The files hosted in the CDN are available also on https://github.com/sigstore/root-signing/tree/main/repository/repository[GitHub]. -This is the source where you need to get the files. -Then there are two ways to provide these files to the Policy Controller inside of your air-gapped Kubernetes. -Either by hosting them with a HTTP server that is reachable by the Policy Controller, or by zipping the files, serializing them and putting them directly into a custom resource. -For both options we refer to the Sigstore documentation: https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[configuring a mirror] or https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[serializing the files into a custom resource]. +1. Serve them via an HTTP server that is reachable by the Policy Controller. + + Example: ++ +[source,bash] +---- +git clone https://github.com/sigstore/root-signing +cd root-signing/repository/repository +python3 -m http.server 8081 +---- ++ +Now you can provide the host's IP address and port (8081 in the example) as the mirror URL. For how to do this exactly, we refer to the https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[Policy Controller's documentation]. ++ +NOTE: Since we're using Sigstore's TUF repository, you don't have to provide the `.spec.root` attribute in the `TrustRoot` resource, `.spec.mirror` is sufficient. + +2. Packing the files into an archive, serializing them and putting them directly into a the `TrustRoot` resource. This is explained in the https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[Policy Controller's documentation]. -Both options yield you a TrustRoot custom resource which you then need to configure in your ClusterImagePolicy. +Both options yield you a `TrustRoot` custom resource which you then need to configure in your `ClusterImagePolicy`. This is done via the `trustRootRef` attribute, as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[in the Policy Controller's documentation]. === Updating @@ -71,26 +80,18 @@ The problem for air-gapped environments is that expiration of keys is built into That means, to verify image signatures continuously, the Policy Controller needs an up-to-date version of the root of trust. Depending on which way you are providing the root of trust (mirror or direct files), you need to update that accordingly. -If your cluster has access to for example a bastion host that in turn has limited internet access, configuring a mirror might be the easier way to go for you. -You might even be able to simply configure a reverse proxy to https://tuf-repo-cdn.sigstore.dev/ to avoid manually updating files periodically. +If, for example, you can reach a bastion host from your air-gapped environment that has internet access, configuring a mirror might be the easier way to go for you. In that case, you could simply configure a reverse proxy to https://tuf-repo-cdn.sigstore.dev/ on the bastion host, to avoid manually updating files periodically. -If your setup is completely air-gapped, you will have to do periodic manual updates of the files that you deployed earlier. +If your setup is completely air-gapped, you will have to do periodic manual updates of the files that you deployed earlier (e.g. in the first example, you could run `git pull` daily). It is not clear how often the root of trust needs to be updated (TODO: research if we can find out more) -Either refresh your mirror or periodically supply the files directly via other methods into your airgapped system. - -The Policy Controller does not need to be restarted. (TODO verify) +The Policy Controller does not need to be restarted after the files have been updated. (TODO: verify this) == Further reading -... - -=== Background: How it usually works online with Fulcio - -Describing the whole flow with all the components is out of scope for this documentation, so we will try to provide a summary of the most important parts instead: + -To verify that an image has been signed by Stackable, customers check that the image has a valid signature and that this signature was created by Stackable's CI (Github Actions). More specifically, they check that the identity of the signer is one of Stackable's Github Actions workflows and that this identity has been confirmed by a trusted authority (Github in that case). The role of the Sigstore project https://github.com/sigstore/fulcio[Fulcio] is to issue a certificate for exactly that: + -"This Fulcio instance confirms that this signature was created by `https://github.com/stackabletech/docker-images/.github/workflows/release.yml@refs/tags/23.11.0` and `https://token.actions.githubusercontent.com` confirmed that identity". - -By default, the public Fulcio instance hosted by Sigstore is used for this, which is what we do at Stackable as well. +There's a lot more to learn about how keyless signing and verification works. We recommend the following resources: -That means customers wanting to verify these image signatures need to trust the Fulcio instance, which issues the certificates that attest the identity of the signer. The root of trust for Sigstore components like the public Fulcio instance is distributed by a framework called https://docs.sigstore.dev/signing/overview/#root-of-trust[The Update Framework (TUF)]. Thankfully, the whole initialization of the root of trust via TUF is handled by the Policy Controller. +* https://docs.sigstore.dev/signing/overview/ +* https://docs.sigstore.dev/policy-controller/overview/ +* https://www.chainguard.dev/unchained/life-of-a-sigstore-signature +* https://blog.sigstore.dev/why-you-cant-use-sigstore-without-sigstore-de1ed745f6fc/ \ No newline at end of file From 2256b0d50f3efd388c61b3a63cd738c8d29d3b4d Mon Sep 17 00:00:00 2001 From: dervoeti Date: Tue, 16 Jan 2024 16:20:13 +0100 Subject: [PATCH 7/8] Replaced "we" --- .../pages/enabling_verification_of_image_signatures.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc index 65243ba08..2105d3f1f 100644 --- a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc +++ b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc @@ -20,7 +20,7 @@ The default settings might not be appropriate for your environment, please refer == Creating a policy to verify image signatures -Now that the Policy Controller is installed, we can create a policy that verifies that all images provided by Stackable are signed by Stackable's CI pipeline (Github Actions): +Now that the Policy Controller is installed, you can create a policy that verifies that all images provided by Stackable are signed by Stackable's CI pipeline (Github Actions): [source,yaml] include::example$verify-signatures/stackable-image-policy.yaml[] @@ -67,7 +67,7 @@ python3 -m http.server 8081 + Now you can provide the host's IP address and port (8081 in the example) as the mirror URL. For how to do this exactly, we refer to the https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[Policy Controller's documentation]. + -NOTE: Since we're using Sigstore's TUF repository, you don't have to provide the `.spec.root` attribute in the `TrustRoot` resource, `.spec.mirror` is sufficient. +NOTE: Since Sigstore's TUF repository is used, you don't have to provide the `.spec.root` attribute in the `TrustRoot` resource, `.spec.mirror` is sufficient. 2. Packing the files into an archive, serializing them and putting them directly into a the `TrustRoot` resource. This is explained in the https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[Policy Controller's documentation]. From c18c9a09b7474586296fdd755cc93a598f1afd89 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Thu, 18 Jan 2024 15:44:45 +0100 Subject: [PATCH 8/8] Clarifications --- ...ling_verification_of_image_signatures.adoc | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc index 2105d3f1f..d73724f49 100644 --- a/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc +++ b/modules/tutorials/pages/enabling_verification_of_image_signatures.adoc @@ -48,15 +48,16 @@ As mentioned before, our images and Helm charts for SDP are signed keyless. Keyl === The general setup -To verify keyless signatures, the Policy Controller needs an up-to-date version of the root of trust, which is distributed as a collection of files (to put it simply). In an online setting, these files are automatically fetched from a CDN, by default the https://tuf-repo-cdn.sigstore.dev/[Sigstore TUF Repo CDN]. +To verify keyless signatures, the Policy Controller needs an up-to-date version of the root of trust, which is distributed as a collection of files (to put it simply). In an online setting, these files are automatically fetched via HTTP, by default from the https://tuf-repo-cdn.sigstore.dev/[Sigstore TUF Repo CDN]. NOTE: https://docs.sigstore.dev/signing/overview/#root-of-trust[The Update Framework (TUF)] is the mechanism used by the Policy Controller to initialize and update the root of trust. In an air-gapped environment, this CDN is not reachable, so instead you have to provide those files yourself. You can get these files from https://github.com/sigstore/root-signing/tree/main/repository/repository[GitHub]. -There two multiple ways how you can provide these files to the Policy Controller, please pick the one that works best for your air-gapped environment: +There are multiple ways how you can provide these files to the Policy Controller, please pick the one that works best for your air-gapped environment: -1. Serve them via an HTTP server that is reachable by the Policy Controller. + - Example: +* Serve them via an HTTP server that is reachable by the Policy Controller. + + If you can reach a bastion host from your air-gapped environment that has internet access, configuring a reverse proxy to https://tuf-repo-cdn.sigstore.dev/ will most likely be the easiest way to go for you. This avoids the need to manually update files periodically. + + If that's not possible, you can clone the TUF repository and serve it via HTTP, like so: + [source,bash] ---- @@ -65,27 +66,22 @@ cd root-signing/repository/repository python3 -m http.server 8081 ---- + -Now you can provide the host's IP address and port (8081 in the example) as the mirror URL. For how to do this exactly, we refer to the https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[Policy Controller's documentation]. -+ -NOTE: Since Sigstore's TUF repository is used, you don't have to provide the `.spec.root` attribute in the `TrustRoot` resource, `.spec.mirror` is sufficient. +In both cases, you can provide the host's IP address and port as the mirror URL to the policy controller. For how to do this exactly, we refer to the https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-root[Policy Controller's documentation]. -2. Packing the files into an archive, serializing them and putting them directly into a the `TrustRoot` resource. This is explained in the https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[Policy Controller's documentation]. +* Packing the files into an archive, serializing them and putting them directly into a the `TrustRoot` resource. This is explained in the https://docs.sigstore.dev/policy-controller/overview/#configuring-trustroot-for-custom-tuf-repository[Policy Controller's documentation] as well. Both options yield you a `TrustRoot` custom resource which you then need to configure in your `ClusterImagePolicy`. This is done via the `trustRootRef` attribute, as shown https://docs.sigstore.dev/policy-controller/overview/#configuring-verification-against-different-sigstore-instances[in the Policy Controller's documentation]. -=== Updating +Now there's one problem left: When starting, the Policy Controller tries to fetch the root of trust from https://tuf-repo-cdn.sigstore.dev/ by default. This will obviously fail in an air-gapped environment. To circumvent this, you can either set `.webhook.extraArgs.disable-tuf` to `true` in the Helm chart values, which disables the default initialization of the TUF repository. Or, if you configured a TUF mirror that's reachable via HTTP anyway, you can set `.webhook.extraArgs.tuf-mirror` to the URL of your mirror, to use it as the default TUF repository. In that case, you also don't have to create and configure the `TrustRoot` resource anymore. -The problem for air-gapped environments is that expiration of keys is built into TUF. -That means, to verify image signatures continuously, the Policy Controller needs an up-to-date version of the root of trust. +=== Updating the root of trust -Depending on which way you are providing the root of trust (mirror or direct files), you need to update that accordingly. -If, for example, you can reach a bastion host from your air-gapped environment that has internet access, configuring a mirror might be the easier way to go for you. In that case, you could simply configure a reverse proxy to https://tuf-repo-cdn.sigstore.dev/ on the bastion host, to avoid manually updating files periodically. +The problem for air-gapped environments is that expiration of keys is built into TUF, which means the root of trust expires after some time and needs to be updated before that happens. This only affects you if you are not using the proxy on a bastion host, as explained before. -If your setup is completely air-gapped, you will have to do periodic manual updates of the files that you deployed earlier (e.g. in the first example, you could run `git pull` daily). -It is not clear how often the root of trust needs to be updated (TODO: research if we can find out more) +So, depending on which way you are providing the files for the root of trust (serve them via HTTP or provide them as serialized repository), you need to update them accordingly. In the example above with the HTTP server, this would mean running `git pull` to get an up-to-date version of the TUF repository. -The Policy Controller does not need to be restarted after the files have been updated. (TODO: verify this) +If you provide the files as serialized repository in the `TrustRoot` resource, the Policy Controller should automatically pick up the change once you update the resource. However, when serving them over HTTP, the Policy Controller does not automatically detect the change. In that case, you can either restart the Policy Controller deployment or modify the `TrustRoot` resource (e.g. by adding an annotation or label) to trigger a reload. == Further reading