From c5cc28e63f01e14f9d825d6389ec56210f973214 Mon Sep 17 00:00:00 2001 From: Peter Fiddes Date: Fri, 12 Jan 2024 16:23:42 +0000 Subject: [PATCH] docs: Remove unecessary additions and restructure to one policy Signed-off-by: Peter Fiddes --- .../tutorials/certificate-defaults/README.md | 160 ++++++++---------- .../cpol-mutate-certificate-required.yaml | 31 ---- ...s.yaml => cpol-mutate-certificates-0.yaml} | 4 +- .../cpol-mutate-certificates-1.yaml | 72 ++++++++ .../mutatingwebhookconfiguration-patch.yaml | 15 -- 5 files changed, 140 insertions(+), 142 deletions(-) delete mode 100644 public/docs/tutorials/certificate-defaults/cpol-mutate-certificate-required.yaml rename public/docs/tutorials/certificate-defaults/{cpol-mutate-certificate-defaults.yaml => cpol-mutate-certificates-0.yaml} (91%) create mode 100644 public/docs/tutorials/certificate-defaults/cpol-mutate-certificates-1.yaml delete mode 100644 public/docs/tutorials/certificate-defaults/mutatingwebhookconfiguration-patch.yaml diff --git a/content/docs/tutorials/certificate-defaults/README.md b/content/docs/tutorials/certificate-defaults/README.md index 2d6cd9db6be..89ea9241355 100644 --- a/content/docs/tutorials/certificate-defaults/README.md +++ b/content/docs/tutorials/certificate-defaults/README.md @@ -29,15 +29,30 @@ By setting custom defaults across our cluster, we enable platform teams to tackl Use a `ClusterPolicy` to set custom default values for the `Certificate.Spec.PrivateKey` fields. -- **To to default the `Issuer` for users within the cluster.** +- **To default the `Issuer` for users within the cluster.** Use a `ClusterPolicy` to set a custom default for the `Certificate.spec.issuerRef` fields. +- **To set a default pattern for the naming of the `Secret` where the certificate will be populated.** + + Use a `ClusterPolicy` to set a custom default value for the `spec.secretName` required field. + +- **To enable users to request a certificate by providing only one certificate identity field** + + Use a `ClusterPolicy` to set all other required `Certificate.spec` fields. + A `Certificate` resource user will then only need to supply a single specification field, one of: + - `commonName` or `literalSubject` + - `dnsNames` + - `uris` + - `emailAddresses` + - `ipAddresses` + - `otherNames` + ## Process We will set up defaults for three different scenarios, getting slightly more advanced each time: -1. Setting defaults for optional `Certificate` resource fields. +1. Setting defaults for optional `Certificate` resource fields. 2. Setting defaults for required `Certificate` resource fields. 3. Setting defaults for `Certificate` resource fields, when using `Ingress` annotations to request certificates. @@ -50,8 +65,6 @@ We will set up defaults for three different scenarios, getting slightly more adv 1. [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl): The Kubernetes command-line tool which allows you to configure Kubernetes clusters. 1. [helm](https://helm.sh/): A package manager for Kubernetes. -1. [yq](https://github.com/mikefarah/yq#install): A command-line tool for - parsing YAML with helpful coloring. 1. [kind](https://kind.sigs.k8s.io/) (**OPTIONAL**): For creating a local Kubernetes environment that runs in Docker or other container runtimes. @@ -65,7 +78,7 @@ We will set up defaults for three different scenarios, getting slightly more adv kind create cluster --name defaults ``` - > ⏲ It should take less than 1 minute to create the cluster, depending on your machine. + > ⏲ It should take less than one minute to create the cluster, depending on your machine. > > ⚠️ This cluster is only suitable for learning purposes. It is not suitable for production use. @@ -118,7 +131,6 @@ Once you have your cluster environment, install the required Kubernetes packages > - [Kyverno installation instructions](https://kyverno.io/docs/installation/methods/#install-kyverno-using-helm) > - [ingress-nginx installation instructions](https://kubernetes.github.io/ingress-nginx/deploy/) - # Setting Defaults The main tutorial starts here with some background, before tackling each of the three scenarios. @@ -141,26 +153,26 @@ That means anyone can follow this tutorial even without their own domain. ## 1 - Defaulting optional fields -In this section we will create rules which set 3 fields for all `Certificate` resources automatically. -None of the 3 fields here are required fields, but they might need to be set depending on platform and issuer preferences. +In this section we will create rules which set three fields for all `Certificate` resources automatically. +None of the three fields here are required fields, but they might need to be set depending on platform and issuer preferences. These rules will: - Set a default value of: `revisionHistoryLimit: 2`. -- Set a default value of `Always` under `spec.privateKey.rotationPolicy`. +- Set a [default value of `Always` under `spec.privateKey.rotationPolicy`](../../usage/certificate/#the-rotationpolicy-setting). - Set defaults for all `spec.privateKey` fields. -> ℹ️ Note how these rules tackle the first two of our [3 uses cases](#use-cases). +> ℹ️ Note how these rules tackle the first two of our [uses cases](#use-cases). 1. First take a look at the `ClusterPolicy`: - ```yaml file=../../../../public/docs/tutorials/certificate-defaults/cpol-mutate-certificate-defaults.yaml + ```yaml file=../../../../public/docs/tutorials/certificate-defaults/cpol-mutate-certificates-0.yaml ``` - 🔗 `cpol-mutate-certificate-defaults.yaml` + 🔗 `cpol-mutate-certificates-0.yaml` 1. Apply the policy to the cluster and check that it is ready: ```shell - kubectl apply -f cpol-mutate-certificate-defaults.yaml + kubectl apply -f cpol-mutate-certificates-0.yaml kubectl get cpol ``` @@ -168,7 +180,7 @@ These rules will: ```log NAME BACKGROUND VALIDATE ACTION READY AGE MESSAGE - 0-mutate-certificate-defaults true Audit True 4s Ready + mutate-certificates true Audit True 4s Ready ``` 1. Now inspect the "test-revision" `Certificate`: @@ -258,27 +270,29 @@ These rules will: ## 2 - Defaulting required fields > ⚠️ This section requires cert-manager v1.14.x or newer to work properly out of the box. -> If using an older version of cert-manager, see the [Appendix](#cert-manager-version-requirement) section for a full explanation. +> See the [Appendix](#cert-manager-version-requirement) section for details. Now we can set a Kyverno `ClusterPolicy` to apply default values to any of the `Certificate` fields. This includes the *required* fields. In our example `ClusterPolicy` we will do two things: -- Apply a default `secretName` that is the name of the Certificate object suffixed with "-cert". - Set the relevant `issuerRef` fields to default to use the "our-corp-issuer" `ClusterIssuer`. +- Apply a default `secretName` that is the name of the `Certificate` object suffixed with "-cert". -> ℹ️ Note how the second rule is tackling the third of our [three uses cases](#use-cases). +> ℹ️ Note how these rules are tackling the third and fourth [uses cases](#use-cases). 1. Here is the `ClusterPolicy` resource to set both fields with defaults: - ```yaml file=../../../../public/docs/tutorials/certificate-defaults/cpol-mutate-certificate-required.yaml + ```yaml file=../../../../public/docs/tutorials/certificate-defaults/cpol-mutate-certificates-1.yaml ``` - 🔗 `cpol-mutate-certificate-required.yaml` + 🔗 `cpol-mutate-certificates-1.yaml` + + This `ClusterPolicy` is an extension of the policy we applied previously. 1. Apply this policy: ```shell - kubectl apply -f cpol-mutate-certificate-required.yaml + kubectl apply -f cpol-mutate-certificates-1.yaml ``` You should now see two `ClusterPolicy` resources if you run: @@ -291,21 +305,10 @@ In our example `ClusterPolicy` we will do two things: ```shell NAME ADMISSION BACKGROUND VALIDATE ACTION READY AGE MESSAGE - 0-mutate-certificate-defaults true true Audit True 3m6s Ready - 1-mutate-certificate-required true true Audit True 4s Ready - ``` - -1. Patch the previous policy we applied to disable schema validation after mutation: - - ```shell - kubectl patch cpol 0-mutate-certificate-defaults --type=merge -p '{"spec":{"schemaValidation": false}}' + mutate-certificates true true Audit True 3m6s Ready ``` - > ⚠️ Read about the schema validation setting before using this elsewhere. - > We have disabled schema validation here because we have two policies both affecting `Certificates`. Cert-manager will validate the resolved resource with the `ValidatingWebhookConfiguration` resource after all mutations are applied. - > You could avoid this completely by using one policy with all required mutation rules. - -1. Look at the "test-minimal" `Certificate` designed to validate that all our policies are operative: +1. Look at the "test-minimal" `Certificate` designed to validate that all our rules within the policy are operative: ```yaml file=../../../../public/docs/tutorials/certificate-defaults/cert-test-minimal.yaml ``` @@ -350,9 +353,10 @@ In our example `ClusterPolicy` we will do two things: + secretName: test-minimal-cert ``` - See how both Kyverno `ClusterPolicies` have been applied and resulted in all the other default values being inserted for us! + See how we have automatically populated the `spec.issuerRef` and `spec.secretName` field values. + This indicates the Kyverno `ClusterPolicy` has been applied to the supplied `Certificate` resource. -1. To be absolutely sure we have not enforced any settings, let us explicitly set each property for which we have a default rule in a `Certificate`. We will use the "test-revision-override" `Certificate`: +1. To be absolutely sure we have not enforced any settings, let us explicitly set each property of the `Certificate` for which we have a default rule. We will use the "test-revision-override" `Certificate`: ```yaml file=../../../../public/docs/tutorials/certificate-defaults/cert-test-revision-override.yaml ``` @@ -396,13 +400,13 @@ Many cert-manager users don't create `Certificate` resources directly and instea cert-manager creates `Certificate` resources based on the [supported annotations](https://cert-manager.io/docs/usage/ingress/#supported-annotations) and the `Ingress` specification. Let's see how we can still use `ClusterPolicy` to apply our defaults in this use case. -1. Check the example `Ingress` resource has the correct annotation to select an `Issuer` or `ClusterIssuer`: +1. This example `Ingress` resource has a `cert-manager.io/cluster-issuer` annotation which instructs cert-manager to create a `Certificate` with an `issuerRef` field pointing at a `ClusterIssuer` called `our-corp-issuer`: ```yaml file=../../../../public/docs/tutorials/certificate-defaults/ingress.yaml ``` 🔗 `ingress.yaml` -1. This annotation and the relevant `ingress.spec.tls` configuration are all we need: +1. This annotation and the relevant `ingress.spec.tls` configuration are all we need so apply the resource: ```shell kubectl apply -f ingress.yaml @@ -411,7 +415,7 @@ Let's see how we can still use `ClusterPolicy` to apply our defaults in this use 1. Now validate that the `Certificate` resource was automatically generated: ```shell - kubectl get cert defaults-example-certificate-tls -o yaml | yq + kubectl get cert defaults-example-certificate-tls -o yaml ``` This command should return some output similar to this example: @@ -464,9 +468,10 @@ Let's see how we can still use `ClusterPolicy` to apply our defaults in this use reason: DoesNotExist status: "False" type: Ready - nextPrivateKeySecretName: defaults-example-certificate-tls-2hmpj ``` + nextPrivateKeySecretName: defaults-example-certificate-tls-2hmpj + ``` -1. You can optionally validate that only the "0-mutate-certificate-defaults" `ClusterPolicy` has been applied by viewing the logs of the Kyverno admission controller container. +1. You can optionally validate that the "mutate-certificates" `ClusterPolicy` has been applied by viewing the logs of the Kyverno admission controller container. ```shell kubectl logs -n kyverno-system $(kubectl get pod -n kyverno-system -l app.kubernetes.io/component=admission-controller -o jsonpath='{.items[0].metadata.name}') -c kyverno --tail 5 @@ -491,12 +496,19 @@ Let's see how we can still use `ClusterPolicy` to apply our defaults in this use See the `object` key indicates that our policy has been applied. In the `note` section you can identify that it was applied to the `Certificate` resource that was created by cert-manager based on the `Ingress` resource that we applied. -Whilst you are not able to default the `secretName` and `issuerRef` fields when using the ingress-shim, you can default all other fields. -This is reasonable given that the `Ingress` specification needs to know what `Secret` to mount to the ingress controller. +When using an `Ingress` resource, you always need to specify the `secretName` from which to load the certificate. +No defaulting is required in this use case because this is a required part of the `Ingress` specification. + +The only additional YAML that a user is required to specify on the `Ingress` resource is the annotation: + +```yaml +cert-manager.io/cluster-issuer: "our-corp-issuer" +``` + +This annotation serves as both the trigger for cert-manager to act upon this `Ingress` and also as the configuration value for the `Certificate.spec.issuerRef` fields. +This single line replaces the need for the user to create a `Certificate` resource entirely. +This results in a reduction of the total YAML required to secure the application behind this `Ingress`. -> **Note**: The `ClusterIssuer` can be defaulted by supplying an install time parameter to cert-manager. -> See [cert-manager documentation](../../usage/ingress.md#optional-configuration) for full details. -> You would still need to provide at least one annotation, however this time it is static and doesn't need to be defaulted. # Summary @@ -504,7 +516,7 @@ This is a fairly simple example of how easy it can be to setup *defaults* for yo We've shown how a `ClusterPolicy` doesn't have to "enforce" settings, rather it can be used to set and extend the default options. `Certificate` users can reduce their YAML, whilst maintaining the flexibility to override any value when needed. -We have shown how a few simple policies can change the user experience creating `Certificate` resources from: +We have shown how a simple `ClusterPolicy` with only 5 rules can change the user experience creating `Certificate` resources from: ```yaml file=../../../../public/docs/tutorials/certificate-defaults/cert-test-revision-override.yaml ``` @@ -516,12 +528,10 @@ To instead only need to specify the configuration important to them, for example ``` 🔗 `cert-test-minimal.yaml` -With these policies we achieved our objective and have enabled users to submit minimal `Certifiate` resources, with only a single field contained within the specification, the `dnsNames` entry. +With this policy we achieved our objective and have enabled users to submit minimal `Certifiate` resources. +This completes our fifth [use case](#use-cases), with only a single field contained within the specification, the `dnsNames` entry. Every other specified field was automatically defaulted using Kyverno with `ClusterPolicy` which would typically be setup by a platform administrator. -You may have noticed in the second Kyverno `ClusterPolicy` that we used some `Certificate` resource metadata to create the `secretName` field. -You can read more about this in the [Kyverno documentation](https://kyverno.io/docs/writing-policies/variables/#variables-from-admission-review-requests). - # Cleanup If you created the kind cluster for this tutorial you can simply run: @@ -534,7 +544,8 @@ Otherwise to remove all resources deployed in this tutorial: ```shell # Assuming you are running from this directly or saved all the files to yamls/ -kubectl delete -f yamls/ +kubectl delete -f ingress.yaml +kubectl delete -f cpol-mutate-certificates-1.yaml helm uninstall kyverno -n kyverno-system helm uninstall cert-manager -n cert-manager helm uninstall ingress-nginx -n ingress-nginx @@ -544,53 +555,14 @@ helm uninstall ingress-nginx -n ingress-nginx ## cert-manager version requirement -Prior to cert-manager version v1.14.x, cert-manager's `MutatingWebhookConfiguration` was triggered by all cert-manager.io resources including `Certificates`. -In reality this webhook is only in place to affect `CertificateRequest` resources, but had an unintended consequence that meant Kyverno policies as we had written would not operate as intended. - -When a `Certificate` resource is applied to a Kubernetes cluster, mutating webhooks are applied before validating webhooks. -When the existing cert-manager `MutatingWebhookConfiguration` runs it will add the required field with an empty value, such as: `secretName: ""`, if there is no value in a required field. -The consequence of this action is that our Kyverno policies will not apply as an empty value is already present. - -Starting with v1.14.x the cert-manager-webhook `MutatingWebhookConfiguration` resource has been scoped to only affect `CertificateRequest` resources. -It no longer triggers for `Certificate` resources, which our policies in this tutorial are acting on. - -If you are running a cert-manager installation prior to v1.14.x you should first consider upgrading. -If upgrading is not feasible right now then you will need to consider one of the following potential fixes for this issue: - -1. Rename the 'cert-manager-webhook' mutating and validating webhooks with `z-` so that they execute last, after the Kyverno webhooks. - -1. Fix the cert-manager mutating webhook not trigger for `Certificate` resource changes, as in [PR #6311](https://github.com/cert-manager/cert-manager/pull/6311). - -1. Use enforcement in your policy to explicitly override the value regardless of what the user sets. - -Option 1 seems to work but generally should be avoided as order cannot be counted on. Mutating webhooks should also be [idempotent](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#best-practices-and-warnings). -Option 3 defeats the point of allowing a user to override when needed, so discounted for this tutorial. - -Option 2 is recommended, as this is the fix that is implemented in later versions of cert-manager, based on [PR #6311](https://github.com/cert-manager/cert-manager/pull/6311). -To manually patch the webhook we have a YAML patch resource: - -```yaml file=../../../../public/docs/tutorials/certificate-defaults/mutatingwebhookconfiguration-patch.yaml -``` -🔗 `mutatingwebhookconfiguration-patch.yaml` - -To validate exactly what this patch will do, simply run the following to see a `kubectl diff`: - -```shell -kubectl patch mutatingwebhookconfigurations.admissionregistration.k8s.io cert-manager-webhook --patch-file patches/mutatingwebhookconfiguration-patch.yaml --dry-run=server -o yaml | kubectl diff -f - -``` - -And to apply the patch so it takes effect: - -```shell -kubectl patch mutatingwebhookconfigurations.admissionregistration.k8s.io cert-manager-webhook --patch-file patches/mutatingwebhookconfiguration-patch.yaml -``` - -At this point you should now be able to continue with the rest of this tutorial. +The behaviour of cert-manager's mutating webhook has been changed from v1.14.x onward. +For a more complete explanation and details of the change please refer to [PR #6311](https://github.com/cert-manager/cert-manager/pull/6311). +Instructions for a manual fix can be found [in this comment on PR #6311](https://github.com/cert-manager/cert-manager/pull/6311#issuecomment-1889517418). ## Presets Feature Request For further background reading around setting "defaults" or "presets", you can refer to [issue 2239](ttps://github.com/cert-manager/cert-manager/issues/2239). This tutorial came out of an investigation of that issue. -The cert-manager team reasoned that requested solution could be achieved with the use of other, more generic open-source policy tools. +The cert-manager team reasoned that the requested solution could be achieved with the use of other, more generic open-source policy tools. Kyverno is just one example and similar can be achieved with [Gatekeeper](https://github.com/open-policy-agent/gatekeeper) as an alternative tool. diff --git a/public/docs/tutorials/certificate-defaults/cpol-mutate-certificate-required.yaml b/public/docs/tutorials/certificate-defaults/cpol-mutate-certificate-required.yaml deleted file mode 100644 index 7eeb6fc0ea9..00000000000 --- a/public/docs/tutorials/certificate-defaults/cpol-mutate-certificate-required.yaml +++ /dev/null @@ -1,31 +0,0 @@ -apiVersion: kyverno.io/v1 -kind: ClusterPolicy -metadata: - name: 1-mutate-certificate-required -spec: - rules: - # Test if we can set a secretName when one is not provided - - name: set-default-secret-name - match: - any: - - resources: - kinds: - - Certificate - mutate: - patchStrategicMerge: - spec: - +(secretName): "{{request.object.metadata.name}}-cert" - # Test if we can set a default issuerRef - - name: set-default-issuer-ref - match: - any: - - resources: - kinds: - - Certificate - mutate: - patchStrategicMerge: - spec: - +(issuerRef): - name: our-corp-issuer - kind: ClusterIssuer - group: cert-manager.io diff --git a/public/docs/tutorials/certificate-defaults/cpol-mutate-certificate-defaults.yaml b/public/docs/tutorials/certificate-defaults/cpol-mutate-certificates-0.yaml similarity index 91% rename from public/docs/tutorials/certificate-defaults/cpol-mutate-certificate-defaults.yaml rename to public/docs/tutorials/certificate-defaults/cpol-mutate-certificates-0.yaml index 609ec746aa8..82e107082d8 100644 --- a/public/docs/tutorials/certificate-defaults/cpol-mutate-certificate-defaults.yaml +++ b/public/docs/tutorials/certificate-defaults/cpol-mutate-certificates-0.yaml @@ -1,7 +1,7 @@ apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: - name: 0-mutate-certificate-defaults + name: mutate-certificates spec: failurePolicy: Fail rules: @@ -29,7 +29,7 @@ spec: spec: privateKey: +(rotationPolicy): Always - # Set private key details for algorithm an size + # Set private key details for algorithm and size - name: set-privateKey-details match: any: diff --git a/public/docs/tutorials/certificate-defaults/cpol-mutate-certificates-1.yaml b/public/docs/tutorials/certificate-defaults/cpol-mutate-certificates-1.yaml new file mode 100644 index 00000000000..9ad220a7f4d --- /dev/null +++ b/public/docs/tutorials/certificate-defaults/cpol-mutate-certificates-1.yaml @@ -0,0 +1,72 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: mutate-certificates +spec: + failurePolicy: Fail + rules: + # Set a sane default for the history field if not already present + - name: set-revisionHistoryLimit + match: + any: + - resources: + kinds: + - Certificate + mutate: + patchStrategicMerge: + spec: + # +(...) This is the clever syntax for if not already set + +(revisionHistoryLimit): 2 + # Set rotation to always if not already set + - name: set-privateKey-rotationPolicy + match: + any: + - resources: + kinds: + - Certificate + mutate: + patchStrategicMerge: + spec: + privateKey: + +(rotationPolicy): Always + # Set private key details for algorithm and size + - name: set-privateKey-details + match: + any: + - resources: + kinds: + - Certificate + mutate: + patchStrategicMerge: + spec: + privateKey: + +(algorithm): ECDSA + +(size): 521 + +(encoding): PKCS1 + # Set a secretName when one is not provided + - name: set-default-secret-name + match: + any: + - resources: + kinds: + - Certificate + mutate: + patchStrategicMerge: + spec: + # You can read more about this syntax in the Kyverno documentation: + # https://kyverno.io/docs/writing-policies/variables/#variables-from-admission-review-requests + +(secretName): "{{request.object.metadata.name}}-cert" + # Set a default for issuerRef fields + - name: set-default-issuer-ref + match: + any: + - resources: + kinds: + - Certificate + mutate: + patchStrategicMerge: + spec: + +(issuerRef): + name: our-corp-issuer + kind: ClusterIssuer + group: cert-manager.io diff --git a/public/docs/tutorials/certificate-defaults/mutatingwebhookconfiguration-patch.yaml b/public/docs/tutorials/certificate-defaults/mutatingwebhookconfiguration-patch.yaml deleted file mode 100644 index 16fb04e5424..00000000000 --- a/public/docs/tutorials/certificate-defaults/mutatingwebhookconfiguration-patch.yaml +++ /dev/null @@ -1,15 +0,0 @@ -webhooks: -- name: webhook.cert-manager.io - namespaceSelector: {} - objectSelector: {} - reinvocationPolicy: Never - rules: - - apiGroups: - - cert-manager.io - apiVersions: - - v1 - operations: - - CREATE - resources: - - 'certificaterequests' - scope: '*'