From 48b61d85f3f3cc341ec2a0571f251d27c067a2fe Mon Sep 17 00:00:00 2001 From: Peter Fiddes Date: Fri, 5 Jan 2024 11:03:35 +0000 Subject: [PATCH] docs: Move resources to public folder and rewrite tutorial Signed-off-by: Peter Fiddes --- .../tutorials/certificate-defaults/README.md | 317 +++++++++++------- .../mutatingwebhookconfiguration-patch.yaml | 0 .../yamls/cert-test-minimal.yaml | 0 .../yamls/cert-test-revision-override.yaml | 0 .../yamls/cert-test-revision.yaml | 0 .../cpol-mutate-certificate-defaults.yaml | 0 .../cpol-mutate-certificate-required.yaml | 0 .../yamls/cpol-validate-certificate.yaml | 0 .../certificate-defaults/yamls/ingress.yaml | 0 9 files changed, 195 insertions(+), 122 deletions(-) rename {content => public}/docs/tutorials/certificate-defaults/patches/mutatingwebhookconfiguration-patch.yaml (100%) rename {content => public}/docs/tutorials/certificate-defaults/yamls/cert-test-minimal.yaml (100%) rename {content => public}/docs/tutorials/certificate-defaults/yamls/cert-test-revision-override.yaml (100%) rename {content => public}/docs/tutorials/certificate-defaults/yamls/cert-test-revision.yaml (100%) rename {content => public}/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-defaults.yaml (100%) rename {content => public}/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-required.yaml (100%) rename {content => public}/docs/tutorials/certificate-defaults/yamls/cpol-validate-certificate.yaml (100%) rename {content => public}/docs/tutorials/certificate-defaults/yamls/ingress.yaml (100%) diff --git a/content/docs/tutorials/certificate-defaults/README.md b/content/docs/tutorials/certificate-defaults/README.md index deb954c8971..e8a354e0391 100644 --- a/content/docs/tutorials/certificate-defaults/README.md +++ b/content/docs/tutorials/certificate-defaults/README.md @@ -1,95 +1,150 @@ --- title: Learn how to set Certificate defaults automatically description: | - Learn how to use Kyverno ClusterPolicy to set default values for cert-manager Certificates. + Learn how to use Kyverno ClusterPolicy to set default values for cert-manager Certificates cluster wide. --- -*Last Verified: 08 September 2023* +*Last Verified: 05 January 2024* -There has been a long standing [issue](https://github.com/cert-manager/cert-manager/issues/2239) in [cert-manager](https://cert-manager.io/) about how to set default values on Certificate resources, also known in the issue as presets. In this tutorial we will walk through using [Kyverno](https://kyverno.io/), an open source policy tool to help us setup some useful defaults for our user's Certificates. +# Objective -**Objective**: The end goal here is that a user specifies as little as possible in the `Certificate` resource, and they have all the default values automatically applied. +We will set up a cluster where a user specifies as little YAML as possible in `Certificate` resources. +This will be achieved by utilising Kyverno to apply custom "default" values to the `Certificate` fields, that are not specified by a user. -There are some other good reasons you might want to do this: +There are some benefits to having defaults: -- Defaults allow users to benefit from not having to set config options, minimizing their YAML resource. -- Defaults allow users to override for their use case when needed. -- Defaults allow cluster operators to decide what the default should be, rather than having to rely on an in-built default from cert-manager +- Users minimize their `Certificate` YAML resource. +- Users maintain flexibility to override fields when needed. +- Cluster operators can decide what the default should be, rather than having to rely on an in-built defaults from cert-manager. -Cert-manager does already provide default values for many of the `Certificate` specification fields within the code itself. -Due to these being in the code, they default for the whole cluster and don't appear in the `Certificate` resource itself once applied to the cluster. -As cert-manager has developed over the years, defaults have been set with the primary goal of backwards compatibility in mind. -Sometimes this can mean that a default value is perhaps less than ideal for your setup. -Changing any of these in the code base becomes a tricky balance of avoiding any negative effects from consumers who have come to rely on the existing default behavior, and promoting a better default value for either security or performance reasons. +## Use cases -> **Note:** All resources provided are demonstrative and should be reviewed properly before using in production environments. +By setting customer defaults across our cluster, we enable a platofrm team to tackle use case such as: -# 1 - Prerequisites +- **You want ensure that CertificateRequest resources get cleaned up.** + + Use a `ClusterPolicy` to set a custom default value for the Certificate.Spec.RevisionHistoryLimit field. + +- **You want to help your users choose secure default key settings for their `Certificate` resources.** + + Use a `ClusterPolicy` to set custom default values for the `Certificate.Spec.PrivateKey` fields. + +- **You want to default the `Issuer` for users within the cluster.** + + Use a `ClusterPolicy` to set a custom default for the `Certificate.spec.issuerRef` fields. + +## Process + +We will setup defaults for three different scenarios, getting slightly more advanced each time: + +1. Defaulting optional `Certificate` resource fields. +2. Defaulting required `Certificate` resource fields. +3. Defaulting `Certificate` resource fields when using `Ingress` annotations to request certificates. + +# Setup + +## Prerequisites **💻 Software** 1. [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl): The Kubernetes -command-line tool which allows you to configure Kubernetes clusters. + 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 runtime. - -# 2 - Environment Setup + 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 runtime. -Follow these steps to setup an environment to follow along: +## Local Kubernetes Environment -> **Please note**: This is not a production setup. +> ⚠️ Please note this step is optional. If you have another Kubernetes environment, skip to the next section +> -1. Create a cluster environment for this demo. Skip this step if you already have an environment +1. Create a cluster environment using `kind` for this tutorial. ```shell kind create cluster --name defaults ``` -1. Install both cert-manager & Kyverno in the cluster + > ⏲ It should take approximately 1 minute to create the cluster depending on your machine. + > + > ⚠️ This cluster is only suitable for learning purposes it is not suitable for production use. + > + +## Software Installation + +Once you have your cluster environment, let's install the required Kuberenetes packages using `helm`. + +1. Set some environment variables for the helm chart versions: + + ```shell + export CERT_MANAGER_CHART_VERSION="v1.13.3" \ + KYVERNO_CHART_VERSION="3.1.1" \ + INGRESS_NGINX_CHART_VERSION="4.8.4" + ``` + +1. Install cert-manager ```shell - # Set the chart versions we will use - export CERT_MANAGER_CHART_VERSION="v1.12.3" KYVERNO_CHART_VERSION="3.0.5" - # Install Kyverno with helm - helm upgrade --install kyverno kyverno --namespace kyverno-system --version $KYVERNO_CHART_VERSION --create-namespace --repo https://kyverno.github.io/kyverno/ - # Install cert-manager with helm helm upgrade --install cert-manager cert-manager --namespace cert-manager --version $CERT_MANAGER_CHART_VERSION --set installCRDs=true --create-namespace --repo https://charts.jetstack.io/ ``` - > For full installation instructions, please refer to the following links: - > - [cert-manager installation instructions](./../../../docs/installation/helm.md) - > - [kyverno installation instructions](https://kyverno.io/docs/installation/methods/#install-kyverno-using-helm) +1. Install Kyverno + + ```shell + helm upgrade --install kyverno kyverno --namespace kyverno-system --version $KYVERNO_CHART_VERSION --create-namespace --repo https://kyverno.github.io/kyverno/ + ``` + +1. Install ingress-nginx + + ```shell + helm upgrade --install ingress-nginx ingress-nginx --create-namespace --namespace ingress-nginx --version ${INGRESS_NGINX_CHART_VERSION} --repo https://kubernetes.github.io/ingress-nginx + ``` + +> For complete installation instructions, please refer to the following links: +> - [cert-manager installation instructions](./../../../docs/installation/helm.md) +> - [Kyverno installation instructions](https://kyverno.io/docs/installation/methods/#install-kyverno-using-helm) +> - [ingress-nginx instllation instructions](https://kubernetes.github.io/ingress-nginx/deploy/) -# 3 - What defaults will we apply +# Setting Defaults -We are going to look only at setting fields inside the `Certificate` specification and not other cert-manager CRDs. We will also split this walkthrough into two sections: +The main tutorial starts here with some backgroun before tackling each scenario. -1. Default settings for optional fields. -2. Default settings for required fields. +## Required vs Non-required -We will setup some `ClusterPolicy` resources and `Certificate` resources in this guide. -We will make reference to a `ClusterIssuer` in the `Certificate` spec that doesn't exist, but for this tutorial the issuer is not required as we won't actually be requesting certificates. -That means anyone can walk through this guide even without their own domain. +The `Certificate` resource has a `spec` section with a number of "required" fields. +This means these fields must be present when you create a `Certificate` resource. +There are also a number of other fields that are not required to be explicitly defined on each `Certificate` resource. +This essentially means the value of one of these fields is either not required, or is defaulted somewhere else. +That somewhere else could be in the cert-manager code base, or indeed by the issuer that creates and returns the X.509 certificate. +Let's explore how we can manipulate these values to be something custom and make the `Certificate` users life easier. -We are also demoing this using a cluster scoped `ClusterPolicy` for ease of getting started. -You can scope your defaults to the namespace level through the use of `Policy` resources in the future. +We will set up some `ClusterPolicy` resources and `Certificate` resources in this tutorial. +We will make reference to a `ClusterIssuer` in the `Certificate` spec that doesn't exist, but for this tutorial the `ClusterIssuer`` is not required as we will not actually be requesting certificates. +That means anyone can follow this tutorial even without their own domain. -## Optional field defaults +> **Please note:** This tutorial uses cluster scoped `ClusterPolicy` resource for ease of getting started. +> You can scope your defaults to the namespace level through the use of `Policy` resources in the future, but that will not be covered in this tutorial. +> -Lets set some simple fields, fields that you might find you either don't know to set or aren't really concerned about the consequences of setting them. So we will do this following "defaulting": +## 1 - Defaulting optional fields + +In this section we will set 3 fields for all `Certificate` resource automatically. +All 3 fields here are not required fields, but might need to be set depending on the platform and issuer preferences. +These fields are: - Set a default value of: `revisionHistoryLimit: 2` - Set a default value of `Always` under `spec.privateKey.rotationPolicy` -- Set defaults for all the `spec.privateKey` fields. +- Set defaults for all the `spec.privateKey` fields + +Note how these rules are tackling each of our [3 uses cases](#use-cases) set out above. -1. Lets first take a look at the `ClusterPolicy`: +1. Let's first take a look at the `ClusterPolicy`: - ```yaml file=./yamls/cpol-mutate-certificate-defaults.yaml + ```yaml file=../../../../public/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-defaults.yaml ``` -1. Apply the policy to the cluster and check it is ready: +1. Apply the policy to the cluster and check that it is ready: ```shell kubectl apply -f yamls/cpol-mutate-certificate-defaults.yaml @@ -105,7 +160,7 @@ Lets set some simple fields, fields that you might find you either don't know to 1. Now inspect the `Certificate` for testing with the name "test-revision": - ```yaml file=./yamls/cert-test-revision.yaml + ```yaml file=../../../../public/docs/tutorials/certificate-defaults/yamls/cert-test-revision.yaml ``` You can see that we have set the most minimal configuration currently possible, specifying only a DNS name for the certificate, where to save it (`secretName`) and the issuer to use to request the certificate (`issuerRef`). @@ -158,7 +213,7 @@ Lets set some simple fields, fields that you might find you either don't know to 1. Let's override all of these defaulted fields, to validate that we can still set what we want as an end user. Here is a new `Certificate` resource to use for testing called "test-revision-override": - ```yaml file=./yamls/cert-test-revision-override.yaml + ```yaml file=../../../../public/docs/tutorials/certificate-defaults/yamls/cert-test-revision-override.yaml ``` As before, dry-run apply and diff the output with the input file: @@ -189,47 +244,22 @@ Lets set some simple fields, fields that you might find you either don't know to - example.com ``` -## Required field defaults - -This section is a little more nuanced and requires a minor tweak to the default cert-manager installation to work. When a `Certificate` resource is applied to a Kubernetes cluster, mutating webhooks are applied before validating webhooks. When the existing cert-manager mutating webhook runs, if there is no value in a required field, it will add the required field with an empty value such as: `secretName: ""`. The consequence of this action is that our Kyverno policy will not apply as an empty value is already present. - -There are some 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. We fix cert-manager mutating webhook not mess with `Certificate` resource as in [this PR](https://github.com/cert-manager/cert-manager/pull/6311). - -1. You 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. Plus any mutating webhooks should 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. That leaves us with option 2. We can manually apply this fix to our environment or now and in the future this step will be removed one [this PR](https://github.com/cert-manager/cert-manager/pull/6311) is merged and released. - -To patch the webhook we have YAML patch resource here: - -```yaml file=./patches/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 - -``` +## 2 - Defaulting required fields -And to apply the patch it so it takes effect: - -```shell -kubectl patch mutatingwebhookconfigurations.admissionregistration.k8s.io cert-manager-webhook --patch-file patches/mutatingwebhookconfiguration-patch.yaml -``` +> **Please note:** that this section requires cert-manager 1.14.X to work properly out of the box. +> If using an older version of cert-manager, see the [Appendix](#114x-requirement) section for full explanation. +> -Now we can set a Kyverno `ClusterPolicy` to apply default values any of the `Certificate` fields, including the *required* fields. In our example, lets do two things: +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 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 using our `ClusterIssuer` named, "our-corp-issuer". -Let's implement this now that we have made the relevant patches. - 1. Here is the `ClusterPolicy` resource to set both fields with defaults: - ```yaml file=./yamls/cpol-mutate-certificate-required.yaml + ```yaml file=../../../../public/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-required.yaml ``` 1. Apply this policy: @@ -244,11 +274,14 @@ Let's implement this now that we have made the relevant patches. kubectl patch cpol 0-mutate-certificate-defaults --type=merge -p '{"spec":{"schemaValidation": false}}' ``` - > **NOTE**: Please read about the validation setting before using elsewhere. We have disabled it here because we have two policies both affecting `Certificates`. Cert-manager will validate the resolved resource with the `validatingwebhookconfigurations.admissionregistration.k8s.io`, after all mutations are applied. You could avoid this completely by using one policy with all required mutation rules. + > **Please note:** Read about the schema validation setting before using this elsewhere. + > We have disabled it here because we have two policies both affecting `Certificates`. Cert-manager will validate the resolved resource with the `validatingwebhookconfigurations.admissionregistration.k8s.io`, after all mutations are applied. + > You could avoid this completely by using one policy with all required mutation rules. + > 1. Take a look at another new `Certificate` we have for validating that all our policies will now take effect. This time called "test-minimal": - ```yaml file=./yamls/cert-test-minimal.yaml + ```yaml file=../../../../public/docs/tutorials/certificate-defaults/yamls/cert-test-minimal.yaml ``` 1. Dry run apply and `diff` to validate all our defaults have applied to this minimal `Certificate`: @@ -300,7 +333,7 @@ Let's implement this now that we have made the relevant patches. 1. To be absolutely sure we have not enforced any settings, let us try and set every value of the `Certificate` explicitly, that we have a default rule for. We will use a final `Certificate` named "test-revision-override": - ```yaml file=./yamls/cert-test-revision-override.yaml + ```yaml file=../../../../public/docs/tutorials/certificate-defaults/yamls/cert-test-revision-override.yaml ``` 1. Dry-run apply and `diff` this file: @@ -331,28 +364,19 @@ Let's implement this now that we have made the relevant patches. - example.com ``` - From this command you can see that again, none of the `Certificate` specification fields have been changed. Only the metadata section which tells us the policies hasve applied but not set any defaults, because values were already provided. So you maintain the flexibility to set what you need. - -# 4 - Ingress-shim + From this command you can see that, none of the `Certificate` specification fields have been changed. + Only the metadata section has changed which tells us the policies have applied but not set any defaults because values were already provided. + So you maintain the flexibility to override the cluster defaults when needed. -## Background +## 3 - Defaulting through Ingress Annotations -Our original scope here was a user creating a `Certificate` object. -Many cert-manager users don't actually create these resources, and instead use the [ingress-shim](https://cert-manager.io/docs/usage/ingress/) to have `Certificate` resources created for them based on some [supported annotations](https://cert-manager.io/docs/usage/ingress/#supported-annotations) and the `Ingress` specification. -With this being the case, can we extend these defaults to apply to `Certificates` auto created via this ingress-shim? - -## Steps - -1. Add an ingress controller to your cluster, for example [ingress-nginx](https://kubernetes.github.io/ingress-nginx/): - - ```shell - export INGRESS_NGINX_CHART_VERSION="4.7.1" - helm upgrade --install ingress-nginx ingress-nginx --create-namespace --namespace ingress-nginx --version ${INGRESS_NGINX_CHART_VERSION} --repo https://kubernetes.github.io/ingress-nginx - ``` +Many cert-manager users don't create `Certificate` resources directly and instead use the [ingress-shim](https://cert-manager.io/docs/usage/ingress/) functionality. +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`: - ```yaml file=./yamls/ingress.yaml + ```yaml file=../../../../public/docs/tutorials/certificate-defaults/yamls/ingress.yaml ``` 1. This annotation and the relevant `ingress.spec.tls` configuration is all we need: @@ -425,37 +449,39 @@ With this being the case, can we extend these defaults to apply to `Certificates nextPrivateKeySecretName: defaults-example-certificate-tls-4mlz9 ``` -## Outcome +1. Validate from the `metadata.annotations` that only our "0-mutate-certificate-defaults" rule has applied to the resource. + "1-mutate-certificate-required" should not apply as the fields it managed are required in the `Ingress` resource specification. -You can see from the `metadata.annotations` field of the `Certificate` resource, that our Kyverno policies have been applied. -The default values we defined in the `ClusterPolicy` for `privateKey` and `revisionHistoryLimit` are preset without us needing to manually specify these. -These values are also not the default cert-manger values that would usually have applied when not using our Kyverno defaulting policies. -Our second policy did not apply because we had already set an `ClusterIssuer` and `secretName` via the annotation and TLS specification of the `Ingress` resource. -This means that the Kyverno defaults apply to the ingress-shim generated `Certificates`. +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. -Whilst you are not able to default the `secretName` and `issuerRef` fields with this setup, you can default all other fields. -This is reasonable given that the `Ingress` specification needs to know what `Secret` to mount. -You could of course also template your `Ingress` resource and use your templating engine to set configurable values and defaults. +> **Note**: The `ClusterIssuer` can be defaulted by supplying an install time parameter to cert-manager. +> See [here](../../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. -> **Note**: The `Issuer` can be defaulted by supplying an install time parameter to cert-manager. See [here](../../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 -# 5 - Summary +This is a fairly simple example of how easy it can be to setup *defaults* for your cluster `Certificate` resources. +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. -This is a fairly simple example of how easy it can be to setup *defaults* or *presets* for your cluster `Certificates`. -We've shown how policy doesn't have to mean "enforce", and that you can allow your cluster's users to reduce their YAML, whilst maintaining the flexibility to override any value in specific use cases. -You may have noticed that in the second Kyverno `ClusterPolicy` we actually used some `Certificate` resource metadata to create the `secretName` field. -You read more about this on the [Kyverno documentation](yamls/cert-test-revision-override.yaml). +We have shown how a few simple policies can change the user experience creating `Certificate` resources from: -We reached our goal, the most minimal `Certificate` we created had only a single field contained within the specification, the `dnsNames` entry. +```yaml file=../../../../public/docs/tutorials/certificate-defaults/yamls/cert-test-revision-override.yaml +``` + +To instead only need to specify the configuration important to them, for example: -```yaml file=./yamls/cert-test-minimal.yaml +```yaml file=../../../../public/docs/tutorials/certificate-defaults/yamls/cert-test-minimal.yaml ``` -## Reference links +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. +Every other specified field was automatically defautled using Kyverno with `ClusterPolicy` which would typically be setup by a platform administrator. -You might find it useful to browse some example policies [here](https://github.com/kyverno/policies/) from Kyverno. There are some cert-manager examples [here](https://github.com/kyverno/policies/blob/main/cert-manager/restrict-issuer/restrict-issuer.yaml), but the repo covers many other tools and use cases. +You may have noticed that in the second Kyverno `ClusterPolicy`, we actually used some `Certificate` resource metadata to create the `secretName` field. +You read more about this on the [Kyverno documentation](https://kyverno.io/docs/writing-policies/variables/#variables-from-admission-review-requests). -# 6 - Cleanup +# Cleanup If you created the kind cluster for this tutorial you can simply run: @@ -470,4 +496,51 @@ Otherwise to remove all resources deployed in this tutorial: kubectl delete -f yamls/ helm uninstall kyverno -n kyverno-system helm uninstall cert-manager -n cert-manager +helm uninstall ingress-nginx -n ingress-nginx +``` + +# Appendix + +## v1.14.X requirement + +Prior to cert-manager version v1.14.X, cert-manager's `MutatingWebhookConfiguration` was trigger 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 at v1.14.x the `MutatingWebhookConfiguration` has been scoped back to only `CertificateRequest` resources, so it no longer triggers for `Certificate` resources which out policies in this tutorial are acting on. + +If you are running a cert-manager installation prior to v1.14.X, 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. We fix cert-manager mutating webhook not mess with `Certificate` resource as in [this PR](https://github.com/cert-manager/cert-manager/pull/6311). + +1. You 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/patches/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. + +For further background reading around setting "defaults" or "presets", you can refer to [issue 2239](ttps://github.com/cert-manager/cert-manager/issues/2239). diff --git a/content/docs/tutorials/certificate-defaults/patches/mutatingwebhookconfiguration-patch.yaml b/public/docs/tutorials/certificate-defaults/patches/mutatingwebhookconfiguration-patch.yaml similarity index 100% rename from content/docs/tutorials/certificate-defaults/patches/mutatingwebhookconfiguration-patch.yaml rename to public/docs/tutorials/certificate-defaults/patches/mutatingwebhookconfiguration-patch.yaml diff --git a/content/docs/tutorials/certificate-defaults/yamls/cert-test-minimal.yaml b/public/docs/tutorials/certificate-defaults/yamls/cert-test-minimal.yaml similarity index 100% rename from content/docs/tutorials/certificate-defaults/yamls/cert-test-minimal.yaml rename to public/docs/tutorials/certificate-defaults/yamls/cert-test-minimal.yaml diff --git a/content/docs/tutorials/certificate-defaults/yamls/cert-test-revision-override.yaml b/public/docs/tutorials/certificate-defaults/yamls/cert-test-revision-override.yaml similarity index 100% rename from content/docs/tutorials/certificate-defaults/yamls/cert-test-revision-override.yaml rename to public/docs/tutorials/certificate-defaults/yamls/cert-test-revision-override.yaml diff --git a/content/docs/tutorials/certificate-defaults/yamls/cert-test-revision.yaml b/public/docs/tutorials/certificate-defaults/yamls/cert-test-revision.yaml similarity index 100% rename from content/docs/tutorials/certificate-defaults/yamls/cert-test-revision.yaml rename to public/docs/tutorials/certificate-defaults/yamls/cert-test-revision.yaml diff --git a/content/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-defaults.yaml b/public/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-defaults.yaml similarity index 100% rename from content/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-defaults.yaml rename to public/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-defaults.yaml diff --git a/content/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-required.yaml b/public/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-required.yaml similarity index 100% rename from content/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-required.yaml rename to public/docs/tutorials/certificate-defaults/yamls/cpol-mutate-certificate-required.yaml diff --git a/content/docs/tutorials/certificate-defaults/yamls/cpol-validate-certificate.yaml b/public/docs/tutorials/certificate-defaults/yamls/cpol-validate-certificate.yaml similarity index 100% rename from content/docs/tutorials/certificate-defaults/yamls/cpol-validate-certificate.yaml rename to public/docs/tutorials/certificate-defaults/yamls/cpol-validate-certificate.yaml diff --git a/content/docs/tutorials/certificate-defaults/yamls/ingress.yaml b/public/docs/tutorials/certificate-defaults/yamls/ingress.yaml similarity index 100% rename from content/docs/tutorials/certificate-defaults/yamls/ingress.yaml rename to public/docs/tutorials/certificate-defaults/yamls/ingress.yaml