configMap |
object |
@@ -428,6 +492,56 @@ Target is the current Target that the Bundle is attempting or has completed sync
+### `Bundle.status.target.additionalFormats`
+
+
+AdditionalFormats specifies any additional formats to write to the target
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ jks |
+ object |
+
+ KeySelector is a reference to a key for some map data object.
+ |
+ false |
+
+
+
+
+### `Bundle.status.target.additionalFormats.jks`
+
+
+KeySelector is a reference to a key for some map data object.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ key |
+ string |
+
+ Key is the key of the entry in the object's `data` field to be used.
+ |
+ true |
+
+
+
+
### `Bundle.status.target.configMap`
From 9292a335111d0c0982adbd45721bc448af8ee91a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Valais?=
Date: Mon, 22 May 2023 15:48:08 +0200
Subject: [PATCH 047/264] add documentation on how to write a good release note
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Maël Valais
---
.../docs/contributing/contributing-flow.md | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/content/docs/contributing/contributing-flow.md b/content/docs/contributing/contributing-flow.md
index 4706a0d1699..bd5dff06696 100644
--- a/content/docs/contributing/contributing-flow.md
+++ b/content/docs/contributing/contributing-flow.md
@@ -73,6 +73,46 @@ To let people know that your PR is still a work in progress, we usually add a
`WIP:` prefix to the title of the PR. Prow will then automatically set the label
`do-not-merge/work-in-progress`.
+### Release Note Guidelines
+
+The `release-note` code block in the PR description aims at explaining to the
+end-user whether they should care about this change and whether they will be
+affected. It is OK to have multiple sentences as long as it is written in good
+English (subject verb complement, ends with a dot).
+
+A release note block shouldn't just paraphrase the commit message. For example,
+the end-user doesn't know what "comparisons" are and which custom resources are
+affected:
+
+~~~markdown
+```release-note
+Adds missing comparisons for certain fields which were incorrectly skipped if a LiteralSubject was set
+```
+~~~
+
+A better release note block gives context and specifically tells the end-user
+how they will be affected:
+
+~~~markdown
+```release-note
+When using the `literalSubject` on a Certificate, the IPs, URIs, DNS names, and email addresses subject segments are now properly compared.
+```
+~~~
+
+New lines in the release note block translate to hard line breaks, which means
+it is not possible to soft-wrap the release note. A new line can be useful for
+lists:
+
+~~~markdown
+```release-note
+cainjector:
+- New flags were added to the cainjector binary. They can be used to modify what injectable kinds are enabled. If cainjector is only used as a cert-manager's internal component it is sufficient to only enable validatingwebhookconfigurations and mutatingwebhookconfigurations injectable resources; disabling the rest can improve memory consumption. By default all are enabled.
+- The `--watch-certs` flag was renamed to `--enable-certificates-data-source`.
+```
+~~~
+
+If this PR introduces a breaking change, the release note block must start with
+`**BREAKING:**` (note the bold text).
### Cherry Picking
From b218ae59eba28c8ed3d2f4cf1a8b7f2f87afbae8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Valais?=
Date: Fri, 19 May 2023 15:33:40 +0200
Subject: [PATCH 048/264] post-release 1.12: update supported releases
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Ref: https://github.com/cert-manager/cert-manager/issues/6083
Signed-off-by: Maël Valais
---
.../docs/installation/supported-releases.md | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/content/docs/installation/supported-releases.md b/content/docs/installation/supported-releases.md
index 8e60cca1f56..6fc4859a752 100644
--- a/content/docs/installation/supported-releases.md
+++ b/content/docs/installation/supported-releases.md
@@ -17,18 +17,18 @@ cert-manager expects that ServerSideApply is enabled in the cluster for all vers
Currently supported releases
-| Release | Release Date | End of Life | [Supported Kubernetes versions][s] | [Supported OpenShift versions][s] |
-|----------|:------------:|:---------------:|:----------------------------------:|:---------------------------------:|
-| [1.11][] | Jan 11, 2023 | Release of 1.13 | 1.21 → 1.26 | 4.8 → 4.13 |
-| [1.10][] | Oct 17, 2022 | Release of 1.12 | 1.20 → 1.26 | 4.7 → 4.13 |
+| Release | Release Date | End of Life | [Supported Kubernetes versions][s] | [Supported OpenShift versions][s] |
+|----------|:------------:|:----------------------:|:----------------------------------:|:---------------------------------:|
+| [1.12][] | May 19, 2024 | End of September, 2024 | 1.22 → 1.27 | 4.9 → 4.14 |
+| [1.11][] | Jan 11, 2023 | Release of 1.13 | 1.21 → 1.26 | 4.8 → 4.13 |
\*ServerSideApply should be enabled in the cluster
## Upcoming releases
-| Release | Release Date | End of Life | [Supported Kubernetes versions][s] | [Supported OpenShift versions][s] |
-|----------|:--------------:|:------------------:|:-----------------------------------:|:---------------------------------:|
-| [1.12][] | Apr 26, 2023 | End of August, 2023 | 1.22 → 1.26 | 4.9 → 4.13 |
+| Release | Release Date | End of Life | [Supported Kubernetes versions][s] | [Supported OpenShift versions][s] |
+|----------|:----------------------:|:---------------------:|:----------------------------------:|:---------------------------------:|
+| [1.13][] | End of September, 2024 | End of November, 2024 | 1.22 → 1.27 | 4.9 → 4.14 |
Dates in the future are uncertain and might change.
@@ -36,6 +36,7 @@ Dates in the future are uncertain and might change.
| Release | Release Date | EOL | Compatible Kubernetes versions | Compatible OpenShift versions |
|----------|:------------:|:------------:|:------------------------------:|:-----------------------------:|
+| [1.10][] | Oct 17, 2022 | May 19, 2024 | 1.20 → 1.26 | 4.7 → 4.13 |
| [1.9][] | Jul 22, 2022 | Jan 11, 2023 | 1.20 → 1.24 | 4.7 → 4.11 |
| [1.8][] | Apr 05, 2022 | Oct 17, 2022 | 1.19 → 1.24 | 4.6 → 4.11 |
| [1.7][] | Jan 26, 2021 | Jul 22, 2022 | 1.18 → 1.23 | 4.5 → 4.9 |
@@ -54,7 +55,8 @@ Dates in the future are uncertain and might change.
| [0.11][] | Oct 10, 2019 | Jan 21, 2020 | 1.9 → 1.21 | 3.09 → 4.7 |
[s]: #kubernetes-supported-versions
-[1.12]: https://github.com/cert-manager/cert-manager/milestone/33
+[1.13]: https://github.com/cert-manager/cert-manager/milestone/34
+[1.12]: https://cert-manager.io/docs/release-notes/release-notes-1.12
[1.11]: https://cert-manager.io/docs/release-notes/release-notes-1.11
[1.10]: https://cert-manager.io/docs/release-notes/release-notes-1.10
[1.9]: https://cert-manager.io/docs/release-notes/release-notes-1.9
@@ -233,6 +235,7 @@ For convenience, the following table shows these version mappings:
| OpenShift versions | Kubernetes version |
|--------------------|--------------------|
+| 4.14 | 1.27 |
| 4.13 | 1.26 |
| 4.12 | 1.25 |
| 4.11 | 1.24 |
From 8c4aeb6b9448288079f2c186050a06921a0589a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Valais?=
Date: Fri, 19 May 2023 17:53:53 +0200
Subject: [PATCH 049/264] post-release 1.12: "How we determine supported
Kubernetes"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Maël Valais
---
content/docs/installation/supported-releases.md | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/content/docs/installation/supported-releases.md b/content/docs/installation/supported-releases.md
index 6fc4859a752..930152f250f 100644
--- a/content/docs/installation/supported-releases.md
+++ b/content/docs/installation/supported-releases.md
@@ -212,14 +212,14 @@ In practice, this is largely determined based on what versions of [kind](https:/
are available for testing, and which versions of Kubernetes are provided by major upstream cloud Kubernetes vendors
including EKS, GKE, AKS and OpenShift.
-| Vendor | Oldest Kubernetes Release\* | Other Older Kubernetes Releases |
-|:-----------------:|------------------------------|---------------------------------------------------------------|
-| [EKS][eks] | 1.21 (EOL Feb 2023) | 1.22 (EOL May 2023) |
-| [GKE][gke] | 1.21 (EOL Feb 2023) | 1.22 (EOL May 2023) |
-| [AKS][aks] | 1.23 (EOL ~Feb 2023) | |
-| [OpenShift 4][os] | 1.21 (4.8 EUS, EOL Feb 2023) | 1.22 (4.9, EOL Apr 2023) |
-
-\*Oldest release relevant to the next cert-manager release, as of 2022-07-18
+| Vendor | Oldest Kubernetes Release\* | Other Older Kubernetes Releases |
+|:-----------------:|-----------------------------|------------------------------------------------------------------------------------|
+| [EKS][eks] | 1.22 (EOL Jun 2023) | 1.23 (EOL Oct 2023), 1.24 (EOL Jan 2024), 1.25 (EOL May 2024), 1.26 (EOL Jun 2024) |
+| [GKE][gke] | 1.23 (EOL Jul 2023) | 1.24 (EOL Oct 2023), 1.25 (EOL Feb 2024), 1.26 (EOL May 2024), 1.27 (EOL Jan 2025) |
+| [AKS][aks] | 1.24 (EOL Jul 2023) | 1.25 (EOL Dec 2023), 1.26 (EOL Mar 2024), 1.27 (EOL Jun 2024) |
+| [OpenShift 4][os] | 1.22 (4.9, EOL Jun 2023) | 1.23 (4.10, EOL Oct 2023), 1.24 (4.11, EOL Feb 2024), 1.25 (4.12, EOL Jan 2025) |
+
+\*Oldest release relevant to the next cert-manager release, as of 2023-05-19
[eks]: https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html#kubernetes-release-calendar
[gke]: https://cloud.google.com/kubernetes-engine/docs/release-schedule
From 67087fed1e70ce3e2f23445c98a02179b5ae9f13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Valais?=
Date: Fri, 19 May 2023 18:19:07 +0200
Subject: [PATCH 050/264] post-release 1.12: bump 1.12 in
generate-new-import-path-docs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Maël Valais
---
scripts/gendocs/generate-new-import-path-docs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/gendocs/generate-new-import-path-docs b/scripts/gendocs/generate-new-import-path-docs
index b2289b119c6..fc5a97361b4 100755
--- a/scripts/gendocs/generate-new-import-path-docs
+++ b/scripts/gendocs/generate-new-import-path-docs
@@ -148,13 +148,13 @@ EOF
# This script is _only_ for generating docs for versions of cert-manager with the
# github.com/cert-manager/cert-manager import path!
-LATEST_VERSION="v1.11-docs"
+LATEST_VERSION="v1.12-docs"
#genversionwithcli "release-1.8" "v1.8-docs"
#genversionwithcli "release-1.9" "v1.9-docs"
#genversionwithcli "release-1.10" "v1.10-docs"
-genversionwithcli "release-1.11" "$LATEST_VERSION"
+genversionwithcli "release-1.12" "$LATEST_VERSION"
# Rather than generate the same docs again for /docs, copy from the latest version
From afae87f172132aa63147ffa5c1d30799c433955f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Valais?=
Date: Fri, 19 May 2023 18:20:27 +0200
Subject: [PATCH 051/264] post-release 1.12: freeze docs/ into v1.12-docs/
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Command:
cp -r content/docs content/v1.12-docs
rm -rf content/v1.12-docs/{installation/supported-releases,installation/upgrading,release-notes}
Signed-off-by: Maël Valais
---
content/v1.12-docs/README.md | 26 +
content/v1.12-docs/cli/README.md | 7 +
content/v1.12-docs/cli/acmesolver.md | 17 +
content/v1.12-docs/cli/cainjector.md | 45 +
content/v1.12-docs/cli/cmctl.md | 30 +
content/v1.12-docs/cli/controller.md | 78 +
content/v1.12-docs/cli/webhook.md | 51 +
content/v1.12-docs/concepts/README.md | 11 +
.../concepts/acme-orders-challenges.md | 100 +
content/v1.12-docs/concepts/ca-injector.md | 234 +
content/v1.12-docs/concepts/certificate.md | 106 +
.../v1.12-docs/concepts/certificaterequest.md | 261 +
content/v1.12-docs/concepts/issuer.md | 44 +
content/v1.12-docs/concepts/webhook.md | 80 +
content/v1.12-docs/configuration/README.md | 30 +
.../v1.12-docs/configuration/acme/README.md | 392 ++
.../configuration/acme/dns01/README.md | 186 +
.../configuration/acme/dns01/acme-dns.md | 220 +
.../configuration/acme/dns01/akamai.md | 86 +
.../configuration/acme/dns01/azuredns.md | 505 ++
.../configuration/acme/dns01/cloudflare.md | 108 +
.../configuration/acme/dns01/digitalocean.md | 46 +
.../configuration/acme/dns01/google.md | 242 +
.../configuration/acme/dns01/rfc2136.md | 207 +
.../configuration/acme/dns01/route53.md | 253 +
.../configuration/acme/dns01/webhook.md | 32 +
.../configuration/acme/http01/README.md | 366 ++
.../acme/http01/externalloadbalancer.md | 34 +
content/v1.12-docs/configuration/ca.md | 94 +
content/v1.12-docs/configuration/external.md | 51 +
.../v1.12-docs/configuration/selfsigned.md | 171 +
content/v1.12-docs/configuration/vault.md | 270 +
content/v1.12-docs/configuration/venafi.md | 282 +
content/v1.12-docs/contributing/README.md | 68 +
content/v1.12-docs/contributing/building.md | 267 +
.../contributing/coding-conventions.md | 59 +
.../contributing/contributing-flow.md | 138 +
content/v1.12-docs/contributing/crds.md | 65 +
.../v1.12-docs/contributing/dns-providers.md | 23 +
content/v1.12-docs/contributing/e2e.md | 148 +
.../contributing/external-issuers.md | 77 +
.../v1.12-docs/contributing/featuregates.md | 47 +
.../google-season-of-docs/2022/README.md | 10 +
.../2022/improve-navigation-and-structure.md | 215 +
.../google-season-of-docs/README.md | 8 +
content/v1.12-docs/contributing/importing.md | 42 +
content/v1.12-docs/contributing/kind.md | 31 +
content/v1.12-docs/contributing/policy.md | 159 +
.../contributing/release-process.md | 599 ++
content/v1.12-docs/contributing/security.md | 13 +
content/v1.12-docs/contributing/sign-off.md | 77 +
.../v1.12-docs/contributing/signing-keys.md | 72 +
.../contributing/third-party-code-donation.md | 79 +
content/v1.12-docs/faq/README.md | 182 +
content/v1.12-docs/getting-started/README.md | 36 +
content/v1.12-docs/installation/README.md | 41 +
.../installation/api-compatibility.md | 22 +
.../v1.12-docs/installation/best-practice.md | 48 +
.../v1.12-docs/installation/code-signing.md | 59 +
.../v1.12-docs/installation/compatibility.md | 114 +
.../v1.12-docs/installation/featureflags.md | 72 +
content/v1.12-docs/installation/helm.md | 207 +
content/v1.12-docs/installation/kubectl.md | 124 +
.../operator-lifecycle-manager.md | 243 +
.../v1.12-docs/installation/other-tools.md | 23 +
.../installation/supported-releases.md | 289 +
content/v1.12-docs/installation/uninstall.md | 14 +
content/v1.12-docs/installation/verify.md | 122 +
content/v1.12-docs/manifest.json | 758 +++
content/v1.12-docs/projects/README.md | 31 +
.../projects/approver-policy/README.md | 422 ++
.../projects/approver-policy/api-reference.md | 978 +++
.../v1.12-docs/projects/csi-driver-spiffe.md | 257 +
content/v1.12-docs/projects/csi-driver.md | 231 +
content/v1.12-docs/projects/istio-csr.md | 92 +
.../projects/trust-manager/README.md | 373 ++
.../projects/trust-manager/api-reference.md | 478 ++
content/v1.12-docs/reference/README.md | 15 +
content/v1.12-docs/reference/api-docs.md | 5674 +++++++++++++++++
content/v1.12-docs/reference/cmctl.md | 344 +
.../v1.12-docs/reference/tls-terminology.md | 79 +
content/v1.12-docs/troubleshooting/README.md | 116 +
content/v1.12-docs/troubleshooting/acme.md | 226 +
content/v1.12-docs/troubleshooting/webhook.md | 1071 ++++
content/v1.12-docs/tutorials/README.md | 38 +
.../tutorials/acme/dns-validation.md | 169 +
.../tutorials/acme/example/deployment.yaml | 20 +
.../acme/example/ingress-tls-final.yaml | 24 +
.../tutorials/acme/example/ingress-tls.yaml | 24 +
.../tutorials/acme/example/ingress.yaml | 24 +
.../acme/example/pomerium-certificates.yaml | 36 +
.../example/pomerium-production-issuer.yaml | 19 +
.../acme/example/pomerium-staging-issuer.yaml | 19 +
.../acme/example/pomerium-values.yaml | 39 +
.../acme/example/production-issuer.yaml | 18 +
.../tutorials/acme/example/service.yaml | 11 +
.../acme/example/staging-issuer.yaml | 18 +
.../tutorials/acme/http-validation.md | 159 +
.../acme/migrating-from-kube-lego.md | 232 +
.../tutorials/acme/nginx-ingress.md | 602 ++
.../tutorials/acme/pomerium-ingress.md | 191 +
content/v1.12-docs/tutorials/backup.md | 167 +
.../getting-started-aks-letsencrypt/README.md | 687 ++
.../README.md | 779 +++
.../example/example-cluster-issuer.yaml | 46 +
.../istio-csr/example/example-issuer.yaml | 45 +
.../example/istio-config-getting-started.yaml | 57 +
.../tutorials/istio-csr/istio-csr.md | 276 +
.../syncing-secrets-across-namespaces.md | 143 +
content/v1.12-docs/tutorials/venafi/venafi.md | 586 ++
.../v1.12-docs/tutorials/zerossl/zerossl.md | 180 +
content/v1.12-docs/usage/README.md | 31 +
content/v1.12-docs/usage/approver-policy.md | 14 +
content/v1.12-docs/usage/certificate.md | 368 ++
content/v1.12-docs/usage/csi.md | 85 +
content/v1.12-docs/usage/gateway.md | 402 ++
content/v1.12-docs/usage/ingress.md | 175 +
content/v1.12-docs/usage/istio.md | 17 +
content/v1.12-docs/usage/kube-csr.md | 166 +
.../v1.12-docs/usage/prometheus-metrics.md | 69 +
120 files changed, 25539 insertions(+)
create mode 100644 content/v1.12-docs/README.md
create mode 100644 content/v1.12-docs/cli/README.md
create mode 100644 content/v1.12-docs/cli/acmesolver.md
create mode 100644 content/v1.12-docs/cli/cainjector.md
create mode 100644 content/v1.12-docs/cli/cmctl.md
create mode 100644 content/v1.12-docs/cli/controller.md
create mode 100644 content/v1.12-docs/cli/webhook.md
create mode 100644 content/v1.12-docs/concepts/README.md
create mode 100644 content/v1.12-docs/concepts/acme-orders-challenges.md
create mode 100644 content/v1.12-docs/concepts/ca-injector.md
create mode 100644 content/v1.12-docs/concepts/certificate.md
create mode 100644 content/v1.12-docs/concepts/certificaterequest.md
create mode 100644 content/v1.12-docs/concepts/issuer.md
create mode 100644 content/v1.12-docs/concepts/webhook.md
create mode 100644 content/v1.12-docs/configuration/README.md
create mode 100644 content/v1.12-docs/configuration/acme/README.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/README.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/acme-dns.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/akamai.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/azuredns.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/cloudflare.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/digitalocean.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/google.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/rfc2136.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/route53.md
create mode 100644 content/v1.12-docs/configuration/acme/dns01/webhook.md
create mode 100644 content/v1.12-docs/configuration/acme/http01/README.md
create mode 100644 content/v1.12-docs/configuration/acme/http01/externalloadbalancer.md
create mode 100644 content/v1.12-docs/configuration/ca.md
create mode 100644 content/v1.12-docs/configuration/external.md
create mode 100644 content/v1.12-docs/configuration/selfsigned.md
create mode 100644 content/v1.12-docs/configuration/vault.md
create mode 100644 content/v1.12-docs/configuration/venafi.md
create mode 100644 content/v1.12-docs/contributing/README.md
create mode 100644 content/v1.12-docs/contributing/building.md
create mode 100644 content/v1.12-docs/contributing/coding-conventions.md
create mode 100644 content/v1.12-docs/contributing/contributing-flow.md
create mode 100644 content/v1.12-docs/contributing/crds.md
create mode 100644 content/v1.12-docs/contributing/dns-providers.md
create mode 100644 content/v1.12-docs/contributing/e2e.md
create mode 100644 content/v1.12-docs/contributing/external-issuers.md
create mode 100644 content/v1.12-docs/contributing/featuregates.md
create mode 100644 content/v1.12-docs/contributing/google-season-of-docs/2022/README.md
create mode 100644 content/v1.12-docs/contributing/google-season-of-docs/2022/improve-navigation-and-structure.md
create mode 100644 content/v1.12-docs/contributing/google-season-of-docs/README.md
create mode 100644 content/v1.12-docs/contributing/importing.md
create mode 100644 content/v1.12-docs/contributing/kind.md
create mode 100644 content/v1.12-docs/contributing/policy.md
create mode 100644 content/v1.12-docs/contributing/release-process.md
create mode 100644 content/v1.12-docs/contributing/security.md
create mode 100644 content/v1.12-docs/contributing/sign-off.md
create mode 100644 content/v1.12-docs/contributing/signing-keys.md
create mode 100644 content/v1.12-docs/contributing/third-party-code-donation.md
create mode 100644 content/v1.12-docs/faq/README.md
create mode 100644 content/v1.12-docs/getting-started/README.md
create mode 100644 content/v1.12-docs/installation/README.md
create mode 100644 content/v1.12-docs/installation/api-compatibility.md
create mode 100644 content/v1.12-docs/installation/best-practice.md
create mode 100644 content/v1.12-docs/installation/code-signing.md
create mode 100644 content/v1.12-docs/installation/compatibility.md
create mode 100644 content/v1.12-docs/installation/featureflags.md
create mode 100644 content/v1.12-docs/installation/helm.md
create mode 100644 content/v1.12-docs/installation/kubectl.md
create mode 100644 content/v1.12-docs/installation/operator-lifecycle-manager.md
create mode 100644 content/v1.12-docs/installation/other-tools.md
create mode 100644 content/v1.12-docs/installation/supported-releases.md
create mode 100644 content/v1.12-docs/installation/uninstall.md
create mode 100644 content/v1.12-docs/installation/verify.md
create mode 100644 content/v1.12-docs/manifest.json
create mode 100644 content/v1.12-docs/projects/README.md
create mode 100644 content/v1.12-docs/projects/approver-policy/README.md
create mode 100644 content/v1.12-docs/projects/approver-policy/api-reference.md
create mode 100644 content/v1.12-docs/projects/csi-driver-spiffe.md
create mode 100644 content/v1.12-docs/projects/csi-driver.md
create mode 100644 content/v1.12-docs/projects/istio-csr.md
create mode 100644 content/v1.12-docs/projects/trust-manager/README.md
create mode 100644 content/v1.12-docs/projects/trust-manager/api-reference.md
create mode 100644 content/v1.12-docs/reference/README.md
create mode 100644 content/v1.12-docs/reference/api-docs.md
create mode 100644 content/v1.12-docs/reference/cmctl.md
create mode 100644 content/v1.12-docs/reference/tls-terminology.md
create mode 100644 content/v1.12-docs/troubleshooting/README.md
create mode 100644 content/v1.12-docs/troubleshooting/acme.md
create mode 100644 content/v1.12-docs/troubleshooting/webhook.md
create mode 100644 content/v1.12-docs/tutorials/README.md
create mode 100644 content/v1.12-docs/tutorials/acme/dns-validation.md
create mode 100644 content/v1.12-docs/tutorials/acme/example/deployment.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/ingress-tls-final.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/ingress-tls.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/ingress.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/pomerium-certificates.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/pomerium-production-issuer.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/pomerium-staging-issuer.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/pomerium-values.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/production-issuer.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/service.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/example/staging-issuer.yaml
create mode 100644 content/v1.12-docs/tutorials/acme/http-validation.md
create mode 100644 content/v1.12-docs/tutorials/acme/migrating-from-kube-lego.md
create mode 100644 content/v1.12-docs/tutorials/acme/nginx-ingress.md
create mode 100644 content/v1.12-docs/tutorials/acme/pomerium-ingress.md
create mode 100644 content/v1.12-docs/tutorials/backup.md
create mode 100644 content/v1.12-docs/tutorials/getting-started-aks-letsencrypt/README.md
create mode 100644 content/v1.12-docs/tutorials/getting-started-with-cert-manager-on-google-kubernetes-engine-using-lets-encrypt-for-ingress-ssl/README.md
create mode 100644 content/v1.12-docs/tutorials/istio-csr/example/example-cluster-issuer.yaml
create mode 100644 content/v1.12-docs/tutorials/istio-csr/example/example-issuer.yaml
create mode 100644 content/v1.12-docs/tutorials/istio-csr/example/istio-config-getting-started.yaml
create mode 100644 content/v1.12-docs/tutorials/istio-csr/istio-csr.md
create mode 100644 content/v1.12-docs/tutorials/syncing-secrets-across-namespaces.md
create mode 100644 content/v1.12-docs/tutorials/venafi/venafi.md
create mode 100644 content/v1.12-docs/tutorials/zerossl/zerossl.md
create mode 100644 content/v1.12-docs/usage/README.md
create mode 100644 content/v1.12-docs/usage/approver-policy.md
create mode 100644 content/v1.12-docs/usage/certificate.md
create mode 100644 content/v1.12-docs/usage/csi.md
create mode 100644 content/v1.12-docs/usage/gateway.md
create mode 100644 content/v1.12-docs/usage/ingress.md
create mode 100644 content/v1.12-docs/usage/istio.md
create mode 100644 content/v1.12-docs/usage/kube-csr.md
create mode 100644 content/v1.12-docs/usage/prometheus-metrics.md
diff --git a/content/v1.12-docs/README.md b/content/v1.12-docs/README.md
new file mode 100644
index 00000000000..c53f1bc99fa
--- /dev/null
+++ b/content/v1.12-docs/README.md
@@ -0,0 +1,26 @@
+---
+title: cert-manager
+description: cert-manager documentation homepage
+---
+
+cert-manager adds certificates and certificate issuers as resource types in
+Kubernetes clusters, and simplifies the process of obtaining, renewing and
+using those certificates.
+
+It can issue certificates from a variety of supported sources, including
+[Let's Encrypt](https://letsencrypt.org), [HashiCorp Vault](https://www.vaultproject.io),
+and [Venafi](https://www.venafi.com/) as well as private PKI.
+
+It will ensure certificates are valid and up to date, and attempt to
+renew certificates at a configured time before expiry.
+
+It is loosely based upon the work of
+[kube-lego](https://github.com/jetstack/kube-lego) and has borrowed some
+wisdom from other similar projects such as
+[kube-cert-manager](https://github.com/PalmStoneGames/kube-cert-manager).
+
+![High level overview diagram explaining cert-manager architecture](/images/high-level-overview.svg)
+
+This website provides the full technical documentation for the project, and can be
+used as a reference; if you feel that there's anything missing, please let us know
+or [raise a PR](https://github.com/cert-manager/website/pulls) to add it.
diff --git a/content/v1.12-docs/cli/README.md b/content/v1.12-docs/cli/README.md
new file mode 100644
index 00000000000..0d1a516335c
--- /dev/null
+++ b/content/v1.12-docs/cli/README.md
@@ -0,0 +1,7 @@
+---
+title: CLI reference
+description: cert-manager CLI documentation
+---
+
+View the `--help` output from our various CLI tools, including those which run in containers in your cluster.
+This might help if you need to tweak an option or if you need to check which values are valid!
\ No newline at end of file
diff --git a/content/v1.12-docs/cli/acmesolver.md b/content/v1.12-docs/cli/acmesolver.md
new file mode 100644
index 00000000000..baee31aff49
--- /dev/null
+++ b/content/v1.12-docs/cli/acmesolver.md
@@ -0,0 +1,17 @@
+---
+title: acmesolver CLI reference
+description: "cert-manager acmesolver CLI documentation"
+---
+```
+HTTP server used to solve ACME challenges.
+
+Usage:
+ acmesolver [flags]
+
+Flags:
+ --domain string the domain name to verify
+ -h, --help help for acmesolver
+ --key string the challenge key to respond with
+ --listen-port int the port number to listen on for connections (default 8089)
+ --token string the challenge token to verify against
+```
diff --git a/content/v1.12-docs/cli/cainjector.md b/content/v1.12-docs/cli/cainjector.md
new file mode 100644
index 00000000000..0bcdf500140
--- /dev/null
+++ b/content/v1.12-docs/cli/cainjector.md
@@ -0,0 +1,45 @@
+---
+title: cainjector CLI reference
+description: "cert-manager cainjector CLI documentation"
+---
+```
+
+cert-manager CA injector is a Kubernetes addon to automate the injection of CA data into
+webhooks and APIServices from cert-manager certificates.
+
+It will ensure that annotated webhooks and API services always have the correct
+CA data from the referenced certificates, which can then be used to serve API
+servers and webhook servers.
+
+Usage:
+ ca-injector [flags]
+
+Flags:
+ --add_dir_header If true, adds the file directory to the header of the log messages
+ --alsologtostderr log to standard error as well as files (no effect when -logtostderr=true)
+ --enable-profiling Enable profiling for cainjector
+ --feature-gates mapStringBool A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:
+ AllAlpha=true|false (ALPHA - default=false)
+ AllBeta=true|false (BETA - default=false)
+ -h, --help help for ca-injector
+ --kubeconfig string Paths to a kubeconfig. Only required if out-of-cluster.
+ --leader-elect If true, cainjector will perform leader election between instances to ensure no more than one instance of cainjector operates at a time (default true)
+ --leader-election-lease-duration duration The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate. This is only applicable if leader election is enabled. (default 1m0s)
+ --leader-election-namespace string Namespace used to perform leader election. Only used if leader election is enabled (default "kube-system")
+ --leader-election-renew-deadline duration The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than or equal to the lease duration. This is only applicable if leader election is enabled. (default 40s)
+ --leader-election-retry-period duration The duration the clients should wait between attempting acquisition and renewal of a leadership. This is only applicable if leader election is enabled. (default 15s)
+ --log-flush-frequency duration Maximum number of seconds between log flushes (default 5s)
+ --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
+ --log_dir string If non-empty, write log files in this directory (no effect when -logtostderr=true)
+ --log_file string If non-empty, use this log file (no effect when -logtostderr=true)
+ --log_file_max_size uint Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
+ --logtostderr log to standard error instead of files (default true)
+ --namespace string If set, this limits the scope of cainjector to a single namespace. If set, cainjector will not update resources with certificates outside of the configured namespace.
+ --one_output If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)
+ --profiler-address string Address of the Go profiler (pprof) if enabled. This should never be exposed on a public interface. (default "localhost:6060")
+ --skip_headers If true, avoid header prefixes in the log messages
+ --skip_log_headers If true, avoid headers when opening log files (no effect when -logtostderr=true)
+ --stderrthreshold severity logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=false) (default 2)
+ -v, --v Level number for the log level verbosity
+ --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
+```
diff --git a/content/v1.12-docs/cli/cmctl.md b/content/v1.12-docs/cli/cmctl.md
new file mode 100644
index 00000000000..dff83b3bc26
--- /dev/null
+++ b/content/v1.12-docs/cli/cmctl.md
@@ -0,0 +1,30 @@
+---
+title: cmctl CLI reference
+description: "cert-manager cmctl CLI documentation"
+---
+```
+
+cmctl is a CLI tool manage and configure cert-manager resources for Kubernetes
+
+Usage: cmctl [command]
+
+Available Commands:
+ approve Approve a CertificateRequest
+ check Check cert-manager components
+ convert Convert cert-manager config files between different API versions
+ create Create cert-manager resources
+ deny Deny a CertificateRequest
+ experimental Interact with experimental features
+ help Help about any command
+ inspect Get details on certificate related resources
+ renew Mark a Certificate for manual renewal
+ status Get details on current status of cert-manager resources
+ upgrade Tools that assist in upgrading cert-manager
+ version Print the cert-manager CLI version and the deployed cert-manager version
+
+Flags:
+ -h, --help help for cmctl
+ --log-flush-frequency duration Maximum number of seconds between log flushes (default 5s)
+
+Use "cmctl [command] --help" for more information about a command.
+```
diff --git a/content/v1.12-docs/cli/controller.md b/content/v1.12-docs/cli/controller.md
new file mode 100644
index 00000000000..768ffb05ccd
--- /dev/null
+++ b/content/v1.12-docs/cli/controller.md
@@ -0,0 +1,78 @@
+---
+title: controller CLI reference
+description: "cert-manager controller CLI documentation"
+---
+```
+
+cert-manager is a Kubernetes addon to automate the management and issuance of
+TLS certificates from various issuing sources.
+
+It will ensure certificates are valid and up to date periodically, and attempt
+to renew certificates at an appropriate time before expiry.
+
+Usage:
+ cert-manager-controller [flags]
+
+Flags:
+ --acme-http01-solver-image string The docker image to use to solve ACME HTTP01 challenges. You most likely will not need to change this parameter unless you are testing a new feature or developing cert-manager. (default "quay.io/jetstack/cert-manager-acmesolver:canary")
+ --acme-http01-solver-nameservers strings A list of comma separated dns server endpoints used for ACME HTTP01 check requests. This should be a list containing host and port, for example 8.8.8.8:53,8.8.4.4:53
+ --acme-http01-solver-resource-limits-cpu string Defines the resource limits CPU size when spawning new ACME HTTP01 challenge solver pods. (default "100m")
+ --acme-http01-solver-resource-limits-memory string Defines the resource limits Memory size when spawning new ACME HTTP01 challenge solver pods. (default "64Mi")
+ --acme-http01-solver-resource-request-cpu string Defines the resource request CPU size when spawning new ACME HTTP01 challenge solver pods. (default "10m")
+ --acme-http01-solver-resource-request-memory string Defines the resource request Memory size when spawning new ACME HTTP01 challenge solver pods. (default "64Mi")
+ --acme-http01-solver-run-as-non-root Defines the ability to run the http01 solver as root for troubleshooting issues (default true)
+ --add_dir_header If true, adds the file directory to the header of the log messages
+ --alsologtostderr log to standard error as well as files (no effect when -logtostderr=true)
+ --auto-certificate-annotations strings The annotation consumed by the ingress-shim controller to indicate a ingress is requesting a certificate (default [kubernetes.io/tls-acme])
+ --cluster-issuer-ambient-credentials Whether a cluster-issuer may make use of ambient credentials for issuers. 'Ambient Credentials' are credentials drawn from the environment, metadata services, or local files which are not explicitly configured in the ClusterIssuer API object. When this flag is enabled, the following sources for credentials are also used: AWS - All sources the Go SDK defaults to, notably including any EC2 IAM roles available via instance metadata. (default true)
+ --cluster-resource-namespace string Namespace to store resources owned by cluster scoped resources such as ClusterIssuer in. This must be specified if ClusterIssuers are enabled. (default "kube-system")
+ --controllers strings A list of controllers to enable. '--controllers=*' enables all on-by-default controllers, '--controllers=foo' enables just the controller named 'foo', '--controllers=*,-foo' disables the controller named 'foo'.
+ All controllers: issuers, clusterissuers, certificates-metrics, ingress-shim, gateway-shim, orders, challenges, certificaterequests-issuer-acme, certificaterequests-approver, certificaterequests-issuer-ca, certificaterequests-issuer-selfsigned, certificaterequests-issuer-vault, certificaterequests-issuer-venafi, certificates-trigger, certificates-issuing, certificates-key-manager, certificates-request-manager, certificates-readiness, certificates-revision-manager (default [*])
+ --copied-annotation-prefixes strings Specify which annotations should/shouldn't be copiedfrom Certificate to CertificateRequest and Order, as well as from CertificateSigningRequest to Order, by passing a list of annotation key prefixes.A prefix starting with a dash(-) specifies an annotation that shouldn't be copied. Example: '*,-kubectl.kuberenetes.io/'- all annotationswill be copied apart from the ones where the key is prefixed with 'kubectl.kubernetes.io/'. (default [*,-kubectl.kubernetes.io/,-fluxcd.io/,-argocd.argoproj.io/])
+ --default-issuer-group string Group of the Issuer to use when the tls is requested but issuer group is not specified on the ingress resource. (default "cert-manager.io")
+ --default-issuer-kind string Kind of the Issuer to use when the tls is requested but issuer kind is not specified on the ingress resource. (default "Issuer")
+ --default-issuer-name string Name of the Issuer to use when the tls is requested but issuer name is not specified on the ingress resource.
+ --dns01-check-retry-period duration The duration the controller should wait between a propagation check. Despite the name, this flag is used to configure the wait period for both DNS01 and HTTP01 challenge propagation checks. For DNS01 challenges the propagation check verifies that a TXT record with the challenge token has been created. For HTTP01 challenges the propagation check verifies that the challenge token is served at the challenge URL.This should be a valid duration string, for example 180s or 1h (default 10s)
+ --dns01-recursive-nameservers strings A list of comma separated dns server endpoints used for DNS01 check requests. This should be a list containing host and port, for example 8.8.8.8:53,8.8.4.4:53
+ --dns01-recursive-nameservers-only When true, cert-manager will only ever query the configured DNS resolvers to perform the ACME DNS01 self check. This is useful in DNS constrained environments, where access to authoritative nameservers is restricted. Enabling this option could cause the DNS01 self check to take longer due to caching performed by the recursive nameservers.
+ --enable-certificate-owner-ref Whether to set the certificate resource as an owner of secret where the tls certificate is stored. When this flag is enabled, the secret will be automatically removed when the certificate resource is deleted.
+ --enable-profiling Enable profiling for controller.
+ --feature-gates mapStringBool A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:
+ AdditionalCertificateOutputFormats=true|false (ALPHA - default=false)
+ AllAlpha=true|false (ALPHA - default=false)
+ AllBeta=true|false (BETA - default=false)
+ ExperimentalCertificateSigningRequestControllers=true|false (ALPHA - default=false)
+ ExperimentalGatewayAPISupport=true|false (ALPHA - default=false)
+ LiteralCertificateSubject=true|false (ALPHA - default=false)
+ ServerSideApply=true|false (ALPHA - default=false)
+ StableCertificateRequestName=true|false (ALPHA - default=false)
+ UseCertificateRequestBasicConstraints=true|false (ALPHA - default=false)
+ ValidateCAA=true|false (ALPHA - default=false)
+ -h, --help help for cert-manager-controller
+ --issuer-ambient-credentials Whether an issuer may make use of ambient credentials. 'Ambient Credentials' are credentials drawn from the environment, metadata services, or local files which are not explicitly configured in the Issuer API object. When this flag is enabled, the following sources for credentials are also used: AWS - All sources the Go SDK defaults to, notably including any EC2 IAM roles available via instance metadata.
+ --kube-api-burst int the maximum burst queries-per-second of requests sent to the Kubernetes apiserver (default 50)
+ --kube-api-qps float32 indicates the maximum queries-per-second requests to the Kubernetes apiserver (default 20)
+ --kubeconfig string Paths to a kubeconfig. Only required if out-of-cluster.
+ --leader-elect If true, cert-manager will perform leader election between instances to ensure no more than one instance of cert-manager operates at a time (default true)
+ --leader-election-lease-duration duration The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate. This is only applicable if leader election is enabled. (default 1m0s)
+ --leader-election-namespace string Namespace used to perform leader election. Only used if leader election is enabled (default "kube-system")
+ --leader-election-renew-deadline duration The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than or equal to the lease duration. This is only applicable if leader election is enabled. (default 40s)
+ --leader-election-retry-period duration The duration the clients should wait between attempting acquisition and renewal of a leadership. This is only applicable if leader election is enabled. (default 15s)
+ --log-flush-frequency duration Maximum number of seconds between log flushes (default 5s)
+ --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
+ --log_dir string If non-empty, write log files in this directory (no effect when -logtostderr=true)
+ --log_file string If non-empty, use this log file (no effect when -logtostderr=true)
+ --log_file_max_size uint Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
+ --logtostderr log to standard error instead of files (default true)
+ --master string Optional apiserver host address to connect to. If not specified, autoconfiguration will be attempted.
+ --max-concurrent-challenges int The maximum number of challenges that can be scheduled as 'processing' at once. (default 60)
+ --metrics-listen-address string The host and port that the metrics endpoint should listen on. (default "0.0.0.0:9402")
+ --namespace string If set, this limits the scope of cert-manager to a single namespace and ClusterIssuers are disabled. If not specified, all namespaces will be watched
+ --one_output If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)
+ --profiler-address string The host and port that Go profiler should listen on, i.e localhost:6060. Ensure that profiler is not exposed on a public address. Profiler will be served at /debug/pprof. (default "localhost:6060")
+ --skip_headers If true, avoid header prefixes in the log messages
+ --skip_log_headers If true, avoid headers when opening log files (no effect when -logtostderr=true)
+ --stderrthreshold severity logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=false) (default 2)
+ -v, --v Level number for the log level verbosity
+ --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
+```
diff --git a/content/v1.12-docs/cli/webhook.md b/content/v1.12-docs/cli/webhook.md
new file mode 100644
index 00000000000..f4d6ef30c33
--- /dev/null
+++ b/content/v1.12-docs/cli/webhook.md
@@ -0,0 +1,51 @@
+---
+title: webhook CLI reference
+description: "cert-manager webhook CLI documentation"
+---
+```
+Webhook component providing API validation, mutation and conversion functionality for cert-manager (canary) ()
+
+Usage:
+ webhook [flags]
+
+Flags:
+ --add-dir-header If true, adds the file directory to the header of the log messages
+ --alsologtostderr log to standard error as well as files (no effect when -logtostderr=true)
+ --api-server-host string Optional apiserver host address to connect to. If not specified, autoconfiguration will be attempted.
+ --config string Path to a file containing a WebhookConfiguration object used to configure the webhook
+ --dynamic-serving-ca-secret-name string name of the secret used to store the CA that signs serving certificates certificates
+ --dynamic-serving-ca-secret-namespace string namespace of the secret used to store the CA that signs serving certificates
+ --dynamic-serving-dns-names strings DNS names that should be present on certificates generated by the dynamic serving CA
+ --enable-profiling Enable profiling for webhook.
+ --feature-gates mapStringBool A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:
+ AdditionalCertificateOutputFormats=true|false (ALPHA - default=false)
+ AllAlpha=true|false (ALPHA - default=false)
+ AllBeta=true|false (BETA - default=false)
+ ExperimentalCertificateSigningRequestControllers=true|false (ALPHA - default=false)
+ ExperimentalGatewayAPISupport=true|false (ALPHA - default=false)
+ LiteralCertificateSubject=true|false (ALPHA - default=false)
+ ServerSideApply=true|false (ALPHA - default=false)
+ StableCertificateRequestName=true|false (ALPHA - default=false)
+ UseCertificateRequestBasicConstraints=true|false (ALPHA - default=false)
+ ValidateCAA=true|false (ALPHA - default=false)
+ --healthz-port int port number to listen on for insecure healthz connections (default 6080)
+ -h, --help help for webhook
+ --kubeconfig string optional path to the kubeconfig used to connect to the apiserver. If not specified, in-cluster-config will be used
+ --log-backtrace-at traceLocation when logging hits line file:N, emit a stack trace (default :0)
+ --log-dir string If non-empty, write log files in this directory (no effect when -logtostderr=true)
+ --log-file string If non-empty, use this log file (no effect when -logtostderr=true)
+ --log-file-max-size uint Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
+ --logtostderr log to standard error instead of files (default true)
+ --one-output If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)
+ --profiler-address string Address of the Go profiler (pprof). This should never be exposed on a public interface. If this flag is not set, the profiler is not run. (default "localhost:6060")
+ --secure-port int port number to listen on for secure TLS connections (default 6443)
+ --skip-headers If true, avoid header prefixes in the log messages
+ --skip-log-headers If true, avoid headers when opening log files (no effect when -logtostderr=true)
+ --stderrthreshold severity logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=false) (default 2)
+ --tls-cert-file string path to the file containing the TLS certificate to serve with
+ --tls-cipher-suites strings Comma-separated list of cipher suites for the server. If omitted, the default Go cipher suites will be use. Possible values: TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_3DES_EDE_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_RC4_128_SHA
+ --tls-min-version string Minimum TLS version supported. Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13
+ --tls-private-key-file string path to the file containing the TLS private key to serve with
+ -v, --v Level number for the log level verbosity
+ --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
+```
diff --git a/content/v1.12-docs/concepts/README.md b/content/v1.12-docs/concepts/README.md
new file mode 100644
index 00000000000..48ed7e23777
--- /dev/null
+++ b/content/v1.12-docs/concepts/README.md
@@ -0,0 +1,11 @@
+---
+title: Concepts
+description: cert-manager core concepts
+---
+
+There are several components and ideas that make up cert-manager. This section
+describes them on a conceptual level, to aid with understanding how cert-manager
+does its job.
+
+You probably don't want this section if you're just getting started; check out
+a [tutorial](../tutorials/README.md) instead.
\ No newline at end of file
diff --git a/content/v1.12-docs/concepts/acme-orders-challenges.md b/content/v1.12-docs/concepts/acme-orders-challenges.md
new file mode 100644
index 00000000000..80c31606e4e
--- /dev/null
+++ b/content/v1.12-docs/concepts/acme-orders-challenges.md
@@ -0,0 +1,100 @@
+---
+title: ACME Orders and Challenges
+description: 'cert-manager core concepts: ACME Orders and Challenges'
+---
+
+cert-manager supports requesting certificates from ACME servers, including from
+[Let's Encrypt](https://letsencrypt.org/), with use of the [ACME
+Issuer](../configuration/acme/README.md). These certificates are typically trusted on
+the public Internet by most computers. To successfully request a certificate,
+cert-manager must solve ACME Challenges which are completed in order to prove
+that the client owns the DNS addresses that are being requested.
+
+In order to complete these challenges, cert-manager introduces two
+`CustomResource` types; `Orders` and `Challenges`.
+
+## Orders
+
+`Order` resources are used by the ACME issuer to manage the lifecycle of an ACME
+'order' for a signed TLS certificate. More details on ACME orders and domain
+validation can be found on the Let's Encrypt website
+[here](https://letsencrypt.org/how-it-works/). An order represents a single
+certificate request which will be created automatically once a new
+[`CertificateRequest`](./certificaterequest.md) resource referencing an ACME
+issuer has been created. `CertificateRequest` resources are created
+automatically by cert-manager once a [`Certificate`](./certificate.md) resource
+is created, has its specification changed, or needs renewal.
+
+As an end-user, you will never need to manually create an `Order` resource.
+Once created, an `Order` cannot be changed. Instead, a new `Order` resource must
+be created.
+
+The `Order` resource encapsulates multiple ACME 'challenges' for that 'order',
+and as such, will manage one or more `Challenge` resources.
+
+## Challenges
+
+`Challenge` resources are used by the ACME issuer to manage the lifecycle of an
+ACME 'challenge' that must be completed in order to complete an 'authorization'
+for a single DNS name/identifier.
+
+When an `Order` resource is created, the order controller will create
+`Challenge` resources for each DNS name that is being authorized with the ACME
+server.
+
+As an end-user, you will never need to manually create a `Challenge` resource.
+Once created, a `Challenge` cannot be changed. Instead, a new `Challenge`
+resource must be created.
+
+### Challenge Lifecycle
+
+After a `Challenge` resource has been created, it will be initially queued for
+processing. Processing will not begin until the challenge has been 'scheduled'
+to start. This scheduling process prevents too many challenges being attempted
+at once, or multiple challenges for the same DNS name being attempted at once.
+For more information on how challenges are scheduled, read the [challenge
+scheduling](#challenge-scheduling).
+
+Once a challenge has been scheduled, it will first be 'synced' with the ACME
+server in order to determine its current state. If the challenge is already
+valid, its 'state' will be updated to 'valid', and will also set
+`status.processing = false` to 'unschedule' itself.
+
+If the challenge is still 'pending', the challenge controller will 'present' the
+challenge using the configured solver, one of HTTP01 or DNS01. Once the
+challenge has been 'presented', it will set `status.presented = true`.
+
+Once 'presented', the challenge controller will perform a 'self check' to
+ensure that the challenge has 'propagated' (i.e. the authoritative DNS servers
+have been updated to respond correctly, or the changes to the ingress resources
+have been observed and in-use by the ingress controller).
+
+If the self check fails, cert-manager will retry the self check with a fixed 10
+second retry interval. Challenges that do not ever complete the self check will
+continue retrying until the user intervenes by either retrying the `Order` (by
+deleting the `Order` resource) or amending the associated `Certificate` resource
+to resolve any configuration errors.
+
+Once the self check is passing, the ACME 'authorization' associated with this
+challenge will be 'accepted'.
+
+The final state of the authorization after accepting it will be copied across to
+the Challenge's `status.state` field, as well as the 'error reason' if an error
+occurred whilst the ACME server attempted to validate the challenge.
+
+Once a Challenge has entered the `valid`, `invalid`, `expired` or `revoked`
+state, it will set `status.processing = false` to prevent any further processing
+of the ACME challenge, and to allow another challenge to be scheduled if there
+is a backlog of challenges to complete.
+
+### Challenge Scheduling
+
+Instead of attempting to process all challenges at once, challenges are
+'scheduled' by cert-manager.
+
+This scheduler applies a cap on the maximum number of simultaneous challenges
+as well as disallows two challenges for the same DNS name and solver type
+(`HTTP01` or `DNS01`) to be completed at once.
+
+The maximum number of challenges that can be processed at a time is 60 as of
+[`ddff78`](https://github.com/cert-manager/cert-manager/blob/ddff78f011558e64186d61f7c693edced1496afa/pkg/controller/acmechallenges/scheduler/scheduler.go#L31-L33).
\ No newline at end of file
diff --git a/content/v1.12-docs/concepts/ca-injector.md b/content/v1.12-docs/concepts/ca-injector.md
new file mode 100644
index 00000000000..2c7c8dd6385
--- /dev/null
+++ b/content/v1.12-docs/concepts/ca-injector.md
@@ -0,0 +1,234 @@
+---
+title: CA Injector
+description: 'cert-manager core concepts: CA Injector'
+---
+
+`cainjector` helps to configure the CA certificates for:
+[Mutating Webhooks],
+[Validating Webhooks]
+[Conversion Webhooks] and [API Services]
+
+In particular, `cainjector` populates the `caBundle` field of four API types:
+`ValidatingWebhookConfiguration`,
+`MutatingWebhookConfiguration`
+`CustomResourceDefinition` and `APIService`.
+The first three resource types are used to configure how the Kubernetes API server connects to webhooks.
+This `caBundle` data is loaded by the Kubernetes API server and used to verify the serving certificates of webhook API servers.
+`APIService` is used to represent an [Extension API Server]. `caBundle` of `APIService` can be populated with CA cert that can be used to validate the API server's serving certificate.
+
+We will refer to these four API types as *injectable* resources.
+
+
+An *injectable* resource MUST have one of these annotations:
+`cert-manager.io/inject-ca-from`,
+`cert-manager.io/inject-ca-from-secret`, or
+`cert-manager.io/inject-apiserver-ca`, depending on the injection *source*.
+This is explained in more detail below.
+
+`cainjector` copies CA data from one of three *sources*:
+a Kubernetes `Secret`,
+a cert-manager `Certificate`, or from
+the Kubernetes API server CA certificate (which `cainjector` itself uses to verify its TLS connection to the Kubernetes API server).
+
+If the *source* is a Kubernetes `Secret`, that resource MUST also have an `cert-manager.io/allow-direct-injection: "true"` annotation.
+The three *source* types are explained in more detail below.
+
+
+## Examples
+
+Here are examples demonstrating how to use the three `cainjector` *sources*.
+In each case we use `ValidatingWebhookConfiguration` as the *injectable*,
+but you can substitute `MutatingWebhookConfiguration` or `CustomResourceDefinition` definition instead.
+
+### Injecting CA data from a Certificate resource
+
+Here is an example of a `ValidatingWebhookConfiguration`
+configured with the annotation `cert-manager.io/inject-ca-from`,
+which will make `cainjector` populate the `caBundle` field using CA data from a cert-manager `Certificate`.
+
+NOTE: This example does not deploy a webhook server,
+it only deploys a partial webhook configuration,
+but it should be sufficient to help you understand what `cainjector` does:
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: example1
+
+---
+
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ name: webhook1
+ annotations:
+ cert-manager.io/inject-ca-from: example1/webhook1-certificate
+webhooks:
+- name: webhook1.example.com
+ admissionReviewVersions:
+ - v1
+ clientConfig:
+ service:
+ name: webhook1
+ namespace: example1
+ path: /validate
+ port: 443
+ sideEffects: None
+
+---
+
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: webhook1-certificate
+ namespace: example1
+spec:
+ secretName: webhook1-certificate
+ dnsNames:
+ - webhook1.example1
+ issuerRef:
+ name: selfsigned
+
+---
+
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: selfsigned
+ namespace: example1
+spec:
+ selfSigned: {}
+```
+
+You should find that the `caBundle` value is now identical to the CA value in the `Secret` for the `Certificate`:
+
+```
+kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io webhook1 -o yaml | grep caBundle
+kubectl -n example1 get secret webhook1-certificate -o yaml | grep ca.crt
+```
+
+And after a short time, the Kubernetes API server will read that new `caBundle` value and use it to verify a TLS connection to the webhook server.
+
+### Injecting CA data from a Secret resource
+
+Here is another example of a `ValidatingWebhookConfiguration`
+this time configured with the annotation `cert-manager.io/inject-ca-from-secret`,
+which will make `cainjector` populate the `caBundle` field using CA data from a Kubernetes `Secret`.
+
+NOTE: This example does not deploy a webhook server,
+it only deploys a partial webhook configuration,
+but it should be sufficient to help you understand what `cainjector` does:
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: example2
+
+---
+
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ name: webhook2
+ annotations:
+ cert-manager.io/inject-ca-from-secret: example2/example-ca
+webhooks:
+- name: webhook2.example.com
+ admissionReviewVersions:
+ - v1
+ clientConfig:
+ service:
+ name: webhook2
+ namespace: example2
+ path: /validate
+ port: 443
+ sideEffects: None
+
+---
+
+apiVersion: v1
+kind: Secret
+metadata:
+ name: example-ca
+ namespace: example2
+ annotations:
+ cert-manager.io/allow-direct-injection: "true"
+type: kubernetes.io/tls
+data:
+ ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM5akNDQWQ2Z0F3SUJBZ0lRTkdJZ24yM3BQYVpNbk9MUjJnVmZHakFOQmdrcWhraUc5dzBCQVFzRkFEQVYKTVJNd0VRWURWUVFERXdwRmVHRnRjR3hsSUVOQk1CNFhEVEl3TURreU5ERTFOREEwTVZvWERUSXdNVEl5TXpFMQpOREEwTVZvd0ZURVRNQkVHQTFVRUF4TUtSWGhoYlhCc1pTQkRRVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFECmdnRVBBRENDQVFvQ2dnRUJBS2F3RzVoMzlreHdyNEl0WCtHaDNYVWQrdTVJc2ZlSFdoTTc4TTRQTmZFeXhQMXoKRmNLN1d0MHJFMkwwNUppYmQ4ZjNpb3k5OXNnQ3I4OEw2SWxYZTB0RnkzNysxenJ4TFluR2hDQnZzZjltd0hLbgpIVTEvNERwQjROZkhPbFllNE9tbHVoNE9HdmZINU1EbDh5OWZGMjhXRXVBQ2dwdmpCUWxvRDNlVjJ5UmJvQ2kyCmtSTDJWYTFZL0FQZEpWK21VYkFvZmg0bllmUmNLRTJsSUg0RG5ZdXFPU3JaaituZUQ2M2RTSktxcHQ5K2luN2YKNHljZ2pQYU93MmdyKzhLK291QTlSQTV1VDI3SVNJcUJDcEV6elRqbVBUUWNvUTYxZGF0aDZkc1lsTEU4aWZWUwp4RWZuVEdQKy94M0FXQXR4eU5lanVuZGFXbVNFL3h5OHh0K0FxblVDQXdFQUFhTkNNRUF3RGdZRFZSMFBBUUgvCkJBUURBZ0trTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkowNkc5eEc2V1VBTHB6T3JYaHAKV2dsTm5qMkFNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUI3ZG9CZnBLR3o4VlRQSnc0YXhpdisybzJpMHE1SQpSRzU2UE81WnhKQktZQlRROElHQmFOSm1yeGtmNTJCV0ttUGp4cXlNSGRwWjVBU00zOUJkZVUzRGtEWHp4RkgwCjM5RU12UnhIUERyMGQ4cTFFbndQT0xZY1hzNjJhYjdidE11cTJUMFNNZzRYMkY5VmNKTW5YdjlrNnA0VGZNR3MKVThCQnJhVGhUZm53ejBsWXMyblFjdzNmZjZ1bG1wWlk4K3BTak1aVDNJZHZOMFA4Y2hOdUlmUFRHWDJmSlo2NQpxcUUrelRoU3hIeXFTOTVoczhsd1lRRUhGQlVsalRnMCtQZThXL0hOSXZBOU9TYWw1U3UvdlhydmcxN04xdHVyCk5XcWRyZU5OVm1ubXMvTFJodmthWTBGblRvbFNBRkNXWS9GSDY5ZzRPcThiMHVyK3JVMHZOZFFXCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
+ tls.key: ""
+ tls.crt: ""
+```
+
+You should find that the `caBundle` value is now identical to the `ca.crt` value in the `Secret`:
+
+```
+kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io webhook2 -o yaml | grep caBundle
+```
+
+And after a short time, the Kubernetes API server will read that new `caBundle` value and use it to verify a TLS connection to the webhook server.
+
+This `Secret` based injection mechanism can operate independently of the `Certificate` based mechanism described earlier.
+It will work without the cert-manager CRDs installed
+and it will work if the cert-manager CRDs and associated webhook servers are not yet configured.
+
+NOTE: For this reason, cert-manager uses the `Secret` based injection mechanism to bootstrap its own webhook server.
+The cert-manager webhook server generates its own private key and self-signed certificate and places them in a `Secret` when it starts up.
+
+### Injecting the Kubernetes API Server CA
+
+Here is another example of a `ValidatingWebhookConfiguration`
+this time configured with the annotation `cert-manager.io/inject-apiserver-ca: "true"`,
+which will make `cainjector` populate the `caBundle` field using the same CA certificate used by the Kubernetes API server.
+
+NOTE: This example does not deploy a webhook server,
+it only deploys a partial webhook configuration,
+but it should be sufficient to help you understand what `cainjector` does:
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: example3
+
+---
+
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+ name: webhook3
+ annotations:
+ cert-manager.io/inject-apiserver-ca: "true"
+webhooks:
+- name: webhook3.example.com
+ admissionReviewVersions:
+ - v1
+ clientConfig:
+ service:
+ name: webhook3
+ namespace: example3
+ path: /validate
+ port: 443
+ sideEffects: None
+
+```
+
+You should find that the `caBundle` value is now identical to the CA used in your `KubeConfig` file:
+
+```
+kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io webhook3 -o yaml | grep caBundle
+kubectl config view --minify --raw | grep certificate-authority-data
+```
+
+And after a short time, the Kubernetes API server will read that new `caBundle` value and use it to verify a TLS connection to the webhook server.
+
+NOTE: In this case you will have to ensure that your webhook is configured to serve a TLS certificate that has been signed by the Kubernetes cluster CA.
+The disadvantages of this mechanism are that: you will require access to the private key of the Kubernetes cluster CA and you will need to manually rotate the webhook certificate.
+
+[Validating Webhooks]: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#validatingadmissionwebhook
+[Mutating Webhooks]: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#mutatingadmissionwebhook
+[Conversion Webhooks]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-conversion
+[API Services]: https://kubernetes.io/docs/reference/kubernetes-api/cluster-resources/api-service-v1/
+[Extension API Server]: https://kubernetes.io/docs/tasks/extend-kubernetes/setup-extension-api-server/
\ No newline at end of file
diff --git a/content/v1.12-docs/concepts/certificate.md b/content/v1.12-docs/concepts/certificate.md
new file mode 100644
index 00000000000..3d8ca12198e
--- /dev/null
+++ b/content/v1.12-docs/concepts/certificate.md
@@ -0,0 +1,106 @@
+---
+title: Certificate
+description: 'cert-manager core concepts: Certificates'
+---
+
+cert-manager has the concept of `Certificates` that define a desired X.509
+certificate which will be renewed and kept up to date. A `Certificate` is a
+namespaced resource that references an `Issuer` or `ClusterIssuer` that
+determine what will be honoring the certificate request.
+
+When a `Certificate` is created, a corresponding `CertificateRequest` resource
+is created by cert-manager containing the encoded X.509 certificate request,
+`Issuer` reference, and other options based upon the specification of the
+`Certificate` resource.
+
+Here is one such example of a `Certificate` resource.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: acme-crt
+spec:
+ secretName: acme-crt-secret
+ dnsNames:
+ - example.com
+ - foo.example.com
+ issuerRef:
+ name: letsencrypt-prod
+ # We can reference ClusterIssuers by changing the kind here.
+ # The default value is Issuer (i.e. a locally namespaced Issuer)
+ kind: Issuer
+ group: cert-manager.io
+```
+
+This `Certificate` will tell cert-manager to attempt to use the `Issuer` named
+`letsencrypt-prod` to obtain a certificate key pair for the `example.com` and
+`foo.example.com` domains. If successful, the resulting TLS key and certificate
+will be stored in a secret named `acme-crt-secret`, with keys of `tls.key`, and
+`tls.crt` respectively. This secret will live in the same namespace as the
+`Certificate` resource.
+
+When a certificate is issued by an intermediate CA and the `Issuer` can provide
+the issued certificate's chain, the contents of `tls.crt` will be the requested
+certificate followed by the certificate chain.
+
+Additionally, if the Certificate Authority is known, the corresponding CA
+certificate will be stored in the secret with key `ca.crt`. For example, with
+the ACME issuer, the CA is not known and `ca.crt` will not exist in
+`acme-crt-secret`.
+
+cert-manager intentionally avoids adding root certificates to `tls.crt`, because they
+are useless in a situation where TLS is being done securely. For more information,
+see [RFC 5246 section 7.4.2](https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.2)
+which contains the following explanation:
+
+> Because certificate validation requires that root keys be distributed
+> independently, the self-signed certificate that specifies the root
+> certificate authority MAY be omitted from the chain, under the
+> assumption that the remote end must already possess it in order to
+> validate it in any case.
+
+
+
+When configuring a client to connect to a TLS server with a serving certificate that is signed by a private CA,
+you will need to provide the client with the CA certificate in order for it to verify the server.
+`ca.crt` will likely contain the certificate you need to trust,
+but __do not mount the same `Secret` as the server__ to access `ca.crt`.
+This is because:
+
+1. That `Secret` also contains the private key of the server, which should only be accessible to the server.
+ You should use RBAC to ensure that the `Secret` containing the serving certificate and private key are only accessible to Pods that need it.
+2. Rotating CA certificates safely relies on being able to have both the old and new CA certificates trusted at the same time.
+ By consuming the CA directly from the source, this isn't possible;
+ you'll be _forced_ to have some down-time in order to rotate certificates.
+
+When configuring the client you should independently choose and fetch the CA certificates that you want to trust.
+Download the CA out of band and store it in a `Secret` or `ConfigMap` separate from the `Secret` containing the server's private key and certificate.
+
+This ensures that if the material in the `Secret` containing the server key and certificate is tampered with,
+the client will fail to connect to the compromised server.
+
+The same concept also applies when configuring a server for mutually-authenticated TLS;
+don't give the server access to Secret containing the client certificate and private key.
+
+
+
+The `dnsNames` field specifies a list of [`Subject Alternative
+Names`](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to be associated
+with the certificate.
+
+The referenced `Issuer` must exist in the same namespace as the `Certificate`.
+A `Certificate` can alternatively reference a `ClusterIssuer` which is
+non-namespaced and so can be referenced from any namespace.
+
+You can read more on how to configure your `Certificate` resources
+[here](../usage/certificate.md).
+
+## Certificate Lifecycle
+
+This diagram shows the lifecycle of a Certificate named `cert-1` using an
+ACME / Let's Encrypt issuer. You don't need to understand all of these steps
+to use cert-manager; this is more of an explanation of the logic which happens
+under the hood for those curious about the process.
+
+![Life of a Certificate](/images/letsencrypt-flow-cert-manager.png)
\ No newline at end of file
diff --git a/content/v1.12-docs/concepts/certificaterequest.md b/content/v1.12-docs/concepts/certificaterequest.md
new file mode 100644
index 00000000000..5dbc1ca5465
--- /dev/null
+++ b/content/v1.12-docs/concepts/certificaterequest.md
@@ -0,0 +1,261 @@
+---
+title: CertificateRequest
+description: 'cert-manager core concepts: CertificateRequests'
+---
+
+The `CertificateRequest` is a namespaced resource in cert-manager that is used
+to request X.509 certificates from an [`Issuer`](./issuer.md). The resource
+contains a base64 encoded string of a PEM encoded certificate request which is
+sent to the referenced issuer. A successful issuance will return a signed
+certificate, based on the certificate signing request. `CertificateRequests` are
+typically consumed and managed by controllers or other systems and should not be
+used by humans - unless specifically needed.
+
+A simple `CertificateRequest` looks like the following:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: CertificateRequest
+metadata:
+ name: my-ca-cr
+spec:
+ request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQzNqQ0NBY1lDQVFBd2daZ3hDekFKQmdOVkJBWVRBbHBhTVE4d0RRWURWUVFJREFaQmNHOXNiRzh4RFRBTApCZ05WQkFjTUJFMXZiMjR4RVRBUEJnTlZCQW9NQ0VwbGRITjBZV05yTVJVd0V3WURWUVFMREF4alpYSjBMVzFoCmJtRm5aWEl4RVRBUEJnTlZCQU1NQ0dwdmMyaDJZVzVzTVN3d0tnWUpLb1pJaHZjTkFRa0JGaDFxYjNOb2RXRXUKZG1GdWJHVmxkWGRsYmtCcVpYUnpkR0ZqYXk1cGJ6Q0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQwpBUW9DZ2dFQkFLd01tTFhuQkNiRStZdTIvMlFtRGsxalRWQ3BvbHU3TlZmQlVFUWl1bDhFMHI2NFBLcDRZQ0c5Cmx2N2kwOHdFMEdJQUgydnJRQmxVd3p6ZW1SUWZ4YmQvYVNybzRHNUFBYTJsY2NMaFpqUlh2NEVMaER0aVg4N3IKaTQ0MWJ2Y01OM0ZPTlRuczJhRkJYcllLWGxpNG4rc0RzTEVuZmpWdXRiV01Zeis3M3ptaGZzclRJUjRzTXo3cQpmSzM2WFM4UkRjNW5oVVcyYU9BZ3lnbFZSOVVXRkxXNjNXYXVhcHg2QUpBR1RoZnJYdVVHZXlZUUVBSENxZmZmCjhyOEt3YTFYK1NwYm9YK1ppSVE0Nk5jQ043OFZnL2dQVHNLZmphZURoNWcyNlk1dEVidHd3MWdRbWlhK0MyRHIKWHpYNU13RzJGNHN0cG5kUnRQckZrU1VnMW1zd0xuc0NBd0VBQWFBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQgpBUUFXR0JuRnhaZ0gzd0N3TG5IQ0xjb0l5RHJrMUVvYkRjN3BJK1VVWEJIS2JBWk9IWEFhaGJ5RFFLL2RuTHN3CjJkZ0J3bmlJR3kxNElwQlNxaDBJUE03eHk5WjI4VW9oR3piN0FVakRJWHlNdmkvYTJyTVhjWjI1d1NVQmxGc28Kd005dE1QU2JwcEVvRERsa3NsOUIwT1BPdkFyQ0NKNnZGaU1UbS9wMUJIUWJSOExNQW53U0lUYVVNSFByRzJVMgpjTjEvRGNMWjZ2enEyeENjYVoxemh2bzBpY1VIUm9UWmV1ZEp6MkxmR0VHM1VOb2ppbXpBNUZHd0RhS3BySWp3ClVkd1JmZWZ1T29MT1dNVnFNbGRBcTlyT24wNHJaT3Jnak1HSE9tTWxleVdPS1AySllhaDNrVDdKU01zTHhYcFYKV0ExQjRsLzFFQkhWeGlKQi9Zby9JQWVsCi0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
+ isCA: false
+ usages:
+ - signing
+ - digital signature
+ - server auth
+ # 90 days
+ duration: 2160h
+ issuerRef:
+ name: ca-issuer
+ # We can reference ClusterIssuers by changing the kind here.
+ # The default value is Issuer (i.e. a locally namespaced Issuer)
+ kind: Issuer
+ group: cert-manager.io
+```
+
+This `CertificateRequest` will make cert-manager attempt to request the `Issuer`
+`ca-issuer` in the default issuer group `cert-manager.io`, return a
+certificate based upon the certificate signing request. Other groups can be
+specified inside the `issuerRef` which will change the targeted issuer to other
+external, third party issuers you may have installed.
+
+The resource also exposes the option for stating the certificate as CA, Key
+Usages, and requested validity duration.
+
+All fields within the `spec` of the `CertificateRequest`, as well as any managed
+cert-manager annotations, are immutable and cannot be modified after creation.
+
+A successful issuance of the certificate signing request will cause an update to
+the resource, setting the status with the signed certificate, the CA of the
+certificate (if available), and setting the `Ready` condition to `True`.
+
+Whether issuance of the certificate signing request was successful or not, a retry of the
+issuance will _not_ happen. It is the responsibility of some other controller to
+manage the logic and life cycle of `CertificateRequests`.
+
+## Conditions
+`CertificateRequests` have a set of strongly defined conditions that should be
+used and relied upon by controllers or services to make decisions on what
+actions to take next on the resource.
+
+### Ready
+Each ready condition consists of the pair `Ready` - a boolean value, and
+`Reason` - a string. The set of values and meanings are as follows:
+
+| Ready | Reason | Condition Meaning |
+| ----- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| False | Pending | The `CertificateRequest` is currently pending, waiting for some other operation to take place. This could be that the `Issuer` does not exist yet or the `Issuer` is in the process of issuing a certificate. |
+| False | Failed | The certificate has failed to be issued - either the returned certificate failed to be decoded or an instance of the referenced issuer used for signing failed. No further action will be taken on the `CertificateRequest` by its controller and it can be considered terminally failed. |
+| True | Issued | A signed certificate has been successfully issued by the referenced `Issuer`. |
+
+This condition should be set by the issuer.
+
+### Denied
+| Denied | Reason | Condition Meaning |
+| ----- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| True | \ | The `CertificateRequest` was Denied by an approver. This `CertificateRequest` can be considered terminally failed.
+
+This condition should only be set by an approver.
+
+### Approved
+| Approved | Reason | Condition Meaning |
+| ----- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| True | \ | The `CertificateRequest` was approved by the approver. This `CertificateRequest` is approved and can be issued by the issuer.
+
+This condition should only be set by an approver.
+
+### InvalidRequest
+| InvalidRequest | Reason | Condition Meaning |
+| ----- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| True | \ | The `CertificateRequest` is invalid. This `CertificateRequest` can be considered terminally failed.
+
+
+## UserInfo
+
+`CertificateRequests` include a set of `UserInfo` fields as part of the spec,
+namely: `username`, `groups`, `uid`, and `extra`. These values contain the user
+who created the `CertificateRequest`. This user will be cert-manager itself in
+the case that the `CertificateRequest` was created by a
+[`Certificate`](./certificate.md) resource, or instead the user who created the
+`CertificateRequest` directly.
+
+> **Warning**: These fields are managed by cert-manager and should _never_ be
+> set or modified by anything else. When the `CertificateRequest` is created,
+> these fields will be overridden, and any request attempting to modify them
+> will be rejected.
+
+
+### Approval
+CertificateRequests can be `Approved` or `Denied`. These mutually exclusive
+conditions gate a CertificateRequest from being signed by its managed signer.
+
+- A signer should _not_ sign a managed CertificateRequest without an Approved condition
+- A signer _will_ sign a managed CertificateRequest with an Approved condition
+- A signer will _never_ sign a managed CertificateRequest with a Denied condition
+
+These conditions are _permanent_, and cannot be modified or changed once set.
+
+```bash
+NAMESPACE NAME APPROVED DENIED READY ISSUER REQUESTOR AGE
+istio-system service-mesh-ca-whh5b True True mesh-ca system:serviceaccount:istio-system:istiod 16s
+istio-system my-app-fj9sa True mesh-ca system:serviceaccount:my-app:my-app 4s
+```
+
+
+#### Behavior
+
+The Approved and Denied conditions are two distinct condition types on the
+CertificateRequest. These conditions must only have the status of True, and
+are mutually exclusive (i.e. a CertificateRequest cannot have an Approved and
+Denied condition simultaneously). This behavior is enforced in the cert-manager
+validating admission webhook.
+
+An "approver" is an entity that is responsible for setting the Approved/Denied
+conditions. It is up to the approver's implementation as to what
+CertificateRequests are managed by that approver.
+
+The Reason field of the Approved/Denied condition should be set to *who* set the
+condition. Who can be interpreted however makes sense to the approver
+implementation. For example, it may include the API group of an approving policy
+controller, or the client agent of a manual request.
+
+The Message field of the Approved/Denied condition should be set to *why* the
+condition is set. Again, why can be interpreted however makes sense to the
+implementation of the approver. For example, the name of the resource that
+approves this request, the violations which caused the request to be denied, or
+the team to who manually approved the request.
+
+
+#### Approver Controller
+
+By default, cert-manager will run an internal approval controller which will
+automatically approve _all_ CertificateRequests that reference any internal
+issuer type in any namespace: `cert-manager.io/Issuer`,
+`cert-manager.io/ClusterIssuer`.
+
+To disable this controller, add the following argument to the
+cert-manager-controller: `--controllers=*,-certificaterequests-approver`. This
+can be achieved with helm by appending:
+
+```bash
+--set extraArgs={--controllers='*\,-certificaterequests-approver'}
+```
+
+Alternatively, in order for the internal approver controller to approve
+CertificateRequests that reference an external issuer, add the following RBAC to
+the cert-manager-controller Service Account. Please replace the given resource
+names with the relevant names:
+
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: cert-manager-controller-approve:my-issuer-example-com # edit
+rules:
+- apiGroups:
+ - cert-manager.io
+ resources:
+ - signers
+ verbs:
+ - approve
+ resourceNames:
+ - issuers.my-issuer.example.com/* # edit
+ - clusterissuers.my-issuer.example.com/* # edit
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: cert-manager-controller-approve:my-issuer-example-com # edit
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cert-manager-controller-approve:my-issuer-example-com # edit
+subjects:
+- kind: ServiceAccount
+ name: cert-manager
+ namespace: cert-manager
+```
+
+#### RBAC Syntax
+
+When a user or controller attempts to approve or deny a CertificateRequest, the
+cert-manager webhook will evaluate whether it has sufficient permissions to do
+so. These permissions are based upon the request
+itself- specifically the request's IssuerRef:
+
+```yaml
+apiGroups: ["cert-manager.io"]
+resources: ["signers"]
+verbs: ["approve"]
+resourceNames:
+ # namesapced signers
+ - "./."
+ # cluster scoped signers
+ - "./"
+ # all signers of this resource name
+ - "./*"
+```
+
+An example ClusterRole that would grant the permissions to set the Approve and
+Denied conditions of CertificateRequests that reference the cluster scoped
+`myissuers` external issuer, in the group `my-example.io`, with the name `myapp`:
+
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: my-example-io-my-issuer-myapp-approver
+rules:
+ - apiGroups: ["cert-manager.io"]
+ resources: ["signers"]
+ verbs: ["approve"]
+ resourceNames: ["myissuers.my-example.io/myapp"]
+```
+
+If the approver does not have sufficient permissions defined above to set the
+Approved or Denied conditions, the request will be rejected by the cert-manager
+validating admission webhook.
+
+- The RBAC permissions *must* be granted at the cluster scope
+- Namespaced signers are represented by a namespaced resource using the syntax of `./.`
+- Cluster scoped signers are represented using the syntax of `./`
+- An approver can be granted approval for all namespaces via `./*`
+- The apiGroup must *always* be `cert-manager.io`
+- The resource must *always* be `signers`
+- The verb must *always* be `approve`, which grants the approver the permissions to set *both* Approved and Denied conditions
+
+An example of signing all `myissuer` signers in all namespaces, and
+`clustermyissuers` with the name `myapp`, in the `my-example.io` group:
+
+```yaml
+ resourceNames: ["myissuers.my-example.io/*", "clustermyissuers.my-example.io/myapp"]
+```
+
+An example of signing `myissuer` with the name `myapp` in the namespaces `foo`
+and `bar`:
+
+```yaml
+ resourceNames: ["myissuers.my-example.io/foo.myapp", "myissuers.my-example.io/bar.myapp"]
+```
\ No newline at end of file
diff --git a/content/v1.12-docs/concepts/issuer.md b/content/v1.12-docs/concepts/issuer.md
new file mode 100644
index 00000000000..6293369992c
--- /dev/null
+++ b/content/v1.12-docs/concepts/issuer.md
@@ -0,0 +1,44 @@
+---
+title: Issuer
+description: 'cert-manager core concepts: Issuers and ClusterIssuers'
+---
+
+`Issuers`, and `ClusterIssuers`, are Kubernetes resources that represent
+certificate authorities (CAs) that are able to generate signed certificates by honoring
+certificate signing requests. All cert-manager certificates require a referenced
+issuer that is in a ready condition to attempt to honor the request.
+
+An example of an `Issuer` type is `CA`. A simple `CA` `Issuer` is as follows:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: ca-issuer
+ namespace: mesh-system
+spec:
+ ca:
+ secretName: ca-key-pair
+```
+
+This is a simple `Issuer` that will sign certificates based on a private key.
+The certificate stored in the secret `ca-key-pair` can then be used to trust
+newly signed certificates by this `Issuer` in a Public Key Infrastructure (PKI)
+system.
+
+## Namespaces
+
+An `Issuer` is a namespaced resource, and it is not possible to issue
+certificates from an `Issuer` in a different namespace. This means you will need
+to create an `Issuer` in each namespace you wish to obtain `Certificates` in.
+
+If you want to create a single `Issuer` that can be consumed in multiple
+namespaces, you should consider creating a `ClusterIssuer` resource. This is
+almost identical to the `Issuer` resource, however is non-namespaced so it
+can be used to issue `Certificates` across all namespaces.
+
+## Supported Issuers
+
+cert-manager supports a number of 'in-tree', as well as 'out-of-tree' `Issuer`
+types. An exhaustive list of these `Issuer` types can be found in the
+cert-manager [configuration documentation](../configuration/README.md).
diff --git a/content/v1.12-docs/concepts/webhook.md b/content/v1.12-docs/concepts/webhook.md
new file mode 100644
index 00000000000..1bcbbee7695
--- /dev/null
+++ b/content/v1.12-docs/concepts/webhook.md
@@ -0,0 +1,80 @@
+---
+title: All About the cert-manager Webhook
+description: |
+ Learn about the webhook component of cert-manager, which validates, converts and sets default values for the cert-manager custom resources
+---
+
+cert-manager extends the Kubernetes API using Custom Resource Definitions.
+It installs a webhook which has three main functions:
+
+- [Validation](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#validatingadmissionwebhook):
+ Ensures that when cert-manager resources are created or updated, they conform
+ to the rules of the API. This validation is more in depth than for example
+ ensuring resources conform to the OpenAPI schema, but instead contains logic such as
+ not allowing to specify more than one `Issuer` type per `Issuer` resource. The
+ validating admission is always called and will respond with a success or
+ failed response.
+- [Mutation / Defaulting](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#mutatingadmissionwebhook):
+ Changes the contents of resources during create and update operations, for
+ example to set default values.
+- [Conversion](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-conversion):
+ The webhook is also responsible for implementing a conversion over versions
+ in the cert-manager `CustomResources` (`cert-manager.io`). This means that
+ multiple API versions can be supported simultaneously; from `v1alpha2` through to `v1`.
+ This makes it possible to rely on a particular version of our
+ configuration schema.
+
+> ℹ️ This is known as Dynamic Admission Control.
+> Read more about [Dynamic Admission Control](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) in the Kubernetes documentation.
+
+## Overview
+
+The webhook component is deployed as another pod that runs alongside the main
+cert-manager controller and CA injector components.
+
+In order for the API server to communicate with the webhook component, the
+webhook requires a TLS certificate that the apiserver is configured to trust.
+
+The [`cainjector`](./ca-injector.md) creates `secret/cert-manager-webhook-ca`, a self-signed root CA certificate which is used to sign certificates for the webhook pod.
+
+Then the webhook can be configured with either
+
+1. paths to a TLS certificate and key signed by the webhook CA, or
+2. a reference to the CA Secret for dynamic generation of the certificate and key on webhook startup
+
+## Known Problems and Solutions
+
+### Webhook connection problems on GKE private cluster
+
+If errors occur around the webhook but the webhook is running then the webhook
+is most likely not reachable from the API server. In this case, ensure that the
+API server can communicate with the webhook by following the [GKE private
+cluster explanation](../installation/compatibility.md#gke).
+
+### Webhook connection problems on AWS EKS
+
+When using a custom CNI (such as Weave or Calico) on EKS, the webhook cannot be reached by cert-manager.
+This happens because the control plane cannot be configured to run on a custom CNI on EKS,
+so the CNIs differ between control plane and worker nodes.
+The solution is to [run the webhook in the host network](../installation/compatibility.md#aws-eks) so it can be reached by cert-manager.
+
+### Webhook connection problems shortly after cert-manager installation
+
+When you first install cert-manager, it will take a few seconds before the cert-manager API is usable.
+This is because the cert-manager API requires the cert-manager webhook server, which takes some time to start up.
+Here's why:
+
+* The webhook server performs a leader election at startup which may take a few seconds.
+* The webhook server may take a few seconds to start up and to generate its self-signed CA and serving certificate and to publish those to a Secret.
+* `cainjector` performs a leader election at start up which can take a few seconds.
+* `cainjector`, once started, will take a few seconds to update the `caBundle` in all the webhook configurations.
+
+For these reasons, after installing cert-manager and when performing post-installation cert-manager API operations,
+you will need to check for temporary API configuration errors and retry.
+
+You could also add a post-installation check which performs `kubectl --dry-run` operations on the cert-manager API.
+Or you could add a post-installation check which automatically retries the [Installation Verification](../installation/verify.md) steps until they succeed.
+
+### Other Webhook Problems
+
+If you encounter any other problems with the webhook, please refer to the [webhook troubleshooting guide](../troubleshooting/webhook.md).
diff --git a/content/v1.12-docs/configuration/README.md b/content/v1.12-docs/configuration/README.md
new file mode 100644
index 00000000000..85c5d1334f7
--- /dev/null
+++ b/content/v1.12-docs/configuration/README.md
@@ -0,0 +1,30 @@
+---
+title: Issuer Configuration
+description: Learn about configuring cert-manager using Issuer and ClusterIssuer resources.
+---
+
+The first thing you'll need to configure after you've installed cert-manager is an `Issuer` or a `ClusterIssuer`.
+These are resources that represent certificate authorities (CAs)
+able to sign certificates in response to certificate signing requests.
+
+This section documents how the different issuer types can be configured. You might want to
+[read more about `Issuer` and `ClusterIssuer` resources](../concepts/issuer.md).
+
+cert-manager comes with a number of built-in certificate issuers which are denoted by being in
+the `cert-manager.io` group. You can also install external issuers in addition to the built-in types.
+Built-in and external issuers are treated the same and are configured similarly.
+
+## Cluster Resource Namespace
+
+When using `ClusterIssuer` resource types, ensure you understand the purpose of the
+Cluster Resource Namespace; this can be a common source
+of issues for people getting started with cert-manager.
+
+The `ClusterIssuer` resource is cluster scoped. This means that when referencing
+a secret via the `secretName` field, secrets will be looked for in the `Cluster
+Resource Namespace`. By default, this namespace is `cert-manager` however it can be
+changed via a flag on the cert-manager-controller component:
+
+```bash
+--cluster-resource-namespace=my-namespace
+```
diff --git a/content/v1.12-docs/configuration/acme/README.md b/content/v1.12-docs/configuration/acme/README.md
new file mode 100644
index 00000000000..3c658510e03
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/README.md
@@ -0,0 +1,392 @@
+---
+title: ACME
+description: 'cert-manager configuration: ACME Issuers'
+---
+
+The ACME Issuer type represents a single account registered with the Automated
+Certificate Management Environment (ACME) Certificate Authority server. When you
+create a new ACME `Issuer`, cert-manager will generate a private key which is
+used to identify you with the ACME server.
+
+Certificates issued by public ACME servers are typically trusted by client's
+computers by default. This means that, for example, visiting a website that is
+backed by an ACME certificate issued for that URL, will be trusted by default by
+most client's web browsers. ACME certificates are typically free.
+
+## Solving Challenges
+
+In order for the ACME CA server to verify that a client owns the domain, or
+domains, a certificate is being requested for, the client must complete
+"challenges". This is to ensure clients are unable to request certificates for
+domains they do not own and as a result, fraudulently impersonate another's
+site. As detailed in the [RFC8555](https://tools.ietf.org/html/rfc8555),
+cert-manager offers two challenge validations - HTTP01 and DNS01 challenges.
+
+[HTTP01](./http01/README.md) challenges are completed by presenting a computed
+key, that should be present at a HTTP URL endpoint and is routable over the
+internet. This URL will use the domain name requested for the certificate. Once
+the ACME server is able to get this key from this URL over the internet, the
+ACME server can validate you are the owner of this domain. When a HTTP01
+challenge is created, cert-manager will automatically configure your cluster
+ingress to route traffic for this URL to a small web server that presents this
+key.
+
+[DNS01](./dns01/README.md) challenges are completed by providing a computed key
+that is present at a DNS TXT record. Once this TXT record has been propagated
+across the internet, the ACME server can successfully retrieve this key via a
+DNS lookup and can validate that the client owns the domain for the requested
+certificate. With the correct permissions, cert-manager will automatically
+present this TXT record for your given DNS provider.
+
+## Configuration
+
+### Creating a Basic ACME Issuer
+
+All ACME `Issuers` follow a similar configuration structure - a clients `email`,
+a `server` URL, a `privateKeySecretRef`, and one or more `solvers`. Below is an
+example of a simple ACME issuer:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-staging
+spec:
+ acme:
+ # You must replace this email address with your own.
+ # Let's Encrypt will use this to contact you about expiring
+ # certificates, and issues related to your account.
+ email: user@example.com
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ privateKeySecretRef:
+ # Secret resource that will be used to store the account's private key.
+ name: example-issuer-account-key
+ # Add a single challenge solver, HTTP01 using nginx
+ solvers:
+ - http01:
+ ingress:
+ class: nginx
+```
+
+Solvers come in the form of [`dns01`](./dns01/README.md) and
+[`http01`](./http01/README.md) stanzas. For more information on how to configure
+these solver types, visit their respective documentation -
+[DNS01](./dns01/README.md), [HTTP01](./http01/README.md).
+
+### External Account Bindings
+
+cert-manager supports using External Account Bindings with your ACME account.
+External Account Bindings are used to associate your ACME account with an
+external account such as a CA custom database. This is typically not needed for
+most cert-manager users unless you know it is explicitly needed.
+
+External Account Bindings require two fields on an ACME `Issuer` which
+represents your ACME account. These fields are:
+
+- `keyID` - the key ID or account ID of which your external account binding is indexed by the
+external account manager
+- `keySecretRef` - the name and key of a secret containing a base 64 encoded
+URL string of your external account symmetric MAC key
+
+> Note: In _most_ cases, the MAC key must be encoded in `base64URL`. The
+> following command will base64-encode a key and convert it to `base64URL`:
+>
+> ```console
+> $ echo 'my-secret-key' | base64 -w0 | sed -e 's/+/-/g' -e 's/\//_/g' -e 's/=//g'
+> ```
+>
+> You can then create the Secret resource with:
+>
+> ```console
+> $ kubectl create secret generic eab-secret --from-literal \
+> secret={base64 encoded secret key}
+> ```
+
+An example of an ACME issuer with an External Account Binding is as follows.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: my-acme-server-with-eab
+spec:
+ acme:
+ email: user@example.com
+ server: https://my-acme-server-with-eab.com/directory
+ externalAccountBinding:
+ keyID: my-keyID-1
+ keySecretRef:
+ name: eab-secret
+ key: secret
+ privateKeySecretRef:
+ name: example-issuer-account-key
+ solvers:
+ - http01:
+ ingress:
+ class: nginx
+```
+> Note: cert-manager versions pre-`v1.3.0` also required users to specify the
+> MAC algorithm for EAB by setting
+> `Issuer.spec.acme.externalAccountBinding.keyAlgorithm` field. This field is
+> now deprecated because the upstream Go `x/crypto` library hardcodes the algorithm
+> to `HS256`. (See related discussion upstream
+> [`CL#41430`](https://github.com/golang/go/issues/41430)).
+### Reusing an ACME Account
+
+You may want to reuse a single ACME account across multiple clusters. This
+might especially be useful when using EAB. If the `disableAccountKeyGeneration`
+field is set, cert-manager will not create a new ACME account and use the
+existing key specified in `privateKeySecretRef`. Note that the
+`Issuer`/`ClusterIssuer` will not be ready and will continue to retry until the
+`Secret` is provided.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: my-acme-server-with-existing-acme-account
+spec:
+ acme:
+ email: user@example.com
+ disableAccountKeyGeneration: true
+ privateKeySecretRef:
+ name: example-issuer-account-key
+```
+
+
+### Adding Multiple Solver Types
+
+You may want to use different types of challenge solver configurations for
+different ingress controllers, for example if you want to issue wildcard
+certificates using `DNS01` alongside other certificates that are validated using
+`HTTP01`.
+
+The `solvers` stanza has an optional `selector` field, that can be used to
+specify which `Certificates`, and further, what DNS names *on those*
+`Certificates` should be used to solve challenges.
+
+There are three selector types that can be used to form the requirements that a
+`Certificate` must meet in order to be selected for a solver - `matchLabels`,
+`dnsNames` and `dnsZones`. You can have any number of these three selectors on a
+single solver.
+
+
+#### Match Labels
+
+The `matchLabel` selector requires that all `Certificates` match all of
+the labels that are defined in the string map list of that stanza. For example,
+the following `Issuer` will only match on `Certificates` that have the labels
+`"user-cloudflare-solver": "true"` and `"email": "user@example.com"`.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-staging
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ cloudflare:
+ email: user@example.com
+ apiKeySecretRef:
+ name: cloudflare-apikey-secret
+ key: apikey
+ selector:
+ matchLabels:
+ "use-cloudflare-solver": "true"
+ "email": "user@example.com"
+```
+
+#### DNS Names
+
+The `dnsNames` selector is a list of exact DNS names that should be mapped to a
+solver. This means that `Certificates` containing any of these DNS names will
+be selected. If a match is found, a `dnsNames` selector will take precedence
+over a [`dnsZones`](#dns-zones) selector. If multiple solvers match with the
+same `dnsNames` value, the solver with the most matching labels in
+[`matchLabels`](#match-labels) will be selected. If neither has more matches,
+the solver defined earlier in the list will be selected.
+
+The following example will solve challenges of `Certificates` with DNS names
+`example.com` and `*.example.com` for these domains.
+
+> Note: `dnsNames` take an exact match and do not resolve wildcards, meaning the
+> following `Issuer` *will not* solve for DNS names such as `foo.example.com`.
+> Use the [`dnsZones`](#dns-zones) selector type to match all subdomains within
+> a zone.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-staging
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ cloudflare:
+ email: user@example.com
+ apiKeySecretRef:
+ name: cloudflare-apikey-secret
+ key: apikey
+ selector:
+ dnsNames:
+ - 'example.com'
+ - '*.example.com'
+```
+
+#### DNS Zones
+
+The `dnsZones` stanza defines a list of DNS zones that can be solved by this
+solver. If a DNS name is an exact match, or a subdomain of any of the specified
+`dnsZones`, this solver will be used, unless a more specific
+[`dnsNames`](#dns-names) match is configured. This means that `sys.example.com`
+will be selected over one specifying `example.com` for the domain
+`www.sys.example.com`. If multiple solvers match with the same `dnsZones` value,
+the solver with the most matching labels in [`matchLabels`](#match-labels) will
+be selected. If neither has more matches, the solver defined earlier in the list
+will be selected.
+
+In the following example, this solver will resolve challenges for the domain
+`example.com`, as well as all of its subdomains `*.example.com`.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-staging
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ cloudflare:
+ email: user@example.com
+ apiKeySecretRef:
+ name: cloudflare-apikey-secret
+ key: apikey
+ selector:
+ dnsZones:
+ - 'example.com'
+```
+
+#### All Together
+
+Each solver is able to have any number of the three selector types defined. In
+the following example, the `DNS01` solver for CloudFlare will be used to solve
+challenges for domains for `Certificates` that contain the DNS names
+`a.example.com` and `b.example.com`. The `DNS01` solver for Google CloudDNS will
+be used to solve challenges for `Certificates` whose DNS names match
+zone `test.example.com` and all of its subdomains (e.g. `foo.test.example.com`).
+
+For all other challenges, the `HTTP01` solver will be used *only* if the
+`Certificate` also contains the label `"use-http01-solver": "true"`.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-staging
+spec:
+ acme:
+ ...
+ solvers:
+ - http01:
+ ingress:
+ class: nginx
+ selector:
+ matchLabels:
+ "use-http01-solver": "true"
+ - dns01:
+ cloudflare:
+ email: user@example.com
+ apiKeySecretRef:
+ name: cloudflare-apikey-secret
+ key: apikey
+ selector:
+ dnsNames:
+ - 'a.example.com'
+ - 'b.example.com'
+ - dns01:
+ cloudDNS:
+ project: my-project-id
+ hostedZoneName: 'test-example.com'
+ serviceAccountSecretRef:
+ key: sa
+ name: gcp-sa-secret
+ selector:
+ dnsZones:
+ - 'test.example.com' # This should be the DNS name of the zone
+```
+
+Each individual selector block can contain more than one selector type for
+example:
+
+```yaml
+solvers:
+- dns01:
+ cloudflare:
+ email: user@example.com
+ apiKeySecretRef:
+ name: cloudflare-apikey-secret
+ key: apikey
+ selector:
+ matchLabels:
+ 'email': 'user@example.com'
+ 'solver': 'cloudflare'
+ dnsZones:
+ - 'test.example.com'
+ - 'example.dev'
+```
+
+In this case the `DNS01` solver for Cloudflare will only be used to solve a
+challenge for a DNS name if the `Certificate` has a label from
+`matchLabels` _and_ the DNS name matches a zone from `dnsZones`.
+
+## Private ACME Servers
+
+cert-manager should also work with private or self-hosted ACME servers, as long as they follow the ACME spec.
+
+If your ACME server doesn't use a publicly trusted certificate, you can pass a trusted CA to use when creating your
+issuer, from cert-manager 1.11 onwards:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: my-acme-server-issuer
+spec:
+ acme:
+ server: https://my-acme-server.example.com
+ caBundle:
+ ...
+```
+
+
+## Alternative Certificate Chains
+
+{/* The empty link below preserves old links to #alternative-certificate-chain", which matched the old title of this section */}
+
+
+
+It's possible to choose alternative certificate chains when fetching a certificate from an ACME server. This allows issuers to gracefully roll people over to a new root certificate during a transition period; the most famous example was the Let's Encrypt ["ISRG Root" changeover](https://community.letsencrypt.org/t/transition-to-isrgs-root-delayed-until-jan-11-2021/125516).
+
+This functionality is not exclusive to Let's Encrypt; if your ACME server supports signing by multiple CAs you can use `preferredChain` with the value of the Common Name of the chain you want in the Issuer part of the certificate. If the common name matches a difference chain, the server can choose to use and return that new chain.
+
+If the `preferredChain` does not match a certificate the server will return whatever it considers to be its default certificate.
+
+By way of an example, below is how a user would have requested an alternative chain before the (now completed) "ISRG Root" changeover, but note that since this change has already happened there's no need for this with Let's Encrypt any more:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt
+spec:
+ acme:
+ server: https://acme-v02.api.letsencrypt.org/directory
+ preferredChain: "ISRG Root X1"
+```
diff --git a/content/v1.12-docs/configuration/acme/dns01/README.md b/content/v1.12-docs/configuration/acme/dns01/README.md
new file mode 100644
index 00000000000..b9240f8045a
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/README.md
@@ -0,0 +1,186 @@
+---
+title: DNS01
+description: 'cert-manager configuration: ACME DNS-01 challenges overview'
+---
+
+## Configuring DNS01 Challenge Provider
+
+This page contains details on the different options available on the `Issuer`
+resource's DNS01 challenge solver configuration.
+
+For more information on configuring ACME `Issuers` and their API format, read the
+[ACME Issuers](../README.md) documentation.
+
+DNS01 provider configuration must be specified on the `Issuer` resource, similar
+to the examples in the setting up documentation.
+
+You can read about how the DNS01 challenge type works on the [Let's Encrypt
+challenge types
+page](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge).
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ email: user@example.com
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ privateKeySecretRef:
+ name: example-issuer-account-key
+ solvers:
+ - dns01:
+ cloudDNS:
+ project: my-project
+ serviceAccountSecretRef:
+ name: prod-clouddns-svc-acct-secret
+ key: service-account.json
+```
+
+Each issuer can specify multiple different DNS01 challenge providers, and
+it is also possible to have multiple instances of the same DNS provider on a
+single `Issuer` (e.g. two CloudDNS accounts could be set, each with their own
+name).
+
+For more information on utilizing multiple solver types on a single `Issuer`,
+read the multiple-solver-types section.
+
+## Setting Nameservers for DNS01 Self Check
+
+cert-manager will check the correct DNS records exist before attempting a DNS01
+challenge. By default cert-manager will use the recursive nameservers taken
+from `/etc/resolv.conf` to query for the authoritative nameservers, which it will
+then query directly to verify the DNS records exist.
+
+If this is not desired (for example with multiple authoritative nameservers or
+split-horizon DNS), the cert-manager controller exposes two flags that allows
+you alter this behavior:
+
+`--dns01-recursive-nameservers` Comma separated string with host and port of the
+recursive nameservers cert-manager should query.
+
+`--dns01-recursive-nameservers-only` Forces cert-manager to only use the
+recursive nameservers for verification. Enabling this option could cause the DNS01
+self check to take longer due to caching performed by the recursive nameservers.
+
+
+Example usage:
+```bash
+--dns01-recursive-nameservers-only --dns01-recursive-nameservers=8.8.8.8:53,1.1.1.1:53
+```
+
+If you're using the `cert-manager` helm chart, you can set recursive nameservers
+through `.Values.extraArgs` or at the command at helm install/upgrade time
+with `--set`:
+
+```bash
+--set 'extraArgs={--dns01-recursive-nameservers-only,--dns01-recursive-nameservers=8.8.8.8:53\,1.1.1.1:53}'
+```
+
+## Delegated Domains for DNS01
+
+By default, cert-manager will not follow CNAME records pointing to subdomains.
+
+If granting cert-manager access to the root DNS zone is not desired, then the
+`_acme-challenge.example.com` subdomain can instead be delegated to some other,
+less privileged domain (`less-privileged.example.org`). This could be achieved in the following way. Say, one has two zones:
+
+* `example.com`
+* `less-privileged.example.org`
+
+1. Create a CNAME record pointing to this less privileged domain:
+```
+_acme-challenge.example.com IN CNAME _acme-challenge.less-privileged.example.org.
+```
+
+2. Grant cert-manager rights to update less privileged `less-privileged.example.org` zone
+
+3. Provide configuration/credentials for updating this less privileged zone
+and add an additional field into the relevant `dns01` solver. Note that `selector`
+field is still working for the original `example.com`, while credentials are provided for
+`less-privileged.example.org`
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ ...
+spec:
+ acme:
+ ...
+ solvers:
+ - selector:
+ dnsZones:
+ - 'example.com'
+ dns01:
+ # Valid values are None and Follow
+ cnameStrategy: Follow
+ route53:
+ region: eu-central-1
+ accessKeyID:
+ hostedZoneID:
+ secretAccessKeySecretRef:
+ ...
+```
+
+If you have a multitude of (sub)domains requiring separate certificates,
+it is possible to share an aliased less-privileged domain. To achieve it one should
+create a CNAME record for each (sub)domain like this:
+
+```txt
+_acme-challenge.example.com IN CNAME _acme-challenge.less-privileged.example.org.
+_acme-challenge.www.example.com IN CNAME _acme-challenge.less-privileged.example.org.
+_acme-challenge.foo.example.com IN CNAME _acme-challenge.less-privileged.example.org.
+_acme-challenge.bar.example.com IN CNAME _acme-challenge.less-privileged.example.org.
+```
+
+With this configuration cert-manager will follow CNAME records recursively in order to determine
+which DNS zone to update during DNS01 challenges.
+
+
+## Supported DNS01 providers
+
+A number of different DNS providers are supported for the ACME `Issuer`. Below
+is a listing of available providers, their `.yaml` configurations, along with
+additional Kubernetes and provider specific notes regarding their usage.
+
+- [ACMEDNS](./acme-dns.md)
+- [Akamai](./akamai.md)
+- [AzureDNS](./azuredns.md)
+- [CloudFlare](./cloudflare.md)
+- [Google](./google.md)
+- [Route53](./route53.md)
+- [DigitalOcean](./digitalocean.md)
+- [RFC2136](./rfc2136.md)
+
+## Webhook
+
+cert-manager also supports out of tree DNS providers using an external webhook.
+Links to these supported providers along with their documentation are below:
+
+- [`AliDNS-Webhook`](https://github.com/pragkent/alidns-webhook)
+- [`cert-manager-alidns-webhook`](https://github.com/DEVmachine-fr/cert-manager-alidns-webhook)
+- [`cert-manager-webhook-civo`](https://github.com/okteto/cert-manager-webhook-civo)
+- [`cert-manager-webhook-dnspod`](https://github.com/qqshfox/cert-manager-webhook-dnspod)
+- [`cert-manager-webhook-dnsimple`](https://github.com/neoskop/cert-manager-webhook-dnsimple)
+- [`cert-manager-webhook-gandi`](https://github.com/bwolf/cert-manager-webhook-gandi)
+- [`cert-manager-webhook-infomaniak`](https://github.com/Infomaniak/cert-manager-webhook-infomaniak)
+- [`cert-manager-webhook-inwx`](https://gitlab.com/smueller18/cert-manager-webhook-inwx)
+- [`cert-manager-webhook-linode`](https://github.com/slicen/cert-manager-webhook-linode)
+- [`cert-manager-webhook-oci`](https://gitlab.com/dn13/cert-manager-webhook-oci) (Oracle Cloud Infrastructure)
+- [`cert-manager-webhook-scaleway`](https://github.com/scaleway/cert-manager-webhook-scaleway)
+- [`cert-manager-webhook-selectel`](https://github.com/selectel/cert-manager-webhook-selectel)
+- [`cert-manager-webhook-softlayer`](https://github.com/cgroschupp/cert-manager-webhook-softlayer)
+- [`cert-manager-webhook-ibmcis`](https://github.com/jb-dk/cert-manager-webhook-ibmcis)
+- [`cert-manager-webhook-loopia`](https://github.com/Identitry/cert-manager-webhook-loopia)
+- [`cert-manager-webhook-arvan`](https://github.com/kiandigital/cert-manager-webhook-arvan)
+- [`bizflycloud-certmanager-dns-webhook`](https://github.com/bizflycloud/bizflycloud-certmanager-dns-webhook)
+- [`cert-manager-webhook-hetzner`](https://github.com/vadimkim/cert-manager-webhook-hetzner)
+- [`cert-manager-webhook-yandex-cloud`](https://github.com/malinink/cert-manager-webhook-yandex-cloud)
+- [`cert-manager-webhook-netcup`](https://github.com/aellwein/cert-manager-webhook-netcup)
+- [`cert-manager-webhook-pdns`](https://github.com/zachomedia/cert-manager-webhook-pdns)
+
+You can find more information on how to configure webhook providers [here](./webhook.md).
+
+To create a new unsupported DNS provider, follow the development documentation [here](../../../contributing/dns-providers.md).
diff --git a/content/v1.12-docs/configuration/acme/dns01/acme-dns.md b/content/v1.12-docs/configuration/acme/dns01/acme-dns.md
new file mode 100644
index 00000000000..968531bf5f0
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/acme-dns.md
@@ -0,0 +1,220 @@
+---
+title: ACMEDNS
+description: 'cert-manager configuration: ACME DNS-01 challenges using ACMEDNS'
+---
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ solvers:
+ - dns01:
+ acmeDNS:
+ host: https://acme.example.com
+ accountSecretRef:
+ name: acme-dns
+ key: acmedns.json
+```
+
+In general, clients to ACMEDNS perform registration on the users behalf and
+inform them of the CNAME entries they must create. This is not possible in
+cert-manager, it is a non-interactive system. Registration must be carried out
+beforehand and the resulting credentials JSON uploaded to the cluster as a
+`Secret`. In this example, we use `curl` and the API endpoints directly.
+Information about setting up and configuring ACMEDNS is available on the
+[ACMEDNS project page](https://github.com/joohoi/acme-dns).
+
+1. First, register with the ACMEDNS server, in this example, there is one
+ running at `auth.example.com`. The command:
+
+ ```sh
+ curl -X POST http://auth.example.com/register
+ ```
+
+ will return a JSON with credentials for your registration:
+
+ ```json
+ {
+ "username": "eabcdb41-d89f-4580-826f-3e62e9755ef2",
+ "password": "pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0",
+ "fulldomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com",
+ "subdomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf",
+ "allowfrom": []
+ }
+ ```
+
+ It is strongly recommended to restrict the update endpoint to the IP
+ range of your pods. This is done at registration time as follows:
+
+ ```sh
+ curl -X POST http://auth.example.com/register \
+ -H "Content-Type: application/json" \
+ --data '{"allowfrom": ["10.244.0.0/16"]}'
+ ```
+
+ Make sure to update the `allowfrom` field to match your cluster
+ configuration. The JSON will now look like:
+
+ ```json
+ {
+ "username": "eabcdb41-d89f-4580-826f-3e62e9755ef2",
+ "password": "pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0",
+ "fulldomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com",
+ "subdomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf",
+ "allowfrom": ["10.244.0.0/16"]
+ }
+ ```
+
+2. Save this JSON to a file with the key as your domain. You can specify
+ multiple domains with the same credentials if you like. In our example,
+ the returned credentials can be used to verify ownership of
+ `example.com` and and `example.org`.
+
+ ```json
+ {
+ "example.com": {
+ "username": "eabcdb41-d89f-4580-826f-3e62e9755ef2",
+ "password": "pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0",
+ "fulldomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com",
+ "subdomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf",
+ "allowfrom": ["10.244.0.0/16"]
+ },
+ "example.org": {
+ "username": "eabcdb41-d89f-4580-826f-3e62e9755ef2",
+ "password": "pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0",
+ "fulldomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com",
+ "subdomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf",
+ "allowfrom": ["10.244.0.0/16"]
+ }
+ }
+ ```
+
+3. Next, update your primary DNS server with the CNAME record that will tell the
+ verifier how to locate the challenge TXT record. This is obtained from the
+ `fulldomain` field in the registration:
+
+ ```
+ _acme-challenge.example.com CNAME d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com
+ _acme-challenge.example.org CNAME d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com
+ ```
+
+ The "name" of the record always has the _acme-challenge subdomain, and
+ the "value" of the record matches exactly the fulldomain field from
+ registration.
+
+ At verification time, the domain name `d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com` will be a TXT
+ record that is set to your validation token. When the verifier queries `_acme-challenge.example.com`, it will
+ be directed to the correct location by this CNAME record. This proves that you control `example.com`
+
+4. Create a secret from the credentials JSON that was saved in step 2, this
+ secret is referenced in the `accountSecretRef` field of your DNS01
+ issuer settings. When creating an `Issuer` both this `Issuer` and
+ `Secret` must be in the same namespace. However for a `ClusterIssuer`
+ (which does not have a namespace) the `Secret` must be placed in the
+ same namespace as where the cert-manager pod is running in (in the
+ default setup `cert-manager`).
+
+ ```sh
+ kubectl create secret generic acme-dns --from-file acmedns.json
+ ```
+
+## Limitation of the `acme-dns` server
+
+The [`acme-dns`](https://github.com/joohoi/acme-dns) server has a [known
+limitation](https://github.com/cert-manager/cert-manager/issues/3610#issuecomment-849792721):
+when a set of credentials is used with more than 2 domains, cert-manager
+will fail solving the DNS01 challenges.
+
+Imagining that you have configured the ACMEDNS issuer with a single set of
+credentials, and that the "subdomain" of this set of credentials is
+`d420c923-bbd7-4056-ab64-c3ca54c9b3cf`:
+
+```yaml
+kind: Secret
+metadata:
+ name: auth-example-com
+stringData:
+ acmedns.json: |
+ {
+ "example.com": {
+ "username": "eabcdb41-d89f-4580-826f-3e62e9755ef2",
+ "password": "pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0",
+ "fulldomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com",
+ "subdomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf",
+ "allowfrom": ["10.244.0.0/16"]
+ },
+ }
+---
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: my-acme-dns
+spec:
+ acme:
+ solvers:
+ - dns01:
+ acmeDNS:
+ accountSecretRef:
+ name: auth-example-com
+ key: acmedns.json
+ host: auth.example.com
+```
+
+and imagine that you want to create a Certificate with three subdomains:
+
+```yaml
+kind: Certificate
+spec:
+ issuerRef:
+ name: issuer-1
+ dnsNames:
+ - "example.com"
+ - "*.example.com"
+ - "foo.example.com"
+```
+
+cert-manager will only be able to solve 2 challenges out of 3 in a non
+deterministic way. This limitation comes from a "feature" mentioned [this
+acme-dns issue](https://github.com/joohoi/acme-dns/issues/76).
+
+One workaround is to issue one set of acme-dns credentials for each
+domain that we want to be challenged, keeping in mind that each acme-dns
+"subdomain" can only accept at most 2 challenged domains. For example, the
+above secret would become:
+
+```yaml
+kind: Secret
+metadata:
+ name: auth-example-com
+stringData:
+ acmedns.json: |
+ {
+ "example.com": {
+ "username": "eabcdb41-d89f-4580-826f-3e62e9755ef2",
+ "password": "pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0",
+ "fulldomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com",
+ "subdomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf",
+ "allowfrom": ["10.244.0.0/16"]
+ },
+ "foo.example.com": {
+ "username": "eabcdb41-d89f-4580-826f-3e62e9755ef2",
+ "password": "pbAXVjlIOE01xbut7YnAbkhMQIkcwoHO0ek2j4Q0",
+ "fulldomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf.auth.example.com",
+ "subdomain": "d420c923-bbd7-4056-ab64-c3ca54c9b3cf",
+ "allowfrom": ["10.244.0.0/16"]
+ }
+```
+
+With this setup, we have:
+
+- `example.com` and `*.example.com` are registered in the acme-dns
+ "subdomain" `d420c923-bbd7-4056-ab64-c3ca54c9b3cf`.
+- `foo.example.com` is registered in the acme-dns "subdomain"
+ `d420c923-bbd7-4056-ab64-c3ca54c9b3cf`.
+
+Another workaround is to use `--max-concurrent-challenges 2` when running
+the `cert-manager-controller`. With this setting, acme-dns will only have 2
+TXT records in its database at any time, which mitigates the issue.
\ No newline at end of file
diff --git a/content/v1.12-docs/configuration/acme/dns01/akamai.md b/content/v1.12-docs/configuration/acme/dns01/akamai.md
new file mode 100644
index 00000000000..271f7fd6209
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/akamai.md
@@ -0,0 +1,86 @@
+---
+title: Akamai
+description: 'cert-manager configuration: ACME DNS-01 challenges using Akamai DNS'
+---
+
+## Edge DNS
+
+Use Edge DNS to solve DNS01 ACME challenges by creating a `Secret` using [Akamai API credentials](https://developer.akamai.com/getting-started/edgegrid) and an `Issuer` that references the `Secret` and sets the solver type.
+
+### Create a Secret
+
+The `Secret` should look like the following for the `Issuer` to reference. Replace `use_akamai_client_secret`, `use_akamai_access_token` and `use_akamai_client_token` with the respective Akamai API credential values.
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: akamai-secret
+type: Opaque
+stringData:
+ clientSecret: use_akamai_client_secret
+ accessToken: use_akamai_access_token
+ clientToken: use_akamai_client_token
+```
+
+### Create an Issuer
+
+To set Edge DNS for challenge tokens, `cert-manager` uses an `Issuer` that references the above `Secret` and other attributes such as the solver type. The `Issuer` should look like the following. Replace `use_akamai_host` with the Akamai API credential `host` value.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt-akamai-dns
+spec:
+ acme:
+ server: https://acme-v02.api.letsencrypt.org/directory
+ email: contact@me.com
+ privateKeySecretRef:
+ name: letsencrypt-akamai-issuer-account-key
+ solvers:
+ - dns01:
+ akamai:
+ serviceConsumerDomain: use_akamai_host
+ clientTokenSecretRef:
+ name: akamai-secret
+ key: clientToken
+ clientSecretSecretRef:
+ name: akamai-secret
+ key: clientSecret
+ accessTokenSecretRef:
+ name: akamai-secret
+ key: accessToken
+```
+
+### Create a Certificate
+
+The `Certificate` should look like the following and reference the Akamai Edge DNS `Issuer` above.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-zone
+spec:
+ secretName: akamai-crt-secret
+ dnsNames:
+ - '*.example.zone'
+ issuerRef:
+ name: letsencrypt-akamai-dns
+ kind: Issuer
+```
+
+> Note: `cert-manager` will wait for challenge tokens to propagate across the Edge DNS network. Follow the `certificate` status with a command such as the following.
+
+```bash
+kubectl describe certificate example-zone
+```
+
+### Troubleshooting
+
+Follow the `cert-manager` events to identify any issues with a command such as the following.
+
+```bash
+cmctl status certificate example-zone
+```
\ No newline at end of file
diff --git a/content/v1.12-docs/configuration/acme/dns01/azuredns.md b/content/v1.12-docs/configuration/acme/dns01/azuredns.md
new file mode 100644
index 00000000000..bc5de32fec7
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/azuredns.md
@@ -0,0 +1,505 @@
+---
+title: AzureDNS
+description: 'cert-manager configuration: ACME DNS-01 challenges using AzureDNS'
+---
+
+cert-manager can create and then delete DNS-01 records in Azure DNS but it needs to authenticate to Azure first.
+There are four authentication methods available:
+
+- [Managed Identity Using AAD Workload Identity](#managed-identity-using-aad-pod-identity) (recommended)
+- [Managed Identity Using AAD Pod Identities](#managed-identity-using-aad-pod-identities) (deprecated)
+- [Managed Identity Using AKS Kubelet Identity](#managed-identity-using-aks-kubelet-identity)
+- [Service Principal](#service-principal)
+
+## Managed Identity Using AAD Workload Identity
+
+> ℹ️ This feature is available in cert-manager `>= v1.11.0`.
+>
+> 📖 Read the [AKS + LoadBalancer + Let's Encrypt tutorial](../../../tutorials/getting-started-aks-letsencrypt/README.md) for an end-to-end example of this authentication method.
+
+Azure AD workload identity (preview) on Azure Kubernetes Service (AKS) allows cert-manager to authenticate to Azure using a Kubernetes ServiceAccount Token and then to manage DNS-01 records in Azure DNS.
+This is the recommended authentication method because it is more secure and easier to maintain than the other methods.
+
+### Reconfigure the cluster
+
+Enable the workload identity federation features on your cluster.
+If you have an Azure AKS cluster you can use the following command:
+
+```bash
+az aks update \
+ --name ${CLUSTER} \
+ --enable-oidc-issuer \
+ --enable-workload-identity # ℹ️ This option is currently only available when using the aks-preview extension.
+```
+
+> ℹ️ You can [install the Azure workload identity extension on other managed and self-managed clusters](https://azure.github.io/azure-workload-identity/docs/installation.html) if you are not using Azure AKS.
+>
+> 📖 Read [Deploy and configure workload identity on an Azure Kubernetes Service (AKS) cluster](https://learn.microsoft.com/en-us/azure/aks/workload-identity-deploy-cluster) for more information about the `--enable-workload-identity` feature.
+>
+### Reconfigure cert-manager
+
+Label the cert-manager controller Pod and ServiceAccount for the attention of the Azure Workload Identity webhook,
+which will result in the cert-manager controller Pod having an extra volume containing a Kubernetes ServiceAccount token which it will use to authenticate with Azure.
+
+If you installed cert-manager using Helm, the labels can be configured using Helm values:
+
+```yaml
+# values.yaml
+podLabels:
+ azure.workload.identity/use: "true"
+serviceAccount:
+ labels:
+ azure.workload.identity/use: "true"
+```
+
+If successful, the cert-manager Pod will have some new environment variables set,
+and the Azure workload-identity ServiceAccount token as a projected volume:
+
+```bash
+kubectl describe pod -n cert-manager -l app.kubernetes.io/component=controller
+```
+
+```terminal
+Containers:
+ ...
+ cert-manager-controller:
+ ...
+ Environment:
+ ...
+ AZURE_CLIENT_ID:
+ AZURE_TENANT_ID: f99bd6a4-665c-41cf-aff1-87a89d5c62d4
+ AZURE_FEDERATED_TOKEN_FILE: /var/run/secrets/azure/tokens/azure-identity-token
+ AZURE_AUTHORITY_HOST: https://login.microsoftonline.com/
+ Mounts:
+ /var/run/secrets/azure/tokens from azure-identity-token (ro)
+Volumes:
+ ...
+ azure-identity-token:
+ Type: Projected (a volume that contains injected data from multiple sources)
+ TokenExpirationSeconds: 3600
+```
+
+> 📖 Read about [the role of the Mutating Admission Webhook](https://azure.github.io/azure-workload-identity/docs/installation/mutating-admission-webhook.html) in Azure AD Workload Identity for Kubernetes.
+
+
+### Create a Managed Identity
+
+In order for cert-manager to use the Azure API and manipulate the records in the Azure DNS zone,
+it needs an Azure account and the best type of account to use is called a "Managed Identity".
+This account does not come with a password or an API key and it is designed for use by machines rather than humans.
+
+Choose a managed identity name and create the Managed Identity:
+
+```bash
+export IDENTITY_NAME=cert-manager
+az identity create --name "${IDENTITY_NAME}"
+```
+
+Grant it permission to modify the DNS zone records:
+
+```bash
+export IDENTITY_CLIENT_ID=$(az identity show --name "${IDENTITY_NAME}" --query 'clientId' -o tsv)
+az role assignment create \
+ --role "DNS Zone Contributor" \
+ --assignee IDENTITY_CLIENT_ID \
+ --scope $(az network dns zone show --name $DOMAIN_NAME -o tsv --query id)
+```
+
+> 📖 Read [What are managed identities for Azure resources?](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview)
+> for an overview of managed identities and their uses.
+>
+> 📖 Read [Azure built-in roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) to learn about the "DNS Zone Contributor" role.
+>
+> 📖 Read more about [the `az identity` command](https://learn.microsoft.com/en-us/cli/azure/identity).
+
+### Add a Federated Identity
+
+Now associate a federated identity with the managed identity that you created earlier.
+cert-manager will authenticate to Azure using a short lived Kubernetes ServiceAccount token,
+and it will be able to impersonate the managed identity that you created in the previous step.
+
+```bash
+export SERVICE_ACCOUNT_NAME=cert-manager # ℹ️ This is the default Kubernetes ServiceAccount used by the cert-manager controller.
+export SERVICE_ACCOUNT_NAMESPACE=cert-manager # ℹ️ This is the default namespace for cert-manager.
+export SERVICE_ACCOUNT_ISSUER=$(az aks show --resource-group $AZURE_DEFAULTS_GROUP --name $CLUSTER --query "oidcIssuerProfile.issuerUrl" -o tsv)
+az identity federated-credential create \
+ --name "cert-manager" \
+ --identity-name "${IDENTITY_NAME}" \
+ --issuer "${SERVICE_ACCOUNT_ISSUER}" \
+ --subject "system:serviceaccount:${SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME}"
+```
+
+- `--subject`: is the distinguishing name of the Kubernetes ServiceAccount.
+- `--issuer`: is a URL from which the Azure will download the JWT signing certificate and other metadata
+
+> 📖 Read about [Workload identity federation](https://learn.microsoft.com/en-us/azure/active-directory/develop/workload-identity-federation) in the Microsoft identity platform documentation.
+>
+> 📖 Read more about [the `az identity federated-credential` command](https://learn.microsoft.com/en-us/cli/azure/identity/federated-credential).
+
+### Configure a ClusterIssuer
+
+For example:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-staging
+spec:
+ acme:
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ email: $EMAIL_ADDRESS
+ privateKeySecretRef:
+ name: letsencrypt-staging
+ solvers:
+ - dns01:
+ azureDNS:
+ hostedZoneName: $AZURE_ZONE_NAME
+ resourceGroupName: $AZURE_RESOURCE_GROUP
+ subscriptionID: $AZURE_SUBSCRIPTION_ID
+ environment: AzurePublicCloud
+ managedIdentity:
+ clientID: $IDENTITY_CLIENT_ID
+```
+
+The following variables need to be filled in.
+
+```bash
+# An email address to which Let's Encrypt will send renewal reminders.
+export EMAIL_ADDRESS=
+# The Azure DNS zone in which the DNS-01 records will be created and deleted.
+export AZURE_ZONE_NAME=
+# The Azure resource group containing the DNS zone.
+export AZURE_RESOURCE_GROUP=
+# The Azure billing account name and ID for the DNS zone.
+export AZURE_SUBSCRIPTION=
+export AZURE_SUBSCRIPTION_ID=$(az account show --name $AZURE_SUBSCRIPTION --query 'id' -o tsv)
+```
+
+#### ⚠️ Using 'Ambient Credentials' with ClusterIssuer and Issuer resources
+
+This authentication method is an example of what cert-manager calls 'ambient credentials'.
+Ambient credentials are enabled by default for ClusterIssuer resources, but disabled by default for Issuer resources.
+This is to prevent unprivileged users, who have permission to create Issuer resources, from issuing certificates using credentials that cert-manager incidentally has access to.
+ClusterIssuer resources are cluster scoped (not namespaced) and only platform administrators should be granted permission to create them.
+
+If you are using this authentication mechanism and ambient credentials are not enabled, you will see this error:
+
+```bash
+error instantiating azuredns challenge solver: ClientID is not set but neither --cluster-issuer-ambient-credentials nor --issuer-ambient-credentials are set.
+```
+
+> ⚠️ It is possible (but not recommended) to enable this authentication mechanism for `Issuer` resources, by setting the `--issuer-ambient-credentials` flag on the cert-manager controller to true.
+
+## Managed Identity Using AAD Pod Identities
+
+> ⚠️ The [open source Azure AD pod-managed identity (preview) in Azure Kubernetes Service has been deprecated as of 10/24/2022](https://github.com/Azure/aad-pod-identity#-announcement).
+> Use Workload Identity instead.
+
+[AAD Pod Identities](https://azure.github.io/aad-pod-identity) allows assigning a [Managed Identity](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) to a pod. This removes the need for adding explicit credentials into the cluster to create the required DNS records.
+
+> Note: When using Pod identity, even though assigning multiple identities to a single pod is allowed, currently cert-manager does not support this as it is not able to identify which identity to use.
+
+Firstly an identity should be created that has access to contribute to the DNS Zone.
+
+- Example creation using `azure-cli` and `jq`:
+
+```bash
+# Choose a unique Identity name and existing resource group to create identity in.
+IDENTITY=$(az identity create --name $IDENTITY_NAME --resource-group $IDENTITY_GROUP --output json)
+
+# Gets principalId to use for role assignment
+PRINCIPAL_ID=$(echo $IDENTITY | jq -r '.principalId')
+
+# Used for identity binding
+CLIENT_ID=$(echo $IDENTITY | jq -r '.clientId')
+RESOURCE_ID=$(echo $IDENTITY | jq -r '.id')
+
+# Get existing DNS Zone Id
+ZONE_ID=$(az network dns zone show --name $ZONE_NAME --resource-group $ZONE_GROUP --query "id" -o tsv)
+
+# Create role assignment
+az role assignment create --role "DNS Zone Contributor" --assignee $PRINCIPAL_ID --scope $ZONE_ID
+```
+
+- Example creation using Terraform
+
+```terraform
+variable resource_group_name {}
+variable location {}
+variable dns_zone_id {}
+
+# Creates Identity
+resource "azurerm_user_assigned_identity" "dns_identity" {
+ name = "cert-manager-dns01"
+ resource_group_name = var.resource_group_name
+ location = var.location
+}
+
+# Creates Role Assignment
+resource "azurerm_role_assignment" "dns_contributor" {
+ scope = var.dns_zone_id
+ role_definition_name = "DNS Zone Contributor"
+ principal_id = azurerm_user_assigned_identity.dns_identity.principal_id
+}
+
+# Client Id Used for identity binding
+output "identity_client_id" {
+ value = azurerm_user_assigned_identity.dns_identity.client_id
+}
+
+# Resource Id Used for identity binding
+output "identity_resource_id" {
+ value = azurerm_user_assigned_identity.dns_identity.id
+}
+```
+
+Next we need to ensure we have installed [AAD Pod Identity](https://azure.github.io/aad-pod-identity) using their walk-through. This will install the CRDs and deployment required to assign the identity.
+
+Now we can create the identity resource and binding using the below manifest as an example:
+
+```yaml
+apiVersion: "aadpodidentity.k8s.io/v1"
+kind: AzureIdentity
+metadata:
+ annotations:
+ # recommended to use namespaced identites https://azure.github.io/aad-pod-identity/docs/configure/match_pods_in_namespace/
+ aadpodidentity.k8s.io/Behavior: namespaced
+ name: certman-identity
+ namespace: cert-manager # change to your preferred namespace
+spec:
+ type: 0 # MSI
+ resourceID: # Resource Id From Previous step
+ clientID: # Client Id from previous step
+---
+apiVersion: "aadpodidentity.k8s.io/v1"
+kind: AzureIdentityBinding
+metadata:
+ name: certman-id-binding
+ namespace: cert-manager # change to your preferred namespace
+spec:
+ azureIdentity: certman-identity
+ selector: certman-label # This is the label that needs to be set on cert-manager pods
+```
+
+Next we need to ensure the cert-manager pod has a relevant label to use the pod identity binding. This can be done by editing the deployment and adding the below into the `.spec.template.metadata.labels` field
+
+```yaml
+spec:
+ template:
+ metadata:
+ labels:
+ aadpodidbinding: certman-label # must match selector in AzureIdentityBinding
+```
+
+Or by using the helm values `podLabels`
+
+```yaml
+podLabels:
+ aadpodidbinding: certman-label
+```
+
+Lastly when we create the certificate issuer we only need to specify the `hostedZoneName`, `resourceGroupName` and `subscriptionID` fields for the DNS zone. Example below:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ azureDNS:
+ subscriptionID: AZURE_SUBSCRIPTION_ID
+ resourceGroupName: AZURE_DNS_ZONE_RESOURCE_GROUP
+ hostedZoneName: AZURE_DNS_ZONE
+ # Azure Cloud Environment, default to AzurePublicCloud
+ environment: AzurePublicCloud
+```
+
+This authentication mechanism is what cert-manager considers 'ambient credentials'. Use of ambient credentials is disabled by default for cert-manager `Issuer`s. This to ensure unprivileged users who have permission to create issuers cannot issue certificates using any credentials cert-manager incidentally has access to. To enable this authentication mechanism for `Issuer`s, you will need to set `--issuer-ambient-credentials` flag on cert-manager controller to true. (There is a corresponding `--cluster-issuer-ambient-credentials` flag which is set to `true` by default).
+
+If you are using this authentication mechanism and ambient credentials are not enabled, you will see this error:
+```bash
+error instantiating azuredns challenge solver: ClientID is not set but neither --cluster-issuer-ambient-credentials nor --issuer-ambient-credentials are set.
+```
+
+These are necessary to enable Azure Managed Identities.
+
+## Managed Identity Using AKS Kubelet Identity
+
+When creating an AKS cluster in Azure there is the option to use a managed identity that is assigned to the kubelet. This identity is assigned to the underlying node pool in the AKS cluster and can then be used by the cert-manager pods to authenticate to Azure Active Directory.
+
+There are some caveats with this approach, these mainly being:
+
+- Any permissions granted to this identity will also be accessible to all containers running inside the Kubernetes cluster.
+- Using AKS extensions like `Kube Dashboard`, `Virtual Node`, or `HTTP Application Routing` (see full list [here](https://docs.microsoft.com/en-us/azure/aks/use-managed-identity#summary-of-managed-identities)) will create additional identities that are assigned to your node pools. If your node pools have more than one identity assigned, you will need to specify either `clientID` or `resourceID` to select the correct one.
+
+To set this up, firstly you will need to retrieve the identity that the kubelet is using by querying the AKS cluster. This can then be used to create the appropriate permissions in the DNS zone.
+
+- Example commands using `azure-cli`:
+
+```bash
+# Get AKS Kubelet Identity
+PRINCIPAL_ID=$(az aks show -n $CLUSTERNAME -g $CLUSTER_GROUP --query "identityProfile.kubeletidentity.objectId" -o tsv)
+
+# Get existing DNS Zone Id
+ZONE_ID=$(az network dns zone show --name $ZONE_NAME --resource-group $ZONE_GROUP --query "id" -o tsv)
+
+# Create role assignment
+az role assignment create --role "DNS Zone Contributor" --assignee $PRINCIPAL_ID --scope $ZONE_ID
+```
+
+- Example terraform:
+
+```terraform
+variable dns_zone_id {}
+
+# Creating the AKS cluster, abbreviated.
+resource "azurerm_kubernetes_cluster" "cluster" {
+ ...
+ # Creates Identity associated to kubelet
+ identity {
+ type = "SystemAssigned"
+ }
+ ...
+}
+
+resource "azurerm_role_assignment" "dns_contributor" {
+ scope = var.dns_zone_id
+ role_definition_name = "DNS Zone Contributor"
+ principal_id = azurerm_kubernetes_cluster.cluster.kubelet_identity[0].object_id
+ skip_service_principal_aad_check = true # Allows skipping propagation of identity to ensure assignment succeeds.
+}
+```
+
+Then when creating the cert-manager issuer we need to specify the `hostedZoneName`, `resourceGroupName` and `subscriptionID` fields for the DNS Zone.
+
+We also need to specify `managedIdentity.clientID` or `managedIdentity.resourceID` if multiple managed identities are assigned to the node pools.
+
+The value for `managedIdentity.clientID` can be fetched by running this command:
+
+```bash
+az aks show -n $CLUSTERNAME -g $CLUSTER_GROUP --query "identityProfile.kubeletidentity.clientId" -o tsv
+```
+
+Example below:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ azureDNS:
+ subscriptionID: AZURE_SUBSCRIPTION_ID
+ resourceGroupName: AZURE_DNS_ZONE_RESOURCE_GROUP
+ hostedZoneName: AZURE_DNS_ZONE
+ # Azure Cloud Environment, default to AzurePublicCloud
+ environment: AzurePublicCloud
+ # optional, only required if node pools have more than 1 managed identity assigned
+ managedIdentity:
+ # client id of the node pool managed identity (can not be set at the same time as resourceID)
+ clientID: YOUR_MANAGED_IDENTITY_CLIENT_ID
+ # resource id of the managed identity (can not be set at the same time as clientID)
+ # resourceID: YOUR_MANAGED_IDENTITY_RESOURCE_ID
+```
+
+## Service Principal
+
+Configuring the AzureDNS DNS01 Challenge for a Kubernetes cluster requires
+creating a service principal in Azure.
+
+To create the service principal you can use the following script (requires
+`azure-cli` and `jq`):
+
+```bash
+# Choose a name for the service principal that contacts azure DNS to present
+# the challenge.
+$ AZURE_CERT_MANAGER_NEW_SP_NAME=NEW_SERVICE_PRINCIPAL_NAME
+# This is the name of the resource group that you have your dns zone in.
+$ AZURE_DNS_ZONE_RESOURCE_GROUP=AZURE_DNS_ZONE_RESOURCE_GROUP
+# The DNS zone name. It should be something like domain.com or sub.domain.com.
+$ AZURE_DNS_ZONE=AZURE_DNS_ZONE
+
+$ DNS_SP=$(az ad sp create-for-rbac --name $AZURE_CERT_MANAGER_NEW_SP_NAME --output json)
+$ AZURE_CERT_MANAGER_SP_APP_ID=$(echo $DNS_SP | jq -r '.appId')
+$ AZURE_CERT_MANAGER_SP_PASSWORD=$(echo $DNS_SP | jq -r '.password')
+$ AZURE_TENANT_ID=$(echo $DNS_SP | jq -r '.tenant')
+$ AZURE_SUBSCRIPTION_ID=$(az account show --output json | jq -r '.id')
+```
+
+For security purposes, it is appropriate to utilize RBAC to ensure that you
+properly maintain access control to your resources in Azure. The service
+principal that is generated by this tutorial has fine-grained access to ONLY the
+DNS Zone in the specific resource group specified. It requires this permission
+so that it can read/write the \_acme\_challenge TXT records to the zone.
+
+Lower the Permissions of the service principal.
+
+```bash
+$ az role assignment delete --assignee $AZURE_CERT_MANAGER_SP_APP_ID --role Contributor
+```
+
+Give Access to DNS Zone.
+
+```bash
+$ DNS_ID=$(az network dns zone show --name $AZURE_DNS_ZONE --resource-group $AZURE_DNS_ZONE_RESOURCE_GROUP --query "id" --output tsv)
+$ az role assignment create --assignee $AZURE_CERT_MANAGER_SP_APP_ID --role "DNS Zone Contributor" --scope $DNS_ID
+```
+
+Check Permissions. As the result of the following command, we would like to see just one object in the permissions array with "DNS Zone Contributor" role.
+
+```bash
+$ az role assignment list --all --assignee $AZURE_CERT_MANAGER_SP_APP_ID
+```
+
+A secret containing service principal password should be created on Kubernetes to facilitate presenting the challenge to Azure DNS. You can create the secret with the following command:
+
+```bash
+$ kubectl create secret generic azuredns-config --from-literal=client-secret=$AZURE_CERT_MANAGER_SP_PASSWORD
+```
+
+Get the variables for configuring the issuer.
+
+```bash
+$ echo "AZURE_CERT_MANAGER_SP_APP_ID: $AZURE_CERT_MANAGER_SP_APP_ID"
+$ echo "AZURE_CERT_MANAGER_SP_PASSWORD: $AZURE_CERT_MANAGER_SP_PASSWORD"
+$ echo "AZURE_SUBSCRIPTION_ID: $AZURE_SUBSCRIPTION_ID"
+$ echo "AZURE_TENANT_ID: $AZURE_TENANT_ID"
+$ echo "AZURE_DNS_ZONE: $AZURE_DNS_ZONE"
+$ echo "AZURE_DNS_ZONE_RESOURCE_GROUP: $AZURE_DNS_ZONE_RESOURCE_GROUP"
+```
+
+To configure the issuer, substitute the capital cased variables with the values
+from the previous script. You can get the subscription id from the Azure portal.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ azureDNS:
+ clientID: AZURE_CERT_MANAGER_SP_APP_ID
+ clientSecretSecretRef:
+ # The following is the secret we created in Kubernetes. Issuer will use this to present challenge to Azure DNS.
+ name: azuredns-config
+ key: client-secret
+ subscriptionID: AZURE_SUBSCRIPTION_ID
+ tenantID: AZURE_TENANT_ID
+ resourceGroupName: AZURE_DNS_ZONE_RESOURCE_GROUP
+ hostedZoneName: AZURE_DNS_ZONE
+ # Azure Cloud Environment, default to AzurePublicCloud
+ environment: AzurePublicCloud
+```
diff --git a/content/v1.12-docs/configuration/acme/dns01/cloudflare.md b/content/v1.12-docs/configuration/acme/dns01/cloudflare.md
new file mode 100644
index 00000000000..b3f4ded449f
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/cloudflare.md
@@ -0,0 +1,108 @@
+---
+title: Cloudflare
+description: 'cert-manager configuration: ACME DNS-01 challenges using Cloudflare DNS'
+---
+
+To use Cloudflare, you may use one of two types of tokens. **API Tokens** allow application-scoped keys bound to specific zones and permissions, while **API Keys** are globally-scoped keys that carry the same permissions as your account.
+
+**API Tokens** are recommended for higher security, since they have more restrictive permissions and are more easily revocable.
+
+## API Tokens
+
+Tokens can be created at **User Profile > API Tokens > API Tokens**. The following settings are recommended:
+
+- Permissions:
+ - `Zone - DNS - Edit`
+ - `Zone - Zone - Read`
+- Zone Resources:
+ - `Include - All Zones`
+
+To create a new `Issuer`, first make a Kubernetes secret containing your new API token:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: cloudflare-api-token-secret
+type: Opaque
+stringData:
+ api-token:
+```
+
+Then in your `Issuer` manifest:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ cloudflare:
+ apiTokenSecretRef:
+ name: cloudflare-api-token-secret
+ key: api-token
+```
+
+## API Keys
+
+API keys can be retrieved at **User Profile > API Tokens > API Keys > Global API Key > View**.
+
+To create a new `Issuer`, first make a Kubernetes secret containing your API key:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: cloudflare-api-key-secret
+type: Opaque
+stringData:
+ api-key:
+```
+
+Then in your `Issuer` manifest:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ cloudflare:
+ email: my-cloudflare-acc@example.com
+ apiKeySecretRef:
+ name: cloudflare-api-key-secret
+ key: api-key
+```
+
+## Troubleshooting
+
+### Actor `com.cloudflare.api.token.xxxx` requires permission `com.cloudflare.api.account.zone.list` to list zones
+If you get the error that your token does not have the correct permission to list zones there can be 2 causes.
+1. The token lacks the `Zone - Zone - Read` permission
+2. cert-manager identified the wrong zone name for the domain due to DNS issues.
+
+In the case of the 2nd issue you will see an error like below:
+```
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Started 6s cert-manager Challenge scheduled for processing
+ Warning PresentError 3s (x2 over 3s) cert-manager Error presenting challenge: Cloudflare API Error for GET "/zones?name="
+ Error: 0: Actor 'com.cloudflare.api.token.xxxx' requires permission 'com.cloudflare.api.account.zone.list' to list zones
+```
+
+In this case we recommend [changing your DNS01 self-check nameservers](./README.md#setting-nameservers-for-dns01-self-check).
+
+## `Cloudflare API error for POST "/zones//dns_records` generic error
+
+You might be hitting this as Cloudflare blocks the use of the API to update DNS records for the following TLDs: `.cf`, `.ga`, `.gq`, `.ml` and `.tk`.
+This is discussed in the [Cloudflare Community](https://community.cloudflare.com/t/unable-to-update-ddns-using-api-for-some-tlds/167228).
+We recommend using an alternative DNS provider when using these TLDs.
\ No newline at end of file
diff --git a/content/v1.12-docs/configuration/acme/dns01/digitalocean.md b/content/v1.12-docs/configuration/acme/dns01/digitalocean.md
new file mode 100644
index 00000000000..4d6c155863c
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/digitalocean.md
@@ -0,0 +1,46 @@
+---
+title: DigitalOcean
+description: 'cert-manager configuration: ACME DNS-01 challenges using DigitalOcean DNS'
+---
+
+This provider uses a Kubernetes `Secret` resource to work. In the following
+example, the `Secret` will have to be named `digitalocean-dns` and have a
+sub-key `access-token` with the token in it. For example:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: digitalocean-dns
+data:
+ # insert your DO access token here
+ access-token: "base64 encoded access-token here"
+ ```
+
+The access token must have write access.
+
+To create a Personal Access Token, see [DigitalOcean documentation](https://docs.digitalocean.com/reference/api/create-personal-access-token/).
+
+Handy direct link: https://cloud.digitalocean.com/account/api/tokens/new
+
+To encode your access token into base64, you can use the following
+
+```bash
+echo -n 'your-access-token' | base64
+```
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ digitalocean:
+ tokenSecretRef:
+ name: digitalocean-dns
+ key: access-token
+```
\ No newline at end of file
diff --git a/content/v1.12-docs/configuration/acme/dns01/google.md b/content/v1.12-docs/configuration/acme/dns01/google.md
new file mode 100644
index 00000000000..460239de80c
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/google.md
@@ -0,0 +1,242 @@
+---
+title: Google CloudDNS
+description: 'cert-manager configuration: ACME DNS-01 challenges using Google CloudDNS'
+---
+
+This guide explains how to set up an `Issuer`, or `ClusterIssuer`, to use Google
+CloudDNS to solve DNS01 ACME challenges. It's advised you read the [DNS01
+Challenge Provider](./README.md) page first for a more general understanding of
+how cert-manager handles DNS01 challenges.
+
+This guide assumes that your cluster is hosted on Google Cloud Platform (GCP)
+and that you already have a domain set up with CloudDNS.
+
+You'll need to be using a **Public DNS Zone**, so that the ACME challenge checker
+is able to access the DNS records that cert-manager will create.
+
+## Set up a Service Account
+
+cert-manager needs to be able to add records to CloudDNS in order to solve the
+DNS01 challenge. To enable this, a GCP service account must be created with the
+`dns.admin` role.
+
+> Note: For this guide the `gcloud` command will be used to set up the service
+> account. Ensure that `gcloud` is using the correct project and zone before
+> entering the commands. These steps could also be completed using the Cloud
+> Console.
+
+```bash
+PROJECT_ID=myproject-id
+gcloud iam service-accounts create dns01-solver --display-name "dns01-solver"
+```
+
+In the command above, replace `myproject-id` with the ID of your project.
+
+```bash
+gcloud projects add-iam-policy-binding $PROJECT_ID \
+ --member serviceAccount:dns01-solver@$PROJECT_ID.iam.gserviceaccount.com \
+ --role roles/dns.admin
+```
+
+> **Note**: The use of the `dns.admin` role in this example role is for convenience.
+> If you want to ensure cert-manager runs under a least privilege service account,
+> you will need to create a custom role with the following permissions:
+>
+> * `dns.resourceRecordSets.*`
+> * `dns.changes.*`
+> * `dns.managedZones.list`
+
+## Use Static Credentials
+
+Follow the instructions in the following sections to deploy cert-manager using
+static credentials for the service account you created. You should rotate these
+credentials periodically.
+
+### Create a Service Account Secret
+
+To access this service account, cert-manager uses a key stored in a Kubernetes
+`Secret`. First, create a key for the service account and download it as a JSON
+file, then create a `Secret` from this file.
+
+Keep the key file safe and do not share it, as it could be used to gain access
+access to your cloud resources. The key file can be deleted once it has been
+used to generate the `Secret`.
+
+If you did not create the service account `dns01-solver` before, you need to
+create it first.
+
+```bash
+gcloud iam service-accounts create dns01-solver
+```
+
+Replace instances of `$PROJECT_ID` with the ID of your project.
+```bash
+gcloud iam service-accounts keys create key.json \
+ --iam-account dns01-solver@$PROJECT_ID.iam.gserviceaccount.com
+kubectl create secret generic clouddns-dns01-solver-svc-acct \
+ --from-file=key.json
+```
+
+> Note: If you have already added the `Secret` but get an error: `...due to
+> error processing: error getting clouddns service account: secret "XXX" not
+> found`, the `Secret` may be in the wrong namespace. If you're configuring a
+> `ClusterIssuer`, move the `Secret` to the `Cluster Resource Namespace` which
+> is `cert-manager` by default. If you're configuring an `Issuer`, the `Secret`
+> should be stored in the same namespace as the `Issuer` resource.
+
+### Create an Issuer That Uses CloudDNS
+
+Next, create an `Issuer` (or `ClusterIssuer`) with a `cloudDNS` provider. An
+example `Issuer` manifest can be seen below with annotations.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ cloudDNS:
+ # The ID of the GCP project
+ project: $PROJECT_ID
+ # This is the secret used to access the service account
+ serviceAccountSecretRef:
+ name: clouddns-dns01-solver-svc-acct
+ key: key.json
+```
+
+For more information about `Issuers` and `ClusterIssuers`, see
+[Configuration](../../README.md).
+
+Once an `Issuer` (or `ClusterIssuer`) has been created successfully, a
+`Certificate` can then be added to verify that everything works.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com
+ namespace: default
+spec:
+ secretName: example-com-tls
+ issuerRef:
+ # The issuer created previously
+ name: example-issuer
+ dnsNames:
+ - example.com
+ - www.example.com
+```
+
+For more details about `Certificates`, see [Usage](../../../usage/README.md).
+
+## GKE Workload Identity
+
+If you are deploying cert-manager into a [Google Container Engine (GKE)
+cluster](https://cloud.google.com/kubernetes-engine/) with workload identity
+enabled, you can leverage workload identity to avoid creating and managing
+static service account credentials. The [workload identity
+how-to](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
+provides more detail on how workload identity functions, but briefly workload
+identity allows you to link a Google service accounts (GSA) to Kubernetes
+service accounts (KSA). This GSA/KSA linking is two-way, i.e., you must
+establish the link in GCP _and_ Kubernetes. Once configured, workload identity
+allows Kubernetes pods running under a KSA to access the GCP APIs with the
+permissions of the linked GSA. The workload identity how-to also provides
+detailed instructions on how to enable workload identity in your GKE cluster.
+The instructions in the following sections assume you are deploying cert-manager
+to a GKE cluster with workload identity already enabled.
+
+### Enable Ambient Credential Usage
+
+'Ambient Credentials' are credentials drawn from the environment, metadata services, or local files which are not explicitly configured in the ClusterIssuer API object. When this flag is enabled Cert-Manager will access the GKE Metadata server for credentials. By default this is enabled for ClusterIssuer resources but is disabled for Issuer resources. To enable it for Issuer resources set the `--issuer-ambient-credentials` flag.
+
+### Link KSA to GSA in GCP
+
+The cert-manager component that needs to modify DNS records is the pod created
+as part of the cert-manager deployment. The [standard methods for deploying
+cert-manager to Kubernetes](../../../installation/README.md) create the
+cert-manager deployment in the cert-manager namespace and its pod spec specifies
+it runs under the cert-manager service account. To link the GSA you created
+above to the cert-manager KSA in the cert-manager namespace in your GKE cluster,
+run the following command.
+
+```bash
+gcloud iam service-accounts add-iam-policy-binding \
+ --role roles/iam.workloadIdentityUser \
+ --member "serviceAccount:$PROJECT_ID.svc.id.goog[cert-manager/cert-manager]" \
+ dns01-solver@$PROJECT_ID.iam.gserviceaccount.com
+```
+
+If your cert-manager pods are running under a different service account, replace
+`goog[cert-manager/cert-manager]` with `goog[NAMESPACE/SERVICE_ACCOUNT]`, where
+`NAMESPACE` is the namespace of the service account and `SERVICE_ACCOUNT` is the
+name of the service account.
+
+### Link KSA to GSA in Kubernetes
+
+After deploying cert-manager, add the proper workload identity annotation to the
+cert-manager service account.
+
+```bash
+kubectl annotate serviceaccount --namespace=cert-manager cert-manager \
+ "iam.gke.io/gcp-service-account=dns01-solver@$PROJECT_ID.iam.gserviceaccount.com"
+```
+
+Again, if your cert-manager pods are running under a different service account,
+replace `--namespace=cert-manager cert-manager` with `--namespace=NAMESPACE
+SERVICE_ACCOUNT`, where `NAMESPACE` is the namespace of the service account and
+`SERVICE_ACCOUNT` is the name of the service account.
+
+If you are deploying cert-manager using its helm chart, you can use the
+`serviceAccount.annotations` configuration parameter to add the above workload
+identity annotation to the cert-manager KSA.
+
+### Create an Issuer That Uses CloudDNS
+
+Next, create an `Issuer` (or `ClusterIssuer`) with a `clouddns` provider. An
+example `Issuer` manifest can be seen below with annotations. Note that the
+issuer does not include a `serviceAccountSecretRef` property. Excluding this
+instructs cert-manager to use the default credentials provided by GKE workload
+identity.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ cloudDNS:
+ # The ID of the GCP project
+ project: $PROJECT_ID
+```
+
+For more information about `Issuers` and `ClusterIssuers`, see
+[Configuration](../../README.md).
+
+Once an `Issuer` (or `ClusterIssuer`) has been created successfully, a
+`Certificate` can then be added to verify that everything works.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com
+ namespace: default
+spec:
+ secretName: example-com-tls
+ issuerRef:
+ # The issuer created previously
+ name: example-issuer
+ dnsNames:
+ - example.com
+ - www.example.com
+```
+
+For more details about `Certificates`, see [Usage](../../../usage/README.md).
diff --git a/content/v1.12-docs/configuration/acme/dns01/rfc2136.md b/content/v1.12-docs/configuration/acme/dns01/rfc2136.md
new file mode 100644
index 00000000000..86e9dd32df3
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/rfc2136.md
@@ -0,0 +1,207 @@
+---
+title: RFC-2136
+description: 'cert-manager configuration: ACME DNS-01 challenges using RFC2136-compliant DNS providers'
+---
+
+The goal of this document is to provide a configuration overview of the various
+facilities required to deploy cert-manager against a RFC2136 compliant DNS
+server such as BIND `named`. This capability is also commonly known as “dynamic
+DNS”.
+
+Unlike the peer of other cert-manager DNS integrations, `named` is a bit of a
+“Swiss Army Knife” of domain name servers. Over the years, it has been highly
+optimized to provide maximal vertical scalability for a single node, as well as
+horizontal scalability with service provider interfaces. This flexibility makes
+it impossible to go into every possible `named` deployment that a user may run
+in to though. Instead, this document will try to make sure your server is ready
+to accept requests from cert-manager using command line tools, then get on to
+the making the two work together.
+
+## Transaction Signatures ⇒ TSIG
+
+Dynamic DNS updates are essentially server queries which otherwise might return
+resource records (RRs). Since DNS servers are commonly exposed to the public
+internet, being able to push an unauthenticated update to any server that
+responds to queries would be immediately untenable.
+
+In the eyes of the `named` architects, the generic solution to this problem
+space was twofold. The first is to require manual enablement of updates at a
+zone level, such as `example.com`. In a naive network, there is no requirement
+that zone updates have any security to them, and clients can be configured such
+that they can provide updates without any authentication. An example of where
+this is useful is for machines booting using DHCP, in this case the machines
+know about themselves and the DNS server can be configured to accept updates
+when they come from the address being configured.
+
+This clearly has limitations in situations such as cert-manager and the DNS01
+challenge. In this environment, a TXT RR must be created after coordination with
+the ACME server. After negotiating with the ACME server, a the TXT RR that is
+published on the domain validates that the domain is legitimately engaged with
+the process of creating a certificate for it. In the bigger picture of DNS, this
+means that an arbitrary actor (cert-manager, in this case) must be able to add
+one of these KV mappings to the domain and delete it after the certificate has
+been issued. `cert-manager` does not have a convenient physical characteristic
+such as a DHCP allocation to validate it's requests.
+
+For cases like this, we need to be able to sign a request that is being sent to
+the DNS server. We do that through TSIGs, or Transaction SIGnatures.
+
+### Configuration Step 1 - Set up your DNS server for secure dynamic updates
+
+There are many excellent tutorials on the net that walk through
+preparing a basic `named` server for dynamic updates:
+
+- https://www.cyberciti.biz/faq/unix-linux-bind-named-configuring-tsig/
+- https://tomthorp.me/blog/using-tsig-enable-secure-zone-transfers-between-bind-9x-servers
+
+More complex `name` deployments will not use text files, but rather may use LDAP
+or SQL for a database for resource records. An additional wrinkle is metadata
+configuration, such as for zone metadata like enabling dynamic updates or access
+control lists (ACLs) for a zone. There are too many configurations to go into
+here, but you should be able to find the documentation to do so.
+
+Whatever your deployment is, the goal at this stage has nothing to do with
+cert-manager and everything to do with a tool called `nsupdate` generating
+updates signed with TSIG. Once this is out of the way, you can attack the
+cert-manager configuration with far greater confidence.
+
+#### Using `nsupdate`
+
+Most paths to configuring BIND `named` will go through using `dnssec-keygen`.
+This command-line tool generates a named private key that is used for signing
+TSIG requests. When a request is signed, both the signature and the name of the
+private key are attached to the request in an unencrypted form. In this manner,
+when the request is received, the name of the private key can be used to by the
+recipient to find the private key itself, build a new signature with it, and
+compare the two for acceptance.
+
+Since there are dozens of ways to have your `named` server misconfigured, we’ll
+use `nsupdate` to test that the server behaves as expected before we get there.
+`https://debian-administration.org/article/591/Using_the_dynamic_DNS_editor_nsupdate`
+is a solid breakdown of how to use the tool.
+
+To get started, we’ll simply run `nsupdate -k ` where `keyID` is the value
+returned from `dnssec-keygen`. This will read the key from disk and provide a
+command prompt to issue commands. In general, we want to write a simple TXT RR
+and make sure we can delete it.
+
+```bash
+$ nsupdate -k
+update add www1.example.com 60 txt testing
+send
+… test here with `nslookup`
+update delete www1.example.com txt
+send
+… test here with `nslookup`
+```
+
+Any failures to write, read or delete the record will mean that cert-manager
+will not be able to do so either, no matter how well it is configured.
+
+### Configuration Step 2 - Set up cert-manager
+
+Now we get to the fun stuff, seeing everything work. Remember that we need to
+set up the ACME DNS01 issuer and challenge mechanism as well as the `rfc2136`
+provider. Since the documentation covers the other parts sufficiently, let’s
+focus on the provider here.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ rfc2136:
+ nameserver:
+ tsigKeyName:
+ tsigAlgorithm: HMACSHA512 // should be matched to the algo you chose in `dnssec-keygen`
+ tsigSecretSecretRef:
+ name:
+ key:
+```
+
+For example:
+
+```yaml
+ rfc2136:
+ nameserver: 1.2.3.4:53
+ tsigKeyName: example-com-secret
+ tsigAlgorithm: HMACSHA512
+ tsigSecretSecretRef:
+ name: tsig-secret
+ key: tsig-secret-key
+```
+
+For this example configuration, we’ll need the following two commands. The
+first, on your `named` server generates the key. Note how `example-com-secret`
+is both in the `tsigKeyName` above and the `dnssec-keygen` command that follows.
+
+```bash
+$ dnssec-keygen -r /dev/urandom -a HMAC-SHA512 -b 512 -n HOST example-com-secret
+```
+
+Also note how the `tsigAlgorithm` is provided in both the configuration and the
+`keygen` command. They are listed at
+`https://github.com/miekg/dns/blob/v1.0.12/tsig.go#L18-L23`.
+
+The second bit of configuration you need on the Kubernetes side is to create a
+secret. Pulling the secret key string from the `.private` file generated
+above, use the secret in the placeholder below:
+
+```bash
+$ kubectl -n cert-manager create secret generic tsig-secret --from-literal=tsig-secret-key=
+```
+
+Note how the `tsig-secret` and `tsig-secret-key` match the configuration in the
+`tsigSecretSecretRef` above.
+
+## Rate Limits
+
+The `rfc2136` provider waits until *all* nameservers to in your domain's SOA RR
+respond with the same result before it contacts Let's Encrypt to complete the
+challenge process. This is because the challenge server contacts a
+non-authoritative DNS server that does a recursive query (a query for records it
+does not maintain locally). If the servers in the SOA do not contain the correct
+values, it's likely that the non-authoritative server will have bad information
+as well, causing the request to go against rate limits and eventually locking
+the process out.
+
+This process is in place to protect users from server misconfiguration creating
+a more subtle lockout that persists after the server configuration has been
+repaired.
+
+As documented elsewhere, it is prudent to fully debug configurations using the
+ACME staging servers before using the production servers. The staging servers
+have less aggressive rate limits, but the certificates they issue are not signed
+with a root certificate trusted by browsers.
+
+## What’s next?
+
+This configuration so far will actually do nothing. You still have to request a
+certificate as described [here](../../../usage/README.md). Once a certificate is
+requested, the provider will begin processing the request.
+
+## Troubleshooting
+
+- Be sure that you have fully tested the DNS server updates using `nsupdate`
+ first. Ideally, this is done from a pod in the same namespace as the `rfc2136`
+ provider to ensure there are no firewall issues.
+- The logs for the `cert-manager` pod are your friend. Additional logs can be
+ generated by adding the `--v=5` argument to the container launch.
+- The TSIG key is encoded with `base64`, but the Kubernetes API server also
+ expects that key literals will be decoded before they are stored. In some
+ cases, a key must be double-encoded. (If you've tested using `nsupdate`, it's
+ pretty easy to spot when you are running into this.)
+- Pay attention to the refresh time of the zone you are working with. For zones
+ with low traffic, it will not make a significant difference to reduce the
+ refresh time down to about five minutes while getting initial certificates.
+ Once the process is working, the beauty of `cert-manager` is it doesn't matter
+ if a renewal takes hours due to refresh times, it's all automated!
+- Compared to the other providers that often use REST APIs to modify DNS RRs,
+ this provider can take a little longer. You can `watch kubectl certificate
+ yourcert` to get a display of what's going on. It's not uncommon for the process
+ to take five minutes in total.
\ No newline at end of file
diff --git a/content/v1.12-docs/configuration/acme/dns01/route53.md b/content/v1.12-docs/configuration/acme/dns01/route53.md
new file mode 100644
index 00000000000..f18bbf128c1
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/route53.md
@@ -0,0 +1,253 @@
+---
+title: Route53
+description: 'cert-manager configuration: ACME DNS-01 challenges using Amazon AWS Route53 DNS'
+---
+
+This guide explains how to set up an `Issuer`, or `ClusterIssuer`, to use Amazon
+Route53 to solve DNS01 ACME challenges. It's advised you read the [DNS01
+Challenge Provider](./README.md) page first for a more general understanding of
+how cert-manager handles DNS01 challenges.
+
+> Note: This guide assumes that your cluster is hosted on Amazon Web Services
+> (AWS) and that you already have a hosted zone in Route53.
+
+## Set up an IAM Role
+
+cert-manager needs to be able to add records to Route53 in order to solve the
+DNS01 challenge. To enable this, create a IAM policy with the following
+permissions:
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": "route53:GetChange",
+ "Resource": "arn:aws:route53:::change/*"
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "route53:ChangeResourceRecordSets",
+ "route53:ListResourceRecordSets"
+ ],
+ "Resource": "arn:aws:route53:::hostedzone/*"
+ },
+ {
+ "Effect": "Allow",
+ "Action": "route53:ListHostedZonesByName",
+ "Resource": "*"
+ }
+ ]
+}
+```
+
+> Note: The `route53:ListHostedZonesByName` statement can be removed if you
+> specify the (optional) `hostedZoneID`. You can further tighten the policy by
+> limiting the hosted zone that cert-manager has access to (e.g.
+> `arn:aws:route53:::hostedzone/DIKER8JEXAMPLE`).
+
+## Credentials
+
+You have two options for the set up - either create a user or a role and attach
+that policy from above. Using a role is considered best practice because you do
+not have to store permanent credentials in a secret.
+
+cert-manager supports two ways of specifying credentials:
+
+- explicit by providing a `accessKeyID` and `secretAccessKey`
+- or implicit (using [metadata
+ service](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)
+ or [environment variables or credentials
+ file](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials).
+
+cert-manager also supports specifying a `role` to enable cross-account access
+and/or limit the access of cert-manager. Integration with
+[`kiam`](https://github.com/uswitch/kiam) and
+[`kube2iam`](https://github.com/jtblin/kube2iam) should work out of the box.
+
+
+## Cross Account Access
+
+Example: Account Y manages Route53 DNS Zones. Now you want cert-manager running in Account X (or many other accounts) to be able to manage records in Route53 zones hosted in Account Y.
+
+First, create a role with the permissions policy above (let's call the role `dns-manager`)
+in Account Y, and attach a trust relationship like the one below.
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::XXXXXXXXXXX:role/cert-manager"
+ },
+ "Action": "sts:AssumeRole"
+ }
+ ]
+}
+```
+
+Bear in mind, that you won't be able to define this policy until `cert-manager` role on account Y is created. If you are setting this up using a configuration language, you may want to define principal as:
+
+```json
+"Principal": {
+ "AWS": "XXXXXXXXXXX"
+ }
+```
+And restrict it, in a future step, after all the roles are created.
+
+This allows the role `cert-manager` in Account X to assume the `dns-manager` role in Account Y to manage the Route53 DNS zones in Account Y. For more information visit the [official
+documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html).
+
+Second, create the cert-manager role in Account X; this will be used as a credentials source for the cert-manager pods running in Account X. Attach to the role the following **permissions** policy:
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Resource": "arn:aws:iam::YYYYYYYYYYYY:role/dns-manager",
+ "Action": "sts:AssumeRole"
+ }
+ ]
+}
+```
+
+And the following trust relationship (Add AWS `Service`s as needed):
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": {
+ "Service": "ec2.amazonaws.com"
+ },
+ "Action": "sts:AssumeRole"
+ }
+ ]
+}
+```
+
+## Creating an Issuer (or `ClusterIssuer`)
+
+Here is an example configuration for a `ClusterIssuer`:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-prod
+spec:
+ acme:
+ ...
+ solvers:
+
+ # example: cross-account zone management for example.com
+ # this solver uses ambient credentials (i.e. inferred from the environment or EC2 Metadata Service)
+ # to assume a role in a different account
+ - selector:
+ dnsZones:
+ - "example.com"
+ dns01:
+ route53:
+ region: us-east-1
+ hostedZoneID: DIKER8JEXAMPLE # optional, see policy above
+ role: arn:aws:iam::YYYYYYYYYYYY:role/dns-manager
+
+ # this solver handles example.org challenges
+ # and uses explicit credentials
+ - selector:
+ dnsZones:
+ - "example.org"
+ dns01:
+ route53:
+ region: eu-central-1
+ accessKeyID: AKIAIOSFODNN7EXAMPLE
+ secretAccessKeySecretRef:
+ name: prod-route53-credentials-secret
+ key: secret-access-key
+ # you can also assume a role with these credentials
+ role: arn:aws:iam::YYYYYYYYYYYY:role/dns-manager
+```
+
+Note that, as mentioned above, the pod is using `arn:aws:iam::XXXXXXXXXXX:role/cert-manager` as a credentials source in Account X, but the `ClusterIssuer` ultimately assumes the `arn:aws:iam::YYYYYYYYYYYY:role/dns-manager` role to actually make changes in Route53 zones located in Account Y.
+
+## EKS IAM Role for Service Accounts (IRSA)
+
+While [`kiam`](https://github.com/uswitch/kiam) / [`kube2iam`](https://github.com/jtblin/kube2iam) work directly with cert-manager, some special attention is needed for using the [IAM Roles for Service Accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) feature available on EKS.
+
+### OIDC provider
+
+First follow the AWS documentation [Enabling IAM roles for service accounts on your cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html) to ensure that the OIDC provider for the EKS cluster is enabled. The OIDC information is needed to create the trust relationship for the cert-manager role below.
+
+### IAM role trust policy
+
+The cert-manager role needs the following trust relationship attached to the role in order to use the IRSA method. Replace the following:
+
+- `` with the AWS account ID of the EKS cluster.
+- `` with the region where the EKS cluster is located.
+- `` with the hash in the EKS API URL; this will be a random 32 character hex string (example: `45DABD88EEE3A227AF0FA468BE4EF0B5`)
+- `` with the namespace where cert-manager is running.
+- `` with the name of the `ServiceAccount` object created by cert-manager.
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": "sts:AssumeRoleWithWebIdentity",
+ "Principal": {
+ "Federated": "arn:aws:iam:::oidc-provider/oidc.eks..amazonaws.com/id/"
+ },
+ "Condition": {
+ "StringEquals": {
+ "oidc.eks..amazonaws.com/id/:sub": "system:serviceaccount::"
+ }
+ }
+ }
+ ]
+}
+```
+
+**Note:** If you're following the Cross Account example above, this trust policy is attached to the cert-manager role in Account X with ARN `arn:aws:iam::XXXXXXXXXXX:role/cert-manager`. The permissions policy is the same as above.
+
+### Service annotation
+
+Annotate the `ServiceAccount` created by cert-manager:
+
+```yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ annotations:
+ eks.amazonaws.com/role-arn: arn:aws:iam::XXXXXXXXXXX:role/cert-manager
+```
+
+You will also need to modify the cert-manager `Deployment` with the correct file system permissions, so the `ServiceAccount` token can be read.
+
+```yaml
+spec:
+ template:
+ spec:
+ securityContext:
+ fsGroup: 1001
+```
+
+The cert-manager Helm chart provides a variable for injecting annotations into cert-manager's `ServiceAccount` and `Deployment` object like so:
+
+```yaml
+serviceAccount:
+ annotations:
+ eks.amazonaws.com/role-arn: arn:aws:iam::XXXXXXXXXXX:role/cert-manager
+securityContext:
+ fsGroup: 1001
+```
+
+**Note:** If you're following the Cross Account example above, modify the `ClusterIssuer` in the same way as above with the role from Account Y.
diff --git a/content/v1.12-docs/configuration/acme/dns01/webhook.md b/content/v1.12-docs/configuration/acme/dns01/webhook.md
new file mode 100644
index 00000000000..d9a4339e393
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/dns01/webhook.md
@@ -0,0 +1,32 @@
+---
+title: Webhook
+description: 'cert-manager configuration: ACME DNS-01 challenges using External Webhook Solvers'
+---
+
+The webhook `Issuer` is a generic ACME solver. The actual work is done by an
+external service. Look at the respective documentation of
+[`dns-providers`](../../../contributing/dns-providers.md).
+
+View more webhook solvers at https://github.com/topics/cert-manager-webhook.
+
+Here is an example of how webhook providers are to be configured. All `DNS01`
+providers will contain their own specific configuration however all require a
+`groupName` and `solverName` field.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ ...
+ solvers:
+ - dns01:
+ webhook:
+ groupName: $WEBHOOK_GROUP_NAME
+ solverName: $WEBHOOK_SOLVER_NAME
+ config:
+ ...
+
+```
diff --git a/content/v1.12-docs/configuration/acme/http01/README.md b/content/v1.12-docs/configuration/acme/http01/README.md
new file mode 100644
index 00000000000..ee46fdbe405
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/http01/README.md
@@ -0,0 +1,366 @@
+---
+title: HTTP01
+description: 'cert-manager configuration: ACME HTTP-01 challenges'
+---
+
+
+
+📌 This page focuses on solving ACME HTTP-01 challenges. If you are looking for
+how to automatically create Certificate resources by annotating Ingress or
+Gateway resources, see [Securing Ingress Resources](../../../usage/ingress.md) and
+[Securing Gateway Resources](../../../usage/gateway.md).
+
+
+
+cert-manager uses your existing Ingress or Gateway configuration in order to
+solve HTTP01 challenges.
+
+
+## Configuring the HTTP01 Ingress solver
+
+This page contains details on the different options available on the `Issuer`
+resource's HTTP01 challenge solver configuration. For more information on
+configuring ACME issuers and their API format, read the [ACME Issuers](../README.md)
+documentation.
+
+You can read about how the HTTP01 challenge type works on the [Let's Encrypt
+challenge types
+page](https://letsencrypt.org/docs/challenge-types/#http-01-challenge).
+
+Here is an example of a simple `HTTP01` ACME issuer with more options for
+configuration below:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: example-issuer
+spec:
+ acme:
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ privateKeySecretRef:
+ name: example-issuer-account-key
+ solvers:
+ - http01:
+ ingress:
+ class: nginx
+```
+
+## Options
+
+The HTTP01 Issuer supports a number of additional options. For full details on
+the range of options available, read the [reference
+documentation](../../../reference/api-docs.md#acme.cert-manager.io/v1.ACMEChallengeSolverHTTP01).
+
+### `class`
+
+If the `class` field is specified, cert-manager will create new `Ingress`
+resources in order to route traffic to the `acmesolver` pods, which are
+responsible for responding to ACME challenge validation requests.
+
+If this field is not specified, and `name` is also not specified,
+cert-manager will default to create *new* `Ingress` resources but will **not**
+set the ingress class on these resources, meaning *all* ingress controllers
+installed in your cluster will serve traffic for the challenge solver,
+potentially incurring additional cost.
+
+
+### `name`
+
+If the `name` field is specified, cert-manager will edit the named
+ingress resource in order to solve HTTP01 challenges.
+
+This is useful for compatibility with ingress controllers such as `ingress-gce`,
+which utilize a unique IP address for each `Ingress` resource created.
+
+This mode should be avoided when using ingress controllers that expose a single
+IP for all ingress resources, as it can create compatibility problems with
+certain ingress-controller specific annotations.
+
+`serviceType`
+
+In rare cases it might be not possible/desired to use `NodePort` as type for the
+HTTP01 challenge response service, e.g. because of Kubernetes limit
+restrictions. To define which Kubernetes service type to use during challenge
+response specify the following HTTP01 configuration:
+
+```yaml
+ http01:
+ ingress:
+ # Valid values are ClusterIP and NodePort
+ serviceType: ClusterIP
+```
+
+By default, type `NodePort` will be used when you don't set HTTP01 or when you set
+`serviceType` to an empty string. Normally there's no need to change this.
+
+
+### `podTemplate`
+
+You may wish to change or add to the labels and annotations of solver pods.
+These can be configured under the `metadata` field under `podTemplate`.
+
+Similarly, you can set the `nodeSelector`, tolerations and affinity of solver
+pods by configuring under the `spec` field of the `podTemplate`. No other
+spec fields can be edited.
+
+An example of how you could configure the template is as so:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: ...
+spec:
+ acme:
+ server: ...
+ privateKeySecretRef:
+ name: ...
+ solvers:
+ - http01:
+ ingress:
+ podTemplate:
+ metadata:
+ labels:
+ foo: "bar"
+ env: "prod"
+ spec:
+ nodeSelector:
+ bar: baz
+```
+
+The added labels and annotations will merge on top of the cert-manager defaults,
+overriding entries with the same key.
+
+No other fields of the `podTemplate` exist.
+
+### `ingressTemplate`
+
+It is possible to add labels and annotations to the solver ingress resources.
+It can be really useful when you are managing several Ingress Controllers across your cluster and you want to make sure that the right one will pick up and expose the solver (for the upcoming challenge to resolve).
+These can be configured under the `metadata` field under `ingressTemplate`:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: ...
+spec:
+ acme:
+ server: ...
+ privateKeySecretRef:
+ name: ...
+ solvers:
+ - http01:
+ ingress:
+ ingressTemplate:
+ metadata:
+ labels:
+ foo: "bar"
+ annotations:
+ "nginx.ingress.kubernetes.io/whitelist-source-range": "0.0.0.0/0,::/0"
+ "nginx.org/mergeable-ingress-type": "minion"
+ "traefik.ingress.kubernetes.io/frontend-entry-points": "http"
+```
+
+The added labels and annotations will merge on top of the cert-manager defaults,
+overriding entries with the same key.
+
+No other fields of the ingress can be edited.
+
+## Configuring the HTTP-01 Gateway API solver
+
+**FEATURE STATE**: cert-manager 1.5 [alpha]
+
+The Gateway and HTTPRoute resources are part of the [Gateway API][gwapi], a set
+of CRDs that you install on your Kubernetes cluster that provide various
+improvements over the Ingress API.
+
+[gwapi]: https://gateway-api.sigs.k8s.io
+
+
+
+📌 This feature requires the installation of the [Gateway API bundle](https://gateway-api.sigs.k8s.io/guides/#installing-a-gateway-controller) and passing a
+feature flag to the cert-manager controller.
+
+To install v1.5.1 Gateway API bundle (Gateway CRDs and webhook), run the following command:
+
+```sh
+kubectl apply -f "https://github.com/kubernetes-sigs/gateway-api/releases/download/v0.5.1/standard-install.yaml"
+```
+
+To enable the feature in cert-manager, turn on the `GatewayAPI` feature gate:
+
+- If you are using Helm:
+
+ ```sh
+ helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager \
+ --set "extraArgs={--feature-gates=ExperimentalGatewayAPISupport=true}"
+ ```
+
+- If you are using the raw cert-manager manifests, add the following flag to the
+ cert-manager controller Deployment:
+
+ ```yaml
+ args:
+ - --feature-gates=ExperimentalGatewayAPISupport=true
+ ```
+
+The Gateway API CRDs should either be installed before cert-manager starts or
+the cert-manager Deployment should be restarted after installing the Gateway API
+CRDs. This is important because some of the cert-manager components only perform
+the Gateway API check on startup. You can restart cert-manager with the
+following command:
+
+```sh
+kubectl rollout restart deployment cert-manager -n cert-manager
+```
+
+
+
+
+
+
+🚧 cert-manager 1.8+ is tested with v1alpha2 Kubernetes Gateway API. It should also work
+with v1beta1 because of resource conversion, but has not been tested with it.
+
+
+The Gateway API HTTPRoute HTTP-01 solver creates a temporary HTTPRoute using the
+given labels. These labels must match a Gateway that contains a listener on port
+80.
+
+Here is an example of a HTTP-01 ACME Issuer using the Gateway API:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt
+ namespace: default
+spec:
+ acme:
+ solvers:
+ - http01:
+ gatewayHTTPRoute:
+ parentRefs:
+ - name: traefik
+ namespace: traefik
+ kind: Gateway
+```
+
+The Issuer relies on an existing Gateway present on the cluster. cert-manager
+does not edit Gateway resources.
+
+For example, the following Gateway will allow the Issuer to solve the challenge:
+
+```yaml
+apiVersion: gateway.networking.k8s.io/v1alpha2
+kind: Gateway
+metadata:
+ name: traefik
+ namespace: traefik
+spec:
+ gatewayClassName: traefik
+ listeners:
+ - name: http
+ protocol: HTTP
+ port: 80
+ allowedRoutes:
+ namespaces:
+ from: All
+```
+
+In the above example, the Gateway has been specifically created for the purpose
+of solving HTTP-01 challenges, but you can also choose to re-use your existing
+Gateway, as long as it has a listener on port 80.
+
+The `labels` on your Issuer may reference a Gateway that is on a separate
+namespace, as long as the Gateway's port 80 listener is configured with `from:
+All`. Note that the Certificate will still be created on the same namespace as
+the Issuer, which means that you won't be able to reference this Secret in the
+above-mentioned Gateway.
+
+When the above Issuer is presented with a Certificate, cert-manager creates the
+temporary HTTPRoute. For example, with the following Certificate:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-tls
+ namespace: default
+spec:
+ issuerRef:
+ name: letsencrypt
+ dnsNames:
+ - example.net
+```
+
+You will see an HTTPRoute appear:
+
+```yaml
+apiVersion: gateway.networking.k8s.io/v1alpha2
+kind: HTTPRoute
+metadata:
+ name: cm-acme-http-solver-gdhvg
+ namespace: default
+spec:
+ parentRefs:
+ - name: traefik
+ namespace: traefik
+ kind: Gateway
+ hostnames:
+ - example.net
+ rules:
+ - forwardTo:
+ - port: 8089
+ serviceName: cm-acme-http-solver-gdhvg
+ weight: 1
+ matches:
+ - path:
+ type: Exact
+ value: /.well-known/acme-challenge/YadC4gaAzqEPU1Yea0D2MrzvNRWiBCtUizCtpiRQZqI
+```
+
+After the Certificate is issued, the HTTPRoute is deleted.
+
+`labels`
+
+These labels are copied into the temporary HTTPRoute created by cert-manager for
+solving the HTTP-01 challenge. These labels must match one of the Gateway
+resources on your cluster. The matched Gateway have a listener on port 80.
+
+Note that when the labels do not match any Gateway on your cluster, cert-manager
+will create the temporary HTTPRoute challenge and nothing will happen.
+
+`serviceType`
+
+This field has the same meaning as the
+[`http01.ingress.serviceType`](#ingress-service-type).
+
+
+## Setting Nameservers for HTTP-01 solver propagation checks
+
+cert-manager will perform reachability tests before attempting a HTT01
+challenge. By default cert-manager will use the recursive nameservers taken
+from `/etc/resolv.conf` to query the challenge URL.
+
+If this is not desired (for example with split-horizon DNS), the cert-manager
+controller exposes a flag that allows you alter this behavior:
+
+`--acme-http01-solver-nameservers` Comma separated string with host and port of the
+recursive nameservers cert-manager should query.
+
+
+Example usage:
+```bash
+--acme-http01-solver-nameservers="8.8.8.8:53,1.1.1.1:53"
+```
+
+If you're using the `cert-manager` helm chart, you can set recursive nameservers
+through `.Values.extraArgs` or at the command at helm install/upgrade time
+with `--set`:
+
+```bash
+--set 'extraArgs={--acme-http01-solver-nameservers=8.8.8.8:53\,1.1.1.1:53}'
+```
diff --git a/content/v1.12-docs/configuration/acme/http01/externalloadbalancer.md b/content/v1.12-docs/configuration/acme/http01/externalloadbalancer.md
new file mode 100644
index 00000000000..a85966bd291
--- /dev/null
+++ b/content/v1.12-docs/configuration/acme/http01/externalloadbalancer.md
@@ -0,0 +1,34 @@
+---
+title: External Load Balancer
+description: 'cert-manager configuration: ACME HTTP-01 challenges using External Load Balancers'
+---
+
+When you are using an external load balancer provided by any host, you can face several configuration issues to get it work with cert-manager.
+
+This documentation is intended to help configure the HTTP-01 challenge type for instances behind external load balancer.
+
+## NAT Loopback / Hairpin
+
+The first configuration point is NAT loopback. You can face check issues due to Load Balancer preventing instances behind it to access its external interface.
+
+Some Network Load Balancer have this kind of limitation for several reasons. It can be configured through `iptables` rerouting configuration known as `NAT loopback`.
+
+To check if you are facing this problem :
+
+1. Check that the endpoint of the challenge is accessible to the public : `curl `
+2. Check that the challenge endpoint is NOT accessible from inside behind the Load Balancer: use SSH to open a session on a node places behind the LB; then launch the same command than before : `curl `
+
+The `HTTP-01` challenge's endpoint can be found in the logs when the `pre-check` fails. If it does not appear in the logs, you can check the challenge URL by `kubectl`command.
+
+`` is the URL used to test the HTTP-01 from the certificate `Issuer`. For Let's Encrypt for example, the URL is formed like `/.well-known/acme-challenge/`
+
+
+## Load Balancer HTTP endpoints
+
+If you are using a Load Balancer (outside a managed Kubernetes service), you should be able to configure the Load Balancer protocol as HTTP, HTTPS, TCP, UDP. Several Load Balancer now offer free TLS certificates with Let's Encrypt.
+
+When using HTTP(s) protocols for your Load Balancer, it can intercept the challenge URL to replace the response's verification hash with their hash.
+
+In this case, cert-manager will fail `did not get expected response when querying endpoint, expected 'xxxx' but got: yyyy (truncated)`.
+
+This kind of error can be thrown for multiple reasons. This case shows a correctly formatted response, but not the expected one. The solution is to configure the Load Balancer with TCP protocol so that the HTTP request will not be intercepted by the host.
\ No newline at end of file
diff --git a/content/v1.12-docs/configuration/ca.md b/content/v1.12-docs/configuration/ca.md
new file mode 100644
index 00000000000..fffb6f2401d
--- /dev/null
+++ b/content/v1.12-docs/configuration/ca.md
@@ -0,0 +1,94 @@
+---
+title: CA
+description: 'cert-manager configuration: CA Issuers'
+---
+
+⚠️ CA issuers are generally either for trying cert-manager out or else for advanced users with
+a good idea of how to run a PKI. To be used safely in production, CA issuers introduce complex
+planning requirements around rotation, trust store distribution and disaster recovery.
+
+If you're not planning to run your own PKI, use a different issuer type.
+
+The CA issuer represents a Certificate Authority whose certificate and
+private key are stored inside the cluster as a Kubernetes `Secret`.
+
+Certificates issued by a CA issuer will not be publicly trusted and so are unlikely to be trusted
+by your applications without further configuration.
+
+Consider [trust-manager](../projects/trust-manager/README.md) for distributing your CA certificate safely
+across your cluster!
+
+## Deployment
+
+CA Issuers must be configured with a certificate and private key stored in a Kubernetes
+secret. You can create this externally if you wish, or you could bootstrap a root certificate
+using a [`SelfSigned` issuer](./selfsigned.md#bootstrapping-ca-issuers).
+
+Your certificate's secret should reside in the same namespace as the `Issuer`, or otherwise
+in the `Cluster Resource Namespace` in the case of a `ClusterIssuer`.
+
+The `Cluster Resource Namespace` is defaulted as being the `cert-manager` namespace, but
+can be configured using the `--cluster-resource-namespace` flag on the cert-manager controller.
+
+Below is an example of a secret resource that will be used for signing. Take
+note of the index keys used for each field as these are required in order for
+cert-manager to find the certificate and key. Also note that, like all secrets,
+data must be base64 encoded. The command `$ cat crt.pem | base64 -w0` should help you
+on GNU-based systems (Debian, Ubuntu, etc.) and `$ cat crt.pem | base64 -b0` on BSD-based
+systems (most notably macOS).
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: ca-key-pair
+ namespace: sandbox
+data:
+ tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMrVENDQWVHZ0F3SUJBZ0lKQUtQR3dLRGwvNUhuTUEwR0NTcUdTSWIzRFFFQkN3VUFNQk14RVRBUEJnTlYKQkFNTUNHcHZjMmgyWVc1c01CNFhEVEU1TURneU1qRTJNRFUxT0ZvWERUSTVNRGd4T1RFMk1EVTFPRm93RXpFUgpNQThHQTFVRUF3d0lhbTl6YUhaaGJtd3dnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCCkFRQ3doU0IvcVc2L2tMYjJ6cHUrRUp2RDl3SEZhcStRQS8wSkgvTGxseW83ekFGeCtISHErQ09BYmsrQzhCNHQKL0hVRXNuczVSTDA5Q1orWDRqNnBiSkZkS2R1UHhYdTVaVllua3hZcFVEVTd5ZzdPU0tTWnpUbklaNzIzc01zMApSNmpZbi9Ecmo0eFhNSkVmSFVEcVllU1dsWnIzcWkxRUZhMGM3ZlZEeEgrNHh0WnROTkZPakg3YzZEL3ZXa0lnCldRVXhpd3Vzc2U2S01PV2pEbnYvNFZyamVsMlFnVVlVYkhDeWVaSG1jdGkrSzBMV0Nmby9SZzZQdWx3cmJEa2gKam1PZ1l0MzBwZGhYME9aa0F1a2xmVURIZnA4YmpiQ29JMnRhWUFCQTZBS2pLc08zNUxBRVU3OUNMMW1MVkh1WgpBQ0k1VWppamEzVlBXVkhTd21KUEp5dXhBZ01CQUFHalVEQk9NQjBHQTFVZERnUVdCQlFtbDVkVEFaaXhGS2hqCjkzd3VjUldoYW8vdFFqQWZCZ05WSFNNRUdEQVdnQlFtbDVkVEFaaXhGS2hqOTN3dWNSV2hhby90UWpBTUJnTlYKSFJNRUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCK2tsa1JOSlVLQkxYOHlZa3l1VTJSSGNCdgpHaG1tRGpKSXNPSkhac29ZWGRMbEcxcFpORmpqUGFPTDh2aDQ0Vmw5OFJoRVpCSHNMVDFLTWJwMXN1NkNxajByClVHMWtwUkJlZitJT01UNE1VN3ZSSUNpN1VPbFJMcDFXcDBGOGxhM2hQT2NSYjJ5T2ZGcVhYeVpXWGY0dDBCNDUKdEhpK1pDTkhCOUZ4alNSeWNiR1lWaytUS3B2aEphU1lOTUdKM2R4REthUDcrRHgzWGNLNnNBbklBa2h5SThhagpOVSttdzgvdG1Sa1A0SW4va1hBUitSaTBxVW1Iai92d3ZuazRLbTdaVXkxRllIOERNZVM1TmtzbisvdUhsUnhSClY3RG5uMDM5VFJtZ0tiQXFONzJnS05MbzVjWit5L1lxREFZSFlybjk4U1FUOUpEZ3RJL0svQVRwVzhkWAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
+ tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBc0lVZ2Y2bHV2NUMyOXM2YnZoQ2J3L2NCeFdxdmtBUDlDUi95NVpjcU84d0JjZmh4CjZ2Z2pnRzVQZ3ZBZUxmeDFCTEo3T1VTOVBRbWZsK0krcVd5UlhTbmJqOFY3dVdWV0o1TVdLVkExTzhvT3praWsKbWMwNXlHZTl0N0RMTkVlbzJKL3c2NCtNVnpDUkh4MUE2bUhrbHBXYTk2b3RSQld0SE8zMVE4Ui91TWJXYlRUUgpUb3grM09nLzcxcENJRmtGTVlzTHJMSHVpakRsb3c1Ny8rRmE0M3Bka0lGR0ZHeHdzbm1SNW5MWXZpdEMxZ242ClAwWU9qN3BjSzJ3NUlZNWpvR0xkOUtYWVY5RG1aQUxwSlgxQXgzNmZHNDJ3cUNOcldtQUFRT2dDb3lyRHQrU3cKQkZPL1FpOVppMVI3bVFBaU9WSTRvMnQxVDFsUjBzSmlUeWNyc1FJREFRQUJBb0lCQUNFTkhET3JGdGg1a1RpUApJT3dxa2UvVVhSbUl5MHlNNHFFRndXWXBzcmUxa0FPMkFDWjl4YS96ZDZITnNlanNYMEM4NW9PbmtrTk9mUHBrClcxVS94Y3dLM1ZpRElwSnBIZ09VNzg1V2ZWRXZtU3dZdi9Fb1V3eHFHRVMvcnB5Z1drWU5WSC9XeGZGQlg3clMKc0dmeVltbXJvM09DQXEyLzNVVVFiUjcrT09md3kzSHdUdTBRdW5FSnBFbWU2RXdzdWIwZzhTTGp2cEpjSHZTbQpPQlNKSXJyL1RjcFRITjVPc1h1Vm5FTlVqV3BBUmRQT1NrRFZHbWtCbnkyaVZURElST3NGbmV1RUZ1NitXOWpqCmhlb1hNN2czbkE0NmlLenUzR0YwRWhLOFkzWjRmeE42NERkbWNBWnphaU1vMFJVaktWTFVqbVlQSEUxWWZVK3AKMkNYb3dNRUNnWUVBMTgyaU52UEkwVVlWaUh5blhKclNzd1YrcTlTRStvVi90U2ZSUUNGU2xsV0d3KzYyblRiVwpvNXpoL1RDQW9VTVNSbUFPZ0xKWU1LZUZ1SWdvTEoxN1pvWjN0U1czTlVtMmRpT0lPSHorcTQxQzM5MDRrUzM5CjkrYkFtVmtaSFA5VktLOEMraS9tek5mSkdHZEJadGIweWtTM2t3OUIxTHdnT3o3MDhFeXFSQ2tDZ1lFQTBXWlAKbzF2MThnV2tMK2FnUDFvOE13eDRPZlpTN3dKY3E0Z0xnUWhjYS9pSkttY0x0RFN4cUJHckJ4UVo0WTIyazlzdQpzTFVrNEJobGlVM29iUUJNaUdtMGtITHVBSEFRNmJvdWZBMUJwZjN2VFdHSkhSRjRMeFJsNzc2akw4UXI4VnpxClpURVBtY0R0T0hpYjdwb2I1Z2IzSDhiVGhYeUhmdGZxRW55alhFa0NnWUVBdk9DdDZZclZhTlQrWThjMmRFYk4Kd3dJOExBaUZtdjdkRjZFUjlCODJPWDRCeGR0WTJhRDFtNTNqN2NaVnpzNzFYOE1TN25FcDN1dkFqaElkbDI3KwpZbTJ1dUUyYVhIbDN5VTZ3RzBETFpUcnVIU0Z5TVI4ZithbHRTTXBDd0s1NXluSGpHVFp6dXpYaVBBbWpwRzdmCk1XbVRncE1IK3puc3UrNE9VNFBHUW9FQ2dZQWNqdUdKbS84YzlOd0JsR2lDZTJIK2JGTHhSTURteStHcm16QkcKZHNkMENqOWF3eGI3aXJ3MytjRGpoRUJMWExKcjA5YTRUdHdxbStrdElxenlRTG92V0l0QnNBcjVrRThlTVVBcAp0djBmRUZUVXJ0cXVWaldYNWlaSTNpMFBWS2ZSa1NSK2pJUmVLY3V3aWZKcVJpWkw1dU5KT0NxYzUvRHF3Yk93CnRjTHAwUUtCZ0VwdEw1SU10Sk5EQnBXbllmN0F5QVBhc0RWRE9aTEhNUGRpL2dvNitjSmdpUmtMYWt3eUpjV3IKU25QSG1TbFE0aEluNGMrNW1lbHBDWFdJaklLRCtjcTlxT2xmQmRtaWtYb2RVQ2pqWUJjNnVGQ1QrNWRkMWM4RwpiUkJQOUNtWk9GL0hOcHN0MEgxenhNd1crUHk5Q2VnR3hhZ0ZCekxzVW84N0xWR2h0VFFZCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
+```
+
+> Note: If your issuer represents an intermediate, ensure that `tls.crt` contains
+> the issuer's full chain in the correct order: `issuer -> intermediate(s) -> root`.
+> The root (self-signed) CA certificate is optional, but adding it will ensure that
+> the correct CA certificate is stored in the secrets for issued `Certificate`s under
+> the `ca.crt` key. If you fail to provide a complete chain, it might not be possible
+> for consumers of issued `Certificate`s to verify whether they're trusted.
+
+Next is to deploy the CA issuer which references this `Secret`. This is done by
+referencing the secret name under the `ca` stanza in the `Issuer` spec.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: ca-issuer
+ namespace: sandbox
+spec:
+ ca:
+ secretName: ca-key-pair
+```
+
+Optionally, you can specify [CRL](https://en.wikipedia.org/wiki/Certificate_revocation_list) Distribution Points; an array of strings each of which identifies the location of the CRL from which the revocation of this certificate can be checked.
+
+```yaml
+...
+spec:
+ ca:
+ secretName: ca-key-pair
+ crlDistributionPoints:
+ - "http://example.com"
+```
+
+Once deployed, you can then check that the issuer has been successfully
+configured by checking the ready status of the certificate. Replace `issuers`
+here with `clusterissuers` if that is what has been deployed.
+
+```bash
+$ kubectl get issuers ca-issuer -n sandbox -o wide
+NAME READY STATUS AGE
+ca-issuer True Signing CA verified 2m
+```
+
+Certificates are now ready to be requested by using the CA `Issuer` named
+`ca-issuer` within the `sandbox` namespace.
diff --git a/content/v1.12-docs/configuration/external.md b/content/v1.12-docs/configuration/external.md
new file mode 100644
index 00000000000..d4bc78088f8
--- /dev/null
+++ b/content/v1.12-docs/configuration/external.md
@@ -0,0 +1,51 @@
+---
+title: External
+description: 'cert-manager configuration: External Issuers'
+---
+
+cert-manager supports external `Issuer` types. While external issuers are not
+implemented in the main cert-manager repository, they are otherwise treated the
+same as any other issuer.
+
+External issuers are typically deployed as a pod which is configured
+to watch for `CertificateRequest` resources in the cluster whose `issuerRef`
+matches the name of the issuer. External issuers exist outside of the
+`cert-manager.io` group.
+
+Installation for each issuer may differ; check the documentation for each
+external issuer for more details on installing, configuring and using it.
+
+## Known External Issuers
+
+If you've created an external issuer which you'd like to share,
+[raise a Pull Request](https://github.com/cert-manager/website/pulls) to have
+it added here!
+
+These external issuers are known to support and honor [approval](https://cert-manager.io/docs/concepts/certificaterequest/#approval).
+
+- [kms-issuer](https://github.com/Skyscanner/kms-issuer): Requests
+ certificates signed using an [AWS KMS](https://aws.amazon.com/kms/) asymmetric key.
+- [aws-privateca-issuer](https://github.com/cert-manager/aws-privateca-issuer): Requests
+ certificates from [AWS Private Certificate Authority](https://aws.amazon.com/certificate-manager/private-certificate-authority/)
+ for cloud native/hybrid environments.
+- [google-cas-issuer](https://github.com/jetstack/google-cas-issuer): Used
+ to request certificates signed by private CAs managed by the
+ [Google Cloud Certificate Authority Service](https://cloud.google.com/certificate-authority-service/).
+- [origin-ca-issuer](https://github.com/cloudflare/origin-ca-issuer): Used
+ to request certificates signed by
+ [Cloudflare Origin CA](https://developers.cloudflare.com/ssl/origin-configuration/origin-ca)
+ to enable TLS between Cloudflare edge and your Kubernetes workloads.
+- [step-issuer](https://github.com/smallstep/step-issuer): Requests
+ certificates from the [Smallstep](https://smallstep.com) [Certificate Authority server](https://github.com/smallstep/certificates).
+- [freeipa-issuer](https://github.com/guilhem/freeipa-issuer): Requests
+ certificates signed by [FreeIPA](https://www.freeipa.org).
+- [ADCS Issuer](https://github.com/nokia/adcs-issuer): Requests
+ certificates signed by [Microsoft Active Directory Certificate Service](https://docs.microsoft.com/en-us/windows-server/networking/core-network-guide/cncg/server-certs/install-the-certification-authority).
+ [NOT MAINTAINED]
+- [CFSSL Issuer](https://gerrit.wikimedia.org/r/plugins/gitiles/operations/software/cfssl-issuer/): Request certificates signed by a [CFSSL](https://github.com/cloudflare/cfssl) `multirootca` instance.
+- [ncm-issuer](https://github.com/nokia/ncm-issuer): Requests certificates from the [Nokia](https://www.nokia.com/) [Netguard Certificate Manager](https://www.nokia.com/networks/security-portfolio/netguard/certificate-manager)
+- [tcs-issuer](https://github.com/intel/trusted-certificate-issuer) Requests certificates signed securely using [Intel's SGX technology](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/overview.html).
+
+## Building New External Issuers
+
+If you're interested in building a new external issuer, check the [development documentation](../contributing/external-issuers.md).
diff --git a/content/v1.12-docs/configuration/selfsigned.md b/content/v1.12-docs/configuration/selfsigned.md
new file mode 100644
index 00000000000..bfc2b39b2b4
--- /dev/null
+++ b/content/v1.12-docs/configuration/selfsigned.md
@@ -0,0 +1,171 @@
+---
+title: SelfSigned
+description: 'cert-manager configuration: SelfSigned Issuers'
+---
+
+⚠️ `SelfSigned` issuers are generally useful for bootstrapping a PKI locally, which
+is a complex topic for advanced users. To be used safely in production, running a PKI
+introduces complex planning requirements around rotation, trust store distribution and disaster recovery.
+
+If you're not planning to run your own PKI, use a different issuer type.
+
+The `SelfSigned` issuer doesn't represent a certificate authority as such, but
+instead denotes that certificates will "sign themselves" using a given private
+key. In other words, the private key of the certificate will be used to sign
+the certificate itself.
+
+This `Issuer` type is useful for bootstrapping a root certificate for a
+custom PKI (Public Key Infrastructure), or for otherwise creating simple
+ad-hoc certificates for a quick test.
+
+There are important [caveats](#caveats) - including security issues - to
+consider with `SelfSigned` issuers; in general you'd likely want to use a
+[`CA`](./ca.md) issuer rather than a `SelfSigned` issuer. That said,
+`SelfSigned` issuers are really useful for initially [bootstrapping](#bootstrapping-ca-issuers)
+a `CA` issuer.
+
+> Note: a `CertificateRequest` that references a self-signed certificate _must_
+> also contain the `cert-manager.io/private-key-secret-name` annotation since
+> the private key corresponding to the `CertificateRequest` is required to
+> sign the certificate. This annotation is added automatically by the
+> `Certificate` controller.
+
+## Deployment
+
+Since the `SelfSigned` issuer has no dependency on any other resource, it is
+the simplest to configure. Only the `SelfSigned` stanza is required to be
+present in the issuer spec, with no other configuration required:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: selfsigned-issuer
+ namespace: sandbox
+spec:
+ selfSigned: {}
+```
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: selfsigned-cluster-issuer
+spec:
+ selfSigned: {}
+```
+
+Once deployed, you should be able to see immediately that the issuer is ready
+for signing:
+
+```bash
+$ kubectl get issuers -n sandbox -o wide selfsigned-issuer
+NAME READY STATUS AGE
+selfsigned-issuer True 2m
+
+$ kubectl get clusterissuers -o wide selfsigned-cluster-issuer
+NAME READY STATUS AGE
+selfsigned-cluster-issuer True 3m
+```
+
+### Bootstrapping `CA` Issuers
+
+One of the ideal use cases for `SelfSigned` issuers is to bootstrap a custom
+root certificate for a private PKI, including with the cert-manager [`CA`](./ca.md)
+issuer.
+
+The YAML below will create a `SelfSigned` issuer, issue a root certificate and
+use that root as a `CA` issuer:
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: sandbox
+---
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: selfsigned-issuer
+spec:
+ selfSigned: {}
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: my-selfsigned-ca
+ namespace: sandbox
+spec:
+ isCA: true
+ commonName: my-selfsigned-ca
+ secretName: root-secret
+ privateKey:
+ algorithm: ECDSA
+ size: 256
+ issuerRef:
+ name: selfsigned-issuer
+ kind: ClusterIssuer
+ group: cert-manager.io
+---
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: my-ca-issuer
+ namespace: sandbox
+spec:
+ ca:
+ secretName: root-secret
+```
+
+### CRL Distribution Points
+
+You may also optionally specify [CRL](https://en.wikipedia.org/wiki/Certificate_revocation_list)
+Distribution Points as an array of strings, each of which identifies the location of a CRL in
+which the revocation status of issued certificates can be checked:
+
+```yaml
+...
+spec:
+ selfSigned:
+ crlDistributionPoints:
+ - "http://example.com"
+```
+
+## Caveats
+
+### Trust
+
+Clients consuming `SelfSigned` certificates have _no way_ to trust them
+without already having the certificates beforehand, which can be hard to
+manage when the client is in a different namespace to the server.
+
+This limitation can be tackled by using [trust-manager](../projects/trust-manager/README.md) to distribute `ca.crt`
+to other namespaces.
+
+There is no secure alternative to solving the problem of distributing trust stores; it's possible
+to "TOFU" (trust-on-first-use) a certificate, but that approach is vulnerable to man-in-the-middle attacks.
+
+### Certificate Validity
+
+One side-effect of a certificate being self-signed is that its Subject DN and
+its Issuer DN are identical. The X.509 [RFC 5280, section 4.1.2.4](https://tools.ietf.org/html/rfc5280#section-4.1.2.4)
+requires that:
+
+> The issuer field MUST contain a non-empty distinguished name (DN).
+
+However, self-signed certs don't have a subject DN set by default. Unless you
+manually set a certificate's Subject DN, the Issuer DN will be empty
+and the certificate will technically be invalid.
+
+Validation of this specific area of the spec is patchy and varies between TLS
+libraries, but there's always the risk that a library will improve its
+validation - entirely within spec - in the future and break your app if you're
+using a certificate with an empty Issuer DN.
+
+To avoid this, be sure to set a Subject for `SelfSigned` certs. This can be
+done by setting the `spec.subject` on a cert-manager `Certificate` object
+which will be issued by a `SelfSigned` issuer.
+
+Starting in version 1.3, cert-manager will emit a Kubernetes [warning event](https://github.com/cert-manager/cert-manager/blob/45befd86966c563663d18848943a1066d9681bf8/pkg/controller/certificaterequests/selfsigned/selfsigned.go#L140)
+of type `BadConfig` if it detects that a certificate is being created
+by a `SelfSigned` issuer which has an empty Issuer DN.
diff --git a/content/v1.12-docs/configuration/vault.md b/content/v1.12-docs/configuration/vault.md
new file mode 100644
index 00000000000..c2dd25aee54
--- /dev/null
+++ b/content/v1.12-docs/configuration/vault.md
@@ -0,0 +1,270 @@
+---
+title: Vault
+description: 'cert-manager configuration: Vault Issuers'
+---
+
+The `Vault` `Issuer` represents the certificate authority
+[Vault](https://www.vaultproject.io/) - a multi-purpose secret store that can be
+used to sign certificates for your Public Key Infrastructure (PKI). Vault is an
+external project to cert-manager and as such, this guide will assume it has been
+configured and deployed correctly, ready for signing. You can read more on how
+to configure Vault as a certificate authority
+[here](https://www.vaultproject.io/docs/secrets/pki/).
+
+This `Issuer` type is typically used when Vault is already being used within
+your infrastructure, or you would like to make use of its feature set where the
+CA issuer alone cannot provide.
+
+## Deployment
+
+All Vault issuers share common configuration for requesting certificates,
+namely the server, path, and CA bundle:
+
+- Server is the URL whereby Vault is reachable.
+- Path is the Vault path that will be used for signing. Note that the path
+ *must* use the `sign` endpoint.
+- CA bundle denotes an optional field containing a base64 encoded string of the
+ Certificate Authority to trust the Vault connection. This is typically
+ _always_ required when using an `https` URL.
+
+Below is an example of a configuration to connect a Vault server.
+
+> **Warning**: This configuration is incomplete as no authentication methods have
+> been added.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: vault-issuer
+ namespace: sandbox
+spec:
+ vault:
+ path: pki_int/sign/example-dot-com
+ server: https://vault.local
+ caBundle:
+ auth:
+ ...
+```
+
+## Authenticating
+
+In order to request signing of certificates by Vault, the issuer must be able to
+properly authenticate against it. cert-manager provides multiple approaches to
+authenticating to Vault which are detailed below.
+
+### Authenticating via an AppRole
+
+An [AppRole](https://www.vaultproject.io/docs/auth/approle.html) is a method of
+authenticating to Vault through use of its internal role policy system. This
+authentication method requires that the issuer has possession of the `SecretID`
+secret key, the `RoleID` of the role to assume, and the app role path. Firstly,
+the secret ID key must be stored within a Kubernetes `Secret` that resides in the
+same namespace as the `Issuer`, or otherwise inside the `Cluster Resource
+Namespace` in the case of a `ClusterIssuer`.
+
+```yaml
+apiVersion: v1
+kind: Secret
+type: Opaque
+metadata:
+ name: cert-manager-vault-approle
+ namespace: sandbox
+data:
+ secretId: "MDI..."
+```
+
+Once the `Secret` has been created, the `Issuer` is ready to be deployed which
+references this `Secret`, as well as the data key of the field that stores the
+secret ID.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: vault-issuer
+ namespace: sandbox
+spec:
+ vault:
+ path: pki_int/sign/example-dot-com
+ server: https://vault.local
+ caBundle:
+ auth:
+ appRole:
+ path: approle
+ roleId: "291b9d21-8ff5-..."
+ secretRef:
+ name: cert-manager-vault-approle
+ key: secretId
+```
+
+### Authenticating with a Token
+
+This method of authentication uses a token string that has been generated from
+one of the many authentication backends that Vault supports. These tokens have
+an expiry and so need to be periodically refreshed. You can read more on Vault
+tokens [here](https://www.vaultproject.io/docs/concepts/tokens.html).
+
+> **Note**: cert-manager does not refresh these token automatically and so another
+> process must be put in place to do this.
+
+Firstly, the token is be stored inside a Kubernetes `Secret` inside the same
+namespace as the `Issuer` or otherwise in the `Cluster Resource Namespace` in
+the case of using a `ClusterIssuer`.
+
+```yaml
+apiVersion: v1
+kind: Secret
+type: Opaque
+metadata:
+ name: cert-manager-vault-token
+ namespace: sandbox
+data:
+ token: "MjI..."
+```
+
+Once submitted, the Vault issuer is able to be created using token
+authentication by referencing this `Secret` along with the key of the field the
+token data is stored at.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: vault-issuer
+ namespace: sandbox
+spec:
+ vault:
+ path: pki_int/sign/example-dot-com
+ server: https://vault.local
+ caBundle:
+ auth:
+ tokenSecretRef:
+ name: cert-manager-vault-token
+ key: token
+```
+
+### Authenticating with Kubernetes Service Accounts
+
+Vault can be configured so that applications can authenticate using Kubernetes
+[`Service Account
+Tokens`](https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin).
+You find documentation on how to configure Vault to authenticate using Service
+Account Tokens [here](https://www.vaultproject.io/docs/auth/kubernetes.html).
+
+For the Vault issuer to use this authentication, cert-manager must get access to
+the token that is stored in a Kubernetes `Secret`. Kubernetes Service Account
+Tokens are already stored in `Secret` resources however, you must ensure that
+it is present in the same namespace as the `Issuer`, or otherwise in the
+`Cluster Resource Namespace` in the case of using a `ClusterIssuer`.
+
+> **Note**: In Kubernetes 1.24 onwards, the token secret is no longer created
+> by default for the Service Account. In this case you need to manually create
+> the secret resource. See [this guide](https://kubernetes.io/docs/concepts/configuration/secret/#service-account-token-secrets)
+> for more details.
+
+This authentication method also expects a `role` field which is the Vault role
+that the Service Account is to assume, as well as an optional `mountPath` field which
+is the authentication mount path, defaulting to `kubernetes`.
+
+#### Kubernetes version less than 1.24
+
+The following example will be making use of the Service Account
+`my-service-account`. The secret data field key will be `token` if the `Secret`
+has been created by Kubernetes. The Vault role used is `my-app-1`, using the
+default mount path of `/v1/auth/kubernetes`
+
+1) Create the Service Account:
+
+ ```shell
+ kubectl create serviceaccount -n sandbox vault-issuer
+ ```
+
+1) Get the auto-generated Secret name:
+
+ ```shell
+ kubectl get secret -o json | jq -r '.items[] | select(.metadata.annotations["kubernetes.io/service-account.name"] == "vault-issuer") | .metadata.name'
+ ```
+
+1) Create the Issuer using that Secret name retrieved from the previous step:
+
+ ```yaml
+ apiVersion: cert-manager.io/v1
+ kind: Issuer
+ metadata:
+ name: vault-issuer
+ namespace: sandbox
+ spec:
+ vault:
+ path: pki_int/sign/example-dot-com
+ server: https://vault.local
+ caBundle:
+ auth:
+ kubernetes:
+ role: my-app-1
+ mountPath: /v1/auth/kubernetes
+ secretRef:
+ name:
+ key: token
+ ```
+
+#### Kubernetes version 1.24 and greater
+
+This example is almost the same as above but adjusted for the change in
+Kubernetes 1.24 and above.
+
+1) Create the Service Account:
+
+ ```shell
+ kubectl create serviceaccount -n sandbox vault-issuer
+ ```
+
+1) Create the Secret resource for Kubernetes to populate the `token` value:
+
+ ```yaml
+ apiVersion: v1
+ kind: Secret
+ metadata:
+ name: vault-issuer-token
+ annotations:
+ kubernetes.io/service-account.name: "vault-issuer"
+ type: kubernetes.io/service-account-token
+ data: {}
+ ```
+
+1) Create the Issuer resource referencing the Secret resource:
+
+ ```yaml
+ apiVersion: cert-manager.io/v1
+ kind: Issuer
+ metadata:
+ name: vault-issuer
+ namespace: sandbox
+ spec:
+ vault:
+ path: pki_int/sign/example-dot-com
+ server: https://vault.local
+ caBundle:
+ auth:
+ kubernetes:
+ role: my-app-1
+ mountPath: /v1/auth/kubernetes
+ secretRef:
+ name: vault-issuer-token
+ key: token
+ ```
+
+## Verifying the issuer Deployment
+
+Once the Vault issuer has been deployed, it will be marked as ready if the
+configuration is valid. Replace `issuers` here with `clusterissuers` if that is what has
+been deployed.
+
+```bash
+$ kubectl get issuers vault-issuer -n sandbox -o wide
+NAME READY STATUS AGE
+vault-issuer True Vault verified 2m
+```
+
+Certificates are now ready to be requested by using the Vault issuer named
+`vault-issuer` within the `sandbox` namespace.
\ No newline at end of file
diff --git a/content/v1.12-docs/configuration/venafi.md b/content/v1.12-docs/configuration/venafi.md
new file mode 100644
index 00000000000..93498b0ace9
--- /dev/null
+++ b/content/v1.12-docs/configuration/venafi.md
@@ -0,0 +1,282 @@
+---
+title: Venafi
+description: 'cert-manager configuration: Venafi Issuers'
+---
+
+## Introduction
+
+The Venafi `Issuer` types allows you to obtain certificates from [Venafi
+as a Service (VaaS)](https://vaas.venafi.com/jetstack) and [Venafi Trust Protection
+Platform (TPP)](https://www.venafi.com/platform/tls-protect) instances.
+
+You can have multiple different Venafi `Issuer` types installed within the same
+cluster, including mixtures of Venafi as a Service and TPP issuer types. This allows
+you to be flexible with the types of Venafi account you use.
+
+Automated certificate renewal and management are provided for `Certificates`
+using the Venafi `Issuer`.
+
+A single Venafi `Issuer` represents a single Venafi 'zone' so you must create one
+`Issuer` resource for each zone you want to use. A zone is a single entity that
+combines the policy that governs certificate issuance with information about how
+certificates are organized in Venafi to identify the business application and
+establish ownership.
+
+You can configure your `Issuer` resource to either issue certificates only
+within a single namespace, or cluster-wide (using a `ClusterIssuer` resource).
+For more information on the distinction between `Issuer` and `ClusterIssuer`
+resources, read the [Namespaces](../concepts/issuer.md#namespaces) section.
+
+## Creating a Venafi as a Service Issuer
+
+If you haven't already done so, create your Venafi as a Service account on this
+[page](https://vaas.venafi.com/jetstack) and copy the API key from your user
+preferences. Then you may want to create a custom CA Account and Issuing Template
+or choose instead to use defaults that are automatically created for testing
+("Built-in CA" and "Default", respectively). Lastly you'll need to create an
+Application for establishing ownership of all the certificates requested by your
+cert-manager Issuer, and assign to it the Issuing Template.
+
+> Make a note of the Application name and API alias of the Issuing Template because
+> together they comprise the 'zone' you will need for your `Issuer` configuration.
+
+In order to set up a Venafi as a Service `Issuer`, you must first create a Kubernetes
+`Secret` resource containing your Venafi as a Service API credentials:
+
+```bash
+$ kubectl create secret generic \
+ vaas-secret \
+ --namespace='NAMESPACE OF YOUR ISSUER RESOURCE' \
+ --from-literal=apikey='YOUR_VAAS_API_KEY_HERE'
+```
+
+> **Note**: If you are configuring your issuer as a `ClusterIssuer` resource in
+> order to serve `Certificates` across your whole cluster, you must set the
+> `--namespace` parameter to `cert-manager`, which is the default `Cluster
+> Resource Namespace`. The `Cluster Resource Namespace` can be configured
+> through the `--cluster-resource-namespace` flag on the cert-manager controller
+> component.
+
+This API key will be used by cert-manager to interact with Venafi as a Service
+on your behalf.
+
+Once the API key `Secret` has been created, you can create your `Issuer` or
+`ClusterIssuer` resource. If you are creating a `ClusterIssuer` resource, you
+must change the `kind` field to `ClusterIssuer` and remove the
+`metadata.namespace` field.
+
+Save the below content after making your amendments to a file named
+`vaas-issuer.yaml`.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: vaas-issuer
+ namespace:
+spec:
+ venafi:
+ zone: "My Application\My CIT" # Set this to \
+ cloud:
+ apiTokenSecretRef:
+ name: vaas-secret
+ key: apikey
+```
+
+You can then create the Issuer using `kubectl create`.
+
+```bash
+$ kubectl create -f vaas-issuer.yaml
+```
+
+Verify the `Issuer` has been initialized correctly using `kubectl describe`.
+
+```bash
+$ kubectl get issuer vaas-issuer --namespace='NAMESPACE OF YOUR ISSUER RESOURCE' -o wide
+NAME READY STATUS AGE
+vaas-issuer True Venafi issuer started 2m
+```
+
+You are now ready to issue certificates using the newly provisioned Venafi
+`Issuer` and Venafi as a Service.
+
+Read the [Issuing Certificates](../usage/certificate.md) document for
+more information on how to create Certificate resources.
+
+
+## Creating a Venafi Trust Protection Platform Issuer
+
+The Venafi Trust Protection Platform integration allows you to obtain certificates
+from a properly configured Venafi TPP instance.
+
+The setup is similar to the Venafi as a Service configuration above, however some
+of the connection parameters are slightly different.
+
+> **Note**: You *must* allow "User Provided CSRs" as part of your TPP policy, as
+> this is the only type supported by cert-manager at this time.
+>
+> More specifically, the valid configurations of the "CSR handling" are:
+>
+> - "User Provided CSRs" selected and unlocked,
+> - "User Provided CSRs" selected and locked,
+> - "Service Generated CSRs" selected and unlocked.
+>
+> When using "Service Generated CSRs" selected and unlocked, the default CSR
+> configuration present in your policy folder will override the configuration of
+> your Certificate resource. The subject DN, key algorithm, and key size will be
+> overridden by the values set in the policy folder.
+>
+> With "Service Generated CSRs" selected and locked, the certificate issuance
+> will systematically fail with the following message:
+>
+> ```plain
+> 400 PKCS#10 data will not be processed. Policy "\VED\Policy\foo" is locked to a Server Generated CSR.
+> ```
+
+In order to set up a Venafi Trust Protection Platform `Issuer`, you must first
+create a Kubernetes `Secret` resource containing your Venafi TPP API
+credentials.
+
+### Access Token Authentication
+
+1. [Set up token authentication](https://docs.venafi.com/Docs/21.1/TopNav/Content/SDK/AuthSDK/t-SDKa-Setup-OAuth.php).
+
+ NOTE: Do not select "Refresh Token Enabled" and set a *long* "Token Validity (days)".
+
+2. Create a new user with sufficient privileges to manage and revoke certificates in a particular policy folder (zone).
+
+ E.g. `k8s-xyz-automation`
+
+3. [Create a new application integration](https://docs.venafi.com/Docs/21.1/TopNav/Content/API-ApplicationIntegration/t-APIAppIntegrations-creatingNew-Aperture.php)
+
+ Create an application integration with name and ID `cert-manager`.
+ Set the "API Access Settings" to `Certificates: Read,Manage,Revoke`.
+
+ "Edit Access" to the new application integration, and allow it to be used by the user you created earlier.
+
+4. [Generate an access token](https://github.com/Venafi/vcert/blob/master/README-CLI-PLATFORM.md#obtaining-an-authorization-token)
+
+ ```
+ vcert getcred \
+ --username k8s-xyz-automation \
+ --password somepassword \
+ -u https://tpp.example.com/vedsdk \
+ --client-id cert-manager \
+ --scope "certificate:manage,revoke"
+ ```
+
+ This will print an access-token to `stdout`. E.g.
+
+ ```
+ vCert: 2020/10/07 16:34:27 Getting credentials
+ access_token: I69n.............y1VjNJT3o9U0Wko19g==
+ access_token_expires: 2021-01-05T15:34:30Z
+ ```
+
+5. Save the access-token to a Secret in the Kubernetes cluster
+
+```bash
+$ kubectl create secret generic \
+ tpp-secret \
+ --namespace= \
+ --from-literal=access-token='YOUR_TPP_ACCESS_TOKEN'
+```
+
+### Username / Password Authentication
+
+> ⚠️ When you supply a Venafi TPP username and password,
+> cert-manager uses an older authentication method which is called "API Keys",
+> which has been deprecated since Venafi TPP `19.2`.
+>
+> Beginning in Venafi TPP `22.2`, "API Keys" are disabled by default.
+> You will need to contact Venafi customer support for a special license key which will allow you to re-enable the "API Keys" feature,
+> so that you can continue to use username and password authentication with cert-manager.
+>
+> In Venafi TPP `22.3`, the "API Keys" feature will be permanently removed,
+> and you will need to use access-token authentication instead.
+>
+> 📖 Read [Deprecated functionality from Venafi Platform](https://docs.venafi.com/22.3/deprecation-list-current)
+> and [Functionality Scheduled for Deprecation](https://support.venafi.com/hc/en-us/articles/115001662292) for more information.
+
+```bash
+$ kubectl create secret generic \
+ tpp-secret \
+ --namespace= \
+ --from-literal=username='YOUR_TPP_USERNAME_HERE' \
+ --from-literal=password='YOUR_TPP_PASSWORD_HERE'
+```
+
+> Note: If you are configuring your issuer as a `ClusterIssuer` resource in
+> order to issue `Certificates` across your whole cluster, you must set the
+> `--namespace` parameter to `cert-manager`, which is the default `Cluster
+> Resource Namespace`. The `Cluster Resource Namespace` can be configured
+> through the `--cluster-resource-namespace` flag on the cert-manager controller
+> component.
+
+These credentials will be used by cert-manager to interact with your Venafi TPP
+instance. Username attribute must be adhere to the `:` format. For example: `local:admin`.
+
+Once the Secret containing credentials has been created, you can create your
+`Issuer` or `ClusterIssuer` resource. If you are creating a `ClusterIssuer`
+resource, you must change the `kind` field to `ClusterIssuer` and remove the
+`metadata.namespace` field.
+
+Save the below content after making your amendments to a file named
+`tpp-issuer.yaml`.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: tpp-issuer
+ namespace:
+spec:
+ venafi:
+ zone: \VED\Policy\devops\cert-manager # Set this to the Venafi policy folder you want to use
+ tpp:
+ url: https://tpp.venafi.example/vedsdk # Change this to the URL of your TPP instance
+ caBundle:
+ credentialsRef:
+ name: tpp-secret
+```
+
+You can then create the `Issuer` using `kubectl create -f`.
+
+```bash
+$ kubectl create -f tpp-issuer.yaml
+```
+
+Verify the `Issuer` has been initialized correctly using `kubectl describe`.
+
+```bash
+$ kubectl describe issuer tpp-issuer --namespace='NAMESPACE OF YOUR ISSUER RESOURCE'
+```
+
+You are now ready to issue certificates using the newly provisioned Venafi
+`Issuer` and Trust Protection Platform.
+
+Read the [Issuing Certificates](../usage/certificate.md) document for
+more information on how to create Certificate resources.
+
+## Issuer specific annotations
+
+### Custom Fields
+
+Starting `v0.14` you can pass custom fields to Venafi (TPP version `v19.2` and higher) using the `venafi.cert-manager.io/custom-fields` annotation on Certificate resources.
+The value is a JSON encoded array of custom field objects having a `name` and `value` key.
+For example:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com-certificate
+ annotations:
+ venafi.cert-manager.io/custom-fields: |-
+ [
+ {"name": "field-name", "value": "field value"},
+ {"name": "field-name-2", "value": "field value 2"}
+ ]
+...
+```
diff --git a/content/v1.12-docs/contributing/README.md b/content/v1.12-docs/contributing/README.md
new file mode 100644
index 00000000000..aec6b212543
--- /dev/null
+++ b/content/v1.12-docs/contributing/README.md
@@ -0,0 +1,68 @@
+---
+title: Contributing
+description: 'cert-manager contributing guide: Get involved!'
+---
+
+## Great to See You!
+
+Whether you're a previous contributor or a first timer looking to get involved, we love
+it when the community comes together to improve the project!
+
+In this "contributing" section we document processes we follow as a project, and include
+some details on how to build, test and run cert-manager for development purposes.
+
+## Meetings
+
+All cert-manager meetings are open for everyone to join; if you have a question or a suggestion or just want to chat,
+please feel free to come along and get involved!
+
+To get invites you can subscribe to [our mailing list](https://groups.google.com/forum/#!forum/cert-manager-dev) and
+you should receive calendar invites by mail shortly after joining. The complexities of calendars mean that some invites
+might be sent multiple times depending on your email and calendar providers and you might get some invites for past
+or future meetings which have been rescheduled or edited. Sorry about that!
+
+We have 2 regular repeating meetings: our quick daily check-in and an hour-long community meeting every two weeks.
+
+If you're having any issues joining our meetings, ensure that you're part of the [`cert-manager-dev`](https://groups.google.com/forum/#!forum/cert-manager-dev) Google group, and always feel free to ask in [Slack](./#slack) for help!
+
+
+🔰 All of our meetings happen on London (UK) time; you can add London to the world clocks on your phone to avoid confusion!
+
+When daylight savings time changes in London might be different to when it changes for you if you live in a place that either
+doesn't have DST or which changes on a different schedule like North America or Australia!
+
+
+### Daily Check-In
+
+Our daily check-in meetings [happen on Google Meet](https://meet.google.com/eum-fyvt-xpa) at [10:30 London time](http://www.thetimezoneconverter.com/?t=10:30&tz=Europe/London) every weekday.
+
+The format is a 5 minute social chat, followed by a quick round-robin status report and ending with any longer form talking points.
+
+The status report is a stand-up where we talk about work done yesterday, work coming up and highlight any blockers.
+We'll try to keep to a **strict time limit** during these status reports of around 1 minute per person.
+
+Please don't be offended if someone steps in when you run out of time and moves the reports along to the next person - the idea
+is for everyone to be succinct so it's clear what's being worked on and who is blocked.
+
+We finish with talking points, which are open-ended discussions on any topic related to cert-manager or its sub-projects.
+We'll ensure that anyone outside of the core maintainer team who has a talking point goes first.
+
+### Community Meetings
+
+Our bi-weekly (i.e. every two weeks) community meetings happen [on Google Meet](https://meet.google.com/iga-jwvx-nye) at [17:00 London time](http://www.thetimezoneconverter.com/?t=17:00&tz=Europe/London) (for dates, check calendar invites or [meeting notes](https://docs.google.com/document/d/1Tc5t6ylY9dhXAan1OjOoldeaoys1Yh4Ir710ATfBa5U)).
+
+These meetings are an hour-long chat about cert-manager topics. It's a great way to get involved with contributing for the
+first time; to get answers to any questions you might have; or to propose a new feature which needs some explanation.
+
+If you want to discuss something, please add it to the [meeting notes](https://docs.google.com/document/d/1Tc5t6ylY9dhXAan1OjOoldeaoys1Yh4Ir710ATfBa5U)
+before the meeting. The meeting chair will try to get to everything that was on the notes before the meeting started.
+
+We try to record these meetings and put them on YouTube so they can be checked later - if you don't want to appear on video please keep
+your camera off!
+
+## Slack
+
+We have two cert-manager channels on [Kubernetes Slack](https://slack.k8s.io) which we use to chat:
+
+* [`cert-manager`](https://kubernetes.slack.com/messages/cert-manager): for all users of cert-manager; use this one for any usage related questions
+* [`cert-manager-dev`](https://kubernetes.slack.com/messages/cert-manager-dev): for collaboration between cert-manager contributors and maintainers; please only use this for code related questions
diff --git a/content/v1.12-docs/contributing/building.md b/content/v1.12-docs/contributing/building.md
new file mode 100644
index 00000000000..92fd7a996f9
--- /dev/null
+++ b/content/v1.12-docs/contributing/building.md
@@ -0,0 +1,267 @@
+---
+title: Building cert-manager
+description: 'cert-manager contributing guide: Building cert-manager'
+---
+
+cert-manager is built and tested using [make](https://www.gnu.org/software/make/manual/make.html), with a focus on using the standard Go tooling
+where possible and keeping system dependencies to a minimum. The cert-manager build system can provision most of its dependencies - including Go -
+automatically if required.
+
+cert-manager's build system fully supports developers who use `Linux amd64`, `macOS amd64` and `macOS arm64`.
+
+It also has limited support for `Linux arm64`, although that platform is largely untested and isn't fully supported.
+
+Other operating systems and architectures may work but will likely require hacks and workarounds to develop on.
+
+## Prerequisites
+
+There are very few other requirements needed for developing cert-manager, and crucially the build system should tell you with a friendly error
+message if there's anything missing. If you think an error message which relates to a missing dependency is unhelpful, we consider that a bug and
+we'd appreciate if you raised [an issue](https://github.com/cert-manager/cert-manager/issues/new?assignees=&labels=&template=bug.md) to tell us about it!
+
+You should install the following tools before you start developing cert-manager:
+
+- [git](https://git-scm.com/)
+- [curl](https://curl.se/)
+- [GNU make](https://www.gnu.org/software/make/manual/make.html), `v3.82` or newer
+- GNU Coreutils (usually already installed on Linux, available via [homebrew](https://formulae.brew.sh/formula/coreutils) for macOS)
+- `jq` (available in Linux package managers and in [homebrew](https://formulae.brew.sh/formula/jq))
+- `docker` (or `podman`, see [Container Engines](#container-engines) below)
+- `Go` (optional; see [Go Versions](#go-versions) below)
+
+## Getting Started
+
+The vast majority of commands which you're likely to need to use are documented via `make help`. That's probably the first place to start if you're
+developing cert-manager. We'll also provide an overview on this page of some of the key targets and things to bear in mind.
+
+### Go Versions
+
+cert-manager defaults to using whatever version of Go you've installed locally on your system. If you want to use your system Go, that's totally fine.
+
+Alternatively, make can provision and "vendor" Go specifically for cert-manager, helping to ensure you use the same version that's used in CI and to
+make it easier to get started developing.
+
+To start using a vendored Go, run: `make vendor-go`.
+
+You only need to run `vendor-go` once and it'll be "sticky", being used for all future make invocations in your local checkout.
+
+To return to using your system version of go, run: `make unvendor-go`.
+
+To check which version of Go is _currently_ being used, run: `make which-go`, which prints the version number of Go and the path to the Go binary.
+
+```console
+# Use a vendored version of go
+$ make vendor-go
+cd _bin/tools/ && ln -f -s ../downloaded/tools/_go-1.XY.Z-linux-amd64/goroot .
+cd _bin/tools/ && ln -f -s ../downloaded/tools/_go-1.XY.Z-linux-amd64/goroot/bin/go .
+
+# A path to go inside the cert-manager directory indicates that a vendored Go is being used
+$ make which-go
+go version go1.XY.Z linux/amd64
+go binary used for above version information: /home/user/workspace/cert-manager/_bin/tools/go
+
+# Go back to the system Go
+$ make unvendor-go
+rm -rf _bin/tools/go _bin/tools/goroot
+
+# The binary is now "go" which should be found in $PATH
+$ make which-go
+go version go1.AB.C linux/amd64
+go binary used for above version information: go
+```
+
+### Go Workspaces
+
+In short: Some development tools will complain about cert-manager's module layout; to help with this, generate a
+`go.work` file using `make go-workspace`.
+
+The cert-manager repository as of cert-manager 1.12 contains multiple Go modules, in a setup where only the core module `github.com/cert-manager/cert-manager`
+is expected to be imported by third party modules. There are separate modules (which we call submodules), all of which have replace statements for the core
+cert-manager module.
+
+This setup is intentional to convey that these submodules are not intended to be imported by third parties, and to ensure that each submodule always uses
+whatever the cert-manager core module version is at the same commit - but this structure can have the side effect that certain development tools and scripts
+will not work as expected.
+
+As an example, `go test ./...` will by default only affect the core module. To test, say, the controller, you'd need to use `cd cmd/controller && go test ./...`.
+
+This can be avoided through the use of go workspaces, which will handle local replacements for you and work better with editors such as VS Code.
+
+You can run `make go-workspace` to generate a `go.work` file which should enable `go test ./...` to work across the
+whole repo, and which should help editors to understand the module structure.
+
+Note that go workspaces are not used when testing pull requests in CI. If you see errors in CI which you can't replicate
+locally, try building with the `GOWORK` environment variable set to `off` or deleting the `go.work` file.
+
+### Parallelism
+
+The cert-manager Makefile is designed to be highly parallel wherever possible. Any build and test commands should be able to be executed in parallel using
+standard Make functionality.
+
+One important caveat is that that Go will default to detecting the number of cores available on the system and spinning up as many threads as it can. If you're
+using Make functionality to run multiple builds in parallel, this number of threads can be excessive and actually lead to slower builds.
+
+It's possible to limit the number of threads Go uses we'd generally recommend doing so when using Make parallelism.
+
+The best values to use will depend on your system, but we've had success using around half of the available number of cores for Make and limiting Go to between
+2 and 4 threads per core.
+
+For example, using an 8-core machine:
+
+```bash
+# Run 4 make targets in parallel, and limit each `go build` to 2 threads.
+make GOMAXPROCS=2 -j4 release-artifacts
+```
+
+## Testing
+
+cert-manager's build pipeline and CI infrastructure uses the same Makefile that you use when developing locally,
+so there should be no divergence between what the tests run and what you run. That means you should be able to be pretty confident that any changes you make
+won't break when tested in CI.
+
+### Running Local Changes in a Cluster
+
+It's common that you might want to run a local Kubernetes cluster with your locally-changed copy of cert-manager in it, for manual testing.
+
+There are make targets to help with this; see [Developing with Kind](./kind.md) for more information.
+
+### Unit and Integration Tests
+
+First of all: If you want to test using `go test`, feel free! For unit tests (which we define as any test outside of the `test/` directory), `go test` will
+work on a fresh checkout.
+
+Note that the cert-manager repo is split into multiple modules and unless you're using go workspaces `go test ./...` won't actually run all tests. See [Go Workspaces](./building.md#go-workspaces) above for more details.
+
+Integration tests may require some external tools to be set up first, so to run the integration tests inside `test/` you might need to run:
+
+```bash
+make setup-integration-tests
+```
+
+Helper targets are also available which use [`gotestsum`](https://github.com/gotestyourself/gotestsum) for prettier output. It's also possible to
+configure these targets to run specific tests:
+
+```bash
+# Run all unit and integration tests
+make test
+
+# Run only unit tests
+make unit-test
+
+# Run only integration tests
+make integration-test
+
+# Run all tests in pkg
+make WHAT=./pkg/... test
+
+# Run unit and integration tests exactly as run in CI
+# (NB: usually not needed - this is mostly for JUnit test output for dashboards)
+make test-ci
+```
+
+### End-to-End Testing
+
+cert-manager's end-to-end tests are a little more involved and have [dedicated documentation](./e2e.md) describing their use.
+
+### Other Checks
+
+We run a variety of other tools on every Pull Request to check things like formatting, import ordering and licensing. These checks can all be run locally:
+
+```bash
+make ci-presubmit
+```
+
+NB: One of these checks currently requires Python 3 to be installed, which is a unique requirement in the code base. We'd like to remove that requirement in the future.
+
+## Updating CRDs and Code Generation
+
+Changes to cert-manager's CRDs require some code generation to be done, which will be checked on every pull request.
+
+If you make changes to cert-manager CRDs, you'll need to run some commands locally before raising your PR.
+
+This is documented in our [CRDs](./crds.md) section.
+
+## Building
+
+cert-manager produces many artifacts for a lot of different OS / architecture combinations, including:
+
+- Container images
+- Client binaries (`cmctl` and `kubectl_cert-manager`)
+- Manifests (Helm charts, static YAML)
+
+All of these artifacts can be built locally using make.
+
+### Containers
+
+cert-manager's most important artifacts are the containers which actually run cert-manager in a cluster. We default to using `docker` for this,
+but aim to support docker-compatible CLI tools such as `podman`, too. See [Container Engines](#container-engines) for more info.
+
+There are several targets for building different cert-manager containers locally. These will all default to using `docker`:
+
+```bash
+# Build everything for every architecture
+make all-containers
+
+# Build just the controller containers on every architecture
+make cert-manager-controller-linux
+
+# As above, but for the webhook, cainjector, acmesolver and cmctl containers
+make cert-manager-webhook-linux
+make cert-manager-cainjector-linux
+make cert-manager-acmesolver-linux
+make cert-manager-ctl-linux
+```
+
+#### Container Engines
+
+NB: This section doesn't apply to end-to-end tests, which might not work outside of Docker at the time of writing. See the [end-to-end documentation](./e2e.md#container-engines)
+for more information.
+
+It's possible to use an alternative container engine to build cert-manager containers. This has been successfully tested using `podman`.
+
+Configure an alternative container engine by setting the `CTR` variable:
+
+```bash
+# Build everything for every architecture, using podman
+make CTR=podman all-containers
+```
+
+### Client Binaries
+
+Both `cmctl` and `kubectl_cert-manager` can be built locally for a release. These binaries are built for Linux, macOS and Windows across several architectures.
+
+```bash
+# Build all cmctl binaries for all platforms, then for linux only, then for macOS only, then for Windows only
+make cmctl
+make cmctl-linux
+make cmctl-darwin
+make cmctl-windows
+
+# As above but for kubectl_cert-manager
+make kubectl_cert-manager
+make kubectl_cert-manager-linux
+make kubectl_cert-manager-darwin
+make kubectl_cert-manager-windows
+```
+
+### Manifests
+
+We use "manifests" as a catch-all term for non-binary artifacts which we build as part of a release including static installation YAML and our Helm chart.
+
+Everything can be built using make:
+
+```bash
+make helm-chart
+make static-manifests
+```
+
+### Everything
+
+Sometimes it's useful to build absolutely everything locally, to be sure that a change didn't break some obscure architecture and to build confidence when raising a PR.
+
+It's not easy to build a _complete_ release locally since a full release includes signatures which depend on KMS keys being configured. Most users probably don't
+need that, though, and for this use case there's a make target which will build everything except the signed artifacts:
+
+```bash
+make GOMAXPROCS=2 -j4 release-artifacts
+```
diff --git a/content/v1.12-docs/contributing/coding-conventions.md b/content/v1.12-docs/contributing/coding-conventions.md
new file mode 100644
index 00000000000..8001cc387d1
--- /dev/null
+++ b/content/v1.12-docs/contributing/coding-conventions.md
@@ -0,0 +1,59 @@
+---
+title: Coding Conventions
+description: 'cert-manager contributing guide: Coding conventions'
+---
+
+cert-manager, like most Go projects, delegates almost all stylistic choices to `gofmt`,
+with `goimports` on top for organizing imports. Broadly speaking, if you set your editor to run
+`goimports` when you save a file, your code will be stylistically correct.
+
+cert-manager generally also follows the Kubernetes
+[coding conventions](https://www.kubernetes.dev/docs/guide/coding-convention/) and the Google
+[Go code review comments](https://github.com/golang/go/wiki/CodeReviewComments).
+
+## Organizing Imports
+
+Imports should be organized into 3 blocks, with each block separated by two newlines:
+
+```go
+import (
+ "stdlib"
+
+ "external"
+
+ "internal"
+)
+```
+
+An example might be the following, taken from
+[`pkg/acme/accounts/client.go`](https://github.com/cert-manager/cert-manager/blob/0c71fe7795858b96cabcddabf706d997cd2fba3f/pkg/acme/accounts/client.go):
+
+```go
+import (
+ "crypto/rsa"
+ "crypto/tls"
+ "net"
+ "net/http"
+ "time"
+
+ acmeapi "golang.org/x/crypto/acme"
+
+ acmecl "github.com/cert-manager/cert-manager/pkg/acme/client"
+ acmeutil "github.com/cert-manager/cert-manager/pkg/acme/util"
+ cmacme "github.com/cert-manager/cert-manager/pkg/apis/acme/v1"
+ "github.com/cert-manager/cert-manager/pkg/metrics"
+ "github.com/cert-manager/cert-manager/pkg/util"
+)
+```
+
+Once this manual split of standard library, external and internal imports has been made, it will be
+enforced automatically by `goimports` when executed in the future.
+
+## UK vs. US spelling
+
+For the sake of consistency, cert-manager uses en-US spelling for the
+documentation in https://cert-manager.io as well as within the cert-manager
+codebase. A comprehensive list of en-GB → en-US word substitution is available
+on Ubuntu's
+[`WordSubstitution`](https://wiki.ubuntu.com/EnglishTranslation/WordSubstitution)
+page.
\ No newline at end of file
diff --git a/content/v1.12-docs/contributing/contributing-flow.md b/content/v1.12-docs/contributing/contributing-flow.md
new file mode 100644
index 00000000000..4706a0d1699
--- /dev/null
+++ b/content/v1.12-docs/contributing/contributing-flow.md
@@ -0,0 +1,138 @@
+---
+title: Contributing Flow
+description: 'cert-manager contributing guide: Contribution flow'
+---
+
+All of cert-manager's development is done via
+[GitHub](https://github.com/cert-manager/cert-manager) which contains code, issues and pull
+requests.
+
+All code for the documentation and cert-manager.io can be found at [the cert-manager/website repo](https://github.com/cert-manager/website/).
+Any issues towards the documentation should also be filed there.
+
+## GitHub bot
+
+We use [Prow](https://github.com/k8s-ci-robot/test-infra/tree/master/prow) on all our repositories.
+If you've ever looked at a Kubernetes repo, you will probably already have met Prow. Prow will be able to help you in GitHub using its commands.
+You can find then all [on the command help page](https://prow.build-infra.jetstack.net/command-help).
+Prow will also run all tests and assign certain labels on PRs.
+
+## Bugs
+
+All bugs should be tracked as issues inside the
+[GitHub](https://github.com/cert-manager/cert-manager/issues) repository. Issues should then be
+attached with the `kind/bug` tag. To do this add `/kind bug` to your issue description.
+This may then be assigned a priority and milestone to be addressed in a future release.
+
+The more logs and information you can give about what and how the bug has been
+discovered, the faster it can be resolved.
+
+Critical bug fixes are typically also cherry picked to the current minor stable releases.
+
+> Note: If you are simply looking for _troubleshooting_ then you should post
+> your question to the community `cert-manager` [slack channel](https://slack.k8s.io).
+> Many more people read this channel than GitHub issues, it's likely your problem will
+> be solved quicker by using Slack.
+> Please also check that the bug has not already been filed by searching for key
+> terms in the issue search bar.
+
+### (Re)opening and closing issues
+
+Prow can assist you to reopen or close issues you file, you can trigger it using `/reopen` or `/close` in a GitHub Issue comment.
+
+## Features
+
+Feature requests should be created as
+[GitHub](https://github.com/cert-manager/cert-manager/issues) issues. They should contain
+clear motivation for the feature you wish to see as well as some possible
+solutions for how it can be implemented.
+Issues should then be tagged with `kind/feature`. To do this add `/kind feature` to your issue description.
+
+> Note: It is often a good idea to bring your feature request up on the
+> community `cert-manager` [slack channel](https://slack.k8s.io) to discuss whether
+> the feature request has already been made or is aligned with the project's
+> priorities.
+
+## Creating Pull Requests
+
+Changes to the cert-manager code base is done via [pull
+requests](https://github.com/cert-manager/cert-manager/pulls). Each pull request
+should ideally have a corresponding issue attached that is to be fixed by this
+pull request. It is valid for multiple pull requests to resolve a single issue
+in the interest of keeping code changes self contained and simpler to review.
+
+Once created, a team member will assign themselves for review and enable
+testing. To make sure the changes get merged, keep an eye out for reviews which
+can have multiple cycles.
+
+If the pull request is a critical bug fix then this will probably
+also be cherry picked to the current stable version of cert-manager as a patch
+release.
+
+To let people know that your PR is still a work in progress, we usually add a
+`WIP:` prefix to the title of the PR. Prow will then automatically set the label
+`do-not-merge/work-in-progress`.
+
+
+### Cherry Picking
+
+If the pull request contains a critical bug fix then this should be cherry picked in to the current stable cert-manager branch
+and [released as a patch release](../installation/supported-releases.md#support-policy).
+
+To trigger the cherry-pick process, add a comment to the GitHub PR.
+For example:
+```
+/cherry-pick release-x.y
+```
+
+The `jetstack-bot` will then create a new branch and a PR against the release branch,
+which should be reviewed, approved and merged using the process described above.
+
+### DCO signoff
+
+All commits in the PR should be signed off, more info on how to do this is at the [DCO Sign Off](./sign-off.md) page.
+Exceptions can only be made for small documentation fixes.
+
+## Project Management
+
+Most of cert-manager's project management is done on GitHub, with the help of Prow.
+
+### When will something be released?
+
+Our team works using [GitHub milestones](https://github.com/cert-manager/cert-manager/milestones).
+When a milestone is set on an Issue it is generally an indication of when we plan to address this.
+Prow will apply milestones on merged PRs, this will tell you in which version that PR will land.
+
+The milestone page will also have an indicated due date when we will release. This might have some delay.
+We brief our users/contributors about this in our bi-weekly community meeting, for an up to date status report we recommend joining these.
+
+### Labels
+
+We make a heavy use of GitHub labels for PRs and Issues. The ones on PRs are mostly managed by Prow and code reviewers.
+In issues we always aim to add 3 types: area, priority and kind. These are set using Prow using `/area`, `/kind` and `/priority`.
+Sometimes `/triage` is also added which helps us when following up Issues.
+
+* Area indicates the code area which is/will need changing
+* Kind indicates if it is a `bug` or a `feature` but also can be `documentation` or `cleanup` (general maintenance)
+* Priority is the priority it has for the cert-manager team, PRs are still very welcome for those!
+
+### Assignees meaning in PRs and issues
+
+Sometimes, you might see someone commenting with the
+[`/assign` prow command](https://prow.build-infra.jetstack.net/command-help#assign):
+
+```plain
+/assign @meyskens
+```
+
+Here is the meaning that we give to the GitHub assignees:
+
+- On issues, it means that the assignee is working on it.
+- On PRs, we use it as a way to know who should be taking a look at the PR at any time:
+ - When the author is assigned, it means the PR needs work to be done aka "changes requested";
+ - When nobody is assigned, it means this PR needs review;
+ - When someone different from the author is assigned, it means this person is reviewing this PR.
+
+### Triage Party!
+
+Every few weeks we will plan a Triage Party meeting, where we use the (Triage Party)[https://triage.build-infra.jetstack.net/] tool to go recent/old issues to prioritise them so we can address them in a timely matter. These meetings are open to everyone and invites will be sent out using our mailing list (warning: despite the word party these meetings are sometimes boring).
\ No newline at end of file
diff --git a/content/v1.12-docs/contributing/crds.md b/content/v1.12-docs/contributing/crds.md
new file mode 100644
index 00000000000..1cce203032c
--- /dev/null
+++ b/content/v1.12-docs/contributing/crds.md
@@ -0,0 +1,65 @@
+---
+title: CRDs
+description: 'cert-manager contribution guide: CRDs'
+---
+
+cert-manager uses [Kubernetes Custom Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) to define
+the resources which users interact with when using cert-manager, such as `Certificate`s and `Issuer`s.
+
+When changes are made to the CRDs in code, there are a couple of extra steps which are required.
+
+## Generating CRD Updates
+
+We use [`controller-gen`](https://book.kubebuilder.io/reference/controller-gen.html) to update our CRDs, and [`k8s-code-generator`](https://github.com/kubernetes/code-generator)
+for code generation.
+
+Verifying and updating CRDs and generated code can be done entirely through make. There are two steps; one will update CRDs and one will update generated code:
+
+```bash
+# Check that CRDs and codegen are up to date
+make verify-crds verify-codegen
+
+# Update CRDs based on code
+make update-crds
+
+# Update generated code based on CRD defintions in code
+make update-codegen
+```
+
+## Versions
+
+cert-manager currently has a single `v1` API version for public use.
+
+cert-manager API types are defined in [`pkg/apis/certmanager`](https://github.com/cert-manager/cert-manager/tree/master/pkg/apis/certmanager).
+
+ACME related resources are in [`pkg/apis/acme`](https://github.com/cert-manager/cert-manager/tree/master/pkg/apis/acme).
+
+### Code Comments
+
+Code comments on API type fields are converted into documentation on this website as well as appearing in the output of `kubectl explain`.
+
+That means that `go doc`-style comments on API fields should be written to be user-facing and not developer-facing. For this reason it's also fine to break from
+usual Go standards regarding code comments when editing these fields.
+
+### Internal API Versions
+
+cert-manager also has an internal API version which lives under [`internal/apis`](https://github.com/cert-manager/cert-manager/tree/master/internal/apis).
+
+The internal version is only used for validation and conversion and controllers should not generally use it; it's not intended to be user-friendly or stable and can change.
+However all new fields also have to be added here for the conversion logic to work.
+
+For details on conversion and versions, see the [official Kubernetes docs for CRD versioning](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/).
+
+## Kubebuilder
+
+While cert-manager doesn't fully use Kubebuilder, CRDs can make use of special Kubebuilder flags such as [validation flags](https://book.kubebuilder.io/reference/markers/crd-validation.html).
+
+## Making Changes to APIs
+
+Please see our [API compatibility promise](../installation/api-compatibility.md) for details on which types of changes to APIs are acceptable.
+
+Generally, the gist is that new fields can be added but that existing fields cannot be removed.
+
+This also means that when a field is added to a version of the API, it's permanent and its name cannot be changed. Because of this, we try to be cautious when adding new fields.
+
+The same principles apply to [constants and enumerated types](https://kubernetes.io/docs/reference/using-api/deprecation-policy/#enumerated-or-constant-values).
diff --git a/content/v1.12-docs/contributing/dns-providers.md b/content/v1.12-docs/contributing/dns-providers.md
new file mode 100644
index 00000000000..400f3d17ee8
--- /dev/null
+++ b/content/v1.12-docs/contributing/dns-providers.md
@@ -0,0 +1,23 @@
+---
+title: DNS Providers
+description: 'cert-manager contributing guide: Creating DNS providers'
+---
+
+## Creating DNS Providers
+
+Due to the large number of requests to support DNS providers to resolve DNS
+challenges, it became impractical and infeasible to maintain and test all DNS
+providers in the main cert-manager repository.
+
+For this reason, it was decided that new DNS providers should be supported out-of-tree
+by way of external webhooks.
+
+To implement an external DNS provider webhook, it is recommended to base your
+implementation on the [cert-manager webhook-example](https://github.com/cert-manager/webhook-example).
+
+There's further information available in the configuration section:
+
+- [ACME DNS01 via webhook](../configuration/acme/dns01/README.md#webhook)
+- [Configuring an ACME issuer with external webhook](../configuration/acme/dns01/webhook.md)
+
+If you're struggling with creating a new DNS webhook, reach out on [Slack](./README.md#slack)!
diff --git a/content/v1.12-docs/contributing/e2e.md b/content/v1.12-docs/contributing/e2e.md
new file mode 100644
index 00000000000..5037b28fa48
--- /dev/null
+++ b/content/v1.12-docs/contributing/e2e.md
@@ -0,0 +1,148 @@
+---
+title: Running End-to-End Tests
+description: 'cert-manager contribuing guide: End-to-end (E2E) tests'
+---
+
+cert-manager has an extensive end-to-end (e2e) test suite that verifies functionality against a
+real Kubernetes cluster.
+
+The full end-to-end test suite can take a long time to complete and is run against every pull
+request made to the cert-manager project.
+
+Unless you've made huge changes to the cert-manager codebase --- or to the end-to-end
+tests themselves --- you probably don't _need_ to run the tests locally. If you do want to
+run the tests, though, this document explains how.
+
+
+The status of each commit on the master branch is reported on
+[`testgrid.k8s.io`](https://testgrid.k8s.io/jetstack-cert-manager-master). Join the
+[`cert-manager-dev-alerts`](https://groups.google.com/g/cert-manager-dev-alerts)
+Google group to receive email notifications when tests fail.
+
+
+## Requirements
+
+There are no special requirements for the end-to-end tests. All dependencies can be
+provisioned automatically through the make build system.
+
+## Set up End-to-End Tests
+
+### Create a Cluster
+
+You can create a kind cluster using Make:
+
+```console
+# Create a cluster using whatever K8s version is default, named "kind"
+make e2e-setup-kind
+
+# Create a cluster using K8s 1.23 named "keith"
+make K8S_VERSION=1.23 KIND_CLUSTER_NAME=keith e2e-setup-kind
+```
+
+**IMPORTANT:** the kind cluster will be set up using a specific service CIDR range to enable certain functionality in end-to-end tests. This CIDR range is not currently configurable.
+
+Once complete, the cluster is available via `kubectl` as you'd expect.
+
+### Install Test Dependencies
+
+There are various dependencies which the end-to-end tests require, all of which can also
+be installed via Make:
+
+```console
+make e2e-setup
+```
+
+If you only need to update or reinstall one of these dependencies in your test cluster, you can instead install named components explicitly to save some time.
+
+The most common use case for this is to **reinstall cert-manager itself**, say if you've made a change
+locally and want to test that change in a cluster:
+
+```console
+# Most important: reinstall cert-manager, including rebuilding changed containers locally
+make e2e-setup-certmanager
+
+# An example of reinstalling something else; reinstall bind
+make e2e-setup-bind
+
+# More generally, see make/e2e-setup.mk for different targets!
+```
+
+## Run End-to-End Tests
+
+As with setup, running tests is available through make. In fact, you can just run `make e2e` directly
+and avoid having to set anything up manually!
+
+```console
+# Set up a cluster using the defaults if one's not already present, and then run the end-to-end tests
+make e2e
+
+# Set up a K8s 1.23 cluster and then run tests
+make K8S_VERSION=1.23 e2e
+
+# Run tests exactly as they're run in CI; usually not needed
+make e2e-ci
+```
+
+If you don't want to run every test you can focus on specific tests using `GINKGO_FOCUS` syntax, as described in the
+[Ginkgo documentation](https://onsi.github.io/ginkgo/#focused-specs):
+
+```console
+make GINKGO_FOCUS=".*my test description" e2e
+```
+
+## Cluster IP Details
+
+As mentioned above, the end-to-end tests expect that certain components are deployed in a
+specific way and even at specific IP addresses.
+
+By way of illustration, the following cluster components are deployed with specific IPs:
+
+| Component / Make Target | Used in | IP | DNS A Record |
+| -------------------------- | -------------------------- | ----------- | --------------------------------------- |
+| `e2e-setup-bind` | DNS-01 tests | `10.0.0.16` | |
+| `e2e-setup-ingressnginx` | HTTP-01 `Ingress` tests | `10.0.0.15` | `*.ingress-nginx.db.http01.example.com` |
+| `e2e-setup-projectcontour` | HTTP-01 `GatewayAPI` tests | `10.0.0.14` | `*.gateway.db.http01.example.com` |
+
+If you don't set these components up correctly, you might see that the ACME HTTP01 (and other) end-to-end tests fail.
+
+## End-to-End Test Structure
+
+The end-to-end tests consist of 2 main parts: issuer specific tests and the conformance suite.
+
+Both parts use [Ginkgo](https://onsi.github.io/ginkgo/#getting-ginkgo) to run their tests under the hood.
+
+### Conformance Suite
+
+#### RBAC
+
+This suite tests all RBAC permissions granted to cert-manager on the cluster to check that it is able to operate correctly.
+
+#### Certificates
+
+This suite tests certificate functionality against all issuers.
+
+#### Feature Sets
+
+Some issuers don't support certain features, such as for example issuing Ed25519 certificates or adding an email address
+to the X.509 SAN extension.
+
+Each test specifies a used feature using `s.checkFeatures(feature)`, which is then checked against the issuer's
+`UnsupportedFeatures` list. Tests which use a feature unsupported by an issuer are skipped for that issuer.
+
+### Cloud Provider Tests
+
+The master branch of cert-manager can also be tested against different cloud providers. Currently, tests for [EKS](https://aws.amazon.com/eks/) are present which run as a periodic job once every two days.
+
+#### Extending The Cloud Provider Tests
+
+The infrastructure used to run the e2e tests on cloud providers is present in the [cert-manager/test-infra](https://github.com/cert-manager/test-infra) repository. More cloud providers can be added by creating infrastructure for them using [Terraform](https://www.terraform.io/).
+
+Apart from that, tests for the existing infrastructure can be customized by editing their respective prow jobs present in the [Jetstack testing repository](https://github.com/jetstack/testing/tree/master/config/jobs/cert-manager) repository. Values like the cert-manager version or the cloud provider version are present as variables in Terraform so their values can be changed when using `terraform apply` in the prow jobs, for example, for the [EKS prow job](https://github.com/jetstack/testing/blob/master/config/jobs/cert-manager/cert-manager-periodics.yaml#L524) the cert-manager version being tested can be changed using
+
+```console
+terraform apply -var="cert_manager_version=v1.3.3" -auto-approve
+```
+
+To see a list of all configurable variables present for a particular infrastructure you can see the `variables.tf` file for that cloud provider's [infrastructure](https://github.com/cert-manager/test-infra).
+
+> Please note that the cloud provider tests run the e2e tests present in the **master** branch of cert-manager on a predefined version of cert-manager (can be changed in the prow job). Currently, they do **not** test code in a PR, but we have an [issue](https://github.com/cert-manager/cert-manager/issues/4349) tracking that request.
diff --git a/content/v1.12-docs/contributing/external-issuers.md b/content/v1.12-docs/contributing/external-issuers.md
new file mode 100644
index 00000000000..4d18572fb31
--- /dev/null
+++ b/content/v1.12-docs/contributing/external-issuers.md
@@ -0,0 +1,77 @@
+---
+title: Implementing External Issuers
+description: 'cert-manager contributing guide: External Issuers'
+---
+
+cert-manager offers a number of [core issuer types](../configuration/README.md) that represent
+various certificate authorities.
+
+Since the number of potential issuers is larger than what could reasonably be supported in the
+main cert-manager repository, cert-manager also supports out-of-tree external issuers, and treats
+them the same as in-tree issuer types.
+
+This document is for people looking to _create_ external issuers. For more information on how to
+install and configure external issuer types, read the [configuration documentation](../configuration/external.md).
+
+## General Overview
+
+An issuer represents a certificate authority that signs incoming certificate
+requests. In cert-manager, the `CertificateRequest` resource represents a single
+request for a signed certificate, containing the raw certificate request PEM
+data as well as other information relating to the desired certificate.
+
+In cert-manager, each issuer type has its own controller that watches these
+`CertificateRequest` resources and checks to see if a given `CertificateRequest` is
+configured to use the issuer.
+
+This is done via the `issuerRef` stanza on the `CertificateRequest` which contains
+an issuer `name`, `kind` and `group`.
+
+`group` denotes an API group such as `cert-manager.io` (which is responsible for all core issuer types).
+
+`kind` denotes the "kind" resource type of the issuer - usually `Issuer` or `ClusterIssuer`.
+
+`name` denotes the name of the issuer resource of the specified kind. An example might be `my-ca-issuer`.
+
+When an issuer controller observes a new `CertificateRequest` which refers to it,
+it then ensures that the corresponding issuer resource exists in Kubernetes.
+
+It then uses the information inside the issuer resource to attempt to create a
+signed certificate, based upon the information inside the certificate request.
+
+## Sample External Issuer
+
+If you want to create an External Issuer, the best place to start is likely to be the [Sample External Issuer](https://github.com/cert-manager/sample-external-issuer).
+
+The Sample External Issuer is maintained by the cert-manager team, and its README file has step-by-step instructions
+on how to write an external issuer using Kubebuilder and controller-runtime.
+
+## Approval
+
+Before signing a certificate, Issuers **must** also ensure that the `CertificateRequest` is
+[`Approved`](../concepts/certificaterequest.md#approval).
+
+If the `CertificateRequest` is not `Approved`, the issuer **must** not process it. Issuers are not
+responsible for approving `CertificateRequests` and should refuse to proceed if they find a certificate
+that is not approved.
+
+If a `CertificateRequest` created for an issuance associated with a `Certificate` gets [`Denied`](../concepts/certificaterequest.md#approval), the issuance will be failed by cert-manager's issuing controller.
+
+## Conditions
+
+Once a signed certificate has been gathered by the issuer controller, it updates the status of the
+`CertificateRequest` resource with the signed certificate. It is then important to update the condition
+status of that resource to a ready state, as this is what is used to signal to higher order
+controllers - such as the `Certificate` controller - that the resource is ready to be consumed.
+
+Conversely, if the `CertificateRequest` fails, it is as important to mark the resource as such, as this will
+also be used as a signal to higher order controllers. Valid condition states are listed under [concepts](../concepts/certificaterequest.md#conditions).
+
+## Implementation
+
+It is recommended that you make use of the [kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) project in order
+to implement your external issuer controller. This makes it very simple to generate `CustomResourceDefinitions` and gives
+you a lot of controller functionality out of the box.
+
+If you have further questions on how to implement an external issuer controller, it is best to reach out on [slack](./README.md#slack)
+or to join a [community calls](./README.md#meetings).
diff --git a/content/v1.12-docs/contributing/featuregates.md b/content/v1.12-docs/contributing/featuregates.md
new file mode 100644
index 00000000000..4e6f3329674
--- /dev/null
+++ b/content/v1.12-docs/contributing/featuregates.md
@@ -0,0 +1,47 @@
+---
+Title: Implementing feature gates
+description: 'cert-manager contributing guide: Implementing feature gates'
+---
+
+As of v1 release cert-manager is considered stable. We aim to follow Kubernetes API compatibility policy when making API changes, see [API compatibility](../installation/api-compatibility.md) to avoid breaking users' existing cert-manager installations.
+This means that as developers we are somewhat limited in regards to changing existing behavior, i.e renaming or removing API elements or changing their behavior.
+
+New functionality that is not yet stable[^1] can still be added, but it needs to be placed behind a feature gate.
+
+## Feature gated API fields
+
+Feature gated API fields are implemented using `--feature-gates` flags of cert-manager [webhook](../cli/webhook.md) and [controller](../cli/controller.md).
+
+A feature gated API field is always visible to the user (i.e when running `kubectl explain `), but is only functional if the relevant feature is explicitly enabled via feature flags for both the webhook and controller.
+
+If a user attempts to apply a resource with the feature gated field set to a non-nil value, but the feature gate is not enabled, the resource will get rejected by the webhook validation.
+This mechanism differs from [the one that Kubernetes uses for feature gated API field implementation](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md#new-field-in-existing-api-version) where the field will be simply set to nil if the feature gate is disabled. We chose to use webhook validation instead to make debugging easier for users who are attempting to use the feature gated field, but have forgotten to enable the feature gate.
+
+
+### Implementation
+
+- Implement the new field and document that it is feature gated and in order to use it the controller and webhook feature gates need enabling
+- Add a new [webhook feature gate](https://github.com/cert-manager/cert-manager/blob/3a055cc2f56c1c2874807af4a8f84d0a1c46ccb4/internal/webhook/feature/features.go#L25-L39) for the field
+- Update webhook validation checks for the relevant resource kind to ensure that if the feature gated field is set, but the webhook feature gate is not enabled, the resource gets rejected
+- Add a new [controller feature gate](https://github.com/cert-manager/cert-manager/blob/2417132b3cd017b5f0974006e03c2b8a540efe3f/internal/controller/feature/features.go#L26-L54) for the field
+- Ensure that any control loops that use the feature, check that the feature gate is actually enabled. (This is required to cover edge cases such as if the webhook runs a version of cert-manager where the feature is in GA whereas controller runs an older version where the feature is still in experimental state)
+- Ensure that the feature gate is added to cert-manager installation scripts for CI and local tests in [make](https://github.com/cert-manager/cert-manager/blob/134398e939bb2b1401697eaf589405ad469cd609/make/e2e-setup.mk#L165) and [bazel](https://github.com/cert-manager/cert-manager/blob/fd747b42b9ab4b6409b61b7946e8dc14d532e950/devel/addon/certmanager/install.sh#L26) scripts
+- Default cert-manger e2e CI tests run with all feature gates for all components enabled. There is an additional optional e2e test that runs with all feature gates disabled. You can trigger that for your PR with `/test pull-cert-manager-e2e-feature-gates-disabled` to verify that all works as expected both with and without the new feature gate.
+
+### Potential issues
+
+- The person deploying cert-manager has to remember to set two cert-manager feature gates, one of the webhook one on the controller for the feature to function. Forgetting to set one of them might result in unexpected behavior
+
+- A user must remember to remove the alpha fields from their manifests when disabling a previously enabled API feature. Failing to do so might result in unexpected behavior- for example forgetting to remove feature gated field from a `Certificate` resource might result in failed renewals at some later point when cert-manager's controller will attempt to update the `Certificate` spec, but the webhook will reject the update due to the feature gated field being set.
+
+### References
+
+- cert-manager's [API compatibility promise](../installation/api-compatibility.md)
+
+- An example implementation of an alpha field is [`AdditionalOutputFormats` field on `Certificate` spec](https://github.com/cert-manager/cert-manager/blob/dbad3d98f3d7d85cadb4bd2c2493faf8b666b313/internal/apis/certmanager/types_certificate.go#L169-L174)
+
+- [Kubernetes definition of feature stages](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/#feature-stages)
+
+- Kubernetes [API change design](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md)
+
+[^1]: For example, functionality that might change in the future in response to user feedback
diff --git a/content/v1.12-docs/contributing/google-season-of-docs/2022/README.md b/content/v1.12-docs/contributing/google-season-of-docs/2022/README.md
new file mode 100644
index 00000000000..587036e7e19
--- /dev/null
+++ b/content/v1.12-docs/contributing/google-season-of-docs/2022/README.md
@@ -0,0 +1,10 @@
+---
+title: Google Season of Docs 2022
+description: Google season of docs 2022 proposal
+---
+
+We registered our interest to participate in Google Season of Docs 2022!
+
+There's one project proposal:
+
+[Improve the Navigation and Structure of the cert-manager Website](./improve-navigation-and-structure.md)
diff --git a/content/v1.12-docs/contributing/google-season-of-docs/2022/improve-navigation-and-structure.md b/content/v1.12-docs/contributing/google-season-of-docs/2022/improve-navigation-and-structure.md
new file mode 100644
index 00000000000..8f23636af37
--- /dev/null
+++ b/content/v1.12-docs/contributing/google-season-of-docs/2022/improve-navigation-and-structure.md
@@ -0,0 +1,215 @@
+---
+title: Improve the Navigation and Structure of the cert-manager Website
+description: Google season of docs 2022 proposal
+---
+
+## Project Updates
+
+### 7 Sept 2022: The Webhook Debugging Guide
+
+
+
+
+At the start of the Google Season of Docs program, we built friction logs for
+common user tasks, such as debugging the error "connect: connection refused".
+The friction log for this task, visible in the [GSoD work
+document](https://docs.google.com/document/d/1O-MFWwtpOcNlrRzsiBvrpGHC10EXnvw0XK37M2nEjzg/edit#bookmark=id.cu9ss8s7yl46),
+was to serve as a reference point to see whether the improvements we aimed to
+bring would have an impact or not.
+
+The friction log showed a consistent pattern: the user searches the error on
+Google, is confused by GitHub issues that don't have any solutions, then clicks
+the second link in the Google results, without much luck. We realized that one
+improvement we could make was to add a link to the FAQ page "Troubleshooting
+Problems with the Webhook". We found two problems with this FAQ page:
+
+1. It could not be found by anyone because the error messages were not listed in
+ the page, meaning that Google would not show the page in the search results.
+2. Many error messages were not listed in the page.
+
+We set ourselves to rewrite this page with the goal of making it error-focused,
+meaning that the user would just be able to look for their particular error and
+start debugging it. We called it "The Definitive Debugging Guide for the
+cert-manager Webhook Pod", and it can be found
+[here](../../../troubleshooting/webhook.md).
+
+### 12 Aug 2022: Improved the layout of the navigation menu
+
+On displays `>=1280px` the left-hand menu was too narrow to display the nested menu items clearly,
+On smaller displays the [responsive CSS](https://tailwindcss.com/docs/responsive-design) actually made the menu larger.
+So we've widened it by 1 column on displays `>=1280px` and reduced the width of the content by 1 column to compensate.
+This makes the menu much easier to read on laptop and desktop computer screens.
+
+We fixed an inconsistency in the vertical spacing between menu items with sub-menus and those without.
+
+And finally, we moved the version selector to the bottom of the side-bar to avoid distracting the reader.
+
+### 3 August 2022: The cert-manager.io Documentation Survey is now closed
+
+Thank you to everyone who participated in our documentation survey.
+We will use the results to prioritize sections of the website for restructuring and rewriting.
+Before the conclusion of this Season-of-Docs we will select a random winner from among the responses and contact you about your prize.
+
+### 18 July 2022: The cert-manager.io Documentation Survey
+
+
+
+We have created a short survey, to help us identify what are the top-priorities for the cert-manager.io documentation.
+
+1. We want identify the most useful documentation, so that we don't go and change things that are already working well.
+2. We want to know which documentation is not useful, so that we can make improvements.
+3. We'd like to hear from new and experienced users about how and how often you use the documentation.
+4. And we'd like to know where else you find good information about cert-manager, outside of the cert-manager.io website,
+so that we can try and incorporate some of those sources.
+
+We've added a link to the survey to the banner at the top of this site
+and we will also be sharing the link in our Slack channels and mailing lists.
+
+[Please take 10 minutes to fill in the survey](https://docs.google.com/forms/d/e/1FAIpQLSeqfRkd86_N0L7VOW_ImCT0iyUabhczdiDk2dQDLp55V8kqvw/viewform).
+
+
+
+### 15 July 2022: New "Getting Started" pages
+
+
+
+
+We have been auditing the existing documentation to identify some key tasks that our users and potential new users need to carry out.
+We have created "friction logs" for some of these tasks.
+What this means is that we imagine ourselves in the place of the user and ask, for example,
+
+> How can I get a Let's Encrypt certificate for my server in Kubernetes?
+
+So we searched Google and DuckDuckGo for "Let's Encrypt Kubernetes" and to our surprise, cert-manager.io does not feature among the top search results.
+
+Among the results are some excellent third-party tutorials and videos about using cert-manager to create Let's Encrypt certificates,
+and we are grateful to the authors for taking the time to write such detailed content.
+But inevitably, some of these refer to much older versions of cert-manager and Kubernetes.
+So we have decided to write some official guides, for the cert-manager.io website which demonstrate how to quickly install cert-manager and configure it for Let's Encrypt.
+We hope that in time these will be indexed by the search engines and that they will reach the top of the search results for "Let's Encrypt Kubernetes".
+The advantages will be that users and potential users will find up-to-date information,
+and the cert-manager.io maintainers will receive fewer support requests from new users who are attempting this task.
+
+Go and read the new [Getting Started Guide for GKE Users](../../../getting-started) and tell us what you think.
+
+
+
+### 5 May 2022: Announcing Mehak Saeed as Technical Writer
+
+We are delighted to announce that [Mehak Saeed](https://www.linkedin.com/in/mehak-saeed-29121a12a) will be the technical writer working on this project.
+We were extremely impressed with Mehak's presentation during her interview and impressed with her detailed preparations and planning.
+We look forward to working with her.
+
+Thank you to all the other technical writers who applied for this project.
+
+### 14 April 2022: Project Accepted
+
+This project was [accepted on 14 April 2022](https://developers.google.com/season-of-docs/docs/participants).
+
+### 24 March 2022: Project Registered
+
+We have [registered our interest to participate in Google Season of Docs 2022](https://github.com/google/season-of-docs/pull/483),
+and have submitted a single project proposal detailed in the remaining of this
+page.
+
+You have until 27 April 2022 18:00 UTC to apply for the technical writer role.
+
+We will be sharing the name of the selected candidate on Wed 4 May 2022 at
+15:00 London Time (14:00 UTC) on Slack in the channel `#cert-manager-dev`.
+
+To apply as a technical writer, please let us know by one of the two ways
+below:
+
+- e-mail us at `cert-manager-maintainers@googlegroups.com` with the prefix
+ `GSoD2022:` in the e-mail subject.
+- or open an issue on
+ [cert-manager/website](https://github.com/cert-manager/website) with the
+ prefix `GSoD2022:` in the issue title.
+
+You can join our open standup (every day at 10:30 UK time), and join the
+Kubernetes Slack channel `#cert-manager-dev` to know more about this project
+proposal.
+
+## About cert-manager
+
+cert-manager (current version 1.8.0, first release in October 2017) is an Apache-2.0 licensed Kubernetes add-on to automate the management and issuance of TLS certificates.
+
+Our typical contributors are Go developers from around the world with experience of the Kubernetes ecosystem with experience contributing to core Kubernetes components and Kubernetes operators.
+
+Our users are often developers and system administrators who are trying to automate the rotation of TLS certificates for applications running in their Kubernetes clusters.
+
+Our largest users have cert-manager installed on multiple Kubernetes clusters and managing many thousands of TLS certificates.
+
+## Project Overview
+
+Right now the content is not designed with our target audiences in mind.
+For example a new user will not easily find a guide explaining how to install cert-manager on AWS and configure it for Let’s Encrypt.
+Nor will a Cluster Administrator easily find information about how to optimize cert-manager for a large cluster with many Certificates.
+The information exists but is spread across multiple pages and is often not at the obvious page.
+
+As a visual example, a user looking for a guide on how the Certificate resource can be used may feel helpless when realizing that the "Certificate" page exists twice: once under the "Usage" section, and once under the "Concepts" section.
+
+![Screenshot of the cert-manager.io website with Usage and Concepts visible in the menu](/images/google-season-of-docs-2022-improve-navigation-and-structure.png)
+
+(NB: This screenshot is from our old site design but the text and layout are broadly the same)
+
+We would like a technical writer:
+
+1. to help us identify our target audiences, and
+2. to identify the key tasks of each of these audiences, and
+3. re-structure the cert-manager.io website with this in mind.
+
+For example, we have discussed the following audiences and tasks: Beginner, Cluster Administrator, User, Integrator, New Contributor
+and each of these people will be interested in a different set of tasks.
+We would like them to quickly and easily find the information they need.
+
+By making it easier for each group to find the information they need we aim to reduce the number of support queries.
+
+## Scope
+
+The scope of this project is as follows:
+
+1. Identify and describe three target audiences.
+2. Identify three key top tasks for each of these audiences.
+3. Audit the existing documentation and create a friction log of the current documentation.
+4. Using the friction log as a baseline, re-organize the documentation to minimize friction for three top tasks.
+6. Incorporate feedback from documentation testers (volunteers in the project) and the wider cert-manager community.
+7. Work with the cert-manager team to publish the documentation on cert-manager.io.
+8. Create documentation for website contributors explaining how we structure our content around audiences and tasks.
+
+## Measuring success
+
+After the technical writer has helped us identify the 3 key tasks for each audience
+we will measure a baseline number of clicks required to achieve the task and we will aim to minimize the number of clicks for each task.
+
+## Timeline
+
+| Dates | Action Items |
+|-------------|--------------------------------------------------|
+| May | Orientation |
+| May / June | Identify audiences and tasks |
+| May / June | Audit and friction log |
+| June | Restructuring tasks |
+| June / July | Incorporating feedback |
+| June / July | Publish to cert-manager.io |
+| July | Finish writing guidance for website contributors |
+| July | Project Completion |
+
+## Budget
+
+| Budget item | Amount ($) | Running Total ($) | Notes |
+|-------------------------------------------------------------------------------|-------------|-------------------|---------------------------------|
+| Technical writer audit and restructuring of the cert-manager.io documentation | 12,000 | 12,000 | |
+| Volunteer stipends | 1,500 | 13,500 | 3 volunteer stipends x 500 each |
+| TOTAL | | 13,500 | |
+
+Regarding the amount of $12,000, we assume that it will be enough to fund one experienced technical writer
+part-time (for example, they could work half day from Tuesday to Friday, for a total of 24 days, for 3 months
+at a daily rate of $500).
+
+We will give the "volunteer stipend" to contributors who can show they have one PR within the project
+time frame (from 1st May to 30th July) in which a re-write of one page or a set of pages. Before
+starting the rewriting, the volunteer will suggest which page they wish to work on either on Slack
+(Kubernetes Slack, channel #cert-manager-dev), or in an issue on GitHub, and make sure by asking the
+team whether it makes sense to rework this page. As long as at least one positive reaction, the
+volunteer can start working. For the stipend to be validated, the PR needs to be reviewed and merged.
diff --git a/content/v1.12-docs/contributing/google-season-of-docs/README.md b/content/v1.12-docs/contributing/google-season-of-docs/README.md
new file mode 100644
index 00000000000..cb43f69aa8c
--- /dev/null
+++ b/content/v1.12-docs/contributing/google-season-of-docs/README.md
@@ -0,0 +1,8 @@
+---
+title: Google Season of Docs
+description: cert-manager and Google Season of Docs
+---
+
+The cert-manager project participated in Google Season of Docs 2022
+
+If you're interested in what happened, you can check out our [2022 proposals!](./2022/README.md).
diff --git a/content/v1.12-docs/contributing/importing.md b/content/v1.12-docs/contributing/importing.md
new file mode 100644
index 00000000000..2c39a247e35
--- /dev/null
+++ b/content/v1.12-docs/contributing/importing.md
@@ -0,0 +1,42 @@
+---
+title: Importing cert-manager in Go
+description: 'cert-manager contributing guide: Importing cert-manager'
+---
+
+cert-manager is written in Go, and uses Go modules. You _can_ import it as a Go module, and in some cases
+that's fine or even encouraged, but as a rule we generally recommend against importing cert-manager.
+
+Generally speaking, except for the cases listed below under [When You Might Import cert-manager](#when-you-might-import-cert-manager),
+code in the cert-manager repository is *not* covered under any Go module compatibility guarantee. We can and will make breaking
+changes, even in publicly exported Go code and even in a minor or patch release of cert-manager. We have made breaking changes like
+this in the past.
+
+Note that this doesn't affect _running_ cert-manager. Our commitment on compatibility is to not break the runtime
+functionality of cert-manager, and we take that seriously.
+
+If you're certain that you *do* need to import cert-manager as a module, see [Module Import Paths](#module-import-paths)
+below for a note on how to do that.
+
+## When You Might Import cert-manager
+
+You might need to import cert-manager if you're writing Go code which:
+
+- uses cert-manager custom resources, so you want to import something under `pkg/apis`
+- implements an external DNS solver webhook, as in the [webhook-example](https://github.com/cert-manager/webhook-example)
+- implements an external issuer, as in the [sample-external-issuer](https://github.com/cert-manager/sample-external-issuer)
+
+If you think you really need to import other parts of the code, please do reach out and [talk to us](./README.md#slack) so we're
+aware of this need! We'll always try to avoid breakage where we can.
+
+## Module Import Paths
+
+For all supported versions of cert-manager, the module import path is `github.com/cert-manager/cert-manager`.
+
+Historically, the cert-manager repository was created on GitHub as `https://github.com/jetstack/cert-manager`, and was later
+migrated to `https://github.com/cert-manager/cert-manager`.
+
+This means that the Go module import path you need may be different if you're trying to use an older version of cert-manager.
+
+For cert-manager 1.8 and later, use the new path listed above.
+
+For cert-manager versions older than 1.8 use the old path: `github.com/jetstack/cert-manager`
diff --git a/content/v1.12-docs/contributing/kind.md b/content/v1.12-docs/contributing/kind.md
new file mode 100644
index 00000000000..a6fc15c14a8
--- /dev/null
+++ b/content/v1.12-docs/contributing/kind.md
@@ -0,0 +1,31 @@
+---
+title: Developing with Kind
+description: 'cert-manager contributing guide: Using Kind'
+---
+
+[Kind](https://kind.sigs.k8s.io/) allows you to provision Kubernetes clusters locally using nested Docker containers,
+with no requirement for virtual machines.
+
+These clusters are quick to create and destroy, and are useful for simple testing for
+development. cert-manager also uses kind clusters in its [end-to-end tests](./e2e.md).
+
+## Using Kind Locally
+
+You should be able to make use of cert-manager's end-to-end test setup logic to create a local Kind cluster for
+development. As such, if you want a local cluster you might want to follow some of the details in the
+[end-to-end test documentation](./e2e.md).
+
+If, though, you just want to get a cluster up and running with your local changes to cert-manager running inside
+`kind`, try the following:
+
+```console
+make e2e-setup-kind e2e-setup-certmanager
+```
+
+Or, if you need a specific version of Kubernetes:
+
+```console
+make K8S_VERSION=1.xx e2e-setup-kind e2e-setup-certmanager
+```
+
+That should leave you with a working cluster which you can interact with using `kubectl`!
diff --git a/content/v1.12-docs/contributing/policy.md b/content/v1.12-docs/contributing/policy.md
new file mode 100644
index 00000000000..d29f34e41f6
--- /dev/null
+++ b/content/v1.12-docs/contributing/policy.md
@@ -0,0 +1,159 @@
+---
+title: Feature Policy
+description: 'cert-manager contributing guide: Contribution Policy'
+---
+
+We love to receive both feature requests and PRs which add to and improve cert-manager; the community is at the heart of what we do!
+
+If you're thinking of adding a feature, we recommend you read this doc to maximize the chances of your contribution getting the attention it deserves and hopefully to get it merged quickly!
+
+We recommend creating an issue first for it to be discussed with the cert-manager maintainers. Another possibility is bringing it up in a community meeting for an open discussion on the implementation.
+
+## Feature Sizing: Getting Your Change Accepted
+
+We evaluate new features and PRs based on their size and their significance; either they're small or large.
+
+### Smaller Features
+
+Many contributions are small. That usually - but not always - means that implementing them won't require many lines of code to be added or changed, and in any case they should be easy
+for maintainers to review. A PR being small is a good thing; if you can down-scope your feature to make it smaller, we won't complain!
+
+If you believe your feature is small, please feel free to just raise a PR and optionally also post a link to your PR in the [cert-manager-dev slack channel](./README.md#slack). Usually a sufficiently small PR can be merged without too much ceremony. If we think it's actually a larger piece of work, we'll let you know.
+
+### Larger Features
+
+If you're not sure whether your PR is small, or if you know it's bigger, you'll want to speak to us first before raising a PR. This
+will help to ensure that your PR is something we're likely to merge to avoid wasting your time. It'll also make it easier
+for us to do the design process.
+
+#### Design Documents
+
+Larger feature development should normally start with a design discussion. To get that started, you would raise a PR with a design document against [cert-manager/cert-manager/design](https://github.com/cert-manager/cert-manager/tree/master/design). This allows us to discuss the proposed functionality before starting the work to implement it and serves as a way to document the decisions and reasoning behind them. Ideally, a good design document should allow for faster and more consistent feature development and implementation process by providing a single place where all potential concerns and questions are answered.
+
+We have a [design template](https://github.com/cert-manager/cert-manager/blob/master/design/template.md) that outlines the structure of the document.
+(This is a simplified version of [Kubernetes enhancements KEP template](https://github.com/kubernetes/enhancements/tree/master/keps/NNNN-kep-template)).
+Do reach out if you need help with the design.
+
+Part of the process of discussing a design document may also include a video call with you included! That helps us to plan how a feature should
+be implemented and approached. It'll be pretty informal and casual; we just want to make sure we're all on the same page. This call might be part
+of a biweekly meeting.
+
+#### Making Progress with Larger Features
+
+Larger features with a design document are much more likely to be accepted, and in turn we're much more likely to commit a single
+named cert-manager maintainer to the effort to help the PR to be successful. That maintainer might not be able to answer all your
+questions, but they should certainly be able to point you in the right direction.
+
+To get in touch to discuss a feature, please reach out on the [cert-manager-dev slack channel](./README.md#slack), or join a [cert-manager public meeting](./README.md#meetings) to talk about your proposal.
+
+If you have an open PR with a design document (or have some questions about how to proceed with a design), you should absolutely feel free to add the PR with your design or a link to the relevant GitHub issue to the [meeting notes](https://docs.google.com/document/d/1Tc5t6ylY9dhXAan1OjOoldeaoys1Yh4Ir710ATfBa5U/edit) for our next biweekly meeting
+and join in so we're sure to discuss it and so you can contribute to the discussion!
+
+#### Large Feature Lifecycle
+
+1. Informally ask about the feature in slack or a public meeting
+2. Create a PR with a lightweight design document using the [design template](https://github.com/cert-manager/cert-manager/tree/master/design/template.md), for discussion
+3. Design doc PR gets reviewed - possibly includes meeting or discussion in a biweekly meeting
+4. Implement your feature, helped and reviewed by a named cert-manager maintainer
+
+## Feature Requests We'll Likely Reject
+
+In some cases, people will request features which we've previously rejected or which for some reason we have to reject.
+
+It's nothing personal; sometimes we have to make tough choices and especially when it comes to security and maintainability we have to reject certain
+proposals. If your feature request is listed below, there's a high chance we'll have to reject it.
+
+That said, if you think we've made a mistake and that we should reconsider, we're open to chatting - consider joining our [biweekly meetings](./README.md#meetings) to discuss it with us!
+
+### Vendoring Kubernetes related APIs outside of the `k8s.io/` namespace
+
+Vendoring project APIs that also vendor `k8s.io/apimachinery`, such as OpenShift, Contour, or Velero, is not recommend because the Kubernetes dependency is likely to conflict with cert-manager's instance.
+It could also cause a conflict with different Kubernetes client versions being used.
+
+If this is needed it is suggested to use a "dynamic client" that converts the objects into internal structures copied into the cert-manager codebase.
+
+### Additional configuration options for the Helm chart
+
+cert-manager's Helm chart is intended to allow to create a standard, best practices cert-manager installation with basic configuration options, such as being able to provide flags to cert-manager components, label resources etc.
+We do not aim to include every possible configuration option for resources that the chart creates to avoid maintenance burden and because we do not have automated testing for all chart configuration options. Therefore we are likely to not accept PRs that add advanced or niche configuration options to Helm charts- we recommend that users who require that configuration use another mechanism such as [Helm's post-install hooks](https://helm.sh/docs/topics/charts_hooks/).
+
+### Helm + CRDs
+
+Helm suggests that CRDs be included in a `crds/` subdirectory of a chart, with the `crd-install` annotation included. This has the unfortunate side effect that CRDs are not upgraded if changed in a later release.
+
+CRDs being upgraded without being removed and re-installed is essential for cert-manager to move forward.
+
+This was previously discussed [in the Helm community](https://github.com/helm/helm/issues/5871).
+
+cert-manager works around this limitation by shipping CRDs in the templates.
+
+### Helm Subchart capabilities
+
+cert-manager now has the capability to be [installed as a subchart](../installation/helm.md#installing-cert-manager-as-subchart).
+
+But you need to be careful when adding it to your umbrella chart.
+
+This is because the cert-manager installation creates cluster scoped resources like admission webhooks and custom resource definitions. cert-manager should be seen as part of your cluster and should be treated as such for being installed. An apt comparison
+to other Kubernetes components would be a LoadBalancer controller or a PV provisioner.
+
+It is your responsibility to ensure that cert-manager is only installed once in your cluster.
+This can be managed via the `condition` parameter of the dependency in your `Chart.yaml`, which allows users to disable the installation of a subchart. The condition parameter must be added when using cert-manager as a subchart to allow users to disable your dependency.
+
+```yaml
+apiVersion: v2
+name: example_chart
+description: A Helm chart with cert-manager as subchart
+type: application
+version: 0.1.0
+appVersion: "0.1.0"
+dependencies:
+ - name: cert-manager
+ version: v1.8.0
+ repository: https://charts.jetstack.io
+ alias: cert-manager
+ condition: cert-manager.enabled
+```
+
+### Secret injection or copying
+
+cert-manager deals with very sensitive information (all TLS certificates for your services) and has cluster-level access to secret resources. As such, when designing features we need to consider all of the ways these secrets might be abused to escalate privilege.
+
+Secret data is meant to be securely stored in `Secret` resources and have narrow scoped access privileges for unauthorized users. Because of this, we won't usually add any functionality that allows this data to be copied/injected into any resource
+other than a Kubernetes `Secret`.
+
+#### cainjector
+
+The cainjector component is a special exception to this rule as it deals in non-sensitive information (CAs, not cert/key pairs). This component is able to inject the `ca.crt` file into predefined fields on `ValidatingWebhookConfiguration`, `MutatingWebhookConfiguration`, and `CustomResourceDefinition` resources from Certificate resources.
+
+These 3 components are already scoped only for privileged users, and will already give you cluster scoped access to resources.
+
+If you’re designing a resource that needs a CA Certificate or TLS key pair it is strongly recommended to use a reference to a secret instead of embedding it in a resource.
+
+### Cross namespace resources
+
+Namespace boundaries in Kubernetes provide a barrier for access scopes. Apps or users can be limited to only access resources in a certain namespace.
+
+cert-manager is a controller that operates on cluster wide resources however, and while it may seem interesting to allow access to copy or write certificate data from one namespace to the other, this can cause a bypass of the
+namespace security model for all users, which is usually not intended and can be a major a security issue.
+
+We don't support this behavior; if you believe you need it, and it's intended for your use case then there are other Kubernetes controllers that can do this, although we'd suggest extreme caution.
+
+### Sign certificates using the Kubernetes CA
+
+Kubernetes has a Certificate Signing Requests API, and a `kubectl certificates` command which allows you to approve certificate signing requests and have them signed by the certificate authority (CA) of the Kubernetes cluster. This
+CA is generally used for your nodes.
+
+This API and CLI have occasionally been misused to sign certificates for use by pods outside of the control plane; we believe this is a mistake.
+
+For the security of the Kubernetes cluster it's important to limit access to the Kubernetes certificate authority; such certificates increase the attack surface for the Kubernetes API server since this CA signs certificates for
+authorization against the API server. If cert-manager used this cert, it could allow any user with permission to create cert-manager resources to elevate privileges by signing certificates which are trusted for API access.
+
+[See our FAQ](../faq/README.md#kubernetes-has-a-builtin-certificatesigningrequest-api-why-not-use-that) for more details on this.
+
+### Integrations with third party infrastructure providers
+
+We try to not include in core cert-manager new functionality that involves calling third party APIs that we don't have infrastructure to test (or that the maintainers don't have the skills to work with).
+
+Instead we try to build interfaces such as [external DNS webhook solver](../configuration/acme/dns01/webhook.md) that can be implemented to use cert-manager with a particular third party implementation.
+We believe that this is a more sustainable approach as that way folks who have knowledge and skills to work with particular infrastructure can own a project that interacts with it and it lets us avoid merging potentially untested code to core cert-manager.
+An example of a PR that might be rejected would be adding a new external DNS solver kind, see https://github.com/cert-manager/cert-manager/pull/1088
diff --git a/content/v1.12-docs/contributing/release-process.md b/content/v1.12-docs/contributing/release-process.md
new file mode 100644
index 00000000000..4e0b074fcf1
--- /dev/null
+++ b/content/v1.12-docs/contributing/release-process.md
@@ -0,0 +1,599 @@
+---
+title: Release Process
+description: 'cert-manager contributing: Release process'
+---
+
+This document aims to outline the process that should be followed for
+cutting a new release of cert-manager. If you would like to know more about
+current releases and the timeline for future releases, take a look at the
+[Supported Releases](../installation/supported-releases.md) page.
+
+## Prerequisites
+
+⛔️ Do not proceed with the release process if you do not meet all of the
+following conditions:
+
+1. The relevant [testgrid dashboard](https://testgrid.k8s.io/cert-manager) should not be failing for the release you're trying to perform.
+2. The release process **takes about 40 minutes**. You must have time to complete all the steps.
+3. You currently need to be at Jetstack to get the required GitHub and GCP
+ permissions. (we'd like contributors outside Jetstack to be able to get
+ access; if that's of interest to you, please let us know).
+4. You need to have the GitHub `admin` permission on the cert-manager project.
+ To check that you have the `admin` role, run:
+
+ ```bash
+ brew install gh
+ gh auth login
+ gh api /repos/cert-manager/cert-manager/collaborators/$(gh api /user | jq -r .login)/permission | jq .permission
+ ```
+
+ If your permission is `admin`, then you are good to go. To request the
+ `admin` permission on the cert-manager project, [open a
+ PR](https://github.com/jetstack/platform-board/pulls/new) with a link to
+ here.
+
+5. You need to be added as an "Editor" to the GCP project
+ [cert-manager-release](https://console.cloud.google.com/?project=cert-manager-release).
+ To check if you do have access, try opening [the Cloud Build
+ page](https://console.cloud.google.com/cloud-build?project=cert-manager-release).
+ To get the "Editor" permission on the GCP project, open a PR with your name
+ added to the maintainers list in
+ [`cert_manager_release.tf`](https://github.com/jetstack/terraform-jetstack/blob/master/cert_manager_release.tf)
+
+ ```diff
+ --- a/cert_manager_release.tf
+ +++ b/cert_manager_release.tf
+ @@ -17,6 +17,7 @@ locals {
+ var.personal_email["..."],
+ var.personal_email["..."],
+ var.personal_email["..."],
+ + var.personal_email["mael-valais"],
+ ])
+ }
+ ```
+
+ You may use the following PR description:
+
+ ```markdown
+ Title: Access to the cert-manager-release GCP project
+
+ Hi. As stated in "Prerequisites" on the [release-process][1] page,
+ I need access to the [cert-manager-release][2] project on GCP in
+ order to perform the release process. Thanks!
+
+ [1]: https://cert-manager.io/docs/contributing/release-process/#prerequisites
+ [2]: https://console.cloud.google.com/?project=cert-manager-release
+ ```
+
+This guide applies for versions of cert-manager released using `make`, which should be every version from cert-manager 1.8 and later.
+
+**If you need to release a version of cert-manager 1.7 or earlier** see [older releases](#older-releases).
+
+First, ensure that you have all the tools required to perform a cert-manager release:
+
+1. Install the [`release-notes`](https://github.com/kubernetes/release/blob/master/cmd/release-notes/README.md) CLI:
+
+ ```bash
+ go install k8s.io/release/cmd/release-notes@v0.13.0
+ ```
+
+2. Install our [`cmrel`](https://github.com/cert-manager/release) CLI:
+
+ ```bash
+ go install github.com/cert-manager/release/cmd/cmrel@latest
+ ```
+
+3. Clone the `cert-manager/release` repo:
+
+ ```bash
+ # Don't clone it from inside the cert-manager repo folder.
+ git clone https://github.com/cert-manager/release
+ cd release
+ ```
+
+4. Install the [`gcloud`](https://cloud.google.com/sdk/) CLI.
+5. [Login](https://cloud.google.com/sdk/docs/authorizing#running_gcloud_auth_login)
+ to `gcloud`:
+
+ ```bash
+ gcloud auth application-default login
+ ```
+
+6. Make sure `gcloud` points to the cert-manager-release project:
+
+ ```bash
+ gcloud config set project cert-manager-release
+ export CLOUDSDK_CORE_PROJECT=cert-manager-release # this is used by cmrel
+ ```
+
+7. Get a GitHub access token [here](https://github.com/settings/tokens)
+ with no scope ticked. It is used only by the `release-notes` CLI to
+ avoid API rate limiting since it will go through all the PRs one by one.
+
+## Minor releases
+
+A minor release is a backwards-compatible 'feature' release. It can contain new
+features and bug fixes.
+
+### Release schedule
+
+We aim to cut a new minor release once per month. The rough goals for each
+release are outlined as part of a GitHub milestone. We cut a release even if
+some of these goals are missed, in order to keep up release velocity.
+
+### Process for releasing a version
+
+
+🔰 Please click on the **Edit this page** button on the top-right corner of this
+page if a step is missing or if it is outdated.
+
+
+1. Make sure to note which type of release you are doing. That will be helpful
+ in the next steps.
+
+ | Type of release | Example of git tag |
+ |------------------------------------|--------------------|
+ | initial alpha release | `v1.3.0-alpha.0` |
+ | subsequent alpha release | `v1.3.0-alpha.1` |
+ | initial beta release | `v1.3.0-beta.0` |
+ | subsequent beta release | `v1.3.0-beta.1` |
+ | final release | `v1.3.0` |
+ | (optional) patch pre-release[^1] | `v1.3.1-beta.0` |
+ | patch release (or "point release") | `v1.3.1` |
+
+[^1]: One or more "patch pre-releases" may be created to allow voluntary community testing of a bug fix or security fix before the fix is made generally available. The suffix `-beta` must be used for patch pre-releases.
+
+2. **(final release only)** Make sure that a PR with the new upgrade
+ document is ready to be merged on
+ [cert-manager/website](https://github.com/cert-manager/website). See for
+ example, see
+ [upgrading-1.0-1.1](https://cert-manager.io/docs/installation/upgrading/upgrading-1.0-1.1/).
+
+3. Check that the `origin` remote is correct. To do that, run the following
+ command and make sure it returns the upstream
+ `https://github.com/cert-manager/cert-manager.git`:
+
+ ```bash
+ # Must be run from the cert-manager repo folder.
+ git remote -v | grep origin
+ ```
+
+ It should show:
+
+ ```text
+ origin https://github.com/jetstack/cert-manager (fetch)
+ origin https://github.com/jetstack/cert-manager (push)
+ ```
+
+4. Place yourself on the correct branch:
+
+ - **(initial alpha and subsequent alpha)**: place yourself on the `master`
+ branch:
+
+ ```bash
+ git checkout master
+ git pull origin master
+ ```
+
+ - **(initial beta only)** The release branch doesn't exist yet, so let's
+ create it and push it:
+
+ ```bash
+ # Must be run from the cert-manager repo folder.
+ git checkout master
+ git pull origin master
+ git checkout -b release-1.12 master
+ git push origin release-1.12
+ ```
+
+ **GitHub permissions**: `git push` will only work if you have the `admin`
+ GitHub permission on the cert-manager repo to create or push to the
+ branch, see [prerequisites](#prerequisites). If you do not have this
+ permission, you will have to open a PR to merge master into the release
+ branch), and wait for the PR checks to become green.
+
+ - **(subsequent beta, patch release and final release)**: place yourself on
+ the release branch:
+
+ ```bash
+ git checkout release-1.12
+ git pull origin release-1.12
+ ```
+
+ You don't need to fast-forward the branch because things have been merged
+ using `/cherry-pick release-1.0`.
+
+ **Note about the code freeze:**
+
+ The first beta starts a new "code freeze" period that lasts until the
+ final release. Just before the code freeze, we fast-forward everything
+ from master into the release branch.
+
+ During the code freeze, we continue merging PRs into master as usual.
+
+ We don't fast-forward master into the release branch for the second (and
+ subsequent) beta, and only `/cherry-pick release-1.0` the fixes that should be part
+ of the subsequent beta.
+
+ We don't fast-forward for patch releases and final releases; instead, we
+ prepare these releases using the `/cherry-pick release-1.0` command.
+
+ > Note about branch protection: The release branches are protected by [GitHub branch protection](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule), which is [configured automatically by Prow](https://github.com/jetstack/testing/blob/500b990ad1278982b10d57bf8fbca383040d2fe8/config/config.yaml#L27-L36).
+ > This prevents anyone *accidentally* pushing changes directly to these branches, even repository administrators.
+ > If you need, for some reason, to fast forward the release branch,
+ > you should delete the branch protection for that release branch, using the [GitHub branch protection web UI](https://github.com/cert-manager/cert-manager/settings/branches).
+ > This is only a temporary change to allow you to update the branch.
+ > [Prow will re-apply the branch protection within 24 hours](https://docs.prow.k8s.io/docs/components/optional/branchprotector/#updating).
+
+5. Create the tag for the new release locally and push it upstream (starting the cert-manager build):
+
+ ```bash
+ RELEASE_VERSION=v1.8.0-beta.0
+ git tag -m"$RELEASE_VERSION" $RELEASE_VERSION
+ # be sure to push the named tag explicitly; you don't want to push any other local tags!
+ git push origin $RELEASE_VERSION
+ ```
+
+ **GitHub permissions**: `git push` will only work if you have the
+ `admin` GitHub permission on the cert-manager repo to create or push to
+ the branch, see [prerequisites](#prerequisites). If you do not have this
+ permission, you will have to open a PR to merge master into the release
+ branch), and wait for the PR checks to become green.
+
+ For recent versions of cert-manager, the tag being pushed will trigger a Google Cloud Build job to start,
+ kicking off a build using the steps in `gcb/build_cert_manager.yaml`. Users with access to
+ the cert-manager-release project on GCP should be able to view logs in [GCB build history](https://console.cloud.google.com/cloud-build/builds?project=cert-manager-release).
+
+6. Generate and edit the release notes:
+
+ 1. Use the following two tables to understand how to fill in the four
+ environment variables needed for the next step. These four environment
+ variables are documented on the
+ [README](https://github.com/kubernetes/release/blob/master/cmd/release-notes/README.md#options)
+ for the Kubernetes `release-notes` tool.
+
+ | Variable | Description |
+ | ----------------- | --------------------------------------- |
+ | `RELEASE_VERSION` | The git tag |
+ | `START_TAG`\* | The git tag of the "previous"\* release |
+ | `END_REV` | Name of your release branch (inclusive) |
+ | `BRANCH` | Name of your release branch |
+
+ Examples for each release type (e.g., initial alpha release):
+
+ | Variable | Example 1 | Example 2 | Example 2 | Example 3 | Example 4 |
+ | ----------------- | ---------------- | ---------------- | ---------------- | ------------- | ------------- |
+ | | | | | | |
+ | | initial alpha | subsequent alpha | beta release | final release | patch release |
+ | `RELEASE_VERSION` | `v1.3.0-alpha.0` | `v1.3.0-alpha.1` | `v1.3.0-beta.0` | `v1.3.0` | `v1.3.1` |
+ | `START_TAG`\* | `v1.2.0` | `v1.3.0-alpha.0` | `v1.3.0-alpha.1` | `v1.2.0`\*\* | `v1.3.0` |
+ | `END_REV` | `master` | `master` | `release-1.3` | `release-1.3` | `release-1.3` |
+ | `BRANCH` | `master` | `master` | `release-1.3` | `release-1.3` | `release-1.3` |
+
+ > \*The git tag of the "previous" release (`START_TAG`) depends on which
+ > type of release you count on doing. Look at the above examples to
+ > understand a bit more what those are.
+
+ > \*\*Do not use a patch here (e.g., no `v1.2.3`). It must be `v1.2.0`:
+ > you must use the latest tag that belongs to the release branch you are
+ > releasing on; in the above example, the release branch is
+ > `release-1.3`, and the latest tag on that branch is `v1.2.0`.
+
+ After finding out the value for each of the 4 environment variables, set
+ the variables in your shell (for example, following the example 1):
+
+ ```bash
+ export RELEASE_VERSION="v1.3.0-alpha.0"
+ export START_TAG="v1.2.0"
+ export END_REV="release-1.3"
+ export BRANCH="release-1.3"
+ ```
+
+ 2. Generate `release-notes.md` at the root of your cert-manager repo folder
+ with the following command:
+
+ ```bash
+ # Must be run from the cert-manager folder.
+ export GITHUB_TOKEN=*your-token*
+ git fetch origin $BRANCH
+ export START_SHA="$(git rev-list --reverse --ancestry-path $(git merge-base $START_TAG $BRANCH)..$BRANCH | head -1)"
+ release-notes --debug --repo-path cert-manager \
+ --org cert-manager --repo cert-manager \
+ --required-author "jetstack-bot" \
+ --output release-notes.md
+ ```
+
+
+ The GitHub token **does not need any scope**. The token is required
+ only to avoid rate-limits imposed on anonymous API users.
+
+
+ 3. Replace the GitHub issue numbers and GitHub handles (e.g., `#1234` or
+ `@maelvls`) with actual links:
+
+ ```bash
+ sed release-notes.md \
+ -e 's$#([0-9]+)$[#\1](https://github.com/cert-manager/cert-manager/pull/\1)$g' \
+ -e 's$@(\w+)$[@\1](https://github.com/\1)$g' \
+ -E \
+ -i
+ ```
+
+ 4. Sanity check the notes:
+
+ - Make sure the notes contain details of all the features and bug
+ fixes that you expect to be in the release.
+ - Add additional blurb, notable items and characterize change log.
+
+ You can see the commits that will go into this release by using the
+ [GitHub compare](https://github.com/cert-manager/cert-manager/compare). For
+ example, while releasing `v1.0.0`, you want to compare it with the
+ latest pre-released version `v1.0.0-beta.1`:
+
+ ```text
+ https://github.com/cert-manager/cert-manager/compare/v1.0.0-beta.1...master
+ ```
+
+ 4. **(final release only)** Check the release notes include all changes
+ since the last final release.
+
+7. Check that the build is complete and send Slack messages about the release:
+
+ 1. For recent versions of cert-manager, the build will have been automatically
+ triggered by the tag being pushed earlier. You can check if it's complete on
+ the [GCB Build History](https://console.cloud.google.com/cloud-build/builds?project=cert-manager-release).
+
+ 2. If you're releasing an older version of cert-manager (earlier than 1.10) then the automatic build
+ will failed because the GCB config for that build wasn't backported.
+ In this case, you'll need to trigger the build manually using `cmrel`, which takes about 5 minutes:
+
+ ```bash
+ # Must be run from the "cert-manager/release" repo folder.
+ cmrel makestage --ref=$RELEASE_VERSION
+ ```
+
+ This build takes ~5 minutes. It will build all container images and create
+ all the manifest files, sign Helm charts and upload everything to a storage
+ bucket on Google Cloud. These artifacts will then be published and released
+ in the next steps.
+
+ 3. In any case, send a first Slack message to `#cert-manager-dev`:
+
+
+ Releasing 1.2.0-alpha.2 🧵
+
+
+
+ 🔰 Please have a quick look at the build log as it might contain some unredacted
+ data that we forgot to hide. We try to make sure the sensitive data is
+ properly redacted but sometimes we forget to update this.
+
+
+ 3. Send a second Slack message in reply to this first message with the
+ Cloud Build job link. For example, the message might look like:
+
+
+ Follow the cmrel makestage build: https://console.cloud.google.com/cloud-build/builds/7641734d-fc3c-42e7-9e4c-85bfc4d1d547?project=1021342095237
+
+
+8. Run `cmrel publish`:
+
+ 1. Do a `cmrel publish` dry-run to ensure that all the staged resources are
+ valid. Run the following command:
+
+ ```bash
+ # Must be run from the "cert-manager/release" repo folder.
+ cmrel publish --release-name "$RELEASE_VERSION"
+ ```
+
+ You can view the progress by clicking the Google Cloud Build URL in the
+ output of this command.
+
+ 2. While the build is running, send a third Slack message in reply to the first message:
+
+
+ Follow the `cmrel publish` dry-run build: https://console.cloud.google.com/cloud-build/builds16f6f875-0a23-4fff-b24d-3de0af207463?project=1021342095237
+
+
+ 3. Now publish the release artifacts for real. The following command will publish the artifacts to GitHub, `Quay.io` and to our
+ [helm chart repository](https://charts.jetstack.io):
+
+ ```bash
+ # Must be run from the "cert-manager/release" repo folder.
+ cmrel publish --nomock --release-name "$RELEASE_VERSION"
+ ```
+
+
+
+ 4. While the build is running, send a fourth Slack message in reply to the first message:
+
+
+ Follow the cmrel publish build: https://console.cloud.google.com/cloud-build/builds/b6fef12b-2e81-4486-9f1f-d00592351789?project=1021342095237
+
+
+9. Publish the GitHub release:
+
+ 1. Visit the draft GitHub release and paste in the release notes that you
+ generated earlier. You will need to manually edit the content to match
+ the style of earlier releases. In particular, remember to remove
+ package-related changes.
+
+ 2. **(initial alpha, subsequent alpha and beta only)** Tick the box "This is
+ a pre-release".
+
+ 3. **(final release and patch release)** Tick the box "Set as the latest
+ release".
+
+ 4. Click "Publish" to make the GitHub release live.
+
+10. Merge the pull request containing the Helm chart:
+
+ The Helm charts for cert-manager are served using Cloudflare pages
+ and the Helm chart files and metadata are stored in the [Jetstack charts repository](https://github.com/jetstack/jetstack-charts).
+ The `cmrel publish --nomock` step (above) will have created a PR in this repository which you now have to review and merge, as follows:
+
+ 1. [Visit the pull request](https://github.com/jetstack/jetstack-charts/pulls)
+ 2. Review the changes
+ 3. Fix any failing checks
+ 4. Merge the PR
+ 5. Check that the [cert-manager Helm chart is visible on ArtifactHUB](https://artifacthub.io/packages/helm/cert-manager/cert-manager).
+
+11. **(final release only)** Add the new final release to the
+ [supported-releases](../installation/supported-releases.md) page.
+
+12. Open a PR for a [Homebrew](https://brew.sh) formula update for `cmctl`.
+
+ Assuming you have `brew` installed, you can use the `brew bump-formula-pr`
+ command to do this. You'll need the new tag name and the commit hash of that
+ tag. See `brew bump-formula-pr --help` for up to date details, but the command
+ will be of the form:
+
+ ```bash
+ brew bump-formula-pr --dry-run --tag v0.10.0 --revision da3265115bfd8be5780801cc6105fa857ef71965 cmctl
+ ```
+
+ Replacing the tag and revision with the new ones.
+
+ This will take time for the Homebrew team to review. Once the pull reqeust
+ against https://github.com/homebrew/homebrew-core has been opened, continue
+ with further release steps.
+
+13. Post a Slack message as an answer to the first message. Toggle the check
+ box "Also send to `#cert-manager-dev`" so that the message is well
+ visible. Also cross-post the message on `#cert-manager`.
+
+
+ https://github.com/cert-manager/cert-manager/releases/tag/v1.0.0 🎉
+
+
+14. **(final release only)** Show the release to the world:
+
+ 1. Send an email to
+ [`cert-manager-dev@googlegroups.com`](https://groups.google.com/g/cert-manager-dev)
+ with the `release` label
+ ([examples](https://groups.google.com/g/cert-manager-dev?label=release)).
+
+ 2. Send a tweet on the cert-manager Twitter account! Login details are in Jetstack's 1password (for now).
+ ([Example tweet](https://twitter.com/CertManager/status/1612886311957831680)). Make sure [@JetstackHQ](https://twitter.com/JetstackHQ) retweets it!
+
+ 3. Send a toot from the cert-manager Mastodon account! Login details are in Jetstack's 1password (for now).
+ ([Example toot](https://infosec.exchange/@CertManager/109666434738850493))
+
+15. Proceed to the post-release steps:
+
+ 1. **(initial beta only)** Create a PR on
+ [cert-manager/release](https://github.com/cert-manager/release) in order to
+ add the new release to our list of periodic ProwJobs. Use [this PR](https://github.com/jetstack/testing/pull/774/) as an example.
+
+ 2. **(initial beta only)** Run `cmrel generate-prow --branch='*' -o file` with the new version from the previous step and
+ open a PR to [cert-manager/testing](https://github.com/jetstack/testing) adding the generated prow configs.
+ Use [this PR](https://github.com/jetstack/testing/pull/766) as an example.
+
+ 3. If needed, open a PR to
+ [`cert-manager/website`](https://github.com/cert-manager/website) in
+ order to:
+
+ - Update the section "How we determine supported Kubernetes versions" on
+ the [supported-releases](../installation/supported-releases.md) page.
+ - Add any new release notes, if needed.
+
+ 4. **(final release only)** Create a PR on
+ [cert-manager/release](https://github.com/cert-manager/release),
+ removing the now unsupported release version (2 versions back) in this file:
+
+ ```plain
+ prowspecs/specs.go
+ ```
+
+ This will remove the periodic ProwJobs for this version as they're no longer needed.
+
+ 5. **(final release only)** Run `cmrel generate-prow --branch='*' -o file` with the new version from the previous step and
+ open a PR to [jetstack/testing](https://github.com/jetstack/testing) adding the generated prow configs.
+
+ 6. **(final release only)** Open a PR to [`jetstack/testing`](https://github.com/jetstack/testing)
+ and update the [milestone_applier](https://github.com/jetstack/testing/blob/3110b68e082c3625bf0d26265be2d29e41da14b2/config/plugins.yaml#L69)
+ config so that newly raised PRs on master are applied to a new milestone
+ for the next release. E.g. if master currently points at the `v1.10` milestone, change it to point at `v1.11`.
+
+ If the [milestone](https://github.com/cert-manager/cert-manager/milestones) for the next release doesn't exist,
+ create it first. If you consider the milestone for the version you just released to be complete, close it.
+
+ 7. **(final release only)** Open a PR to
+ [`cert-manager/website`](https://github.com/cert-manager/website) in
+ order to:
+
+ - Update the section "Supported releases" in the
+ [supported-releases](../installation/supported-releases.md) page.
+ - Update the section "How we determine supported Kubernetes versions" on
+ the [supported-releases](../installation/supported-releases.md) page.
+ In the table, set "n/a" for the line where "next periodic" is since
+ these tests will be disabled until we do our first alpha.
+ - Update the [API docs](../reference/api-docs.md) and [CLI docs](../cli/README.md) by running `scripts/gendocs/generate`
+ and commit any changes to a branch and create a PR to merge those into
+ `master` or `release-next` depending on whether this is a minor or
+ patch release.
+
+ 8. Ensure that any installation commands in
+ [`cert-manager/website`](https://github.com/cert-manager/website) install
+ the latest version. This should be done after every release, including
+ patch releases as we want to encourage users to always install the latest
+ patch. In addition, ensure that release notes for the latest version are added.
+
+ 9. Open a PR against the Krew index such as [this one](https://github.com/kubernetes-sigs/krew-index/pull/1724),
+ bumping the versions of our kubectl plugins. This is likely only worthwhile if
+ cmctl / kubectl plugin functionality has changed significantly or after the first release of a new major version.
+
+ 10. Create a new OLM package and publish to OperatorHub
+
+ cert-manager can be [installed](https://cert-manager.io/docs/installation/operator-lifecycle-manager/) using Operator Lifecycle Manager (OLM)
+ so we need to create OLM packages for each cert-manager version and publish them to both
+ [`operatorhub.io`](https://operatorhub.io/operator/cert-manager) and the equivalent package index for RedHat OpenShift.
+
+ Follow [the cert-manager OLM release process](https://github.com/cert-manager/cert-manager-olm#release-process) and, once published,
+ [verify that the cert-manager OLM installation instructions](https://cert-manager.io/docs/installation/operator-lifecycle-manager/) still work.
+
+## Older Releases
+
+The above guide only applies for versions of cert-manager from v1.8 and newer.
+
+Older versions were built using Bazel and this difference in build process is reflected in the release process.
+
+### cert-manager 1.6 and 1.7
+
+Follow [this older version][older-release-process] of the release process on GitHub, rather than the guide on this website.
+
+The most notable difference is you'll call `cmrel stage` rather than `cmrel makestage`. You should be fine to use the latest
+version of `cmrel` to do the release.
+
+### cert-manager 1.5 and earlier
+
+If you're releasing version 1.5 or earlier you must also be sure to install a different version of `cmrel`.
+
+In the step where you install `cmrel`, you'll want to run the following instead:
+
+```bash
+go install github.com/cert-manager/release/cmd/cmrel@cert-manager-pre-1.6
+```
+
+This will ensure that the version of `cmrel` you're using is compatible with the version of cert-manager you're releasing.
+
+In addition, when you check out the `cert-manager/release` repository you should be sure to check out the `cert-manager-pre-1.6` tag in that repo:
+
+```bash
+git checkout cert-manager-pre-1.6
+```
+
+Other than the different `cert-manager/release` tag and `cmrel` version, you can follow the [same older release documentation][older-release-process] as
+is used for 1.6 and 1.7 - just remember to change the version of `cmrel` you install!
+
+[older-release-process]: https://github.com/cert-manager/website/blob/6fa0db74de0ae17d7be638a08155d1b4e036aaa9/content/en/docs/contributing/release-process.md?plain=1
diff --git a/content/v1.12-docs/contributing/security.md b/content/v1.12-docs/contributing/security.md
new file mode 100644
index 00000000000..6d33165ede1
--- /dev/null
+++ b/content/v1.12-docs/contributing/security.md
@@ -0,0 +1,13 @@
+---
+title: Reporting Security Issues
+description: 'cert-manager contributing: Security policy'
+---
+
+Security is the number one priority for cert-manager. If you think you've
+found a vulnerability in any cert-manager project, please follow the
+[vulnerability reporting process](https://github.com/cert-manager/cert-manager/blob/master/SECURITY.md)
+documented in the main cert-manager repository.
+
+The reporting process is the same for all repositories under the
+cert-manager organization. The process is documented in one place to ensure
+a single source of truth and a single list of [security contacts](https://github.com/cert-manager/cert-manager/blob/master/SECURITY_CONTACTS.md).
\ No newline at end of file
diff --git a/content/v1.12-docs/contributing/sign-off.md b/content/v1.12-docs/contributing/sign-off.md
new file mode 100644
index 00000000000..2e0dd8cbfa3
--- /dev/null
+++ b/content/v1.12-docs/contributing/sign-off.md
@@ -0,0 +1,77 @@
+---
+title: DCO Sign Off
+description: 'cert-manager contributing: DCO Sign-off'
+---
+
+All contributors to the project retain copyright to their work, but must only submit
+work which they have the rights to submit.
+
+We require all contributors to acknowledge that they have the rights to the code they're contributing
+by signing their commits in git using a "DCO Sign Off". Note that this is different to "commit signing"
+using something like PGP or [`gitsign`](https://github.com/sigstore/gitsign)!
+
+Any copyright notices in a cert-manager repo should specify the authors as
+"The cert-manager Authors".
+
+To sign your work, pass the `--signoff` option to `git commit` or `git rebase`:
+
+```bash
+# Sign off a commit as you're making it
+git commit --signoff -m"my commit"
+
+# Add a signoff to the last commit you made
+git commit --amend --signoff
+
+# Rebase your branch against master and sign off every commit in your branch
+git rebase --signoff master
+```
+
+This will add a line similar to the following at the end of your commit:
+
+```text
+Signed-off-by: Joe Bloggs
+```
+
+By signing off a commit you're stating that you certify the following:
+
+```text
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+1 Letterman Drive
+Suite D4700
+San Francisco, CA, 94129
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+```
+
+That statement is taken from [https://developercertificate.org/](https://developercertificate.org/).
diff --git a/content/v1.12-docs/contributing/signing-keys.md b/content/v1.12-docs/contributing/signing-keys.md
new file mode 100644
index 00000000000..74d5382d862
--- /dev/null
+++ b/content/v1.12-docs/contributing/signing-keys.md
@@ -0,0 +1,72 @@
+---
+title: Signing Keys
+description: 'cert-manager contributing: Code signing / Signing keys'
+---
+
+This page describes the bootstrapping process for a key, including how to do it and why a bootstrapping
+process is required.
+
+## What do we Serve?
+
+To facilitate verification of signatures, we serve public key information from the cert-manager website
+directly. It's important to serve the keys from a different location to where the artifacts are hosted; if the
+keys were hosted at the same location as the artifacts, an attacker able to change the artifacts would be able
+to also change the keys!
+
+We serve several key types under `static/public-keys`:
+
+- `cert-manager-pgp-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.asc`: ASCII-armored PGP public key, used for verifying signatures on helm charts via `helm verify` (after being converted to a keyring)
+- `cert-manager-keyring-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg`: Old style GPG keyring, needed by the `--keyring` parameter to `helm verify`. See Keyring below.
+- `cert-manager-pubkey-2021-09-20.pem`: The raw, PEM-encoded public key used for signing. Cannot be used with GPG (and therefore helm), but should be used for other verification types.
+
+## Background / Architecture
+
+Code signing for cert-manager artifacts is done entirely using cloud KMS keys, to ensure that nobody
+can get access to the private keys in plain-text; all signing operations using the key are therefore
+done through cloud APIs and are logged.
+
+Currently, all keys are on Google KMS, since the rest of cert-manager's release infrastructure is also
+in GCP. The key - and the role bindings which allow access to it - are specified in terraform in a closed
+source Jetstack repo.
+
+## Why Bootstrap?
+
+While the private key is not retrievable for a KMS key, the public key is and _must_ be retrieved so that
+end-users can verify signatures made by the key. In GCP, retrieving the public key is itself an
+[API call](https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys.cryptoKeyVersions/getPublicKey)
+which returns the raw key in a PEM encoded format.
+
+That PEM-encoded public key works for some cases (e.g. verifying container signature made using `cosign`) but
+it's not sufficient for Helm chart verification, since Helm chart signing (sadly) requires the use of PGP.
+
+## Bootstrapping a PGP Identity
+
+It's possible to use a shim to use GCP KMS as a PGP key which enables us to avoid having two separate signing keys,
+but PGP public identities are slightly more complicated than plain public keys; they also contain a name,
+creation time, comment and email address to identify the signer. This public "identity" must itself be signed by the
+private key (to prove that the information in the identity is legitimate).
+
+This bootstrapping can be done using the cert-manager release tool, `cmrel`:
+
+```console
+# note that the key name might not exactly match this in the future
+$ cmrel bootstrap-pgp --key "projects/cert-manager-release/locations/europe-west1/keyRings/cert-manager-release/cryptoKeys/cert-manager-release-signing-key/cryptoKeyVersions/1"
+```
+
+This will trigger a cloud build job which will output both the armored PGP identity and the raw PEM public key; the values
+can be copied from the job output.
+
+### GPG Keyring
+
+As an additional UX feature, we can also generate a GPG keyring from the PGP identity, since the keyring is what's required
+by the Helm CLI to actually validate a chart:
+
+```console
+# Example of verifying a chart.
+$ helm verify --keyring cert_manager_keyring_1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg /path/to/chart.tgz
+Signed by: cert-manager Maintainers
+Using Key With Fingerprint: 1020....
+Chart Hash Verified: sha256:bb86...
+```
+
+The keyring can be generated using [this script](https://github.com/cert-manager/release/blob/a219e18b2e64ef078bf73b3641d589b43d1fccb8/hack/helm_keyring.sh).
\ No newline at end of file
diff --git a/content/v1.12-docs/contributing/third-party-code-donation.md b/content/v1.12-docs/contributing/third-party-code-donation.md
new file mode 100644
index 00000000000..f53da8e3c67
--- /dev/null
+++ b/content/v1.12-docs/contributing/third-party-code-donation.md
@@ -0,0 +1,79 @@
+---
+title: Donating Third Party Code to cert-manager
+description: 'cert-manager contributing: Third party code donations'
+---
+
+The cert-manager project welcomes external contributions and has benefited greatly from thousands
+of commits from hundreds of different contributors. Most code is usually committed through pull
+requests to a specific repo, whether that be the main cert-manager repository or one of the associated
+repositories such as the website.
+
+Some contributions aren't as well suited to that kind of workflow, however. That would most likely
+be because their functionality doesn't belong in any particular existing cert-manager repo, while still
+relating to the cert-manager project.
+
+This document aims to address the donation of code to the cert-manager project, and to provide a
+framework for sustainable contributions which can be tested and relied upon going forwards by both
+cert-manager maintainers and users.
+
+The requirements in this document are based in part on what's done for CoreDNS, Envoy, Kubernetes
+and containerd.
+
+## Requirements
+
+1. Code must be licensed appropriately, including any dependencies
+ We'd prefer [Apache 2.0](https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)) since that's
+ what cert-manager [uses](https://github.com/cert-manager/cert-manager/blob/master/LICENSE), but the
+ license must be [OSI approved](https://opensource.org/licenses).
+2. Code must conform to CNCF standards and due diligence requirements
+ You don't need to go over this with a fine-toothed comb; the intent here is that no code donation
+ should have a negative effect on cert-manager's progress as a CNCF project. See the
+ [CNCF due diligence template](https://github.com/cncf/toc/blob/main/process/dd-review-template.md)
+3. Must be sponsored by an existing maintainer
+ An existing regular contributor to cert-manager must sponsor the adoption of any third party code
+ donation. This ensures that there's a single point of contact for the party donating the code.
+4. Must pass cert-manager conformance tests
+ This might not apply to all donations, but where conformance tests exist any donated code must
+ pass them. E.g. for [external issuers](https://github.com/cert-manager/cert-manager/blob/dffbf391dbb0fc6c1cfea62e561a9c6f54362ab0/test/e2e/suite/conformance/certificates/external/external.go#L41-L62)
+5. Must provide a point-of-contact for questions about the project for at least 3 months after acceptance
+ We don't anticipate that we'd need to reach out often after the donation has been accepted,
+ but it's important to have someone we can reach out to if we need to.
+6. The donation must be a defined extension type or justify why it doesn't belong in the main repositories
+ E.g. an ACME DNS solver, a custom issuer or an ACME HTTP solver
+7. Code must have a similar level of quality to cert-manager itself
+ This could be enforced by, for example, running static analysis tools on the code base similar to
+ those used by cert-manager.
+8. Code must have a non-trivial test suite, including both unit tests and end-to-end tests
+ These tests must be able to be run in their entirety after a PR is raised against the repo. We don't
+ need 100% code coverage, but there should be tests for important functionality.
+9. The project must adopt the cert-manager security policy and link back to the policy, as in e.g.
+ the [istio-csr `SECURITY.md`](https://github.com/cert-manager/istio-csr/blob/master/SECURITY.md)
+10. Must have DCO sign-offs or coverage for all commits
+ To ensure that all code can legally be donated, all commits should have DCO sign-off or else have
+ a positive affirmation made by each contributor prior to donation. See below.
+
+## Preferences
+
+These items are not absolutely necessary but they definitely help if a code donation is to be accepted.
+
+- Should be written in Go
+ We don't _need_ code to be written in Go, but we'd much prefer that it is. Since cert-manager itself
+ is written in Go, code donations in Go allow us to use existing experience and tooling on Go code.
+
+## DCO Signoff
+
+As a method of ensuring that the donator has permission to donate the code, we require DCO sign-offs -
+or something equivalent - to be in place at the time of the donation.
+
+The cert-manager [DCO signoff process](https://cert-manager.io/docs/contributing/sign-off/)
+would be appropriate. Existing contributors could bootstrap this process by creating an empty signed-off
+with a note that previous code should be considered signed off as of that commit:
+
+```bash
+git commit --allow-empty --signoff --message="bootstrapping DCO signoff for past commits"
+```
+
+## After Donation
+
+Code files in the donated repository must be updated to include the relevant
+[cert-manager boilerplate](https://github.com/cert-manager/cert-manager/blob/master/hack/boilerplate/boilerplate.go.txt)
\ No newline at end of file
diff --git a/content/v1.12-docs/faq/README.md b/content/v1.12-docs/faq/README.md
new file mode 100644
index 00000000000..9bb31f91b55
--- /dev/null
+++ b/content/v1.12-docs/faq/README.md
@@ -0,0 +1,182 @@
+---
+title: Frequently Asked Questions (FAQ)
+description: Find answers to some frequently asked questions about cert-manager
+---
+
+On this page you will find answers to some frequently asked questions about cert-manager.
+
+## Terminology
+
+### What does `publicly trusted` and `self-signed` mean?
+
+These terms are defined in the [TLS Terminology page](../reference/tls-terminology.md).
+
+### What do the terms `root`, `intermediate` and `leaf` _certificate_ mean?
+
+These terms are defined in the [TLS Terminology page](../reference/tls-terminology.md).
+
+## Certificates
+
+### Can I trigger a renewal from cert-manager at will?
+
+This is a feature in cert-manager starting in `v0.16` using the `cmctl` CLI. More information can be found on [the renew command's page](../reference/cmctl.md#renew)
+
+### When do certs get re-issued?
+
+To determine if a certificate needs to be re-issued, cert-manager looks at the the spec of `Certificate` resource and latest `CertificateRequest`s as well as the data in `Secret` containing the X.509 certificate.
+
+The issuance process will always get triggered if the:
+
+- `Secret` named on `Certificate`'s spec, does not exist, is missing private key or certificate data or contains corrupt data
+- private key stored in the `Secret` does not match the private key spec on `Certificate`
+- public key of the issued certificate does not match the private key stored in the `Secret`
+- cert-manager issuer annotations on the `Secret` do not match the issuer specified on the `Certificate`
+- DNS names, IP addresses, URLS or email addresses on the issued certificate do not match those on the `Certificate` spec
+- certificate needs to be renewed (because it has expired or the renewal time is now or in the past)
+- certificate has been marked for renewal manually [using `cmctl`](../reference/cmctl.md#renew)
+
+Additionally, if the latest `CertificateRequest` for the `Certificate` is found, cert-manager will also re-issue if:
+
+- the common name on the CSR found on the `CertificateRequest` does not match that on the `Certificate` spec
+- the subject fields on the CSR found on the `CertificateRequest` do not match the subject fields of the `Certificate` spec
+- the duration on the `CertificateRequest` does not match the duration on the `Certificate` spec
+- `isCA` field value on the `Certificate` spec does not match that on the `CertificateRequest`
+- the DNS names, IP addresses, URLS or email addresses on the `CertificateRequest` spec do not match those on the `Certificate` spec
+- key usages on the `CertificateRequest` spec do not match those on the `Certificate` spec
+
+Note that for certain fields re-issuance on change gets triggered only if there
+is a `CertificateRequest` that cert-manager can use to determine whether
+`Certificate`'s spec has changed since the previous issuance. This is because
+some issuers may not respect the requested values for these fields, so we cannot
+rely on the values in the issued X.509 certificates. One such field is
+`.spec.duration`- change to this field will only trigger re-issuance if there is
+a `CertificateRequest` to compare with. In case where you need to re-issue, but
+re-issuance does not get triggered automatically due to there being no
+`CertificateRequest` (i.e after backup and restore), you can use [`cmctl
+renew`](../reference/cmctl.md#renew) to trigger it manually.
+
+### Why isn't my root certificate in my issued Secret's `tls.crt`?
+
+Occasionally, people work with systems which have made a flawed choice regarding TLS chains. The [TLS spec](https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.2)
+has the following section for the "Server Certificate" section of the TLS handshake:
+
+> This is a sequence (chain) of certificates. The sender's
+> certificate MUST come first in the list. Each following
+> certificate MUST directly certify the one preceding it. Because
+> certificate validation requires that root keys be distributed
+> independently, the self-signed certificate that specifies the root
+> certificate authority MAY be omitted from the chain, under the
+> assumption that the remote end must already possess it in order to
+> validate it in any case.
+
+In a standard, secure and correctly configured TLS environment, adding a root certificate to the chain is
+almost always unnecessary and wasteful.
+
+There are two ways that a certificate can be trusted:
+
+- explicitly, by including it in a trust store.
+- through a signature, by following the certificate's chain back up to an explicitly trusted certificate.
+
+Crucially, root certificates are by definition self-signed and they cannot be validated through a signature.
+
+As such, if we have a client trying to validate the certificate chain sent by the server, the client must already have the
+root before the connection is started. If the client already has the root, there was no point in it being sent by the server!
+
+The same logic with not sending root certificates applies for servers trying to validate client certificates;
+the [same justification](https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.6) is given in the TLS RFC.
+
+### How can I see all the historic events related to a certificate object?
+
+cert-manager publishes all events to the Kubernetes events mechanism, you can get the events for your specific resources using `kubectl describe `.
+
+Due to the nature of the Kubernetes event mechanism these will be purged after a while. If you're using a dedicated logging system it might be able or is already also storing Kubernetes events.
+
+### What happens if issuance fails? Will it be retried?
+
+{/* This empty link preserves old links to #what-happens-if-a-renewal-doesn't happen?-will-it-be-tried-again-after-some-time?", which matched the old title of this section */}
+
+
+
+cert-manager will retry a failed issuance except for a few rare edge cases where
+manual intervention is needed.
+
+We aim to retry after a short delay in case of ephemeral failures such as
+network connection errors and with a longer exponentially increasing delay after
+'terminal' failures.
+
+You can observe that latest issuance has terminally failed if the `Certificate`
+has `Issuing` condition set to false and has `status.lastFailureTime` set. In
+this case the issuance will be retried after an exponentially increasing delay
+(1 to 32 hours) by creating a new `CertficateRequest`. You can trigger an
+immediate renewal using the [`cmctl renew`
+command](../reference/cmctl.md#renew). Terminal failures occur if the issuer
+sets the `CertificateRequest` to failed (for example if CA rejected the request
+due to a rate limit being reached) or invalid or if the `CertificateRequest`
+gets denied by an approver.
+
+Ephemeral failures result in the same `CertificateRequest` being re-synced after
+a short delay (up to 5 minutes). Typically they can only be observed in
+cert-manager controller logs.
+
+If it appears the issuance has got stuck and `cmctl renew` does not work, you
+can delete the latest `CertificateRequest`. This is mostly a harmless action
+(the worst that could happen is duplicate issuance if there was a potentially
+successful one in progress), but we do aim for this to not be part of user flow-
+do reach out if you think you have found a case where the flow could be
+improved.
+
+### Is ECC (elliptic-curve cryptography) supported?
+
+cert-manager supports ECDSA key pairs! You can set your certificate to use ECDSA in the `privateKey` part of your Certificate resource.
+
+For example:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: ecdsa
+spec:
+ secretName: ecdsa-cert
+ isCA: false
+ privateKey:
+ algorithm: ECDSA
+ size: 256
+ dnsNames:
+ - ecdsa.example.com
+ issuerRef:
+ [...]
+```
+
+### If `renewBefore` or `duration` is not defined, what will be the default value?
+
+Default `duration` is [90 days](https://github.com/cert-manager/cert-manager/blob/v1.2.0/pkg/apis/certmanager/v1/const.go#L26). If `renewBefore` has not been set, `Certificate` will be renewed 2/3 through its _actual_ duration.
+
+## Miscellaneous
+
+### Kubernetes has a builtin `CertificateSigningRequest` API. Why not use that?
+
+Kubernetes has a [Certificate Signing Requests API],
+and a [`kubectl certificates` command] which allows you to approve certificate signing requests
+and have them signed by the certificate authority (CA) of the Kubernetes cluster.
+
+This API and CLI have occasionally been misused to sign certificates for use by non-control-plane Pods but this is a mistake.
+For the security of the Kubernetes cluster, it is important to limit access to the Kubernetes certificate authority,
+and it is important that you do not use that certificate authority to sign certificates which are used outside of the control-plane,
+because such certificates increase the opportunity for attacks on the Kubernetes API server.
+
+In Kubernetes 1.19 the [Certificate Signing Requests API] has reached V1
+and it can be used more generally by following (or automating) the [Request Signing Process].
+
+cert-manager currently has some [limited experimental support] for this resource.
+
+[Certificate Signing Requests API]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#certificatesigningrequest-v1-certificates-k8s-io
+[`kubectl certificates` command]: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#certificate
+[Request signing process]: https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/#request-signing-process
+[limited experimental support]: ../usage/kube-csr.md
+
+### How to write "cert-manager"
+
+cert-manager should always be written in lowercase. Even when it would normally be
+capitalized such as in titles or at the start of sentences. A hyphen should always be
+used between the words, don't replace it with a space and don't remove it.
diff --git a/content/v1.12-docs/getting-started/README.md b/content/v1.12-docs/getting-started/README.md
new file mode 100644
index 00000000000..c358360f498
--- /dev/null
+++ b/content/v1.12-docs/getting-started/README.md
@@ -0,0 +1,36 @@
+---
+title: Getting Started with cert-manager
+description: Quick start guides for cert-manager
+---
+
+
+
+ Learn how to deploy cert-manager and how to configure it to get certificates for the **NGINX Ingress controller** from **Let's Encrypt**.
+
+
+
+
+
+ Learn how to deploy cert-manager on **Google Kubernetes Engine** and how to configure it to get certificates for Ingress, from **Let's Encrypt**.
+
+
+
+
+
+ Learn how to deploy cert-manager on **Azure Kubernetes Service (AKS)** and how to configure it to get certificates for an HTTPS web server, from **Let's Encrypt**.
+
diff --git a/content/v1.12-docs/installation/README.md b/content/v1.12-docs/installation/README.md
new file mode 100644
index 00000000000..df829ac3d17
--- /dev/null
+++ b/content/v1.12-docs/installation/README.md
@@ -0,0 +1,41 @@
+---
+title: Installation
+description: Learn about the various ways you can install cert-manager and how to choose between them
+---
+
+Learn about the various ways you can install cert-manager and how to choose between them.
+
+## Default static install
+
+> You don't require any tweaking of the cert-manager install parameters.
+
+The default static configuration can be installed as follows:
+
+```bash
+kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml
+```
+
+📖 Read more about [installing cert-manager using kubectl apply and static manifests](./kubectl.md).
+
+## Getting started
+
+> You quickly want to learn how to use cert-manager and what it can be used for.
+
+📖 **kubectl apply**: For new users we recommend [installing cert-manager using kubectl apply and static manifests](./kubectl.md).
+
+📖 **helm**: You can [use helm to install cert-manager](./helm.md) and this also allows you to customize the installation if necessary.
+
+📖 **OperatorHub**: If you have an OpenShift cluster, consider [installing cert-manager via OperatorHub](./operator-lifecycle-manager.md),
+which you can do from the OpenShift web console.
+
+🚧 **cmctl**: Try the [experimental `cmctl x install` command](../reference/cmctl.md#install) to quickly install cert-manager.
+
+## Continuous deployment
+
+> You know how to configure your cert-manager setup and want to automate this.
+
+📖 **helm**: You can use [the cert-manager Helm chart](./helm.md) directly with systems like Flux, ArgoCD and Anthos.
+
+📖 **helm template**: You can use `helm template` to generate customized cert-manager installation manifests.
+See [Output YAML using helm template](./helm.md#output-yaml) for more details.
+This templated cert-manager manifest can be piped into your preferred deployment tool.
diff --git a/content/v1.12-docs/installation/api-compatibility.md b/content/v1.12-docs/installation/api-compatibility.md
new file mode 100644
index 00000000000..e31b96ae297
--- /dev/null
+++ b/content/v1.12-docs/installation/api-compatibility.md
@@ -0,0 +1,22 @@
+---
+title: API compatibility
+description: cert-manager API compatibility guarantees
+---
+
+cert-manager aims to abide by the same API compatibility policy as upstream Kubernetes APIs as documented in the [Kubernetes Deprecation Policy](https://kubernetes.io/docs/reference/using-api/deprecation-policy/#deprecating-parts-of-the-api).
+
+This is to ensure a smooth upgrade and downgrade experience for users, i.e to make sure that users' cert-manager custom resources keep functioning in the same way
+after an upgrade or downgrade of cert-manager.
+
+In some cases, we may need to require users to take actions before upgrading or may need to diverge from the API compatibility promise but we'll treat this as an absolute
+last resort. In general the main criteria by which we'd determine whether a change is acceptable would be user value.
+
+For example in the event of a truly critical bug, a fix that breaks the API compatibility promise by changing the default behavior of an API field _might_ be acceptable. As of yet, though, there has never been a need for such a change.
+
+## Alpha / Beta API Versions
+
+As in upstream Kubernetes, We don't commit to preserving alpha or beta API versions indefinitely.
+
+In cert-manager v1.7 [all alpha and beta API versions prior to `v1` were removed](https://github.com/cert-manager/cert-manager/pull/4635).
+
+NB: The Kubernetes deprecation policy notes that API removal introduces an issue with objects stored at the removed versions. To fix this, we wrote a [custom tool](https://cert-manager.io/docs/installation/upgrading/remove-deprecated-apis/) that users could run once to migrate their resources.
diff --git a/content/v1.12-docs/installation/best-practice.md b/content/v1.12-docs/installation/best-practice.md
new file mode 100644
index 00000000000..f2ca51b6039
--- /dev/null
+++ b/content/v1.12-docs/installation/best-practice.md
@@ -0,0 +1,48 @@
+---
+title: Best Practice
+description: Learn how to deploy cert-manager to comply with popular security standards such as those produced by the CIS, NSA, and BSI.
+---
+
+Learn how to deploy cert-manager to comply with popular security standards such as
+the [CIS Kubernetes Benchmark](https://www.cisecurity.org/benchmark/kubernetes/),
+the [NSA Kubernetes Hardening Guide](https://media.defense.gov/2022/Aug/29/2003066362/-1/-1/0/CTR_KUBERNETES_HARDENING_GUIDANCE_1.2_20220829.PDF), or
+the [BSI Kubernetes Security Recommendations](https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Grundschutz/International/bsi_it_gs_comp_2022.pdf?__blob=publicationFile&v=2#page=475).
+
+## Overview
+
+The default cert-manager resources in the Helm chart or YAML manifests (Deployment, Pod, ServiceAccount etc) are designed for backwards compatibility rather than for best practice or maximum security.
+You may find that the default resources do not comply with the security policy on your Kubernetes cluster
+and in that case you can modify the installation configuration using Helm chart values to override the defaults.
+
+## Restrict Auto-Mount of Service Account Tokens
+
+This recommendation is described in the [Kyverno Policy Catalogue](https://kyverno.io/policies/other/restrict_automount_sa_token/restrict_automount_sa_token/) as follows:
+> Kubernetes automatically mounts ServiceAccount credentials in each Pod. The
+> ServiceAccount may be assigned roles allowing Pods to access API resources.
+> Blocking this ability is an extension of the least privilege best practice and
+> should be followed if Pods do not need to speak to the API server to function.
+> This policy ensures that mounting of these ServiceAccount tokens is blocked
+
+The cert-manager components *do* need to speak to the API server but we still recommend setting `automountServiceAccountToken: false` for the following reasons:
+1. Setting `automountServiceAccountToken: false` will allow cert-manager to be installed on clusters where Kyverno (or some other policy system) is configured to deny Pods that have this field set to `true`. The Kubernetes default value is `true`.
+2. With `automountServiceAccountToken: true`, *all* the containers in the Pod will mount the ServiceAccount token, including side-car and init containers that might have been injected into the cert-manager Pod resources by Kubernetes admission controllers.
+ The principle of least privilege suggests that it is better to explicitly mount the ServiceAccount token into the cert-manager containers.
+
+So it is recommended to set `automountServiceAccountToken: false` and manually add a projected `Volume` to each of the cert-manager Deployment resources, containing the ServiceAccount token, CA certificate and namespace files that would normally be [added automatically by the Kubernetes ServiceAccount controller](https://github.com/kubernetes/kubernetes/blob/3992eda8e61725c470fb6141a7fe4e7f9ee31ea5/plugin/pkg/admission/serviceaccount/admission.go#L421-L460),
+and to explicitly add a read-only `VolumeMount` to each of the cert-manager containers.
+
+An example of this configuration is included in the Helm Chart Values file below.
+
+## Best Practice Helm Chart Values
+
+Download the following Helm chart values file and supply it to `helm install`, `helm upgrade`, or `helm template` using the `--values` flag:
+
+🔗 `values.best-practice.yaml`
+```yaml file=../../../public/docs/installation/best-practice/values.best-practice.yaml
+```
+
+## Other
+
+This list of recommendations is a work-in-progress.
+If you have other best practice recommendations please [contribute to this page](../contributing/contributing-flow.md).
+
diff --git a/content/v1.12-docs/installation/code-signing.md b/content/v1.12-docs/installation/code-signing.md
new file mode 100644
index 00000000000..cd05c04f2fe
--- /dev/null
+++ b/content/v1.12-docs/installation/code-signing.md
@@ -0,0 +1,59 @@
+---
+title: cert-manager Signature Verification
+description: 'cert-manager installation: Code signing'
+---
+
+To help prevent [supply chain attacks](https://en.wikipedia.org/wiki/Supply_chain_attack), some cert-manager release
+artifacts are cryptographically signed so you can be sure that the version of cert-manager you're about to install
+is actually built by and provided by the cert-manager maintainers.
+
+This signing is vitally important if for any reason you need to use a mirrored version of cert-manager; it allows you
+to confirm that the mirror hasn't tampered with the code you're about to install.
+
+Signing keys required for verification are all available on this website, but the actual key that you need might depend
+on the artifact you're trying to validate in the future. At the time of writing, all signing is done using the same underlying
+key.
+
+## Container Images / Cosign
+
+For all cert-manager versions from `v1.8.0` and later, cert-manager container images are signed and verifiable using [`cosign`](https://docs.sigstore.dev/cosign/overview).
+
+The simplest way to verify signatures is to download the public key and then pass it to the cosign CLI directly:
+
+```console
+curl -sSOL https://cert-manager.io/public-keys/cert-manager-pubkey-2021-09-20.pem
+IMAGE_TAG=v1.11.0 # change as needed
+cosign verify --signature-digest-algorithm sha512 --key cert-manager-pubkey-2021-09-20.pem quay.io/jetstack/cert-manager-acmesolver:$IMAGE_TAG
+cosign verify --signature-digest-algorithm sha512 --key cert-manager-pubkey-2021-09-20.pem quay.io/jetstack/cert-manager-cainjector:$IMAGE_TAG
+cosign verify --signature-digest-algorithm sha512 --key cert-manager-pubkey-2021-09-20.pem quay.io/jetstack/cert-manager-ctl:$IMAGE_TAG
+cosign verify --signature-digest-algorithm sha512 --key cert-manager-pubkey-2021-09-20.pem quay.io/jetstack/cert-manager-controller:$IMAGE_TAG
+cosign verify --signature-digest-algorithm sha512 --key cert-manager-pubkey-2021-09-20.pem quay.io/jetstack/cert-manager-webhook:$IMAGE_TAG
+```
+
+For a more fully-featured signature verification process in Kubernetes, check out [`connaisseur`](https://sse-secure-systems.github.io/connaisseur/).
+
+- PEM-encoded public key: [`cert-manager-pubkey-2021-09-20.pem`](https://cert-manager.io/public-keys/cert-manager-pubkey-2021-09-20.pem)
+
+## Helm Charts
+
+
+Helm requires the use of PGP for verification; the key format is different.
+
+Trying to use "plain" PEM encoded public keys during verification will fail.
+
+
+For all cert-manager versions from `v1.6.0` and later, Helm charts are signed and verifiable through the Helm CLI.
+
+The easiest way to verify is to grab the GPG keyring directly, which can then be passed into `helm verify` like so:
+
+```console
+curl -sSL https://cert-manager.io/public-keys/cert-manager-keyring-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg > cert-manager-keyring-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg
+helm verify --keyring cert-manager-keyring-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg /path/to/cert-manager-vx.y.z.tgz
+```
+
+- GPG keyring: [`cert-manager-keyring-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg`](https://cert-manager.io/public-keys/cert-manager-keyring-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg)
+
+If you know what you're doing and you want the signing key in a format that's easy to import into GPG,
+it's available in an ASCII armored version:
+
+- ASCII-armored signing key: [`cert-manager-pgp-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.asc`](https://cert-manager.io/public-keys/cert-manager-pgp-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.asc)
diff --git a/content/v1.12-docs/installation/compatibility.md b/content/v1.12-docs/installation/compatibility.md
new file mode 100644
index 00000000000..516bc941a0b
--- /dev/null
+++ b/content/v1.12-docs/installation/compatibility.md
@@ -0,0 +1,114 @@
+---
+title: Compatibility with Kubernetes Platform Providers
+description: 'cert-manager installation: Cloud provider compatibility'
+---
+
+Below you will find details on various compatibility issues and quirks that you
+may be affected by when deploying cert-manager. If you believe we've missed something
+please feel free to raise an issue or a pull request with the details!
+
+
+If you're using AWS Fargate or else if you've specifically configured
+cert-manager to run the host's network, be aware that kubelet listens on port
+`10250` by default which clashes with the default port for the cert-manager
+webhook.
+
+As such, you'll need to change the webhook's port when setting up cert-manager.
+
+For installations using Helm, you can set the `webhook.securePort` parameter
+when installing cert-manager either using a command line flag or an entry in
+your `values.yaml` file.
+
+If you have a port clash, you could see confusing error messages regarding
+untrusted certs. See [#3237](https://github.com/cert-manager/cert-manager/issues/3237)
+for more details.
+
+
+## GKE
+
+When Google configure the control plane for private clusters, they automatically
+configure VPC peering between your Kubernetes cluster's network and a separate
+Google-managed project.
+
+In order to restrict what Google are able to access within your cluster, the
+firewall rules configured restrict access to your Kubernetes pods. This means
+that the webhook won't work, and you'll see errors such as
+`Internal error occurred: failed calling admission webhook ... the server is
+currently unable to handle the request`.
+
+In order to use the webhook component with a GKE private cluster, you must
+configure an additional firewall rule to allow the GKE control plane access to
+your webhook pod.
+
+You can read more information on how to add firewall rules for the GKE control
+plane nodes in the [GKE
+docs](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#add_firewall_rules).
+
+
+### GKE Autopilot
+
+GKE Autopilot mode with Kubernetes < 1.21 does not support cert-manager,
+due to a [restriction on mutating admission webhooks](https://github.com/cert-manager/cert-manager/issues/3717).
+
+As of October 2021, only the "rapid" Autopilot release channel has rolled
+out version 1.21 for Kubernetes masters. Installation via the helm chart
+may end in an error message but cert-manager is reported to be working by
+some users. Feedback and PRs are welcome.
+
+**Problem**: GKE Autopilot does not allow modifications to the `kube-system`-namespace.
+
+Historically we've used the `kube-system` namespace to prevent multiple installations of cert-manager in the same cluster.
+
+Installing cert-manager in these environments with default configuration can cause issues with bootstrapping.
+Some signals are:
+
+* `cert-manager-cainjector` logging errors like:
+
+```text
+E0425 09:04:01.520150 1 leaderelection.go:334] error initially creating leader election record: leases.coordination.k8s.io is forbidden: User "system:serviceaccount:cert-manager:cert-manager-cainjector" cannot create resource "leases" in API group "coordination.k8s.io" in the namespace "kube-system": GKEAutopilot authz: the namespace "kube-system" is managed and the request's verb "create" is denied
+```
+
+* `cert-manager-startupapicheck` not completing and logging messages like:
+
+```text
+Not ready: the cert-manager webhook CA bundle is not injected yet
+```
+
+**Solution**: Configure cert-manager to use a different namespace for leader election, like this:
+
+```console
+helm install \
+ cert-manager jetstack/cert-manager \
+ --namespace cert-manager \
+ --create-namespace \
+ --version ${CERT_MANAGER_VERSION} --set global.leaderElection.namespace=cert-manager
+```
+
+The implication for a `kubectl apply` type installation is then either "you must manually update the manifests prior to installation by replacing `kube-system` with cert-manager" or "Don't install cert-manager using kubectl apply. Helm is the recommended solution".
+
+## AWS EKS
+
+When using a custom CNI (such as Weave or Calico) on EKS, the webhook cannot be
+reached by cert-manager. This happens because the control plane cannot be
+configured to run on a custom CNI on EKS, so the CNIs differ between control
+plane and worker nodes.
+
+To address this, the webhook can be run in the host network so it can be reached
+by cert-manager, by setting the `webhook.hostNetwork` key to true on your
+deployment, or, if using Helm, configuring it in your `values.yaml` file.
+
+Note that running on the host network will necessitate changing the webhook's
+port; see the warning at the top of the page for details.
+
+### AWS Fargate
+
+It's worth noting that using AWS Fargate doesn't allow much network configuration and
+will cause the webhook's port to clash with the kubelet running on port 10250, as seen
+in [#3237](https://github.com/cert-manager/cert-manager/issues/3237).
+
+When deploying cert-manager on Fargate, you _must_ change the port on which
+the webhook listens. See the warning at the top of this page for more details.
+
+Because Fargate forces you to use its networking, you cannot manually set the networking
+type and options such as `webhook.hostNetwork` on the helm chart will cause your
+cert-manager deployment to fail in surprising ways.
diff --git a/content/v1.12-docs/installation/featureflags.md b/content/v1.12-docs/installation/featureflags.md
new file mode 100644
index 00000000000..10548df563e
--- /dev/null
+++ b/content/v1.12-docs/installation/featureflags.md
@@ -0,0 +1,72 @@
+---
+title: Feature flags
+description: Using feature gated functionality
+---
+
+New cert-manager features and functionality are often initially implemented behind a feature gate. This is so as to not break users with functionality that has not yet been tested in production as well as to give us a chance to remove or modify API fields and functionality following user feedback.
+
+We have alpha and beta features. We do not aim to keep any of the features in alpha or beta stage indefinitely. Feature gating should only be used for functionality that can eventually be turned on by default for all users (or, if it is opt-in, can be safely toggled on by any user with a supported cert-manager installation).
+
+A feature gate can be toggled on/off using `--feature-gates` flags on cert-manager controller. For feature gated functionality that comes with new API fields there is also a corresponding feature gate on webhook that also needs to be enabled using a `--feature-gates` flag if you want to use it.
+
+**Alpha**
+
+All alpha features are off by default. We retain the right to change or remove
+alpha features without warning. An API field that is part of an alpha feature
+and requires a webhook feature flag to be used also can also be removed from the
+API without warning. An alpha feature might not work for all cert-manager's
+supported Kubernetes versions. If you want to disable a previously enabled alpha
+feature gate, you should make sure that you have updated any resources that have API
+fields set that are only valid if the feature gate is enabled, else the resources
+will end up in an invalid state.
+
+**Beta**
+
+All beta features are off by default. Beta features will not be removed, but may
+be changed. If the feature gets changed in incompatible ways, we will provide
+migration instructions. A beta feature will work with all cert-manager's
+supported Kubernetes versions. If you want to disable a previously enabled beta
+feature gate, you should make sure that you have updated any resources that have API
+fields set that are only valid if the beta feature gate is on, else the resources
+will end up in invalid state.
+
+**GA**
+
+A feature that is GA is on by default and cannot be disabled (unless it's opt in and toggled on/off by another mechanism, such as a flag).
+With regards to API fields and their functionality, we keep Kubernetes API compatibility promise, see [API compatibility](./api-compatibility.md).
+The feature flag for a GA feature might be left in place to avoid breaking folks, but will be non-functional.
+
+## Graduation
+
+The graduation criteria can be different for each feature.
+Generally, we find user feedback most valuable when determining if a feature is sufficiently mature to graduate. If you are using an alpha or beta feature and would like to see it graduate, it would be great if you could give us some feedback about how you use it and whether you find the API useful to initiate graduation process. Feel free to [open a GitHub issue](https://github.com/cert-manager/cert-manager/issues/new/choose) or [join one of our meetings](../contributing/#meetings) to talk about this.
+
+## List of current feature gates
+
+### Alpha
+
+See `--feature-gates` flags on cert-manager controller and webhook to enable any of these features.
+
+- `AdditionalCertificateOutputFormats`. Added in cert-manager 1.7.0. Allows to specify additional formats in which cert-manager will store issued certificates and keys. See [release note](../release-notes/release-notes-1.7.md#additional-certificate-output-formats). Requires the feature to be enabled on both cert-manager controller and webhook
+
+- `ExperimentalCertificateSigningRequestControllers`. Added in cert-manager
+ 1.4.0. Allows to use Kubernetes
+ [CertificateSigningRequest](https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/)
+ resources with cert-manager. See [release notes](../release-notes/release-notes-1.4.md#experimental-support-for-kubernetes-certificatesigningrequests)
+
+- `ExperimentalGatewayAPISupport`. Added in cert-manager 1.5.0. Allows to use cert-manager to automatically issue certificates for `Gateway` resources as well as use `Gateway`s and `HTTPRoute`s to solve ACME HTTP-01 challenges. See [Securing Gateway resources](../usage/gateway.md)
+
+- `LiteralCertificateSubject`. Added in cert-manager 1.9.0. Allows to specify certificate subject in a form that can be used to define a location in LDAP directory tree. See [release notes](../release-notes/release-notes-1.9.md#literal-certificate-subjects)
+
+- `ServerSideApply`. Added in cert-manager 1.8.0. If this feature is enabled, cert-manager uses [Server side apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/) when creating or updating API resources. This will speed cert-manager operations and prevent the resource version conflict errors. See [release notes](../release-notes/release-notes-1.8.md#server-side-apply)
+
+- `StableCertificateRequestName`. Added in cert-manager 1.10.0. Will enable generation of `CertificateRequest` resources with a fixed name. See [`cert-manager#5487`](https://github.com/cert-manager/cert-manager/pull/5487)
+
+- `UseCertificateRequestBasicConstraints`. Added in cert-manager 1.11.0. Makes cert-manager add a basic constraints section to certificate signing requests with the CA constraint set to the correct value. See [`cert-manager#5552`](https://github.com/cert-manager/cert-manager/pull/5552)
+
+- `ValidateCAA`. Added in cert-manager 0.7.2. CAA checking when issuing a certificate.
+
+
+### Beta
+
+There are currently no beta feature gates
diff --git a/content/v1.12-docs/installation/helm.md b/content/v1.12-docs/installation/helm.md
new file mode 100644
index 00000000000..f9b1db130c7
--- /dev/null
+++ b/content/v1.12-docs/installation/helm.md
@@ -0,0 +1,207 @@
+---
+title: Helm
+description: 'cert-manager installation: Using Helm'
+---
+
+## Installing with Helm
+
+cert-manager provides Helm charts as a first-class method of installation on both Kubernetes and OpenShift.
+
+Be sure never to embed cert-manager as a sub-chart of other Helm charts; cert-manager manages
+non-namespaced resources in your cluster and care must be taken to ensure that it is installed exactly once.
+
+### Prerequisites
+
+- [Install Helm version 3 or later](https://helm.sh/docs/intro/install/).
+- Install a [supported version of Kubernetes or OpenShift](./supported-releases.md).
+- Read [Compatibility with Kubernetes Platform Providers](./compatibility.md) if you are using Kubernetes on a cloud platform.
+
+### Steps
+
+
+#### 1. Add the Helm repository
+
+This repository is the only supported source of cert-manager charts. There are some other mirrors and copies across the internet, but those are entirely unofficial and could present a security risk.
+
+Notably, the "Helm stable repository" version of cert-manager is deprecated and should not be used.
+
+```bash
+helm repo add jetstack https://charts.jetstack.io
+```
+
+#### 2. Update your local Helm chart repository cache:
+
+```bash
+helm repo update
+```
+
+#### 3. Install `CustomResourceDefinitions`
+
+cert-manager requires a number of CRD resources, which can be installed manually using `kubectl`,
+or using the `installCRDs` option when installing the Helm chart.
+
+##### Option 1: installing CRDs with `kubectl`
+
+
+```bash
+kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.crds.yaml
+```
+
+##### Option 2: install CRDs as part of the Helm release
+
+To automatically install and manage the CRDs as part of your Helm release, you
+must add the `--set installCRDs=true` flag to your Helm installation command.
+
+Uncomment the relevant line in the next steps to enable this.
+
+Note that if you're using a `helm` version based on Kubernetes `v1.18` or below (Helm `v3.2`), `installCRDs` will not work with cert-manager `v0.16`. See the [v0.16 upgrade notes](./upgrading/upgrading-0.15-0.16.md#helm) for more details.
+
+#### 4. Install cert-manager
+
+To install the cert-manager Helm chart, use the [Helm install command](https://helm.sh/docs/helm/helm_install/) as described below.
+
+```bash
+helm install \
+ cert-manager jetstack/cert-manager \
+ --namespace cert-manager \
+ --create-namespace \
+ --version v1.11.0 \
+ # --set installCRDs=true
+```
+
+A full list of available Helm values is on [cert-manager's ArtifactHub page](https://artifacthub.io/packages/helm/cert-manager/cert-manager).
+
+The example below shows how to tune the cert-manager installation by overwriting the default Helm values:
+
+```bash
+helm install \
+ cert-manager jetstack/cert-manager \
+ --namespace cert-manager \
+ --create-namespace \
+ --version v1.11.0 \
+ # --set installCRDs=true
+ --set prometheus.enabled=false \ # Example: disabling prometheus using a Helm parameter
+ --set webhook.timeoutSeconds=4 # Example: changing the webhook timeout using a Helm parameter
+```
+
+Once you have deployed cert-manager, you can [verify](./verify.md) the installation.
+
+### Installing cert-manager as subchart
+
+If you have configured cert-manager as a subchart all the components of cert-manager will be installed into the namespace of the helm release you are installing.
+
+There may be a situation where you want to specify the namespace to install cert-manager different to the umbrella chart's namespace.
+
+This is a [known issue](https://github.com/helm/helm/issues/5358) with helm and subcharts, that you can't specify the namespace for the subchart and is being solved by most public charts by allowing users to set the namespace via the values file, but needs to be a capability added to the chart by the maintainers.
+
+This capability is now available in the cert-manager chart and can be set either in the values file or via the `--set` switch.
+
+#### Example usage
+
+Below is an example `Chart.yaml` with cert-manager as a subchart
+
+```yaml
+apiVersion: v2
+name: example_chart
+description: A Helm chart with cert-manager as subchart
+type: application
+version: 0.1.0
+appVersion: "0.1.0"
+dependencies:
+ - name: cert-manager
+ version: v1.11.0
+ repository: https://charts.jetstack.io
+ alias: cert-manager
+ condition: cert-manager.enabled
+```
+You can then override the namespace in 2 ways
+1. In `Values.yaml` file
+```yaml
+cert-manager: #defined by either the name or alias of your dependency in Chart.yaml
+ namespace: security
+```
+2. In the helm command using `--set`
+```bash
+helm install example example_chart \
+ --namespace example \
+ --create-namespace \
+ --set cert-manager.namespace=security
+```
+
+The above example will install cert-manager into the security namespace.
+
+## Output YAML
+
+Instead of directly installing cert-manager using Helm, a static YAML manifest can be created using the [Helm template command](https://helm.sh/docs/helm/helm_template/).
+This static manifest can be tuned by providing the flags to overwrite the default Helm values:
+
+```bash
+helm template \
+ cert-manager jetstack/cert-manager \
+ --namespace cert-manager \
+ --create-namespace \
+ --version v1.11.0 \
+ # --set prometheus.enabled=false \ # Example: disabling prometheus using a Helm parameter
+ # --set installCRDs=true \ # Uncomment to also template CRDs
+ > cert-manager.custom.yaml
+```
+
+## Uninstalling
+
+> **Warning**: To uninstall cert-manager you should always use the same process for
+> installing but in reverse. Deviating from the following process whether
+> cert-manager has been installed from static manifests or Helm can cause issues
+> and potentially broken states. Please ensure you follow the below steps when
+> uninstalling to prevent this happening.
+
+Before continuing, ensure that all cert-manager resources that have been created
+by users have been deleted. You can check for any existing resources with the
+following command:
+
+```bash
+kubectl get Issuers,ClusterIssuers,Certificates,CertificateRequests,Orders,Challenges --all-namespaces
+```
+
+Once all these resources have been deleted you are ready to uninstall
+cert-manager using the procedure determined by how you installed.
+
+### Uninstalling with Helm
+
+Uninstalling cert-manager from a `helm` installation is a case of running the
+installation process, *in reverse*, using the delete command on both `kubectl`
+and `helm`.
+
+
+```bash
+helm --namespace cert-manager delete cert-manager
+```
+
+Next, delete the cert-manager namespace:
+
+```bash
+kubectl delete namespace cert-manager
+```
+
+Finally, delete the cert-manager
+[`CustomResourceDefinitions`](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)
+using the link to the version `vX.Y.Z` you installed:
+> **Warning**: This command will also remove installed cert-manager CRDs. All
+> cert-manager resources (e.g. `certificates.cert-manager.io` resources) will
+> be removed by Kubernetes' garbage collector.
+
+```bash
+kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/vX.Y.Z/cert-manager.crds.yaml
+```
+
+### Namespace Stuck in Terminating State
+
+If the namespace has been marked for deletion without deleting the cert-manager
+installation first, the namespace may become stuck in a terminating state. This
+is typically due to the fact that the [`APIService`](https://kubernetes.io/docs/tasks/access-kubernetes-api/setup-extension-api-server) resource still exists
+however the webhook is no longer running so is no longer reachable. To resolve
+this, ensure you have run the above commands correctly, and if you're still
+experiencing issues then run:
+
+```bash
+kubectl delete apiservice v1beta1.webhook.cert-manager.io
+```
diff --git a/content/v1.12-docs/installation/kubectl.md b/content/v1.12-docs/installation/kubectl.md
new file mode 100644
index 00000000000..742f50768d1
--- /dev/null
+++ b/content/v1.12-docs/installation/kubectl.md
@@ -0,0 +1,124 @@
+---
+title: kubectl apply
+description: Learn how to install cert-manager using kubectl and static manifests
+---
+
+Learn how to install cert-manager using kubectl and static manifests.
+
+## Prerequisites
+
+- [Install `kubectl` version `>= v1.19.0`](https://kubernetes.io/docs/tasks/tools/). (otherwise, you'll have issues updating the CRDs - see [v0.16 upgrade notes](./upgrading/upgrading-0.15-0.16.md#issue-with-older-versions-of-kubectl))
+- Install a [supported version of Kubernetes or OpenShift](./supported-releases.md).
+- Read [Compatibility with Kubernetes Platform Providers](./compatibility.md) if you are using Kubernetes on a cloud platform.
+
+## Steps
+
+All resources (the [`CustomResourceDefinitions`](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions) and the cert-manager, cainjector and webhook components)
+are included in a single YAML manifest file:
+
+Install all cert-manager components:
+
+```bash
+kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml
+```
+
+By default, cert-manager will be installed into the `cert-manager`
+namespace. It is possible to run cert-manager in a different namespace, although
+you'll need to make modifications to the deployment manifests.
+
+Once you have deployed cert-manager, you can [verify the installation](./verify.md).
+
+## Permissions Errors on Google Kubernetes Engine
+
+When running on GKE (Google Kubernetes Engine), you might encounter a 'permission denied' error when creating some
+of the required resources. This is a nuance of the way GKE handles RBAC and IAM permissions,
+and as such you might need to elevate your own privileges to that of a "cluster-admin" **before**
+running `kubectl apply`.
+
+If you have already run `kubectl apply`, you should run it again after elevating your permissions:
+
+```bash
+kubectl create clusterrolebinding cluster-admin-binding \
+ --clusterrole=cluster-admin \
+ --user=$(gcloud config get-value core/account)
+```
+
+## Uninstalling
+> **Warning**: To uninstall cert-manager you should always use the same process for
+> installing but in reverse. Deviating from the following process whether
+> cert-manager has been installed from static manifests or Helm can cause issues
+> and potentially broken states. Please ensure you follow the below steps when
+> uninstalling to prevent this happening.
+
+Before continuing, ensure that unwanted cert-manager resources that have been created
+by users have been deleted. You can check for any existing resources with the
+following command:
+
+```bash
+kubectl get Issuers,ClusterIssuers,Certificates,CertificateRequests,Orders,Challenges --all-namespaces
+```
+It is recommended that you delete all these resources before uninstalling cert-manager.
+If you plan on reinstalling later and don't want to lose some custom resources, you can keep them.
+However, this can potentially lead to problems with finalizers. Some resources, like
+`Challenges`, should be deleted to avoid [getting stuck in a pending state](#namespace-stuck-in-terminating-state).
+
+Once the unneeded resources have been deleted, you are ready to uninstall
+cert-manager using the procedure determined by how you installed.
+
+> **Warning**: Uninstalling cert-manager or simply deleting a `Certificate` resource can result in
+> TLS `Secret`s being deleted if they have `metadata.ownerReferences` set by cert-manager.
+> You can control whether owner references are added to `Secret`s using the `--enable-certificate-owner-ref` controller flag.
+> By default, this flag is set to false, which means that no owner references are added.
+> However, in cert-manager v1.8 and older, changing the flag's value from true to false _did not_
+> result in existing owner references being removed. This behavior was fixed in cert-manager v1.8.
+> Do check the owner references to confirm that they actually are removed.
+
+### Uninstalling with regular manifests
+
+Uninstalling from an installation with regular manifests is a case of running
+the installation process, *in reverse*, using the delete command of `kubectl`.
+
+Delete the installation manifests using a link to your currently running version
+`vX.Y.Z` like so:
+> **Warning**: This command will also remove installed cert-manager CRDs. All
+> cert-manager resources (e.g. `certificates.cert-manager.io` resources) will
+> be removed by Kubernetes' garbage collector.
+> You cannot keep any custom resources if you delete the `CustomResourceDefinition`s.
+> If you want to keep resources, you should manage `CustomResourceDefinition`s separately.
+
+```bash
+kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/vX.Y.Z/cert-manager.yaml
+```
+
+### Namespace Stuck in Terminating State
+
+If the namespace has been marked for deletion without deleting the cert-manager
+installation first, the namespace may become stuck in a terminating state. This
+is typically due to the fact that the [`APIService`](https://kubernetes.io/docs/tasks/access-kubernetes-api/setup-extension-api-server) resource still exists
+however the webhook is no longer running so is no longer reachable. To resolve
+this, ensure you have run the above commands correctly, and if you're still
+experiencing issues then run:
+
+```bash
+kubectl delete apiservice v1beta1.webhook.cert-manager.io
+```
+
+#### Deleting pending challenges
+
+`Challenge`s can get stuck in a pending state when the finalizer is unable to complete
+and Kubernetes is waiting for the cert-manager controller to finish.
+This happens when the controller is no longer running to remove the flag,
+and the resources are defined as needing to wait.
+You can fix this problem by doing what the controller does manually.
+
+First, delete existing cert-manager webhook configurations, if any:
+
+```bash
+kubectl delete mutatingwebhookconfigurations cert-manager-webhook
+```
+
+Then change the `.metadata.finalizers` field to an empty list by editing the challenge resource:
+
+```bash
+kubectl edit challenge
+```
diff --git a/content/v1.12-docs/installation/operator-lifecycle-manager.md b/content/v1.12-docs/installation/operator-lifecycle-manager.md
new file mode 100644
index 00000000000..f9982899adc
--- /dev/null
+++ b/content/v1.12-docs/installation/operator-lifecycle-manager.md
@@ -0,0 +1,243 @@
+---
+title: Operator Lifecycle Manager
+description: 'cert-manager installation: Using OLM'
+---
+
+## Installation managed by OLM
+
+### Prerequisites
+
+- Install a [supported version of Kubernetes or OpenShift](./supported-releases.md).
+- Read [Compatibility with Kubernetes Platform Providers](./compatibility.md) if you are using Kubernetes on a cloud platform.
+
+### Option 1: Installing from OperatorHub Web Console on OpenShift
+
+cert-manager is in the [Red Hat-provided Operator catalog][] called "community-operators".
+On OpenShift 4 you can install cert-manager from the [OperatorHub web console][] or from the command line.
+These installation methods are described in Red Hat's [Adding Operators to a cluster][] documentation.
+
+> ⚠️ In cert-manager 1.10 the [secure computing (seccomp) profile](https://kubernetes.io/docs/tutorials/security/seccomp/) for all the Pods
+> is set to `RuntimeDefault`.
+> On some versions and configurations of OpenShift this can cause the Pod to be rejected by the
+> [Security Context Constraints admission webhook](https://docs.openshift.com/container-platform/4.10/authentication/managing-security-context-constraints.html#admission_configuring-internal-oauth).
+>
+> 📖 Read the [Breaking Changes section in the 1.10 release notes](https://cert-manager.io/docs/release-notes/release-notes-1.10/#on-openshift-the-cert-manager-pods-may-fail-until-you-modify-security-context-constraints) before installing or upgrading from an older version to 1.10 or newer.
+
+[Red Hat-provided Operator catalog]: https://docs.openshift.com/container-platform/4.7/operators/understanding/olm-rh-catalogs.html#olm-rh-catalogs_olm-rh-catalogs
+[OperatorHub web console]: https://docs.openshift.com/container-platform/4.7/operators/understanding/olm-understanding-operatorhub.html
+[Adding Operators to a cluster]: https://docs.openshift.com/container-platform/4.7/operators/admin/olm-adding-operators-to-cluster.html
+
+
+### Option 2: Installing from OperatorHub.io
+
+Browse to the [cert-manager page on OperatorHub.io](https://operatorhub.io/operator/cert-manager),
+click the "Install" button and follow the installation instructions.
+
+### Option 3: Manual install via `kubectl operator` plugin
+
+[Install OLM][] and [install the `kubectl operator` plugin][]
+from the [Krew Kubectl plugins index][] and then use that to install the cert-manager as follows:
+
+```sh
+operator-sdk olm install
+kubectl krew install operator
+kubectl operator install cert-manager -n operators --channel stable --approval Automatic
+```
+
+You can monitor the progress of the installation as follows:
+
+```sh
+kubectl get events -w -n operators
+```
+
+And you can see the status of the installation with:
+
+```sh
+kubectl operator list
+```
+
+[install OLM]: https://sdk.operatorframework.io/docs/installation/
+[install the `kubectl operator` plugin]: https://github.com/operator-framework/kubectl-operator#install
+[Krew Kubectl plugins index]: https://krew.sigs.k8s.io/plugins/#:~:text=cert-manager
+
+## Release Channels
+
+Whichever installation method you chose, there will now be an [OLM Subscription resource][] for cert-manager,
+tracking the "stable" release channel. E.g.
+
+```console
+$ kubectl get subscription cert-manager -n operators -o yaml
+...
+spec:
+ channel: stable
+ installPlanApproval: Automatic
+ name: cert-manager
+...
+status:
+ currentCSV: cert-manager.v1.7.1
+ state: AtLatestKnown
+...
+```
+
+This means that OLM will discover new cert-manager releases in the stable channel,
+and, depending on the Subscription settings it will upgrade cert-manager automatically,
+when new releases become available.
+Read [Manually Approving Upgrades via Subscriptions][] for information about automatic and manual upgrades.
+
+[OLM Subscription resource]: https://olm.operatorframework.io/docs/concepts/crds/subscription/
+[Manually Approving Upgrades via Subscriptions]: https://olm.operatorframework.io/docs/concepts/crds/subscription/#manually-approving-upgrades-via-subscriptions
+
+**NOTE:** There is a single release channel called "stable" which will contain all cert-manager releases, shortly after they are released.
+In future we may introduce other release channels with alternative release schedules,
+in accordance with [OLM's Recommended Channel Naming][].
+
+[OLM's Recommended Channel Naming]: https://olm.operatorframework.io/docs/best-practices/channel-naming/#recommended-channel-naming
+
+## Debugging installation issues
+
+If you have any issues with your installation, please refer to the
+[FAQ](../faq/README.md).
+
+## Configuration
+
+The configuration options are quite limited when you install cert-manager using OLM.
+There are a few Deployment settings which can be overridden permanently in the Subscription
+and most other elements of the cert-manager manifests can be changed by editing the ClusterServiceVersion,
+but changes to the ClusterServiceVersion are temporary and will be lost if OLM upgrades cert-manager,
+because an upgrade results in a new ClusterServiceVersion resource.
+
+### Configuration Via Subscription
+
+When you create an OLM Subscription you can override **some** of the cert-manager Deployment settings,
+but the options are quite limited.
+The configuration which you add to the Subscription will be applied immediately to the current cert-manager Deployments.
+It will also be re-applied if OLM upgrades cert-manager.
+
+> 🔰 Read the [Configuring Operators deployed by OLM](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/doc/design/subscription-config.md#configuring-operators-deployed-by-olm) design doc in the OLM repository.
+>
+> 🔰 Refer to the [Subscription API documentation](https://pkg.go.dev/github.com/operator-framework/api@v0.14.0/pkg/operators/v1alpha1#Subscription).
+
+Here are some examples of configuration that can be achieved by modifying the Subscription resource.
+In each case we assume that you are starting with the following [default Subscription from OperatorHub.io](https://operatorhub.io/install/cert-manager.yaml):
+
+```yaml
+# cert-manager.yaml
+apiVersion: operators.coreos.com/v1alpha1
+kind: Subscription
+metadata:
+ name: my-cert-manager
+ namespace: operators
+spec:
+ channel: stable
+ name: cert-manager
+ source: operatorhubio-catalog
+ sourceNamespace: olm
+```
+
+```bash
+kubectl create -f https://operatorhub.io/install/cert-manager.yaml
+```
+
+#### Change the Resource Requests and Limits
+
+It is possible to change the resource requests and limits by adding a `config` stanza to the Subscription:
+
+```yaml
+# resources-patch.yaml
+spec:
+ config:
+ resources:
+ requests:
+ memory: "64Mi"
+ cpu: "250m"
+ limits:
+ memory: "128Mi"
+ cpu: "500m"
+```
+
+
+```bash
+kubectl -n operators patch subscription my-cert-manager --type merge --patch-file resources-patch.yaml
+```
+
+You will see **all** the cert-manager Pods are restarted with the new resources:
+
+```console
+$ kubectl -n operators get pods -o "custom-columns=name:.metadata.name,mem:.spec.containers[*].resources"
+name mem
+cert-manager-669867589c-n8dcn map[limits:map[cpu:500m memory:128Mi] requests:map[cpu:250m memory:100Mi]]
+cert-manager-cainjector-7b7fff8b9c-dxw6b map[limits:map[cpu:500m memory:128Mi] requests:map[cpu:250m memory:100Mi]]
+cert-manager-webhook-975bc87b5-tqdj4 map[limits:map[cpu:500m memory:128Mi] requests:map[cpu:250m memory:100Mi]]
+```
+
+> ⚠️ This configuration will apply to **all** the cert-manager Deployments.
+> This is a known limitation of OLM which [does not support configuration of individual Deployments](https://github.com/operator-framework/operator-lifecycle-manager/issues/1794).
+
+#### Change the NodeSelector
+
+It is possible to change the `nodeSelector` for cert-manager Pods by adding the following stanza to the Subscription:
+
+```yaml
+# nodeselector-patch.yaml
+spec:
+ config:
+ nodeSelector:
+ kubernetes.io/arch: amd64
+```
+
+```bash
+kubectl -n operators patch subscription my-cert-manager --type merge --patch-file nodeselector-patch.yaml
+```
+
+You will see **all** the cert-manager Pods are restarted with the new `nodeSelector`:
+
+```console
+$ kubectl -n operators get pods -o "custom-columns=name:.metadata.name,nodeselector:.spec.nodeSelector"
+name nodeselector
+cert-manager-5b6b8f7d74-k7l94 map[kubernetes.io/arch:amd64 kubernetes.io/os:linux]
+cert-manager-cainjector-b89cd6f46-kdkk2 map[kubernetes.io/arch:amd64 kubernetes.io/os:linux]
+cert-manager-webhook-8464bc7cc8-64b4w map[kubernetes.io/arch:amd64 kubernetes.io/os:linux]
+```
+
+> ⚠️ This configuration will apply to **all** the cert-manager Deployments.
+> This is a known limitation of OLM which [does not support configuration of individual Deployments](https://github.com/operator-framework/operator-lifecycle-manager/issues/1794).
+
+### Configuration Via ClusterServiceVersion (CSV)
+
+The ClusterServiceVersion (CSV) resource contains the templates for all the cert-manager Deployments.
+If you patch these templates, OLM will immediately roll out the changes to the Deployments.
+
+> ⚠️ If OLM upgrades cert-manager your changes will be lost because it will create a new CSV with default Deployment templates.
+
+Nevertheless, editing (patching) the CSV can be a useful way to override certain cert-manager settings. An example:
+
+#### Change the log level of cert-manager components
+
+The following JSON patch will append `-v=6` to command line arguments of the cert-manager controller-manager
+(the first container of the first Deployment).
+
+```bash
+kubectl patch csv cert-manager.v1.11.0 \
+ --type json \
+ -p '[{"op": "add", "path": "/spec/install/spec/deployments/0/spec/template/spec/containers/0/args/-", "value": "-v=6" }]'
+```
+
+You will see the controller-manager Pod is restarted with the new arguments.
+
+```console
+$ kubectl -n operators get pods -o "custom-columns=name:.metadata.name,args:.spec.containers[0].args"
+name args
+cert-manager-797979cbdb-g444r [-v=2 --cluster-resource-namespace=$(POD_NAMESPACE) --leader-election-namespace=kube-system -v=6]
+...
+```
+
+> 🔰 Refer to the [ClusterServiceVersion API documentation](https://pkg.go.dev/github.com/operator-framework/api@v0.14.0/pkg/operators/v1alpha1#ClusterServiceVersion).
+
+## Uninstall
+
+Below is the processes for uninstalling cert-manager on OpenShift.
+
+> ⚠️ To uninstall cert-manager you should always use the same process for
+> installing but in reverse. Deviating from the following process can cause
+> issues and potentially broken states. Please ensure you follow the below steps
+> when uninstalling to prevent this happening.
diff --git a/content/v1.12-docs/installation/other-tools.md b/content/v1.12-docs/installation/other-tools.md
new file mode 100644
index 00000000000..6d7b0b7044c
--- /dev/null
+++ b/content/v1.12-docs/installation/other-tools.md
@@ -0,0 +1,23 @@
+---
+title: Alternative installation methods
+description: 'cert-manager installation: Other tools'
+---
+
+### kubeprod
+
+[Bitnami Kubernetes Production
+Runtime](https://github.com/bitnami/kube-prod-runtime) (`BKPR`, `kubeprod`) is a
+curated collection of the services you would need to deploy on top of your
+Kubernetes cluster to enable logging, monitoring, certificate management,
+automatic discovery of Kubernetes resources via public DNS servers and other
+common infrastructure needs.
+
+It depends on `cert-manager` for certificate management, and it is [regularly
+tested](https://github.com/bitnami/kube-prod-runtime/blob/master/Jenkinsfile) so
+the components are known to work together for GKE, AKS, and EKS clusters. For
+its ingress stack it creates a DNS entry in the configured DNS zone and requests
+a TLS certificate from the Let's Encrypt staging server.
+
+BKPR can be deployed using the `kubeprod install` command, which will deploy
+`cert-manager` as part of it. Details available in the [BKPR installation
+guide](https://github.com/bitnami/kube-prod-runtime/blob/master/docs/install.md).
\ No newline at end of file
diff --git a/content/v1.12-docs/installation/supported-releases.md b/content/v1.12-docs/installation/supported-releases.md
new file mode 100644
index 00000000000..930152f250f
--- /dev/null
+++ b/content/v1.12-docs/installation/supported-releases.md
@@ -0,0 +1,289 @@
+---
+title: Supported Releases
+description: Supported releases, Kubernetes versions, OpenShift versions and upcoming release timeline
+---
+
+{/*
+Inspired by https://istio.io/latest/about/supported-releases/
+*/}
+
+This page lists the status, timeline and policy for currently supported releases.
+
+Each release is supported for a period of four months, and we aim to create a new
+release roughly every two months, accounting for holiday periods, major conferences
+and other world events.
+
+cert-manager expects that ServerSideApply is enabled in the cluster for all version of Kubernetes from 1.24 and above.
+
+Currently supported releases
+
+| Release | Release Date | End of Life | [Supported Kubernetes versions][s] | [Supported OpenShift versions][s] |
+|----------|:------------:|:----------------------:|:----------------------------------:|:---------------------------------:|
+| [1.12][] | May 19, 2024 | End of September, 2024 | 1.22 → 1.27 | 4.9 → 4.14 |
+| [1.11][] | Jan 11, 2023 | Release of 1.13 | 1.21 → 1.26 | 4.8 → 4.13 |
+
+\*ServerSideApply should be enabled in the cluster
+
+## Upcoming releases
+
+| Release | Release Date | End of Life | [Supported Kubernetes versions][s] | [Supported OpenShift versions][s] |
+|----------|:----------------------:|:---------------------:|:----------------------------------:|:---------------------------------:|
+| [1.13][] | End of September, 2024 | End of November, 2024 | 1.22 → 1.27 | 4.9 → 4.14 |
+
+Dates in the future are uncertain and might change.
+
+## Old releases
+
+| Release | Release Date | EOL | Compatible Kubernetes versions | Compatible OpenShift versions |
+|----------|:------------:|:------------:|:------------------------------:|:-----------------------------:|
+| [1.10][] | Oct 17, 2022 | May 19, 2024 | 1.20 → 1.26 | 4.7 → 4.13 |
+| [1.9][] | Jul 22, 2022 | Jan 11, 2023 | 1.20 → 1.24 | 4.7 → 4.11 |
+| [1.8][] | Apr 05, 2022 | Oct 17, 2022 | 1.19 → 1.24 | 4.6 → 4.11 |
+| [1.7][] | Jan 26, 2021 | Jul 22, 2022 | 1.18 → 1.23 | 4.5 → 4.9 |
+| [1.6][] | Oct 26, 2021 | Apr 05, 2022 | 1.17 → 1.22 | 4.4 → 4.9 |
+| [1.5][] | Aug 11, 2021 | Jan 26, 2022 | 1.16 → 1.22 | 4.3 → 4.8 |
+| [1.4][] | Jun 15, 2021 | Oct 26, 2021 | 1.16 → 1.21 | 4.3 → 4.7 |
+| [1.3][] | Apr 08, 2021 | Aug 11, 2021 | 1.16 → 1.21 | 4.3 → 4.7 |
+| [1.2][] | Feb 10, 2021 | Jun 15, 2021 | 1.16 → 1.21 | 4.3 → 4.7 |
+| [1.1][] | Nov 24, 2020 | Apr 08, 2021 | 1.11 → 1.21 | 3.11 → 4.7 |
+| [1.0][] | Sep 02, 2020 | Feb 10, 2021 | 1.11 → 1.21 | 3.11 → 4.7 |
+| [0.16][] | Jul 23, 2020 | Nov 24, 2020 | 1.11 → 1.21 | 3.11 → 4.7 |
+| [0.15][] | May 06, 2020 | Sep 02, 2020 | 1.11 → 1.21 | 3.11 → 4.7 |
+| [0.14][] | Mar 11, 2020 | Jul 23, 2020 | 1.11 → 1.21 | 3.11 → 4.7 |
+| [0.13][] | Jan 21, 2020 | May 06, 2020 | 1.11 → 1.21 | 3.11 → 4.7 |
+| [0.12][] | Nov 27, 2019 | Mar 11, 2020 | 1.11 → 1.21 | 3.11 → 4.7 |
+| [0.11][] | Oct 10, 2019 | Jan 21, 2020 | 1.9 → 1.21 | 3.09 → 4.7 |
+
+[s]: #kubernetes-supported-versions
+[1.13]: https://github.com/cert-manager/cert-manager/milestone/34
+[1.12]: https://cert-manager.io/docs/release-notes/release-notes-1.12
+[1.11]: https://cert-manager.io/docs/release-notes/release-notes-1.11
+[1.10]: https://cert-manager.io/docs/release-notes/release-notes-1.10
+[1.9]: https://cert-manager.io/docs/release-notes/release-notes-1.9
+[1.8]: https://cert-manager.io/docs/release-notes/release-notes-1.8
+[1.7]: https://cert-manager.io/docs/release-notes/release-notes-1.7
+[1.6]: https://cert-manager.io/docs/release-notes/release-notes-1.6
+[1.5]: https://cert-manager.io/docs/release-notes/release-notes-1.5
+[1.4]: https://cert-manager.io/docs/release-notes/release-notes-1.4
+[1.3]: https://cert-manager.io/docs/release-notes/release-notes-1.3
+[1.2]: https://cert-manager.io/docs/release-notes/release-notes-1.2
+[1.1]: https://cert-manager.io/docs/release-notes/release-notes-1.1
+[1.0]: https://cert-manager.io/docs/release-notes/release-notes-1.0
+[0.16]: https://cert-manager.io/docs/release-notes/release-notes-0.16
+[0.15]: https://cert-manager.io/docs/release-notes/release-notes-0.15
+[0.14]: https://cert-manager.io/docs/release-notes/release-notes-0.14
+[0.13]: https://cert-manager.io/docs/release-notes/release-notes-0.13
+[0.12]: https://cert-manager.io/docs/release-notes/release-notes-0.12
+[0.11]: https://cert-manager.io/docs/release-notes/release-notes-0.11
+
+We list cert-manager releases on [GitHub](https://github.com/cert-manager/cert-manager/releases),
+and release notes on [cert-manager.io](https://cert-manager.io/docs/release-notes/).
+
+We also maintain detailed [upgrade instructions](https://cert-manager.io/docs/installation/upgrading/).
+
+## Support policy
+
+### What we mean by support
+
+Our support window is four months for each release branch. In the below
+diagram, `release-1.2` is an example of a release branch. The support
+window corresponds to the two latest releases, given that we produce a new
+final release every two months. We offer two types of support:
+
+- [Technical support](#technical-support),
+- [Security and bug fixes](#bug-fixes-support).
+
+For example, imagining that the latest release is `v1.2.0`, you can expect
+support for both `v1.2.0` and `v1.1.0`. Only the last patch release of each
+branch is actually supported.
+
+```diagram
+ v1.0.0 ^
+ Sep 2, 2020 | UNSUPPORTED
+------+---------------------------------------------> release-1.0 | RELEASES
+ \ v
+ \
+ \ v1.1.0
+ \ Nov 24, 2020 ^
+ ---------+-------------------------------> release-1.1 |
+ \ | SUPPORTED
+ \ | RELEASES
+ \ v1.2.0 | = the two
+ \ Feb 10, 2021 | last
+ ------------+--------------> release-1.2 | releases
+ \ v
+ \
+ \
+ \
+ -----------> master branch
+ April 1, 2021
+```
+
+Technical support
+
+Technical assistance is offered on a best-effort basis for supported
+releases only. You can request support from the community on [Kubernetes
+Slack](https://slack.k8s.io/) (in the `#cert-manager` channel), using
+[GitHub Discussions][discussions] or using the [cert-manager-dev][group]
+Google group.
+
+[discussions]: https://github.com/cert-manager/cert-manager/discussions
+[group]: https://groups.google.com/g/cert-manager-dev
+
+Security and bug fixes
+
+We back-port important bug fixes — including security fixes — to all
+currently supported releases.
+
+- [Security issues](#security-issues),
+- [Critical bugs](#critical-bugs),
+- [Long-standing bugs](#long-standing-bugs).
+
+Security issues
+
+**Security issues** are fixed as soon as possible. They get back-ported to
+the last two releases, and a new patch release is immediately created for them.
+
+Critical bugs
+
+**Critical bugs** include both regression bugs as well as upgrade bugs.
+
+Regressions are functionalities that worked in a previous release but no longer
+work. [#4142][], [#3393][] and [#2857][] are three examples of regressions.
+
+Upgrade bugs are issues (often Helm-related) preventing users from
+upgrading to currently supported releases from earlier releases of
+cert-manager. [#3882][] and [#3644][] are examples of upgrade bugs.
+
+Note that [intentional breaking changes](#breaking-changes) do not belong to
+this category.
+
+Fixes for critical bugs are (usually) immediately back-ported by creating a new
+patch release for the currently supported releases.
+
+Long-standing bugs
+
+**Long-standing bug**: sometimes a bug exists for a long time, and may have
+known workarounds. [#3444][] is an example of a long-standing bug.
+
+Where we feel that back-porting would be difficult or might be a stability
+risk to clusters running cert-manager, we'll make the fix in a major
+release but avoid back-porting the fix.
+
+Breaking changes
+
+Breaking changes are changes that intentionally break the cert-manager
+Kubernetes API or the command line flags. We avoid making breaking changes
+where possible, and where they're required we'll give as much notice as
+possible.
+
+Other back-ports
+
+We aim to be conservative in what we back-port. That applies especially for anything which
+could be a _runtime_ change - that is, a change which might alter behavior for someone
+upgrading between patch releases.
+
+That means that if a candidate for back-porting has a chance of having a runtime impact we're
+unlikely to accept the change unless it addresses a security issue or a critical bug.
+
+We reserve the right to back-port other changes which are unlikely to have a runtime impact, such as
+documentation or tooling changes. An example would be [#5209][] which updated how we perform a release of
+cert-manager but didn't have any realistic chance of having a runtime impact.
+
+Generally we'll seek to be pragmatic. A rule of thumb might be to ask:
+
+"Does this back-port improve cert-manager, bearing in mind that we really value stability for already-released versions?"
+
+[#3393]: https://github.com/cert-manager/cert-manager/issues/3393 "Broken CloudFlare DNS01 challenge"
+[#2857]: https://github.com/cert-manager/cert-manager/issues/2857 "CloudDNS DNS01 challenge crashes cert-manager"
+[#4142]: https://github.com/cert-manager/cert-manager/issues/4142 "Cannot issue a certificate that has the same subject and issuer"
+[#3444]: https://github.com/cert-manager/cert-manager/issues/3444 "Certificates do not get immediately updated after updating them"
+[#3882]: https://github.com/cert-manager/cert-manager/pull/3882 "Certificate's revision history limit validated by webhook"
+[#3644]: https://github.com/cert-manager/cert-manager/issues/3644 "Helm upgrade from v1.2 to v1.2 impossible due to a Helm bug"
+[#5209]: https://github.com/cert-manager/cert-manager/pull/5209 "release-1.8: rclone"
+
+
+How we determine supported Kubernetes versions
+
+The list of supported Kubernetes versions displayed in the [Supported Releases](#supported-releases) section
+depends on what the cert-manager maintainers think is reasonable to support and to test.
+
+In practice, this is largely determined based on what versions of [kind](https://github.com/kubernetes-sigs/kind)
+are available for testing, and which versions of Kubernetes are provided by major upstream cloud Kubernetes vendors
+including EKS, GKE, AKS and OpenShift.
+
+| Vendor | Oldest Kubernetes Release\* | Other Older Kubernetes Releases |
+|:-----------------:|-----------------------------|------------------------------------------------------------------------------------|
+| [EKS][eks] | 1.22 (EOL Jun 2023) | 1.23 (EOL Oct 2023), 1.24 (EOL Jan 2024), 1.25 (EOL May 2024), 1.26 (EOL Jun 2024) |
+| [GKE][gke] | 1.23 (EOL Jul 2023) | 1.24 (EOL Oct 2023), 1.25 (EOL Feb 2024), 1.26 (EOL May 2024), 1.27 (EOL Jan 2025) |
+| [AKS][aks] | 1.24 (EOL Jul 2023) | 1.25 (EOL Dec 2023), 1.26 (EOL Mar 2024), 1.27 (EOL Jun 2024) |
+| [OpenShift 4][os] | 1.22 (4.9, EOL Jun 2023) | 1.23 (4.10, EOL Oct 2023), 1.24 (4.11, EOL Feb 2024), 1.25 (4.12, EOL Jan 2025) |
+
+\*Oldest release relevant to the next cert-manager release, as of 2023-05-19
+
+[eks]: https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html#kubernetes-release-calendar
+[gke]: https://cloud.google.com/kubernetes-engine/docs/release-schedule
+[aks]: https://docs.microsoft.com/en-us/azure/aks/supported-kubernetes-versions#aks-kubernetes-release-calendar
+[os]: https://access.redhat.com/support/policy/updates/openshift#dates
+
+### OpenShift
+
+cert-manager supports versions of OpenShift 4 based on the version of Kubernetes
+that each version maps to.
+
+For convenience, the following table shows these version mappings:
+
+| OpenShift versions | Kubernetes version |
+|--------------------|--------------------|
+| 4.14 | 1.27 |
+| 4.13 | 1.26 |
+| 4.12 | 1.25 |
+| 4.11 | 1.24 |
+| 4.10, 4.10 EUS | 1.23 |
+| 4.9 | 1.22 |
+| 4.8, 4.8 EUS | 1.21 |
+| 4.7 | 1.20 |
+| 4.6, 4.6 EUS | 1.19 |
+
+Note that some OpenShift versions listed above may be predicted, since an updated version of OpenShift may
+not yet be available for the latest Kubernetes releases.
+
+The last version of cert-manager to support OpenShift 3 was cert-manager 1.2, which is
+no longer maintained.
+
+## Terminology
+
+The term "release" (or "minor release") refers to one minor version of
+cert-manager. For example, 1.2 and 1.3 are two releases. Note that we do
+not use the prefix `v` for releases (just "1.2"). This is because releases
+are not used as git tags.
+
+Patch releases use the `v` prefix (e.g., `v1.2.0`, `v1.3.1`...) since one
+patch release = one git tag. The initial patch release is called "final
+release":
+
+| Type of release | Example of git tag | Corresponding release | Corresponding release branch\* |
+| --------------- | ------------------ | --------------------- | ------------------------------ |
+| Final release | `v1.3.0` | 1.3 | `release-1.3` |
+| Patch release | `v1.3.1` | 1.3 | `release-1.3` |
+| Pre-release | `v1.4.0-alpha.0` | N/A\*\* | `release-1.4` |
+
+\*For maintainers: each release has an associated long-lived branch that we
+call the “release branch”. For example, `release-1.2` is the release branch
+for release 1.2.
+
+\*\*Pre-releases (e.g., `v1.3.0-alpha.0`) don't have a corresponding
+release (e.g., 1.3) since a release only exists after a final release
+(e.g., `v1.3.0`) has been created.
+
+Our naming scheme mostly follows [Semantic Versioning
+2.0.0](https://semver.org/) with `v` prepended to git tags and docker
+images:
+
+```plain
+v..
+```
+
+where `` is increased for each release, and `` counts the
+number of patches for the current `` release. A patch is usually a
+small change relative to the `` release.
diff --git a/content/v1.12-docs/installation/uninstall.md b/content/v1.12-docs/installation/uninstall.md
new file mode 100644
index 00000000000..de06fbc9e7f
--- /dev/null
+++ b/content/v1.12-docs/installation/uninstall.md
@@ -0,0 +1,14 @@
+---
+title: Uninstall
+description: 'cert-manager installation: Uninstalling cert-manager'
+---
+
+cert-manager supports running on [Kubernetes](https://kubernetes.io) and
+[OpenShift](https://www.openshift.com). The uninstallation process between the
+two platforms is similar. Select the method that was used for installing
+cert-manager to go to the relevant uninstall documentation.
+
+- [kubectl](./kubectl.md#uninstalling)
+- [helm](./helm.md#uninstalling)
+
+If you need to preserve cert-manager custom resources (`Certificate`s, `Issuer`s etc), that are not version controlled or backed up by other means, take a look at our [backup and restore guide](../tutorials/backup.md).
diff --git a/content/v1.12-docs/installation/verify.md b/content/v1.12-docs/installation/verify.md
new file mode 100644
index 00000000000..4a169f1c953
--- /dev/null
+++ b/content/v1.12-docs/installation/verify.md
@@ -0,0 +1,122 @@
+---
+title: Verifying the Installation
+description: 'cert-manager installation: Verifying an upgrade was successful'
+---
+
+## Check cert-manager API
+
+First, make sure that [cmctl is installed](../reference/cmctl.md#installation).
+
+cmctl performs a dry-run certificate creation check against the Kubernetes cluster.
+If successful, the message `The cert-manager API is ready` is displayed.
+
+```bash
+$ cmctl check api
+The cert-manager API is ready
+```
+
+The command can also be used to wait for the check to be successful.
+Here is an output example of running the command at the same time that cert-manager is being installed:
+
+```bash
+$ cmctl check api --wait=2m
+Not ready: the cert-manager CRDs are not yet installed on the Kubernetes API server
+Not ready: the cert-manager CRDs are not yet installed on the Kubernetes API server
+Not ready: the cert-manager webhook deployment is not ready yet
+Not ready: the cert-manager webhook deployment is not ready yet
+Not ready: the cert-manager webhook deployment is not ready yet
+Not ready: the cert-manager webhook deployment is not ready yet
+The cert-manager API is ready
+```
+
+## Manual verification
+
+Once you've installed cert-manager, you can verify it is deployed correctly by
+checking the `cert-manager` namespace for running pods:
+
+```bash
+$ kubectl get pods --namespace cert-manager
+
+NAME READY STATUS RESTARTS AGE
+cert-manager-5c6866597-zw7kh 1/1 Running 0 2m
+cert-manager-cainjector-577f6d9fd7-tr77l 1/1 Running 0 2m
+cert-manager-webhook-787858fcdb-nlzsq 1/1 Running 0 2m
+```
+
+You should see the `cert-manager`, `cert-manager-cainjector`, and
+`cert-manager-webhook` pods in a `Running` state. The webhook might take a
+little longer to successfully provision than the others.
+
+If you experience problems, first check the [FAQ](../faq/README.md).
+
+Create an `Issuer` to test the webhook works okay.
+```bash
+$ cat < test-resources.yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: cert-manager-test
+---
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: test-selfsigned
+ namespace: cert-manager-test
+spec:
+ selfSigned: {}
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: selfsigned-cert
+ namespace: cert-manager-test
+spec:
+ dnsNames:
+ - example.com
+ secretName: selfsigned-cert-tls
+ issuerRef:
+ name: test-selfsigned
+EOF
+```
+
+Create the test resources.
+```bash
+$ kubectl apply -f test-resources.yaml
+```
+
+Check the status of the newly created certificate. You may need to wait a few
+seconds before cert-manager processes the certificate request.
+```bash
+$ kubectl describe certificate -n cert-manager-test
+
+...
+Spec:
+ Common Name: example.com
+ Issuer Ref:
+ Name: test-selfsigned
+ Secret Name: selfsigned-cert-tls
+Status:
+ Conditions:
+ Last Transition Time: 2019-01-29T17:34:30Z
+ Message: Certificate is up to date and has not expired
+ Reason: Ready
+ Status: True
+ Type: Ready
+ Not After: 2019-04-29T17:34:29Z
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal CertIssued 4s cert-manager Certificate issued successfully
+```
+
+Clean up the test resources.
+```bash
+$ kubectl delete -f test-resources.yaml
+```
+
+If all the above steps have completed without error, you're good to go!
+
+## Community-maintained tool
+
+Alternatively, to automatically check if cert-manager is correctly configured,
+you can run the community-maintained [cert-manager-verifier](https://github.com/alenkacz/cert-manager-verifier) tool.
diff --git a/content/v1.12-docs/manifest.json b/content/v1.12-docs/manifest.json
new file mode 100644
index 00000000000..e8b2685a6ee
--- /dev/null
+++ b/content/v1.12-docs/manifest.json
@@ -0,0 +1,758 @@
+{
+ "routes": [
+ {
+ "title": "cert-manager",
+
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/README.md"
+ },
+ {
+ "title": "Getting Started",
+ "path": "/docs/getting-started/README.md"
+ },
+ {
+ "title": "Installation",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/installation/README.md"
+ },
+ {
+ "title": "Supported Releases",
+ "path": "/docs/installation/supported-releases.md"
+ },
+ {
+ "title": "Cloud Compatibility",
+ "path": "/docs/installation/compatibility.md"
+ },
+ {
+ "title": "kubectl apply",
+ "path": "/docs/installation/kubectl.md"
+ },
+ {
+ "title": "Helm",
+ "path": "/docs/installation/helm.md"
+ },
+ {
+ "title": "OperatorHub (OLM)",
+ "path": "/docs/installation/operator-lifecycle-manager.md"
+ },
+ {
+ "title": "Other tools",
+ "path": "/docs/installation/other-tools.md"
+ },
+ {
+ "title": "Verifying",
+ "path": "/docs/installation/verify.md"
+ },
+ {
+ "title": "Feature flags",
+ "path": "/docs/installation/featureflags.md"
+ },
+ {
+ "title": "Upgrading",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/installation/upgrading/README.md"
+ },
+ {
+ "title": "Notes on Ingress Class Compatibility",
+ "path": "/docs/installation/upgrading/ingress-class-compatibility.md"
+ },
+ {
+ "title": "Migrating Deprecated API Resources",
+ "path": "/docs/installation/upgrading/remove-deprecated-apis.md"
+ },
+ {
+ "title": "v1.10 to v1.11",
+ "path": "/docs/installation/upgrading/upgrading-1.10-1.11.md"
+ },
+ {
+ "title": "v1.9 to v1.10",
+ "path": "/docs/installation/upgrading/upgrading-1.9-1.10.md"
+ },
+ {
+ "title": "v1.8 to v1.9",
+ "path": "/docs/installation/upgrading/upgrading-1.8-1.9.md"
+ },
+ {
+ "title": "v1.7 to v1.8",
+ "path": "/docs/installation/upgrading/upgrading-1.7-1.8.md"
+ },
+ {
+ "title": "v1.6 to v1.7",
+ "path": "/docs/installation/upgrading/upgrading-1.6-1.7.md"
+ },
+ {
+ "title": "v1.5 to v1.6",
+ "path": "/docs/installation/upgrading/upgrading-1.5-1.6.md"
+ },
+ {
+ "title": "v1.4 to v1.5",
+ "path": "/docs/installation/upgrading/upgrading-1.4-1.5.md"
+ },
+ {
+ "title": "v1.3 to v1.4",
+ "path": "/docs/installation/upgrading/upgrading-1.3-1.4.md"
+ },
+ {
+ "title": "v1.2 to v1.3",
+ "path": "/docs/installation/upgrading/upgrading-1.2-1.3.md"
+ },
+ {
+ "title": "v1.1 to v1.2",
+ "path": "/docs/installation/upgrading/upgrading-1.1-1.2.md"
+ },
+ {
+ "title": "v1.0 to v1.1",
+ "path": "/docs/installation/upgrading/upgrading-1.0-1.1.md"
+ },
+ {
+ "title": "v0.16 to v1.0",
+ "path": "/docs/installation/upgrading/upgrading-0.16-1.0.md"
+ },
+ {
+ "title": "v0.15 to v0.16",
+ "path": "/docs/installation/upgrading/upgrading-0.15-0.16.md"
+ },
+ {
+ "title": "v0.14 to v0.15",
+ "path": "/docs/installation/upgrading/upgrading-0.14-0.15.md"
+ },
+ {
+ "title": "v0.13 to v0.14",
+ "path": "/docs/installation/upgrading/upgrading-0.13-0.14.md"
+ },
+ {
+ "title": "v0.12 to v0.13",
+ "path": "/docs/installation/upgrading/upgrading-0.12-0.13.md"
+ },
+ {
+ "title": "v0.11 to v0.12",
+ "path": "/docs/installation/upgrading/upgrading-0.11-0.12.md"
+ },
+ {
+ "title": "v0.10 to v0.11",
+ "path": "/docs/installation/upgrading/upgrading-0.10-0.11.md"
+ },
+ {
+ "title": "v0.9 to v0.10",
+ "path": "/docs/installation/upgrading/upgrading-0.9-0.10.md"
+ },
+ {
+ "title": "v0.8 to v0.9",
+ "path": "/docs/installation/upgrading/upgrading-0.8-0.9.md"
+ },
+ {
+ "title": "v0.7 to v0.8",
+ "path": "/docs/installation/upgrading/upgrading-0.7-0.8.md"
+ },
+ {
+ "title": "v0.6 to v0.7",
+ "path": "/docs/installation/upgrading/upgrading-0.6-0.7.md"
+ },
+ {
+ "title": "v0.5 to v0.6",
+ "path": "/docs/installation/upgrading/upgrading-0.5-0.6.md"
+ },
+ {
+ "title": "v0.4 to v0.5",
+ "path": "/docs/installation/upgrading/upgrading-0.4-0.5.md"
+ },
+ {
+ "title": "v0.3 to v0.4",
+ "path": "/docs/installation/upgrading/upgrading-0.3-0.4.md"
+ },
+ {
+ "title": "v0.2 to v0.3",
+ "path": "/docs/installation/upgrading/upgrading-0.2-0.3.md"
+ }
+ ]
+ },
+ {
+ "title": "Uninstall",
+ "path": "/docs/installation/uninstall.md"
+ },
+ {
+ "title": "API compatibility",
+ "path": "/docs/installation/api-compatibility.md"
+ },
+ {
+ "title": "Signature Verification",
+ "path": "/docs/installation/code-signing.md"
+ },
+ {
+ "title": "Best Practice",
+ "path": "/docs/installation/best-practice.md"
+ }
+ ]
+ },
+ {
+ "title": "Configuration",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/configuration/README.md"
+ },
+ {
+ "title": "SelfSigned",
+ "path": "/docs/configuration/selfsigned.md"
+ },
+ {
+ "title": "CA",
+ "path": "/docs/configuration/ca.md"
+ },
+ {
+ "title": "Vault",
+ "path": "/docs/configuration/vault.md"
+ },
+ {
+ "title": "Venafi",
+ "path": "/docs/configuration/venafi.md"
+ },
+ {
+ "title": "External",
+ "path": "/docs/configuration/external.md"
+ },
+ {
+ "title": "ACME",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/configuration/acme/README.md"
+ },
+ {
+ "title": "HTTP01",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/configuration/acme/http01/README.md"
+ },
+ {
+ "title": "External Load Balancer",
+ "path": "/docs/configuration/acme/http01/externalloadbalancer.md"
+ }
+ ]
+ },
+ {
+ "title": "DNS01",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/configuration/acme/dns01/README.md"
+ },
+ {
+ "title": "ACMEDNS",
+ "path": "/docs/configuration/acme/dns01/acme-dns.md"
+ },
+ {
+ "title": "Akamai",
+ "path": "/docs/configuration/acme/dns01/akamai.md"
+ },
+ {
+ "title": "AzureDNS",
+ "path": "/docs/configuration/acme/dns01/azuredns.md"
+ },
+ {
+ "title": "Cloudflare",
+ "path": "/docs/configuration/acme/dns01/cloudflare.md"
+ },
+ {
+ "title": "DigitalOcean",
+ "path": "/docs/configuration/acme/dns01/digitalocean.md"
+ },
+ {
+ "title": "Google CloudDNS",
+ "path": "/docs/configuration/acme/dns01/google.md"
+ },
+ {
+ "title": "RFC-2136",
+ "path": "/docs/configuration/acme/dns01/rfc2136.md"
+ },
+ {
+ "title": "Route53",
+ "path": "/docs/configuration/acme/dns01/route53.md"
+ },
+ {
+ "title": "Webhook",
+ "path": "/docs/configuration/acme/dns01/webhook.md"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Usage",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/usage/README.md"
+ },
+ {
+ "title": "Certificate Resources",
+ "path": "/docs/usage/certificate.md"
+ },
+ {
+ "title": "Prometheus Metrics",
+ "path": "/docs/usage/prometheus-metrics.md"
+ },
+ {
+ "title": "Securing Ingress Resources",
+ "path": "/docs/usage/ingress.md"
+ },
+ {
+ "title": "Securing Gateway Resources",
+ "path": "/docs/usage/gateway.md"
+ },
+ {
+ "title": "Securing Istio Service Mesh",
+ "path": "/docs/usage/istio.md"
+ },
+ {
+ "title": "CSI Driver",
+ "path": "/docs/usage/csi.md"
+ },
+ {
+ "title": "Kubernetes CertificateSigningRequests",
+ "path": "/docs/usage/kube-csr.md"
+ },
+ {
+ "title": "Policy for cert-manager certificates",
+ "path": "/docs/usage/approver-policy.md"
+ }
+ ]
+ },
+ {
+ "title": "Projects",
+ "routes": [
+ {
+ "title": "Contents",
+ "path": "/docs/projects/README.md"
+ },
+ {
+ "title": "istio-csr",
+ "path": "/docs/projects/istio-csr.md"
+ },
+ {
+ "title": "csi-driver",
+ "path": "/docs/projects/csi-driver.md"
+ },
+ {
+ "title": "csi-driver-spiffe",
+ "path": "/docs/projects/csi-driver-spiffe.md"
+ },
+ {
+ "title": "approver-policy",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/projects/approver-policy/README.md"
+ },
+ {
+ "title": "API Reference",
+ "path": "/docs/projects/approver-policy/api-reference.md"
+ }
+ ]
+ },
+ {
+ "title": "trust-manager",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/projects/trust-manager/README.md"
+ },
+ {
+ "title": "API Reference",
+ "path": "/docs/projects/trust-manager/api-reference.md"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Tutorials",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/tutorials/README.md"
+ },
+ {
+ "title": "Securing NGINX-ingress",
+ "path": "/docs/tutorials/acme/nginx-ingress.md"
+ },
+ {
+ "title": "GKE + Ingress + Let's Encrypt",
+ "path": "/docs/tutorials/getting-started-with-cert-manager-on-google-kubernetes-engine-using-lets-encrypt-for-ingress-ssl/README.md"
+ },
+ {
+ "title": "AKS + LoadBalancer + Let's Encrypt",
+ "path": "/docs/tutorials/getting-started-aks-letsencrypt/README.md"
+ },
+ {
+ "title": "Migrating from Kube-LEGO",
+ "path": "/docs/tutorials/acme/migrating-from-kube-lego.md"
+ },
+ {
+ "title": "Backup and Restore Resources",
+ "path": "/docs/tutorials/backup.md"
+ },
+ {
+ "title": "DNS Validation",
+ "path": "/docs/tutorials/acme/dns-validation.md"
+ },
+ {
+ "title": "HTTP Validation",
+ "path": "/docs/tutorials/acme/http-validation.md"
+ },
+ {
+ "title": "Pomerium Ingress",
+ "path": "/docs/tutorials/acme/pomerium-ingress.md"
+ },
+ {
+ "title": "EKS + Ingress + Venafi",
+ "path": "/docs/tutorials/venafi/venafi.md"
+ },
+ {
+ "title": "Securing the istio Service Mesh using cert-manager",
+ "path": "/docs/tutorials/istio-csr/istio-csr.md"
+ },
+ {
+ "title": "Syncing Secrets Across Namespaces",
+ "path": "/docs/tutorials/syncing-secrets-across-namespaces.md"
+ },
+ {
+ "title": "Securing Ingresses with ZeroSSL",
+ "path": "/docs/tutorials/zerossl/zerossl.md"
+ }
+ ]
+ },
+ {
+ "title": "Troubleshooting",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/troubleshooting/README.md"
+ },
+ {
+ "title": "Troubleshooting ACME / Let's Encrypt Certificates",
+ "path": "/docs/troubleshooting/acme.md"
+ },
+ {
+ "title": "Troubleshooting webhook",
+ "path": "/docs/troubleshooting/webhook.md"
+ }
+ ]
+ },
+ {
+ "title": "FAQ",
+ "path": "/docs/faq/README.md"
+ },
+ {
+ "title": "Contributing",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/contributing/README.md"
+ },
+ {
+ "title": "Feature Policy",
+ "path": "/docs/contributing/policy.md"
+ },
+ {
+ "title": "Building cert-manager",
+ "path": "/docs/contributing/building.md"
+ },
+ {
+ "title": "Contributing Flow",
+ "path": "/docs/contributing/contributing-flow.md"
+ },
+ {
+ "title": "CRDs",
+ "path": "/docs/contributing/crds.md"
+ },
+ {
+ "title": "DNS Providers",
+ "path": "/docs/contributing/dns-providers.md"
+ },
+ {
+ "title": "Running End-to-End Tests",
+ "path": "/docs/contributing/e2e.md"
+ },
+ {
+ "title": "Implementing External Issuers",
+ "path": "/docs/contributing/external-issuers.md"
+ },
+ {
+ "title": "DCO Sign Off",
+ "path": "/docs/contributing/sign-off.md"
+ },
+ {
+ "title": "Release Process",
+ "path": "/docs/contributing/release-process.md"
+ },
+ {
+ "title": "Developing with Kind",
+ "path": "/docs/contributing/kind.md"
+ },
+ {
+ "title": "Implementing Feature Gates",
+ "path": "/docs/contributing/featuregates.md"
+ },
+ {
+ "title": "Google Season of Docs",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/contributing/google-season-of-docs/README.md"
+ },
+ {
+ "title": "2022",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/contributing/google-season-of-docs/2022/README.md"
+ },
+ {
+ "title": "Improve the Navigation and Structure of the cert-manager Website",
+ "path": "/docs/contributing/google-season-of-docs/2022/improve-navigation-and-structure.md"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "title": "Reporting Security Issues",
+ "path": "/docs/contributing/security.md"
+ },
+ {
+ "title": "Coding Conventions",
+ "path": "/docs/contributing/coding-conventions.md"
+ },
+ {
+ "title": "Third Party Code Donations",
+ "path": "/docs/contributing/third-party-code-donation.md"
+ },
+ {
+ "title": "Signing Keys",
+ "path": "/docs/contributing/signing-keys.md"
+ },
+ {
+ "title": "Importing cert-manager in Go",
+ "path": "/docs/contributing/importing.md"
+ }
+ ]
+ },
+ {
+ "title": "Release Notes",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/release-notes/README.md"
+ },
+ {
+ "title": "v1.11",
+ "path": "/docs/release-notes/release-notes-1.11.md"
+ },
+ {
+ "title": "v1.10",
+ "path": "/docs/release-notes/release-notes-1.10.md"
+ },
+ {
+ "title": "v1.9",
+ "path": "/docs/release-notes/release-notes-1.9.md"
+ },
+ {
+ "title": "v1.8",
+ "path": "/docs/release-notes/release-notes-1.8.md"
+ },
+ {
+ "title": "v1.7",
+ "path": "/docs/release-notes/release-notes-1.7.md"
+ },
+ {
+ "title": "v1.6",
+ "path": "/docs/release-notes/release-notes-1.6.md"
+ },
+ {
+ "title": "v1.5",
+ "path": "/docs/release-notes/release-notes-1.5.md"
+ },
+ {
+ "title": "v1.4",
+ "path": "/docs/release-notes/release-notes-1.4.md"
+ },
+ {
+ "title": "v1.3",
+ "path": "/docs/release-notes/release-notes-1.3.md"
+ },
+ {
+ "title": "v1.2",
+ "path": "/docs/release-notes/release-notes-1.2.md"
+ },
+ {
+ "title": "v1.1",
+ "path": "/docs/release-notes/release-notes-1.1.md"
+ },
+ {
+ "title": "v1.0",
+ "path": "/docs/release-notes/release-notes-1.0.md"
+ },
+ {
+ "title": "v0.16",
+ "path": "/docs/release-notes/release-notes-0.16.md"
+ },
+ {
+ "title": "v0.15",
+ "path": "/docs/release-notes/release-notes-0.15.md"
+ },
+ {
+ "title": "v0.14",
+ "path": "/docs/release-notes/release-notes-0.14.md"
+ },
+ {
+ "title": "v0.13",
+ "path": "/docs/release-notes/release-notes-0.13.md"
+ },
+ {
+ "title": "v0.12",
+ "path": "/docs/release-notes/release-notes-0.12.md"
+ },
+ {
+ "title": "v0.11",
+ "path": "/docs/release-notes/release-notes-0.11.md"
+ },
+ {
+ "title": "v0.10",
+ "path": "/docs/release-notes/release-notes-0.10.md"
+ },
+ {
+ "title": "v0.9",
+ "path": "/docs/release-notes/release-notes-0.9.md"
+ },
+ {
+ "title": "v0.8",
+ "path": "/docs/release-notes/release-notes-0.8.md"
+ },
+ {
+ "title": "v0.7",
+ "path": "/docs/release-notes/release-notes-0.7.md"
+ },
+ {
+ "title": "v0.6",
+ "path": "/docs/release-notes/release-notes-0.6.md"
+ },
+ {
+ "title": "v0.5",
+ "path": "/docs/release-notes/release-notes-0.5.md"
+ },
+ {
+ "title": "v0.4",
+ "path": "/docs/release-notes/release-notes-0.4.md"
+ },
+ {
+ "title": "v0.3",
+ "path": "/docs/release-notes/release-notes-0.3.md"
+ },
+ {
+ "title": "v0.2",
+ "path": "/docs/release-notes/release-notes-0.2.md"
+ },
+ {
+ "title": "v0.1",
+ "path": "/docs/release-notes/release-notes-0.1.md"
+ }
+ ]
+ },
+ {
+ "title": "Concepts",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/concepts/README.md"
+ },
+ {
+ "title": "Issuer",
+ "path": "/docs/concepts/issuer.md"
+ },
+ {
+ "title": "Certificate",
+ "path": "/docs/concepts/certificate.md"
+ },
+ {
+ "title": "CertificateRequest",
+ "path": "/docs/concepts/certificaterequest.md"
+ },
+ {
+ "title": "ACME Orders and Challenges",
+ "path": "/docs/concepts/acme-orders-challenges.md"
+ },
+ {
+ "title": "Webhook",
+ "path": "/docs/concepts/webhook.md"
+ },
+ {
+ "title": "CA Injector",
+ "path": "/docs/concepts/ca-injector.md"
+ }
+ ]
+ },
+ {
+ "title": "Reference",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/reference/README.md"
+ },
+ {
+ "title": "Command Line Tool (cmctl)",
+ "path": "/docs/reference/cmctl.md"
+ },
+ {
+ "title": "TLS Terminology",
+ "path": "/docs/reference/tls-terminology.md"
+ },
+
+ {
+ "title": "Components / Docker Images",
+ "routes": [
+ {
+ "title": "Introduction",
+ "path": "/docs/cli/README.md"
+ },
+ {
+ "title": "acmesolver",
+ "path": "/docs/cli/acmesolver.md"
+ },
+ {
+ "title": "cainjector",
+ "path": "/docs/cli/cainjector.md"
+ },
+ {
+ "title": "cmctl",
+ "path": "/docs/cli/cmctl.md"
+ },
+ {
+ "title": "controller",
+ "path": "/docs/cli/controller.md"
+ },
+ {
+ "title": "webhook",
+ "path": "/docs/cli/webhook.md"
+ }
+ ]
+ },
+ {
+ "title": "API Reference",
+ "path": "/docs/reference/api-docs.md"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/content/v1.12-docs/projects/README.md b/content/v1.12-docs/projects/README.md
new file mode 100644
index 00000000000..185df2fce43
--- /dev/null
+++ b/content/v1.12-docs/projects/README.md
@@ -0,0 +1,31 @@
+---
+title: Projects
+description: 'Satellite Projects of cert-manager'
+---
+
+The cert-manager project has a number of [satellite projects](https://github.com/cert-manager)
+that extend the project's functionality, and complement the core cert-manager feature-set.
+
+These tools help with security, compliance and control.
+
+- [istio-csr](./istio-csr.md): Secure Istio service mesh with istio-csr which is
+ an agent that allows for [Istio](https://istio.io) workload and control plane
+ components to be secured using cert-manager.
+- [approver-policy](./approver-policy/README.md):
+ a cert-manager **approver** that will automatically approve or deny
+ certificate requests based on defined policy.
+- [csi-driver](./csi-driver.md):
+ a Container Storage Interface (CSI) driver plugin for Kubernetes to work along
+ cert-manager. The goal for this plugin is to seamlessly request and mount
+ certificate key pairs to pods. This is useful for facilitating mTLS, or
+ otherwise securing connections of pods with guaranteed present certificates
+ whilst having all of the features that cert-manager provides.
+- [csi-driver-spiffe](./csi-driver-spiffe.md):
+ another CSI driver plugin to work along cert-manager. This CSI driver
+ transparently delivers [SPIFFE](https://spiffe.io/)
+ [SVIDs](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#spiffe-verifiable-identity-document-svid)
+ in the form of X.509 certificate key pairs to mounting Kubernetes Pods. The
+ end result is all and any Pod running in Kubernetes can securely request their
+ SPIFFE identity document from a Trust Domain with minimal configuration.
+- [trust-manager](./trust-manager/README.md): the easiest way to manage TLS trust bundles in Kubernetes and OpenShift clusters.
+- [trust-manager API reference](./trust-manager/api-reference.md): full documentation of the trust-manager CRD(s)
diff --git a/content/v1.12-docs/projects/approver-policy/README.md b/content/v1.12-docs/projects/approver-policy/README.md
new file mode 100644
index 00000000000..aa7efcef6c5
--- /dev/null
+++ b/content/v1.12-docs/projects/approver-policy/README.md
@@ -0,0 +1,422 @@
+---
+title: approver-policy
+description: 'Policy plugin for cert-manager'
+---
+
+approver-policy is a cert-manager
+[approver](../../concepts/certificaterequest.md#approval)
+that will approve or deny CertificateRequests based on policies defined in
+the `CertificateRequestPolicy` custom resource.
+
+## Prerequisites
+
+[cert-manager must be installed](../../installation/README.md), and
+the [the default approver in cert-manager must be disabled](../../concepts/certificaterequest.md#approver-controller).
+
+> ⚠️ If the default approver is not disabled in cert-manager, approver-policy will
+> race with cert-manager and policy will be ineffective.
+
+If you install cert-manager using `helm install` or `helm upgrade`,
+you can disable the default approver by [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing) using the `--set` or `--values` command line flags:
+
+```
+# Example --set value
+--set extraArgs={--controllers='*\,-certificaterequests-approver'} # ⚠ Disable cert-manager's built-in approver
+```
+
+```yaml
+# Example --values file content
+extraArgs:
+ - "--controllers=*,-certificaterequests-approver" # ⚠ Disable cert-manager's built-in approver
+```
+
+Here's a full example which will install cert-manager or reconfigure it if it is already installed:
+
+```terminal
+helm upgrade cert-manager jetstack/cert-manager \
+ --install \
+ --create-namespace \
+ --namespace cert-manager \
+ --version REPLACE-WITH-YOUR-CERT-MANAGER-VERSION \
+ --set installCRDs=true \
+ --set extraArgs={--controllers='*\,-certificaterequests-approver'} # ⚠ Disable cert-manager's built-in approver
+```
+
+> ℹ️ The `--set installCRDs=true` setting is a convenient way to install the
+> cert-manager CRDS, but it is optional and has some drawbacks.
+> Read [Helm: Installing Custom Resource Definitions](https://deploy-preview-1216--cert-manager-website.netlify.app/docs/installation/helm/#3-install-customresourcedefinitions) to learn more.
+>
+> ℹ️ Be sure to customize the cert-manager controller `extraArgs`,
+> which are at the top level of the values file.
+> *Do not* change the `webhook.extraArgs`, `startupAPICheck.extraArgs` or `cainjector.extraArgs` settings.
+>
+> ⚠️ If you are reconfiguring an already installed cert-manager,
+> check whether the original installation already customized the `extraArgs` value
+> by running `helm get values cert-manager --namespace cert-manager`.
+> If there are already `extraArgs` values, merge those with the extra `--controllers` value.
+> Otherwise your original `extraArgs` values will be overwritten.
+
+## Installation
+
+To install approver-policy:
+
+```terminal
+helm repo add jetstack https://charts.jetstack.io --force-update
+helm upgrade -i -n cert-manager cert-manager-approver-policy jetstack/cert-manager-approver-policy --wait
+```
+
+If you are using approver-policy with [external
+issuers](../../configuration/external.md), you _must_
+include their signer names so that approver-policy has permissions to approve
+and deny CertificateRequests that
+[reference them](../../concepts/certificaterequest.md#rbac-syntax).
+For example, if using approver-policy for the internal issuer types, along with
+[google-cas-issuer](https://github.com/jetstack/google-cas-issuer), and
+[aws-privateca-issuer](https://github.com/cert-manager/aws-privateca-issuer),
+set the following values when installing:
+
+```terminal
+$ helm upgrade -i -n cert-manager cert-manager-approver-policy jetstack/cert-manager-approver-policy --wait \
+ --set app.approveSignerNames="{\
+issuers.cert-manager.io/*,clusterissuers.cert-manager.io/*,\
+googlecasclusterissuers.cas-issuer.jetstack.io/*,googlecasissuers.cas-issuer.jetstack.io/*,\
+awspcaclusterissuers.awspca.cert-manager.io/*,awspcaissuers.awspca.cert-manager.io/*\
+}"
+```
+
+## Configuration
+
+> Example policy resources can be found
+> [here](https://github.com/cert-manager/approver-policy/tree/main/docs/examples).
+
+When a CertificateRequest is created, approver-policy will evaluate whether the
+request is appropriate for any existing policy, and if so, evaluate whether it
+should be approved or denied.
+
+For a CertificateRequest to be appropriate for a policy and therefore be
+evaluated by it, it must be both bound via RBAC _and_ be selected by the policy
+selector. CertificateRequestPolicy currently only supports `issuerRef` as a
+selector.
+
+**If at least one policy permits the request, the request is approved. If at
+least one policy is appropriate for the request but none of those permit the
+request, the request is denied.**
+
+A denied CertificateRequest is considered to be permanently failed. If it was
+created for a Certificate resource, the issuance will be retried with
+[exponential backoff](../../faq/README.md#what-happens-if-issuance-fails-will-it-be-retried)
+like all other permanent issuance failures. A CertificateRequest that is neither
+approved nor denied (because no matching policy was found) will not be further
+processed by cert-manager until it gets either approved or denied.
+
+CertificateRequestPolicies are cluster scoped resources that can be thought of
+as "policy profiles". They describe any request that is approved by that
+policy. Policies are bound to Kubernetes users and ServiceAccounts using RBAC.
+
+Below is an example of a policy that is bound to all Kubernetes users who may
+only request certificates that have the common name of `"hello.world"`.
+
+```yaml
+apiVersion: policy.cert-manager.io/v1alpha1
+kind: CertificateRequestPolicy
+metadata:
+ name: test-policy
+spec:
+ allowed:
+ commonName:
+ value: "hello.world"
+ required: true
+ selector:
+ # Select all IssuerRef
+ issuerRef: {}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: cert-manager-policy:hello-world
+rules:
+ - apiGroups: ["policy.cert-manager.io"]
+ resources: ["certificaterequestpolicies"]
+ verbs: ["use"]
+ # Name of the CertificateRequestPolicies to be used.
+ resourceNames: ["test-policy"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: cert-manager-policy:hello-world
+roleRef:
+# ClusterRole or Role _must_ be bound to a user for the policy to be considered.
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cert-manager-policy:hello-world
+subjects:
+# The users who should be bound to the policies defined.
+# Note that in the case of users creating Certificate resources, cert-manager
+# is the entity that is creating the actual CertificateRequests, and so the
+# cert-manager controller's
+# Service Account should be bound instead.
+- kind: Group
+ name: system:authenticated
+ apiGroup: rbac.authorization.k8s.io
+```
+
+## Behavior
+
+CertificateRequestPolicy are split into 4 parts; `allowed`, `contraints`,
+`selector`, and `plugins`.
+
+### Allowed
+
+Allowed is the block that defines attributes that match against the
+corresponding attribute in the request. A request is permitted by the policy if
+the request omits an allowed attribute, but will _deny_ the request if it
+contains an attribute which is _not_ present in the allowed block.
+
+An allowed attribute can be marked as `required`, which if true, will enforce
+that the attribute has been defined in the request. A field can only be marked
+as `required` if the corresponding field is also defined. The `required` field
+is not available for `isCA` or `usages`.
+
+In the following CertificateRequestPolicy, a request will be permitted if it
+does not request a DNS name, requests the DNS name `"example.com"`, but will be
+denied when requesting `"bar.example.com"`.
+
+```yaml
+spec:
+ ...
+ allowed:
+ dnsNames:
+ values:
+ - "example.com"
+ - "foo.example.com"
+ ...
+```
+
+In the following, a request will be denied if the request contains no Common
+Name, but will permit requests whose Common Name ends in ".com".
+
+```yaml
+spec:
+ ...
+ allowed:
+ commonName:
+ value: "*.com"
+ required: true
+ ...
+```
+
+If an allowed field is omitted, that attribute is considered "deny all" for
+requests.
+
+Allowed string fields accept wildcards "\*" within its values. Wildcards "\*" in
+patterns represent any string that has a length of 0 or more. A pattern
+containing only "\*" will match anything. A pattern containing `"\*foo"` will
+match `"foo"` as well as any string which ends in `"foo"` (e.g. `"bar-foo"`). A
+pattern containing `"\*.foo"` will match `"bar-123.foo"`, but not `"barfoo"`.
+
+Allowed fields that are lists will permit requests that are a subset of that
+list. This means that if `usages` contains `["server auth", "client auth"]`,
+then a request containing only `["server auth"]` would be permitted, but not
+`["server auth", "cert sign"]`.
+
+Below is an example including all supported allowed fields of
+CertificateRequestPolicy.
+
+```yaml
+apiVersion: policy.cert-manager.io/v1alpha1
+kind: CertificateRequestPolicy
+metadata:
+ name: my-policy
+spec:
+ allowed:
+ commonName:
+ value: "example.com"
+ dnsNames:
+ values:
+ - "example.com"
+ - "*.example.com"
+ ipAddresses:
+ values:
+ - "1.2.3.4"
+ - "10.0.1.*"
+ uris:
+ values:
+ - "spiffe://example.org/ns/*/sa/*"
+ emailAddresses:
+ values:
+ - "*@example.com"
+ required: true
+ isCA: false
+ usages:
+ - "server auth"
+ - "client auth"
+ subject:
+ organizations:
+ values: ["hello-world"]
+ countries:
+ values: ["*"]
+ organizationalUnits:
+ values: ["*"]
+ localities:
+ values: ["*"]
+ provinces:
+ values: ["*"]
+ streetAddresses:
+ values: ["*"]
+ postalCodes:
+ values: ["*"]
+ serialNumber:
+ value: "*"
+ ...
+```
+
+### Constraints
+
+Constraints is the block that is used to limit what attributes the request can
+have. If a constraint is not defined, then the attribute is considered "allow
+all".
+
+Below is an example containing all supported constraints fields of
+CertificateRequestPolicy.
+
+```yaml
+apiVersion: policy.cert-manager.io/v1alpha1
+kind: CertificateRequestPolicy
+metadata:
+ name: my-policy
+spec:
+ ...
+ constraints:
+ minDuration: 1h
+ maxDuration: 24h
+ privateKey:
+ algorithm: RSA
+ minSize: 2048
+ maxSize: 4096
+ ...
+```
+
+### Selector
+
+Selector is a required field that is used for matching
+CertificateRequestPolicies against CertificateRequests for evaluation. A
+CertificateRequestPolicy must select, and therefore match, a CertificateRequest
+for it to be considered for evaluation of the request.
+
+> ⚠️ Note that the user must still be bound by [RBAC](#configuration) for
+> the policy to be considered for evaluation against a request.
+
+approver-policy supports selecting over the `issuerRef` and the `namespace` of a
+request.
+
+At least either an `issuerRef` *or* `namespace` selector must be defined, even
+if set to empty (`{}`). **Both** selectors must match on a CertificateRequest
+for the request to evaluated by the policy if both are defined.
+
+#### `issuerRef`
+
+The `issuerRef` CertificateRequestPolicy selector selects on the corresponding
+`issuerRef` stanza on the CertificateRequest.
+
+`issuerRef` values accept wildcards "\*". If an `issuerRef` is set to an empty
+object `{}`, then the policy will match against _all_ requests.
+
+```yaml
+apiVersion: policy.cert-manager.io/v1alpha1
+kind: CertificateRequestPolicy
+metadata:
+ name: my-policy
+spec:
+ ...
+ selector:
+ issuerRef:
+ name: "my-ca"
+ kind: "*Issuer"
+ group: "cert-manager.io"
+```
+
+```yaml
+apiVersion: policy.cert-manager.io/v1alpha1
+kind: CertificateRequestPolicy
+metadata:
+ name: match-all-requests
+spec:
+ ...
+ selector:
+ issuerRef: {}
+```
+
+#### `namespace`
+
+The `namespace` CertificateRequestPolicy selector selects on the Namespace to
+which the CertificateRequest was created in. The selector can be defined with
+either `matchNames` or `matchLabels`.
+
+`matchNames` takes a list of strings which match the _name_ of the Namespace.
+Accepts wildcards "\*".
+
+`matchLabels` takes a list of key value strings which match on the labels of the
+Namespace that the CertificateRequest was created in. Please see the [Kubernetes
+documentation][] for more information on `matchLabels` behavior.
+
+If a `namespace` is set to an empty object `{}`, then the policy will match
+against _all_ requests.
+
+```yaml
+apiVersion: policy.cert-manager.io/v1alpha1
+kind: CertificateRequestPolicy
+metadata:
+ name: my-policy
+spec:
+ ...
+ selector:
+ namespace:
+ matchNames:
+ - "default"
+ - "app-team-*"
+ matchLabels:
+ foo: bar
+ team: dev
+```
+
+```yaml
+apiVersion: policy.cert-manager.io/v1alpha1
+kind: CertificateRequestPolicy
+metadata:
+ name: match-all-requests
+spec:
+ ...
+ selector:
+ namespace: {}
+```
+
+[Kubernetes documentation]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#resources-that-support-set-based-requirements
+
+### Plugins
+
+Plugins are external approvers that are built into approver-policy at compile
+time. Plugins are designed to be used as extensions to the existing policy
+checks where the user requires special functionality that the existing checks
+can't provide.
+
+Plugins are defined as a block on the CertificateRequestPolicy `spec`.
+
+```yaml
+apiVersion: policy.cert-manager.io/v1alpha1
+kind: CertificateRequestPolicy
+metadata:
+ name: plugins
+spec:
+ ...
+ plugins:
+ my-plugin:
+ values:
+ val-1: key-1
+```
+
+There are currently no open source plugins.
+
+## API Reference
+
+> 📖 Read the [approver-policy API reference](api-reference.md).
diff --git a/content/v1.12-docs/projects/approver-policy/api-reference.md b/content/v1.12-docs/projects/approver-policy/api-reference.md
new file mode 100644
index 00000000000..e4d45bb8297
--- /dev/null
+++ b/content/v1.12-docs/projects/approver-policy/api-reference.md
@@ -0,0 +1,978 @@
+---
+title: approver-policy API Reference
+description: "approver-policy API documentation"
+---
+
+Packages:
+
+- [`policy.cert-manager.io/v1alpha1`](#policycert-manageriov1alpha1)
+
+# `policy.cert-manager.io/v1alpha1`
+
+Resource Types:
+
+
+- [CertificateRequestPolicy](#certificaterequestpolicy)
+
+
+
+
+## `CertificateRequestPolicy`
+
+
+
+
+
+CertificateRequestPolicy is an object for describing a "policy profile" that makes decisions on whether applicable CertificateRequests should be approved or denied.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ apiVersion |
+ string |
+ policy.cert-manager.io/v1alpha1 |
+ true |
+
+
+ kind |
+ string |
+ CertificateRequestPolicy |
+ true |
+
+
+ metadata |
+ object |
+ Refer to the Kubernetes API documentation for the fields of the `metadata` field. |
+ true |
+
+ spec |
+ object |
+
+ CertificateRequestPolicySpec defines the desired state of CertificateRequestPolicy.
+ |
+ false |
+
+ status |
+ object |
+
+ CertificateRequestPolicyStatus defines the observed state of the CertificateRequestPolicy.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec`
+
+
+CertificateRequestPolicySpec defines the desired state of CertificateRequestPolicy.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ selector |
+ object |
+
+ Selector is used for selecting over which CertificateRequests this CertificateRequestPolicy is appropriate for and so will used for its approval evaluation.
+ |
+ true |
+
+ allowed |
+ object |
+
+ Allowed is the set of attributes that are "allowed" by this policy. A CertificateRequest will only be considered permissible for this policy if the CertificateRequest has the same or less as what is allowed. Empty or `nil` allowed fields mean CertificateRequests are not allowed to have that field present to be permissible.
+ |
+ false |
+
+ constraints |
+ object |
+
+ Constraints is the set of attributes that _must_ be satisfied by the CertificateRequest for the request to be permissible by the policy. Empty or `nil` constraint fields mean CertificateRequests satisfy that field with any value of their corresponding attribute.
+ |
+ false |
+
+ plugins |
+ map[string]object |
+
+ Plugins define a set of plugins and their configuration that should be executed when this policy is evaluated against a CertificateRequest. A plugin must already be built within approver-policy for it to be available.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.selector`
+
+
+Selector is used for selecting over which CertificateRequests this CertificateRequestPolicy is appropriate for and so will used for its approval evaluation.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ issuerRef |
+ object |
+
+ IssuerRef is used to match this CertificateRequestPolicy against processed CertificateRequests. This policy will only be evaluated against a CertificateRequest whose `spec.issuerRef` field matches `spec.selector.issuerRef`. CertificateRequests will not be processed on unmatched `issuerRef` if defined, regardless of whether the requestor is bound by RBAC. Accepts wildcards "*". Omitted values are equivalent to "*".
+ The following value will match _all_ `issuerRefs`: ``` issuerRef: {} ```
+ |
+ false |
+
+ namespace |
+ object |
+
+ Namespace is used to select on Namespaces, meaning the CertificateRequestPolicy will only match on CertificateRequests that have been created in matching selected Namespaces. If this field is omitted, all Namespaces are selected.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.selector.issuerRef`
+
+
+IssuerRef is used to match this CertificateRequestPolicy against processed CertificateRequests. This policy will only be evaluated against a CertificateRequest whose `spec.issuerRef` field matches `spec.selector.issuerRef`. CertificateRequests will not be processed on unmatched `issuerRef` if defined, regardless of whether the requestor is bound by RBAC. Accepts wildcards "*". Omitted values are equivalent to "*".
+ The following value will match _all_ `issuerRefs`: ``` issuerRef: {} ```
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ group |
+ string |
+
+ Group is the wildcard selector to match the `spec.issuerRef.group` field on requests. Accepts wildcards "*". An omitted field or value of `nil` matches all.
+ |
+ false |
+
+ kind |
+ string |
+
+ Kind is the wildcard selector to match the `spec.issuerRef.kind` field on requests. Accepts wildcards "*". An omitted field or value of `nil` matches all.
+ |
+ false |
+
+ name |
+ string |
+
+ Name is the wildcard selector to match the `spec.issuerRef.name` field on requests. Accepts wildcards "*". An omitted field or value of `nil` matches all.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.selector.namespace`
+
+
+Namespace is used to select on Namespaces, meaning the CertificateRequestPolicy will only match on CertificateRequests that have been created in matching selected Namespaces. If this field is omitted, all Namespaces are selected.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ matchLabels |
+ map[string]string |
+
+ MatchLabels is the set of Namespace labels that select on CertificateRequests which have been created in a Namespace matching the selector.
+ |
+ false |
+
+ matchNames |
+ []string |
+
+ MatchNames are the set of Namespace names that select on CertificateRequests that have been created in a matching Namespace. Accepts wildcards "*".
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed`
+
+
+Allowed is the set of attributes that are "allowed" by this policy. A CertificateRequest will only be considered permissible for this policy if the CertificateRequest has the same or less as what is allowed. Empty or `nil` allowed fields mean CertificateRequests are not allowed to have that field present to be permissible.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ commonName |
+ object |
+
+ CommonName defines the X.509 Common Name that is permissible.
+ |
+ false |
+
+ dnsNames |
+ object |
+
+ DNSNames defines the X.509 DNS SANs that may be requested for. Accepts wildcards "*".
+ |
+ false |
+
+ emailAddresses |
+ object |
+
+ EmailAddresses defines the X.509 Email SANs that may be requested for.
+ |
+ false |
+
+ ipAddresses |
+ object |
+
+ IPAddresses defines the X.509 IP SANs that may be requested for.
+ |
+ false |
+
+ isCA |
+ boolean |
+
+ IsCA defines whether it is permissible for a CertificateRequest to have the `spec.IsCA` field set to `true`. An omitted field, value of `nil` or `false`, forbids the `spec.IsCA` field from bring `true`. A value of `true` permits CertificateRequests setting the `spec.IsCA` field to `true`.
+ |
+ false |
+
+ subject |
+ object |
+
+ Subject defines the X.509 subject that is permissible. An omitted field or value of `nil` forbids any Subject being requested.
+ |
+ false |
+
+ uris |
+ object |
+
+ URIs defines the X.509 URI SANs that may be requested for.
+ |
+ false |
+
+ usages |
+ []enum |
+
+ Usages defines the list of permissible key usages that may appear on the CertificateRequest `spec.keyUsages` field. An omitted field or value of `nil` forbids any Usages being requested. An empty slice `[]` is equivalent to `nil`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.commonName`
+
+
+CommonName defines the X.509 Common Name that is permissible.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Value is also defined.
+ |
+ false |
+
+ value |
+ string |
+
+ Value defines the value that is permissible to be present on the request. Accepts wildcards "*". An omitted field or value of `nil` forbids the value from being requested. An empty string is equivalent to `nil`, however an empty string pared with Required as `true` is an impossible condition that always denies. Value may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.dnsNames`
+
+
+DNSNames defines the X.509 DNS SANs that may be requested for. Accepts wildcards "*".
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.emailAddresses`
+
+
+EmailAddresses defines the X.509 Email SANs that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.ipAddresses`
+
+
+IPAddresses defines the X.509 IP SANs that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.subject`
+
+
+Subject defines the X.509 subject that is permissible. An omitted field or value of `nil` forbids any Subject being requested.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ countries |
+ object |
+
+ Countries define the X.509 Subject Countries that may be requested for.
+ |
+ false |
+
+ localities |
+ object |
+
+ Localities defines the X.509 Subject Localities that may be requested for.
+ |
+ false |
+
+ organizationalUnits |
+ object |
+
+ OrganizationalUnits defines the X.509 Subject Organizational Units that may be requested for.
+ |
+ false |
+
+ organizations |
+ object |
+
+ Organizations define the X.509 Subject Organizations that may be requested for.
+ |
+ false |
+
+ postalCodes |
+ object |
+
+ PostalCodes defines the X.509 Subject Postal Codes that may be requested for.
+ |
+ false |
+
+ provinces |
+ object |
+
+ Provinces defines the X.509 Subject Provinces that may be requested for.
+ |
+ false |
+
+ serialNumber |
+ object |
+
+ SerialNumber defines the X.509 Subject Serial Number that may be requested for.
+ |
+ false |
+
+ streetAddresses |
+ object |
+
+ StreetAddresses defines the X.509 Subject Street Addresses that may be requested for.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.subject.countries`
+
+
+Countries define the X.509 Subject Countries that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.subject.localities`
+
+
+Localities defines the X.509 Subject Localities that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.subject.organizationalUnits`
+
+
+OrganizationalUnits defines the X.509 Subject Organizational Units that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.subject.organizations`
+
+
+Organizations define the X.509 Subject Organizations that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.subject.postalCodes`
+
+
+PostalCodes defines the X.509 Subject Postal Codes that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.subject.provinces`
+
+
+Provinces defines the X.509 Subject Provinces that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.subject.serialNumber`
+
+
+SerialNumber defines the X.509 Subject Serial Number that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Value is also defined.
+ |
+ false |
+
+ value |
+ string |
+
+ Value defines the value that is permissible to be present on the request. Accepts wildcards "*". An omitted field or value of `nil` forbids the value from being requested. An empty string is equivalent to `nil`, however an empty string pared with Required as `true` is an impossible condition that always denies. Value may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.subject.streetAddresses`
+
+
+StreetAddresses defines the X.509 Subject Street Addresses that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.allowed.uris`
+
+
+URIs defines the X.509 URI SANs that may be requested for.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ required |
+ boolean |
+
+ Required marks this field as being a required value on the request. May only be set to true if Values is also defined. Default is nil which marks the field as not required.
+ |
+ false |
+
+ values |
+ []string |
+
+ Defines the values that are permissible to be present on request. Accepts wildcards "*". An omitted field or value of `nil` forbids any value on the related field in the request from being requested. An empty slice `[]` is equivalent to `nil`, however an empty slice pared with Required `true` is an impossible condition that always denies. Values may not be `nil` if Required is `true`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.constraints`
+
+
+Constraints is the set of attributes that _must_ be satisfied by the CertificateRequest for the request to be permissible by the policy. Empty or `nil` constraint fields mean CertificateRequests satisfy that field with any value of their corresponding attribute.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ maxDuration |
+ string |
+
+ MaxDuration defines the maximum duration a certificate may be requested for. Values are inclusive (i.e. a max value of `1h` will accept a duration of `1h`). MaxDuration and MinDuration may be the same value. An omitted field or value of `nil` permits any maximum duration. If MaxDuration is defined, a duration _must_ be requested on the CertificateRequest.
+ |
+ false |
+
+ minDuration |
+ string |
+
+ MinDuration defines the minimum duration a certificate may be requested for. Values are inclusive (i.e. a min value of `1h` will accept a duration of `1h`). MinDuration and MaxDuration may be the same value. An omitted field or value of `nil` permits any minimum duration. If MinDuration is defined, a duration _must_ be requested on the CertificateRequest.
+ |
+ false |
+
+ privateKey |
+ object |
+
+ PrivateKey defines the shape of permissible private keys that may be used for the request with this policy. An omitted field or value of `nil` permits the use of any private key by the requestor.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.constraints.privateKey`
+
+
+PrivateKey defines the shape of permissible private keys that may be used for the request with this policy. An omitted field or value of `nil` permits the use of any private key by the requestor.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ algorithm |
+ enum |
+
+ Algorithm defines the allowed crypto algorithm that is used by the requestor for their private key in their request. An omitted field or value of `nil` permits any Algorithm.
+
+ Enum: RSA, ECDSA, Ed25519
+ |
+ false |
+
+ maxSize |
+ integer |
+
+ MaxSize defines the maximum key size a requestor may use for their private key. Values are inclusive (i.e. a min value of `2048` will accept a size of `2048`). MaxSize and MinSize may be the same value. An omitted field or value of `nil` permits any maximum size.
+ |
+ false |
+
+ minSize |
+ integer |
+
+ MinSize defines the minimum key size a requestor may use for their private key. Values are inclusive (i.e. a min value of `2048` will accept a size of `2048`). MinSize and MaxSize may be the same value. An omitted field or value of `nil` permits any minimum size.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.spec.plugins[key]`
+
+
+CertificateRequestPolicyPluginData is configuration needed by the plugin approver to evaluate a CertificateRequest on this policy.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ values |
+ map[string]string |
+
+ Values define a set of well-known, to the plugin, key value pairs that are required for the plugin to successfully evaluate a request based on this policy.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.status`
+
+
+CertificateRequestPolicyStatus defines the observed state of the CertificateRequestPolicy.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ conditions |
+ []object |
+
+ List of status conditions to indicate the status of the CertificateRequestPolicy. Known condition types are `Ready`.
+ |
+ false |
+
+
+
+
+### `CertificateRequestPolicy.status.conditions[index]`
+
+
+CertificateRequestPolicyCondition contains condition information for a CertificateRequestPolicyStatus.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ status |
+ string |
+
+ Status of the condition, one of ('True', 'False', 'Unknown').
+ |
+ true |
+
+ type |
+ string |
+
+ Type of the condition, known values are (`Ready`).
+ |
+ true |
+
+ lastTransitionTime |
+ string |
+
+ LastTransitionTime is the timestamp corresponding to the last status change of this condition.
+
+ Format: date-time
+ |
+ false |
+
+ message |
+ string |
+
+ Message is a human readable description of the details of the last transition, complementing reason.
+ |
+ false |
+
+ observedGeneration |
+ integer |
+
+ If set, this represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date with respect to the current state of the CertificateRequestPolicy.
+
+ Format: int64
+ |
+ false |
+
+ reason |
+ string |
+
+ Reason is a brief machine readable explanation for the condition's last transition.
+ |
+ false |
+
+
diff --git a/content/v1.12-docs/projects/csi-driver-spiffe.md b/content/v1.12-docs/projects/csi-driver-spiffe.md
new file mode 100644
index 00000000000..771ce6a1aed
--- /dev/null
+++ b/content/v1.12-docs/projects/csi-driver-spiffe.md
@@ -0,0 +1,257 @@
+---
+title: csi-driver-spiffe
+description: 'Container Storage Interface (CSI) driver plugin for Kubernetes, providing SPIFFE SVIDs using cert-manager'
+---
+
+csi-driver-spiffe is a Container Storage Interface (CSI) driver plugin for
+Kubernetes, designed to work alongside [cert-manager](https://cert-manager.io/).
+
+It transparently delivers [SPIFFE](https://spiffe.io/) [SVIDs](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/#spiffe-verifiable-identity-document-svid)
+(in the form of X.509 certificate key pairs) to mounting Kubernetes Pods.
+
+The end result is that any and all Pods running in Kubernetes can securely request
+a SPIFFE identity document from a Trust Domain with minimal configuration.
+
+These documents in turn have the following properties:
+
+- automatically renewed ✔️
+- private key never leaves the node's virtual memory ✔️
+- each Pod's document is unique ✔️
+- the document shares the same life cycle as the Pod and is destroyed on Pod termination ✔️
+
+```yaml
+...
+ volumeMounts:
+ - mountPath: "/var/run/secrets/spiffe.io"
+ name: spiffe
+ volumes:
+ - name: spiffe
+ csi:
+ driver: spiffe.csi.cert-manager.io
+ readOnly: true
+```
+
+SPIFFE documents can then be used by Pods for mutual TLS (mTLS) or other authentication within their Trust Domain.
+### Components
+
+The project is split into two components.
+
+#### CSI Driver
+
+The CSI driver runs as DaemonSet on the cluster which is responsible for
+generating, requesting, and mounting the certificate key pair to Pods on the
+node it manages. The CSI driver creates and manages a
+[tmpfs](https://www.kernel.org/doc/html/latest/filesystems/tmpfs.html) directory
+which is used to create and mount Pod volumes from.
+
+When a Pod is created with the CSI volume configured, the
+driver will locally generate a private key, and create a cert-manager
+[CertificateRequest](../concepts/certificaterequest.md)
+in the same Namespace as the Pod.
+
+The driver uses [CSI Token Request](https://kubernetes-csi.github.io/docs/token-requests.html) to both
+discover the Pod's identity to form the SPIFFE identity contained in the X.509
+certificate signing request, as well as securely impersonate its ServiceAccount
+when creating the CertificateRequest.
+
+Once signed by the pre-configured target signer, the driver will mount the
+private key and signed certificate into the Pod's Volume to be made available as
+a Volume Mount. This certificate key pair is regularly renewed based on the
+expiry of the signed certificate.
+
+#### Approver
+
+A distinct [cert-manager approver](../concepts/certificaterequest.md#approval)
+Deployment is responsible for managing the approval and denial condition of
+created CertificateRequests that target the configured SPIFFE Trust Domain
+signer.
+
+The approver ensures that requests have:
+
+1. acceptable key usages (Key Encipherment, Digital Signature, Client Auth, Server Auth);
+2. a requested duration which matches the enforced duration (default 1 hour);
+3. no [SANs](https://en.wikipedia.org/wiki/Subject_Alternative_Name) or other
+ identifiable attributes except a single [URI SAN](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier);
+4. a URI SAN which is the SPIFFE identity of the ServiceAccount which created
+ the CertificateRequest;
+5. a SPIFFE ID Trust Domain matching the one that was configured at startup.
+
+If any of these checks do not pass, the CertificateRequest will be marked as
+Denied, else it will be marked as Approved. The approver will only manage
+CertificateRequests who request from the same [IssuerRef](../concepts/certificaterequest.md)
+that has been configured.
+
+## Installation
+
+### Requirements
+
+csi-driver-spiffe generally requires Kubernetes version `v1.21` or newer.
+
+If running on Kubernetes `v1.20`, you'll need the `--feature-gates=CSIServiceAccountToken=true` flag.
+
+cert-manager `v1.3` or higher is also required.
+
+### Steps
+
+#### 1. Install cert-manager
+
+csi-driver-spiffe requires cert-manager to be [installed](../installation/README.md) but
+a default installation of cert-manager **will not work**.
+
+> ⚠️ It is **vital** that the [default approver is disabled in cert-manager](../concepts/certificaterequest.md#approver-controller) ⚠️
+
+If the default approver is not disabled, the csi-driver-spiffe approver will
+race with cert-manager and policy enforcement will become useless.
+
+```bash
+helm repo add jetstack https://charts.jetstack.io --force-update
+
+# NOTE: This isn't the usual cert-manager install process;
+# we're disabling the cert-manager approver.
+# See explanation above!
+
+helm upgrade -i -n cert-manager cert-manager jetstack/cert-manager \
+ --set extraArgs={--controllers='*\,-certificaterequests-approver'} \
+ --set installCRDs=true \
+ --create-namespace
+```
+
+#### 2. Configure an Issuer / ClusterIssuer
+
+Install or configure a [ClusterIssuer](../configuration/README.md) to give
+cert-manager the ability to sign against your Trust Domain.
+
+If you want a namespace-scoped Issuer, then it must be created in every namespace
+that Pods will mount volumes from.
+
+You must use an Issuer type which is compatible with signing URI SAN certificates;
+ACME issuers won't generally work, and the SelfSigned issuer is not appropriate.
+
+An example demo [ClusterIssuer](../concepts/issuer.md#namespaces) can
+be found [in the csi-driver-spiffe repo](https://github.com/cert-manager/csi-driver-spiffe/blob/23a9fe31b9879fb162cb24c98352d4d5019171f2/deploy/example/clusterissuer.yaml).
+
+> ⚠️ This Trust Domain's root CA is generated by cert-manager and **the private key is stored in the cluster**
+> This might not be appropriate for production deployments!
+
+We'll also use [cmctl](../reference/cmctl.md) to approve the CertificateRequest,
+since the default approver was disabled above.
+
+```terminal
+kubectl apply -f https://raw.githubusercontent.com/cert-manager/csi-driver-spiffe/23a9fe31b9879fb162cb24c98352d4d5019171f2/deploy/example/clusterissuer.yaml
+
+# We must also approve the CertificateRequest since we
+# disabled the default approver
+cmctl approve -n cert-manager \
+ $(kubectl get cr -n cert-manager -ojsonpath='{.items[0].metadata.name}')
+```
+
+#### 3. Install csi-driver-spiffe
+
+Install csi-driver-spiffe into the cluster using the issuer we configured. We
+must also configure the issuer resource type and name of the issuer we
+configured so that the approver has [permissions to approve referencing CertificateRequests](../concepts/certificaterequest.md#rbac-syntax).
+
+Note that the `issuer.name`, `issuer.kind` and `issuer.group` will need to be changed to match
+the issuer you're actually using!
+
+```bash
+helm upgrade -i -n cert-manager cert-manager-csi-driver-spiffe jetstack/cert-manager-csi-driver-spiffe --wait \
+ --set "app.logLevel=1" \
+ --set "app.trustDomain=my.trust.domain" \
+ --set "app.approver.signerName=clusterissuers.cert-manager.io/csi-driver-spiffe-ca" \
+ \
+ --set "app.issuer.name=csi-driver-spiffe-ca" \
+ --set "app.issuer.kind=ClusterIssuer" \
+ --set "app.issuer.group=cert-manager.io"
+```
+
+## Usage
+
+Once the driver is successfully installed, Pods can begin to request and mount
+their key and SPIFFE certificate. Since the Pod's ServiceAccount is impersonated
+when creating CertificateRequests, every ServiceAccount must be given that
+permission which intends to use the volume.
+
+Example manifest with a dummy Deployment:
+
+```bash
+kubectl apply -f https://raw.githubusercontent.com/cert-manager/csi-driver-spiffe/23a9fe31b9879fb162cb24c98352d4d5019171f2/deploy/example/example-app.yaml
+
+kubectl exec -n sandbox \
+ $(kubectl get pod -n sandbox -l app=my-csi-app -o jsonpath='{.items[0].metadata.name}') \
+ -- \
+ cat /var/run/secrets/spiffe.io/tls.crt | \
+ openssl x509 --noout --text | \
+ grep "Issuer:"
+# expected output: Issuer: CN = csi-driver-spiffe-ca
+
+kubectl exec -n sandbox \
+ $(kubectl get pod -n sandbox -l app=my-csi-app -o jsonpath='{.items[0].metadata.name}') \
+ -- \
+ cat /var/run/secrets/spiffe.io/tls.crt | \
+ openssl x509 --noout --text | \
+ grep "URI:"
+# expected output: URI:spiffe://foo.bar/ns/sandbox/sa/example-app
+```
+
+### FS-Group
+
+When running Pods with a specified user or group, the volume will not be
+readable by default due to Unix based file system permissions. The mounting
+volumes file group can be specified using the following volume attribute:
+
+```yaml
+...
+ securityContext:
+ runAsUser: 123
+ runAsGroup: 456
+ volumes:
+ - name: spiffe
+ csi:
+ driver: spiffe.csi.cert-manager.io
+ readOnly: true
+ volumeAttributes:
+ spiffe.csi.cert-manager.io/fs-group: "456"
+```
+
+```bash
+kubectl apply -f https://raw.githubusercontent.com/cert-manager/csi-driver-spiffe/23a9fe31b9879fb162cb24c98352d4d5019171f2/deploy/example/fs-group-app.yaml
+
+kubectl exec -n sandbox $(kubectl get pod -n sandbox -l app=my-csi-app-fs-group -o jsonpath='{.items[0].metadata.name}') -- cat /var/run/secrets/spiffe.io/tls.crt | openssl x509 --noout --text | grep URI:
+# expected output: URI:spiffe://foo.bar/ns/sandbox/sa/fs-group-app
+```
+
+### Root CA Bundle
+
+By default, the CSI driver will only mount the Pod's private key and signed
+certificate. csi-driver-spiffe can be optionally configured to also mount a
+statically defined CA bundle from a volume that will be written to all Pod
+volumes.
+
+If the CSI driver detects this bundle has changed (through overwrite, renewal,
+etc), the new bundle will be written to all existing volumes.
+
+The following example mounts the CA certificate used by the Trust Domain
+ClusterIssuer.
+
+```terminal
+helm upgrade -i -n cert-manager cert-manager-csi-driver-spiffe jetstack/cert-manager-csi-driver-spiffe --wait \
+ --set "app.logLevel=1" \
+ --set "app.trustDomain=my.trust.domain" \
+ --set "app.approver.signerName=clusterissuers.cert-manager.io/csi-driver-spiffe-ca" \
+ \
+ --set "app.issuer.name=csi-driver-spiffe-ca" \
+ --set "app.issuer.kind=ClusterIssuer" \
+ --set "app.issuer.group=cert-manager.io" \
+ \
+ --set "app.driver.volumes[0].name=root-cas" \
+ --set "app.driver.volumes[0].secret.secretName=csi-driver-spiffe-ca" \
+ --set "app.driver.volumeMounts[0].name=root-cas" \
+ --set "app.driver.volumeMounts[0].mountPath=/var/run/secrets/cert-manager-csi-driver-spiffe" \
+ --set "app.driver.sourceCABundle=/var/run/secrets/cert-manager-csi-driver-spiffe/ca.crt"
+
+kubectl rollout restart deployment -n sandbox my-csi-app
+
+kubectl exec -it -n sandbox $(kubectl get pod -n sandbox -l app=my-csi-app -o jsonpath='{.items[0].metadata.name}') -- ls /var/run/secrets/spiffe.io/
+# expected output: ca.crt tls.crt tls.key
+```
diff --git a/content/v1.12-docs/projects/csi-driver.md b/content/v1.12-docs/projects/csi-driver.md
new file mode 100644
index 00000000000..31f7f1c74d6
--- /dev/null
+++ b/content/v1.12-docs/projects/csi-driver.md
@@ -0,0 +1,231 @@
+---
+title: csi-driver
+description: ''
+---
+
+csi-driver is a Container Storage Interface (CSI) driver plugin for Kubernetes
+to work along cert-manager. The goal for this plugin is to seamlessly request
+and mount certificate key pairs to pods. This is useful for facilitating mTLS,
+or otherwise securing connections of pods with guaranteed present certificates
+whilst having all of the features that cert-manager provides.
+
+## Why a CSI Driver?
+
+- Ensure private keys never leave the node and are never sent over the network.
+ All private keys are stored locally on the node.
+- Unique key and certificate per application replica with a grantee to be
+ present on application run time.
+- Reduce resource management overhead by defining certificate request spec
+ in-line of the Kubernetes Pod template.
+- Automatic renewal of certificates based on expiry of each individual
+ certificate.
+- Keys and certificates are destroyed during application termination.
+- Scope for extending plugin behavior with visibility on each replica's
+ certificate request and termination.
+
+## Requirements and Installation
+
+This CSI driver plugin makes use of the 'CSI inline volume' feature - Alpha as
+of `v1.15` and beta in `v1.16`. Kubernetes versions `v1.16` and higher require
+no extra configuration however `v1.15` requires the following feature gate set:
+```
+--feature-gates=CSIInlineVolume=true
+```
+
+You must have a working installation of cert-manager present on the cluster.
+Instructions on how to install cert-manager can be found
+[on cert-manager.io](../installation/README.md).
+
+To install the csi-driver, use helm install:
+
+```terminal
+helm repo add jetstack https://charts.jetstack.io --force-update
+helm upgrade -i -n cert-manager cert-manager-csi-driver jetstack/cert-manager-csi-driver --wait
+```
+
+Or apply the static manifests to your cluster:
+
+```terminal
+helm repo add jetstack https://charts.jetstack.io --force-update
+helm template jetstack/cert-manager-csi-driver | kubectl apply -n cert-manager -f -
+```
+
+
+You can verify the installation has completed correctly by checking the presence
+of the CSIDriver resource as well as a CSINode resource present for each node,
+referencing `csi.cert-manager.io`.
+
+```
+$ kubectl get csidrivers
+NAME CREATED AT
+csi.cert-manager.io 2019-09-06T16:55:19Z
+
+$ kubectl get csinodes -o yaml
+apiVersion: v1
+items:
+- apiVersion: storage.k8s.io/v1beta1
+ kind: CSINode
+ metadata:
+ name: kind-control-plane
+ ownerReferences:
+ - apiVersion: v1
+ kind: Node
+ name: kind-control-plane
+...
+ spec:
+ drivers:
+ - name: csi.cert-manager.io
+ nodeID: kind-control-plane
+ topologyKeys: null
+...
+```
+
+The CSI driver is now installed and is ready to be used for pods in the cluster.
+
+## Requesting and Mounting Certificates
+
+To request certificates from cert-manager, simply define a volume mount where
+the key and certificate will be written to, along with a volume with attributes
+that define the cert-manager request. The following is a dummy app that mounts a
+key certificate pair to `/tls` and has been signed by the `ca-issuer` with a DNS
+name valid for `my-service.sandbox.svc.cluster.local`.
+
+```
+apiVersion: v1
+kind: Pod
+metadata:
+ name: my-csi-app
+ namespace: sandbox
+ labels:
+ app: my-csi-app
+spec:
+ containers:
+ - name: my-frontend
+ image: busybox
+ volumeMounts:
+ - mountPath: "/tls"
+ name: tls
+ command: [ "sleep", "1000000" ]
+ volumes:
+ - name: tls
+ csi:
+ driver: csi.cert-manager.io
+ volumeAttributes:
+ csi.cert-manager.io/issuer-name: ca-issuer
+ csi.cert-manager.io/dns-names: ${POD_NAME}.${POD_NAMESPACE}.svc.cluster.local
+```
+
+Once created, the CSI driver will generate a private key locally, request a
+certificate from cert-manager based on the given attributes, then store both
+locally to be mounted to the pod. The pod will remain in a pending state until
+this process has been completed.
+
+For more information on how to set up issuers for your cluster, refer to the
+cert-manager documentation
+[here](../configuration/README.md). **Note** it is not
+possible to use `SelfSigned` Issuers with the CSI Driver. In order for
+cert-manager to self sign a certificate, it needs access to the secret
+containing the private key that signed the certificate request to sign the end
+certificate. This secret is not used and so not available in the CSI driver use
+case.
+
+## Supported Volume Attributes
+
+The csi-driver driver aims to have complete feature parity with all possible
+values available through the cert-manager API however currently supports the
+following values;
+
+| Attribute | Description | Default | Example |
+|-----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|--------------------------------------|----------------------------------|
+| `csi.cert-manager.io/issuer-name` | The Issuer name to sign the certificate request. | | `ca-issuer` |
+| `csi.cert-manager.io/issuer-kind` | The Issuer kind to sign the certificate request. | `Issuer` | `ClusterIssuer` |
+| `csi.cert-manager.io/issuer-group` | The group name the Issuer belongs to. | `cert-manager.io` | `out.of.tree.foo` |
+| `csi.cert-manager.io/common-name` | Certificate common name (supports variables). | | `my-cert.foo` |
+| `csi.cert-manager.io/dns-names` | DNS names the certificate will be requested for. At least a DNS Name, IP or URI name must be present (supports variables). | | `a.b.foo.com,c.d.foo.com` |
+| `csi.cert-manager.io/ip-sans` | IP addresses the certificate will be requested for. | | `192.0.0.1,192.0.0.2` |
+| `csi.cert-manager.io/uri-sans` | URI names the certificate will be requested for (supports variables). | | `spiffe://foo.bar.cluster.local` |
+| `csi.cert-manager.io/duration` | Requested duration the signed certificate will be valid for. | `720h` | `1880h` |
+| `csi.cert-manager.io/is-ca` | Mark the certificate as a certificate authority. | `false` | `true` |
+| `csi.cert-manager.io/key-usages` | Set the key usages on the certificate request. | `digital signature,key encipherment` | `server auth,client auth` |
+| `csi.cert-manager.io/key-encoding` | Set the key encoding format (PKCS1 or PKCS8). | `PKCS1` | `PKCS8` |
+| `csi.cert-manager.io/certificate-file` | File name to store the certificate file at. | `tls.crt` | `foo.crt` |
+| `csi.cert-manager.io/ca-file` | File name to store the ca certificate file at. | `ca.crt` | `foo.ca` |
+| `csi.cert-manager.io/privatekey-file` | File name to store the key file at. | `tls.key` | `foo.key` |
+| `csi.cert-manager.io/fs-group` | Set the FS Group of written files. Should be paired with and match the value of the consuming container `runAsGroup`. | | `2000` |
+| `csi.cert-manager.io/renew-before` | The time to renew the certificate before expiry. Defaults to a third of the requested duration. | `$CERT_DURATION/3` | `72h` |
+| `csi.cert-manager.io/reuse-private-key` | Re-use the same private when when renewing certificates. | `false` | `true` |
+| `csi.cert-manager.io/pkcs12-enable` | Enable writing the signed certificate chain and private key as a PKCS12 file. | | `true` |
+| `csi.cert-manager.io/pkcs12-filename` | File location to write the PKCS12 file. Requires `csi.cert-manager.io/keystore-pkcs12-enable` be set to `true`. | `keystore.p12` | `tls.p12` |
+| `csi.cert-manager.io/pkcs12-password` | Password used to encode the PKCS12 file. Required when PKCS12 is enabled (`csi.cert-manager.io/keystore-pkcs12-enable: true`). | | `my-password` |
+
+### Variables
+
+The following attributes support variables that are evaluated when a request is
+made for the mounting Pod. These variables are useful for constructing requests
+with SANs that contain values from the mounting Pod.
+
+```
+`csi.cert-manager.io/common-name`
+`csi.cert-manager.io/dns-names`
+`csi.cert-manager.io/uri-sans`
+```
+
+Variables follow the [go `os.Expand`](https://pkg.go.dev/os#Expand) structure,
+which is generally what you would expect on a UNIX shell. The CSI driver has
+access to the following variables:
+
+```
+${POD_NAME}
+${POD_NAMESPACE}
+${POD_UID}
+${SERVICE_ACCOUNT_NAME}
+```
+
+#### Example Usage
+
+```yaml
+volumeAttributes:
+ csi.cert-manager.io/issuer-name: ca-issuer
+ csi.cert-manager.io/dns-names: "${POD_NAME}.${POD_NAMESPACE}.svc.cluster.local"
+ csi.cert-manager.io/uri-sans: "spiffe://cluster.local/ns/${POD_NAMESPACE}/pod/${POD_NAME}/${POD_UID}"
+ csi.cert-manager.io/common-name: "${SERVICE_ACCOUNT_NAME}.${POD_NAMESPACE}"
+```
+
+## Requesting Certificates using the mounting Pod's ServiceAccount
+
+If the flag `--use-token-request` is enabled on the csi-driver DaemonSet, the
+[CertificateRequest](../concepts/certificaterequest.md) resource will be created
+by the mounting Pod's ServiceAccount. This can be pared with
+[approver-policy](./approver-policy/README.md) to enable advanced policy on a per
+ServiceAccount basis.
+
+Ensure to give permissions to Pod ServiceAccounts to create CertificateRequests
+with this flag enabled, i.e:
+
+```yaml
+# WARNING: This RBAC will enable any identiy in the cluster to create
+# CertificateRequests. This may or may not be problimatic based on your security
+# model. It is likely worth scoping the set of identities in the
+# `ClusterRoleBinding` `subjects` stanza.
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: cert-manager-csi-driver-all-cr-create
+rules:
+- apiGroups: ["cert-manager.io"]
+ resources: ["certificaterequests"]
+ verbs: [ "create" ]
+---
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: cert-manager-csi-driver-all-cr-create
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cert-manager-csi-driver-all-cr-create
+subjects:
+- apiGroup: rbac.authorization.k8s.io
+ kind: Group
+ name: system:authenticated
+```
diff --git a/content/v1.12-docs/projects/istio-csr.md b/content/v1.12-docs/projects/istio-csr.md
new file mode 100644
index 00000000000..57748517bcf
--- /dev/null
+++ b/content/v1.12-docs/projects/istio-csr.md
@@ -0,0 +1,92 @@
+---
+title: istio-csr
+description: ''
+---
+
+istio-csr is an agent that allows for [Istio](https://istio.io) workload and
+control plane components to be secured using
+[cert-manager](https://cert-manager.io).
+
+Certificates facilitating mTLS — both inter
+and intra-cluster — will be signed, delivered and renewed using [cert-manager
+issuers](https://cert-manager.io/docs/concepts/issuer).
+
+## Getting Started Guide For istio-csr
+
+We have [a guide](../tutorials/istio-csr/istio-csr.md) for setting up istio-csr in a fresh
+[kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) cluster.
+
+Following the guide is the best way to see istio-csr in action.
+
+If you've already seen istio-csr in action or if you're experienced with running
+Istio and just want quick installation instructions, read on for more details.
+
+## Lower-Level Details (For Experienced Istio Users)
+
+⚠️ The [getting started](../tutorials/istio-csr/istio-csr.md) guide is a better place if you just want to try istio-csr out!
+
+Running istio-csr requires a few steps and preconditions in order:
+
+1. A cluster _without_ Istio already installed
+2. cert-manager [installed](https://cert-manager.io/docs/installation/) in the cluster
+3. An `Issuer` or `ClusterIssuer` which will be used to issue Istio certificates
+4. istio-csr installed (likely via helm)
+5. Istio [installed](https://istio.io/latest/docs/setup/install/istioctl/) with
+ some custom config required, e.g. using the example config from the [repository](https://github.com/cert-manager/istio-csr/tree/main/hack).
+
+### Why Custom Istio Install Manifests?
+
+If you take a look at the contents of [the example Istio install
+manifests](https://github.com/cert-manager/istio-csr/tree/main/hack)
+there are a few custom configuration options which are important.
+
+Required changes include setting `ENABLE_CA_SERVER` to `false` and setting the `caAddress` from which Istio will
+request certificates; replacing the CA server is the whole point of istio-csr!
+
+Mounting and statically specifying the root CA is also an important recommended step. Without a manually specified
+root CA istio-csr defaults to trying to discover root CAs automatically, which could theoretically lead to a
+[signer hijacking attack](https://github.com/cert-manager/istio-csr/issues/103#issuecomment-923882792) if for example
+a signer's token was stolen (such as the cert-manager controller's token).
+
+### Issuer or ClusterIssuer?
+
+Unless you know you need a `ClusterIssuer` we'd recommend starting with an `Issuer`, since it should be easier to reason about
+the access controls for an Issuer; they're namespaced and so naturally a little more limited in scope.
+
+That said, if you view your entire Kubernetes cluster as being a trust domain itself, then a ClusterIssuer is the more natural
+fit. The best choice will depend on your specific situation.
+
+Our [getting started guide](../tutorials/istio-csr/istio-csr.md) uses an `Issuer`.
+
+### Which Issuer Type?
+
+Whether you choose to use an `Issuer` or a `ClusterIssuer`, you'll also need to choose the type of issuer you want such as:
+
+- [CA](https://cert-manager.io/docs/configuration/ca/)
+- [Vault](https://cert-manager.io/docs/configuration/vault/)
+- or an [external issuer](https://cert-manager.io/docs/configuration/external/)
+
+The key requirement is that arbitrary values can be placed into the `subjectAltName` (SAN) X.509 extension, since
+Istio places SPIFFE IDs there.
+
+That means that the ACME issuer **will not work** — publicly trusted certificates such as those issued by Let's Encrypt
+don't allow arbitrary entries in the SAN, for very good reasons.
+
+If you're already using [HashiCorp Vault](https://www.vaultproject.io/) then the Vault issuer is an obvious choice. If
+you want to control your own PKI entirely, we'd recommend the CA issuer. The choice is ultimately yours.
+
+### Installing istio-csr After Istio
+
+This is unsupported because it's exceptionally difficult to do safely. It's likely that installing istio-csr _after_ Istio isn't
+possible to do without downtime, since installing istio-csr second would require a time period where all Istio sidecars trust
+both the old Istio-managed CA and the new cert-manager controlled CA.
+
+## How Does istio-csr Work?
+
+istio-csr implements the gRPC Istio certificate service which authenticates,
+authorizes, and signs incoming certificate signing requests from Istio
+workloads, routing all certificate handling through cert-manager installed in
+the cluster.
+
+This seamlessly matches the behavior of istiod in a typical installation, while
+allowing certificate management through cert-manager.
diff --git a/content/v1.12-docs/projects/trust-manager/README.md b/content/v1.12-docs/projects/trust-manager/README.md
new file mode 100644
index 00000000000..30e388fbe1e
--- /dev/null
+++ b/content/v1.12-docs/projects/trust-manager/README.md
@@ -0,0 +1,373 @@
+---
+title: trust-manager
+description: 'Distributing Trust Bundles in Kubernetes'
+---
+
+trust-manager is the easiest way to manage trust bundles in Kubernetes and OpenShift clusters.
+
+It orchestrates bundles of trusted X.509 certificates which are primarily used for validating
+certificates during a TLS handshake but can be used in other situations, too.
+
+## Overview
+
+trust-manager is a small Kubernetes operator which aims to help reduce the overhead of managing
+TLS trust bundles in your clusters.
+
+It adds the `Bundle` custom Kubernetes resource (CRD) which can read input from various sources
+and combine the resultant certificates into a bundle ready to be used by your applications.
+
+trust-manager ensures that it's both quick and easy to keep your trusted certificates up-to-date
+and enables cluster administrators to easily automate providing a secure bundle without having
+to worry about rebuilding containers to update trust stores.
+
+It's designed to complement cert-manager and works well when consuming CA certificates from a
+cert-manager `Issuer` or `ClusterIssuer` but can be used entirely independently from cert-manager
+if needed.
+
+## Usage
+
+trust-manager is intentionally simple, and adds one new Kubernetes `CustomResourceDefintion`: `Bundle`.
+
+A `Bundle` represents a set of PEM-encoded X.509 certificates that should be distributed and made
+available across the cluster. `Bundle`s are cluster scoped.
+
+Users specify a list of `sources`, which trust-manager will query and concatenate certificate data from.
+The only other required field is the `target`, which describes how and where the resulting bundle will
+be written.
+
+An example `Bundle` might look like this:
+
+```yaml
+apiVersion: trust.cert-manager.io/v1alpha1
+kind: Bundle
+metadata:
+ name: my-org.com # The bundle name will also be used for the target
+spec:
+ sources:
+ # Include a bundle of publicly trusted certificates which can be
+ # used to validate most TLS certificates on the internet, such as
+ # those issued by Let's Encrypt, Google, Amazon and others.
+ - useDefaultCAs: true
+
+ # A Secret in the trust-manager namespace
+ - secret:
+ name: "my-db-tls"
+ key: "ca.crt"
+
+ # A ConfigMap in the trust-manager namespace
+ - configMap:
+ name: "my-org.net"
+ key: "root-certs.pem"
+
+ # A manually specified string
+ - inLine: |
+ -----BEGIN CERTIFICATE-----
+ MIIC5zCCAc+gAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
+ ....
+ 0V3NCaQrXoh+3xrXgX/vMdijYLUSo/YPEWmo
+ -----END CERTIFICATE-----
+ target:
+ # Data synced to the ConfigMap `my-org.com` at the key `root-certs.pem` in
+ # every namespace that has the label "linkerd.io/inject=enabled".
+ configMap:
+ key: "root-certs.pem"
+ namespaceSelector:
+ matchLabels:
+ linkerd.io/inject: "enabled"
+```
+
+`Bundle` resources currently support several source types:
+
+- `configMap` - a `ConfigMap` resource in the trust-manager namespace
+- `secret` - a `Secret` resource in the trust-manager namespace
+- `inLine` - a manually specified string containing at least one certificate
+- `useDefaultCAs` - usually, a bundle of publicly trusted certificates
+
+These sources, along with the single currently supported target type (`configMap`)
+are documented in the trust-manager [API reference documentation](./api-reference.md).
+
+#### Namespace Selector
+
+A target's `namespaceSelector` is used to restrict which Namespaces your `Bundle`'s target
+should be synced to.
+
+`namespaceSelector` supports the field `matchLabels`.
+
+Please see [Kubernetes documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors)
+for more information about how label selectors can be configured.
+
+If `namespaceSelector` is empty, a `Bundle`'s target will be synced to all Namespaces.
+
+> ⚠️ A future update to trust-manager **will** change this behavior so that an empty namespace selector will sync only
+to the trust-manager namespace by default.
+
+## Installation
+
+### Helm
+
+Helm is the easiest way to install trust-manager and comes with a publicly trusted certificate bundle package
+(for the`useDefaultCAs` source) derived from Debian containers.
+
+When installed via Helm, trust-manager has a dependency on cert-manager for provisioning an application certificate,
+and as such trust-manager is also installed into the cert-manager namespace.
+
+```bash
+helm repo add jetstack https://charts.jetstack.io --force-update
+helm upgrade -i -n cert-manager cert-manager jetstack/cert-manager --set installCRDs=true --wait --create-namespace
+helm upgrade -i -n cert-manager trust-manager jetstack/trust-manager --wait
+```
+
+### Manual Installation
+
+We strongly recommend that you install trust-manager using Helm and we don't currently support manually installed
+versions of trust-manager. This is so that we can focus on continuing to improve trust-manager with the resources
+we currently have available.
+
+## Quick Start Example
+
+Let's get started with an example of creating our own `Bundle`!
+
+First we'll create a demo cluster:
+
+```bash
+git clone https://github.com/cert-manager/trust-manager trust-manager
+cd trust-manager
+make demo
+```
+
+Once we have a running cluster, we can create a `Bundle` using the default CAs which were configured
+when trust-manager started up. Since we've installed trust-manager using Helm, our default CA package
+contains publicly trusted certificates derived from a Debian container.
+
+```bash
+kubectl --kubeconfig ./bin/kubeconfig.yaml apply -f - < 🤔 Wondering why we used `tls.crt` and not `ca.crt`? More details [below](./README.md#preparing-for-production).
+
+Finally, we'll update our `Bundle` to include our new private CA:
+
+```bash
+kubectl --kubeconfig ./bin/kubeconfig.yaml apply -f - < ⚠️ This upgrade process assumes that it's the only thing running. If another user or process changes Helm values
+> while you're doing this process, you might overwrite their work.
+
+First, we'll dump our current Helm values, so we don't lose them:
+
+```bash
+helm get values -n cert-manager trust-manager -oyaml > values.yaml
+```
+
+Next, if `defaultPackageImage.tag` is already set in `values.yaml`, update it. Otherwise, add it.
+You can find the available tags [on `quay.io`](https://quay.io/repository/jetstack/cert-manager-package-debian?tab=tags&tag=latest).
+
+```yaml
+# values.yaml
+...
+defaultPackageImage:
+ tag: XYZ
+```
+
+These versions of the default package image tags are derived directly from the version of the `ca-certificates` package in Debian.
+
+Finally, apply back the changes, being sure to manually specify the version of trust-manager which is installed, to avoid
+also updating the trust-manager controller at the same as the default CA package:
+
+```bash
+# Get the currently installed version. You could do this manually if you find that easier.
+TRUST_MANAGER_VER=$(helm list --filter "^trust-manager$" -n cert-manager -ojson | jq -r ".[0].app_version")
+
+# Check the version makes sense
+echo $TRUST_MANAGER_VER
+
+# Run the upgrade
+helm upgrade -f values.yaml -n cert-manager trust-manager jetstack/trust-manager --version $TRUST_MANAGER_VER
+```
+
+If an incorrect tag is used, your deployment will fail and you'll likely need to use `helm rollback` to get back
+to a working state.
+
+## Preparing for Production
+
+TLS can be complicated and there are many ways to misuse TLS certificates.
+
+Here are some potential gotchas here to be aware of before running trust-manager in production.
+
+If you're planning on running trust-manager in production and you're using more than just the default CA package,
+we **strongly** advise you to read and understand this section. It could save you from causing an outage later.
+
+> ℹ️ These gotchas aren't specific to trust-manager and you could run into any of them with any method of managing TLS trust!
+
+### Bundling Intermediates
+
+If you've ever used a Let's Encrypt client such as [Certbot](https://certbot.eff.org/) you'll probably have
+seen that it generates several certificate files, such as `cert.pem`, `chain.pem`, and `fullchain.pem`.
+
+These various files are provided to support various different applications, which might require the certificate
+and the chain to be given separately. For most users and applications `fullchain.pem` is the only correct choice.
+
+Unfortunately the existence of these files has the unfortunate side effect of people sometimes assuming that `cert.pem`
+is the correct choice even when `fullchain.pem` would be correct. This means that the rest of the chain will not
+be sent when the certificate is used.
+
+Often, a quick fix that _seems_ to work for this is that clients add the chain to their trust store, which will seem
+to fix certificate errors in the short term. It's easy for this kind of "fix" to end up being embedded somewhere as a
+solution which others can follow.
+
+This "fix" is dangerous; it means that the intermediate cannot be safely rotated without all trust stores
+which contain it being updated first.
+
+Intermediates in this case become _de facto_ root certificates, which completely defeats the point of having
+intermediate certificates in the first place.
+
+Avoid using intermediates in any trust store wherever possible unless you're absolutely certain they should be included.
+An example of where it might be OK would be cross signing, which is not likely to be required in the general case.
+
+It would be better to copy just the root certificate to a new `ConfigMap` and use that as a source rather than trusting
+an intermediate.
+
+### cert-manager Integration: `ca.crt` vs `tls.crt`
+
+If you're pointing trust-manager at a `Secret` containing a cert-manager-issued certificate, you'll see two relevant
+fields: `ca.crt` and `tls.crt`. (We're ignoring `tls.key` - trust-manager definitely doesn't need to access that)
+
+That leads to an obvious question: between `ca.crt` and `tls.crt`, which should I use for trust-manager?
+
+Unfortunately, it's impossible to say in the general case which field is correct to use, but we can provide guidelines.
+
+`tls.crt` will generally contain multiple certificates which may not all be issuers and some of which are likely to be
+intermediate certificates. If that's the case, you shouldn't use `tls.crt` as a source. (See "Bundling Intermediates" above for details.)
+
+`ca.crt` might then seem like the more generally correct choice but it's important to bear in mind that it can only ever
+be populated on a best-effort basis. The contents of `ca.crt` depend on the `Issuer` being configured correctly, and some
+issuer types may not ever be able to provide a useful or correct entry for this field.
+
+As a rule, you should prefer to create `Bundles` exclusively using root certificates (again, see above), and so you should
+only use whichever field has a single root certificate in it. Consider reading below about why you might not want to
+actually rely directly on cert-manager-issued certificates.
+
+### cert-manager Integration: Intentionally Copying CA Certificates
+
+It's very strange in the Kubernetes world to suggest intentionally adding a step which seems to make automating infrastructure
+harder, but in the case of TLS trust stores it can be a wise choice.
+
+Say you have a cert-manager `Issuer` which has the root certificate you want to trust in `ca.crt`. It's tempting to
+use the `Secret` directly and point at `ca.crt`, but a best practice would be to copy that root into a separate `ConfigMap`
+(or `Secret`).
+
+The reason is - as with many TLS gotchas - certificate rotation. If you rotate your issuer such that it's issued from a new root
+certificate, trust-manager will see the `Secret` be updated and automatically update your trust bundle to include the new root -
+immediately distrusting the old root.
+
+That means that if any services were still using a certificate issued by the old root, they'll be distrusted and will break.
+
+Rotation requires that both root certificates are trusted simultaneously for a period, or else that all issued certificates
+are rotated either before or at the same time as the old root.
+
+## Known Issues
+
+### `kubectl describe`
+
+The `useDefaultCAs` option hits a corner case inside `kubectl describe` and is rendered as `Use Default C As: true`. This is
+purely cosmetic.
diff --git a/content/v1.12-docs/projects/trust-manager/api-reference.md b/content/v1.12-docs/projects/trust-manager/api-reference.md
new file mode 100644
index 00000000000..994e70ce3be
--- /dev/null
+++ b/content/v1.12-docs/projects/trust-manager/api-reference.md
@@ -0,0 +1,478 @@
+---
+title: trust-manager API Reference
+description: "trust-manager API documentation for custom resources"
+---
+
+Packages:
+
+- [`trust.cert-manager.io/v1alpha1`](#trustcert-manageriov1alpha1)
+
+# `trust.cert-manager.io/v1alpha1`
+
+Resource Types:
+
+
+- [Bundle](#bundle)
+
+
+
+
+## `Bundle`
+
+
+
+
+
+
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ apiVersion |
+ string |
+ trust.cert-manager.io/v1alpha1 |
+ true |
+
+
+ kind |
+ string |
+ Bundle |
+ true |
+
+
+ metadata |
+ object |
+ Refer to the Kubernetes API documentation for the fields of the `metadata` field. |
+ true |
+
+ spec |
+ object |
+
+ Desired state of the Bundle resource.
+ |
+ true |
+
+ status |
+ object |
+
+ Status of the Bundle. This is set and managed automatically.
+ |
+ false |
+
+
+
+
+### `Bundle.spec`
+
+
+Desired state of the Bundle resource.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ sources |
+ []object |
+
+ Sources is a set of references to data whose data will sync to the target.
+ |
+ true |
+
+ target |
+ object |
+
+ Target is the target location in all namespaces to sync source data to.
+ |
+ true |
+
+
+
+
+### `Bundle.spec.sources[index]`
+
+
+BundleSource is the set of sources whose data will be appended and synced to the BundleTarget in all Namespaces.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ configMap |
+ object |
+
+ ConfigMap is a reference to a ConfigMap's `data` key, in the trust Namespace.
+ |
+ false |
+
+ inLine |
+ string |
+
+ InLine is a simple string to append as the source data.
+ |
+ false |
+
+ secret |
+ object |
+
+ Secret is a reference to a Secrets's `data` key, in the trust Namespace.
+ |
+ false |
+
+ useDefaultCAs |
+ boolean |
+
+ UseDefaultCAs, when true, requests the default CA bundle to be used as a source. Default CAs are available if trust-manager was installed via Helm or was otherwise set up to include a package-injecting init container by using the "--default-package-location" flag when starting the trust-manager controller. If default CAs were not configured at start-up, any request to use the default CAs will fail. The version of the default CA package which is used for a Bundle is stored in the defaultCAPackageVersion field of the Bundle's status field.
+ |
+ false |
+
+
+
+
+### `Bundle.spec.sources[index].configMap`
+
+
+ConfigMap is a reference to a ConfigMap's `data` key, in the trust Namespace.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ key |
+ string |
+
+ Key is the key of the entry in the object's `data` field to be used.
+ |
+ true |
+
+ name |
+ string |
+
+ Name is the name of the source object in the trust Namespace.
+ |
+ true |
+
+
+
+
+### `Bundle.spec.sources[index].secret`
+
+
+Secret is a reference to a Secrets's `data` key, in the trust Namespace.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ key |
+ string |
+
+ Key is the key of the entry in the object's `data` field to be used.
+ |
+ true |
+
+ name |
+ string |
+
+ Name is the name of the source object in the trust Namespace.
+ |
+ true |
+
+
+
+
+### `Bundle.spec.target`
+
+
+Target is the target location in all namespaces to sync source data to.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ configMap |
+ object |
+
+ ConfigMap is the target ConfigMap in Namespaces that all Bundle source data will be synced to.
+ |
+ false |
+
+ namespaceSelector |
+ object |
+
+ NamespaceSelector will, if set, only sync the target resource in Namespaces which match the selector.
+ |
+ false |
+
+
+
+
+### `Bundle.spec.target.configMap`
+
+
+ConfigMap is the target ConfigMap in Namespaces that all Bundle source data will be synced to.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ key |
+ string |
+
+ Key is the key of the entry in the object's `data` field to be used.
+ |
+ true |
+
+
+
+
+### `Bundle.spec.target.namespaceSelector`
+
+
+NamespaceSelector will, if set, only sync the target resource in Namespaces which match the selector.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ matchLabels |
+ map[string]string |
+
+ MatchLabels matches on the set of labels that must be present on a Namespace for the Bundle target to be synced there.
+ |
+ false |
+
+
+
+
+### `Bundle.status`
+
+
+Status of the Bundle. This is set and managed automatically.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ conditions |
+ []object |
+
+ List of status conditions to indicate the status of the Bundle. Known condition types are `Bundle`.
+ |
+ false |
+
+ defaultCAVersion |
+ string |
+
+ DefaultCAPackageVersion, if set and non-empty, indicates the version information which was retrieved when the set of default CAs was requested in the bundle source. This should only be set if useDefaultCAs was set to "true" on a source, and will be the same for the same version of a bundle with identical certificates.
+ |
+ false |
+
+ target |
+ object |
+
+ Target is the current Target that the Bundle is attempting or has completed syncing the source data to.
+ |
+ false |
+
+
+
+
+### `Bundle.status.conditions[index]`
+
+
+BundleCondition contains condition information for a Bundle.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ status |
+ string |
+
+ Status of the condition, one of ('True', 'False', 'Unknown').
+ |
+ true |
+
+ type |
+ string |
+
+ Type of the condition, known values are (`Synced`).
+ |
+ true |
+
+ lastTransitionTime |
+ string |
+
+ LastTransitionTime is the timestamp corresponding to the last status change of this condition.
+
+ Format: date-time
+ |
+ false |
+
+ message |
+ string |
+
+ Message is a human readable description of the details of the last transition, complementing reason.
+ |
+ false |
+
+ observedGeneration |
+ integer |
+
+ If set, this represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date with respect to the current state of the Bundle.
+
+ Format: int64
+ |
+ false |
+
+ reason |
+ string |
+
+ Reason is a brief machine readable explanation for the condition's last transition.
+ |
+ false |
+
+
+
+
+### `Bundle.status.target`
+
+
+Target is the current Target that the Bundle is attempting or has completed syncing the source data to.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ configMap |
+ object |
+
+ ConfigMap is the target ConfigMap in Namespaces that all Bundle source data will be synced to.
+ |
+ false |
+
+ namespaceSelector |
+ object |
+
+ NamespaceSelector will, if set, only sync the target resource in Namespaces which match the selector.
+ |
+ false |
+
+
+
+
+### `Bundle.status.target.configMap`
+
+
+ConfigMap is the target ConfigMap in Namespaces that all Bundle source data will be synced to.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ key |
+ string |
+
+ Key is the key of the entry in the object's `data` field to be used.
+ |
+ true |
+
+
+
+
+### `Bundle.status.target.namespaceSelector`
+
+
+NamespaceSelector will, if set, only sync the target resource in Namespaces which match the selector.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ matchLabels |
+ map[string]string |
+
+ MatchLabels matches on the set of labels that must be present on a Namespace for the Bundle target to be synced there.
+ |
+ false |
+
+
diff --git a/content/v1.12-docs/reference/README.md b/content/v1.12-docs/reference/README.md
new file mode 100644
index 00000000000..473828e355d
--- /dev/null
+++ b/content/v1.12-docs/reference/README.md
@@ -0,0 +1,15 @@
+---
+title: Reference
+description: Reference material including TLS terminology, API documentation, and information about the command line flags of the cert-manager components.
+---
+
+This section contains reference material including TLS terminology, API documentation, and information about the command line flags of the cert-manager components.
+
+* [TLS Terminology](./tls-terminology.md):
+ Learn about the TLS terminology used in the cert-manager documentation such as `publicly trusted`, `self-signed`, `root`, `intermediate` and `leaf` _certificate_.
+
+* [Components / Docker Images](../cli/README.md):
+ Learn about the command line flags of the cert-manager Docker images: `controller`, `webhook`, `cainjector`, `acmesolver`, which run in containers in your cluster.
+
+* [API Reference](./api-docs.md):
+ Learn about the cert-manager API which includes Custom Resources such as Certificate, CertificateRequest, Issuer and ClusterIssuer.
diff --git a/content/v1.12-docs/reference/api-docs.md b/content/v1.12-docs/reference/api-docs.md
new file mode 100644
index 00000000000..35d0f49d6ca
--- /dev/null
+++ b/content/v1.12-docs/reference/api-docs.md
@@ -0,0 +1,5674 @@
+---
+title: API Reference
+description: >-
+ cert-manager API documentation, including Custom Resources such as
+ Certificate, CertificateRequest, Issuer and ClusterIssuer
+---
+cert-manager API documentation, including various Custom Resource Definitions
+Packages:
+
+acme.cert-manager.io/v1
+
+ Package v1 is the v1 version of the API.
+
+Resource Types:
+
+Challenge
+
+ Challenge is a type to represent a Challenge request with an ACME server
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ apiVersion
+
+ string
+ |
+
+ acme.cert-manager.io/v1
+ |
+
+
+
+ kind
+
+ string
+ |
+
+ Challenge
+ |
+
+
+
+ metadata
+
+
+ Kubernetes meta/v1.ObjectMeta
+
+ |
+
+ Refer to the Kubernetes API documentation for the fields of the
+ metadata field.
+ |
+
+
+
+ spec
+
+
+ ChallengeSpec
+
+ |
+
+
+
+
+
+
+ url
+
+ string
+ |
+
+ The URL of the ACME Challenge resource for this challenge. This can be used to lookup details about the status of this challenge.
+ |
+
+
+
+ authorizationURL
+
+ string
+ |
+
+ The URL to the ACME Authorization resource that this challenge is a part of.
+ |
+
+
+
+ dnsName
+
+ string
+ |
+
+ dnsName is the identifier that this challenge is for, e.g. example.com. If the requested DNSName is a ‘wildcard’, this field MUST be set to the non-wildcard domain, e.g. for *.example.com , it must be example.com .
+ |
+
+
+
+ wildcard
+
+ bool
+ |
+
+ (Optional)
+ wildcard will be true if this challenge is for a wildcard identifier, for example ‘*.example.com’.
+ |
+
+
+
+ type
+
+
+ ACMEChallengeType
+
+ |
+
+ The type of ACME challenge this resource represents. One of “HTTP-01” or “DNS-01”.
+ |
+
+
+
+ token
+
+ string
+ |
+
+ The ACME challenge token for this challenge. This is the raw value returned from the ACME server.
+ |
+
+
+
+ key
+
+ string
+ |
+
+
+ The ACME challenge key for this challenge For HTTP01 challenges, this is the value that must be responded with to complete the HTTP01 challenge in the format:
+ <private key JWK thumbprint>.<key from acme server for challenge> . For DNS01 challenges, this is the base64 encoded SHA256 sum of the
+ <private key JWK thumbprint>.<key from acme server for challenge>
+ text that must be set as the TXT record content.
+
+ |
+
+
+
+ solver
+
+
+ ACMEChallengeSolver
+
+ |
+
+ Contains the domain solving configuration that should be used to solve this challenge resource.
+ |
+
+
+
+ issuerRef
+
+
+ ObjectReference
+
+ |
+
+ References a properly configured ACME-type Issuer which should be used to create this Challenge. If the Issuer does not exist, processing will be retried. If the Issuer is not an ‘ACME’ Issuer, an error will be returned and the Challenge will be marked as failed.
+ |
+
+
+ |
+
+
+
+ status
+
+
+ ChallengeStatus
+
+ |
+
+ (Optional)
+ |
+
+
+
+Order
+
+ Order is a type to represent an Order with an ACME server
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ apiVersion
+
+ string
+ |
+
+ acme.cert-manager.io/v1
+ |
+
+
+
+ kind
+
+ string
+ |
+
+ Order
+ |
+
+
+
+ metadata
+
+
+ Kubernetes meta/v1.ObjectMeta
+
+ |
+
+ Refer to the Kubernetes API documentation for the fields of the
+ metadata field.
+ |
+
+
+
+ spec
+
+
+ OrderSpec
+
+ |
+
+
+
+
+
+
+ request
+
+ []byte
+ |
+
+ Certificate signing request bytes in DER encoding. This will be used when finalizing the order. This field must be set on the order.
+ |
+
+
+
+ issuerRef
+
+
+ ObjectReference
+
+ |
+
+ IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an ‘ACME’ Issuer, an error will be returned and the Order will be marked as failed.
+ |
+
+
+
+ commonName
+
+ string
+ |
+
+ (Optional)
+ CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in dnsNames or ipAddresses . This field must match the corresponding field on the DER encoded CSR.
+ |
+
+
+
+ dnsNames
+
+ []string
+ |
+
+ (Optional)
+ DNSNames is a list of DNS names that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR.
+ |
+
+
+
+ ipAddresses
+
+ []string
+ |
+
+ (Optional)
+ IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR.
+ |
+
+
+
+ duration
+
+
+ Kubernetes meta/v1.Duration
+
+ |
+
+ (Optional)
+ Duration is the duration for the not after date for the requested certificate. this is set on order creation as pe the ACME spec.
+ |
+
+
+ |
+
+
+
+ status
+
+
+ OrderStatus
+
+ |
+
+ (Optional)
+ |
+
+
+
+ACMEAuthorization
+ (Appears on: OrderStatus)
+
+ ACMEAuthorization contains data returned from the ACME server on an authorization that must be completed in order validate a DNS name on an ACME Order resource.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ url
+
+ string
+ |
+
+ URL is the URL of the Authorization that must be completed
+ |
+
+
+
+ identifier
+
+ string
+ |
+
+ (Optional)
+ Identifier is the DNS name to be validated as part of this authorization
+ |
+
+
+
+ wildcard
+
+ bool
+ |
+
+ (Optional)
+ Wildcard will be true if this authorization is for a wildcard DNS name. If this is true, the identifier will be the non-wildcard version of the DNS name. For example, if ‘*.example.com’ is the DNS name being validated, this field will be ‘true’ and the ‘identifier’ field will be ‘example.com’.
+ |
+
+
+
+ initialState
+
+
+ State
+
+ |
+
+ (Optional)
+ InitialState is the initial state of the ACME authorization when first fetched from the ACME server. If an Authorization is already ‘valid’, the Order controller will not create a Challenge resource for the authorization. This will occur when working with an ACME server that enables ‘authz reuse’ (such as Let’s Encrypt’s production endpoint). If not set and ‘identifier’ is set, the state is assumed to be pending and a Challenge will be created.
+ |
+
+
+
+ challenges
+
+
+ []ACMEChallenge
+
+ |
+
+ (Optional)
+ Challenges specifies the challenge types offered by the ACME server. One of these challenge types will be selected when validating the DNS name and an appropriate Challenge resource will be created to perform the ACME challenge process.
+ |
+
+
+
+ACMEChallenge
+ (Appears on: ACMEAuthorization)
+
+ Challenge specifies a challenge offered by the ACME server for an Order. An appropriate Challenge resource can be created to perform the ACME challenge process.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ url
+
+ string
+ |
+
+ URL is the URL of this challenge. It can be used to retrieve additional metadata about the Challenge from the ACME server.
+ |
+
+
+
+ token
+
+ string
+ |
+
+ Token is the token that must be presented for this challenge. This is used to compute the ‘key’ that must also be presented.
+ |
+
+
+
+ type
+
+ string
+ |
+
+ Type is the type of challenge being offered, e.g. ‘http-01’, ‘dns-01’, ‘tls-sni-01’, etc. This is the raw value retrieved from the ACME server. Only ‘http-01’ and ‘dns-01’ are supported by cert-manager, other values will be ignored.
+ |
+
+
+
+ACMEChallengeSolver
+ (Appears on: ACMEIssuer, ChallengeSpec)
+
+ An ACMEChallengeSolver describes how to solve ACME challenges for the issuer it is part of. A selector may be provided to use different solving strategies for different DNS names. Only one of HTTP01 or DNS01 must be provided.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ selector
+
+
+ CertificateDNSNameSelector
+
+ |
+
+ (Optional)
+ Selector selects a set of DNSNames on the Certificate resource that should be solved using this challenge solver. If not specified, the solver will be treated as the ‘default’ solver with the lowest priority, i.e. if any other solver has a more specific match, it will be used instead.
+ |
+
+
+
+ http01
+
+
+ ACMEChallengeSolverHTTP01
+
+ |
+
+ (Optional)
+ Configures cert-manager to attempt to complete authorizations by performing the HTTP01 challenge flow. It is not possible to obtain certificates for wildcard domain names (e.g. *.example.com ) using the HTTP01 challenge mechanism.
+ |
+
+
+
+ dns01
+
+
+ ACMEChallengeSolverDNS01
+
+ |
+
+ (Optional)
+ Configures cert-manager to attempt to complete authorizations by performing the DNS01 challenge flow.
+ |
+
+
+
+ACMEChallengeSolverDNS01
+ (Appears on: ACMEChallengeSolver)
+
+ Used to configure a DNS01 challenge provider to be used when solving DNS01 challenges. Only one DNS provider may be configured per solver.
+
+
+ACMEChallengeSolverHTTP01
+ (Appears on: ACMEChallengeSolver)
+
+ ACMEChallengeSolverHTTP01 contains configuration detailing how to solve HTTP01 challenges within a Kubernetes cluster. Typically this is accomplished through creating ‘routes’ of some description that configure ingress controllers to direct traffic to ‘solver pods’, which are responsible for responding to the ACME server’s HTTP requests. Only one of Ingress / Gateway can be specified.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ ingress
+
+
+ ACMEChallengeSolverHTTP01Ingress
+
+ |
+
+ (Optional)
+ The ingress based HTTP01 challenge solver will solve challenges by creating or modifying Ingress resources in order to route requests for ‘/.well-known/acme-challenge/XYZ’ to ‘challenge solver’ pods that are provisioned by cert-manager for each Challenge to be completed.
+ |
+
+
+
+ gatewayHTTPRoute
+
+
+ ACMEChallengeSolverHTTP01GatewayHTTPRoute
+
+ |
+
+ (Optional)
+ The Gateway API is a sig-network community API that models service networking in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will create HTTPRoutes with the specified labels in the same namespace as the challenge. This solver is experimental, and fields / behaviour may change in the future.
+ |
+
+
+
+ACMEChallengeSolverHTTP01GatewayHTTPRoute
+ (Appears on: ACMEChallengeSolverHTTP01)
+
+ The ACMEChallengeSolverHTTP01GatewayHTTPRoute solver will create HTTPRoute objects for a Gateway class routing to an ACME challenge solver pod.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ serviceType
+
+
+ Kubernetes core/v1.ServiceType
+
+ |
+
+ (Optional)
+ Optional service type for Kubernetes solver service. Supported values are NodePort or ClusterIP. If unset, defaults to NodePort.
+ |
+
+
+
+ labels
+
+ map[string]string
+ |
+
+ (Optional)
+ Custom labels that will be applied to HTTPRoutes created by cert-manager while solving HTTP-01 challenges.
+ |
+
+
+
+ parentRefs
+
+ []sigs.k8s.io/gateway-api/apis/v1beta1.ParentReference
+ |
+
+
+ When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. cert-manager needs to know which parentRefs should be used when creating the HTTPRoute. Usually, the parentRef references a Gateway. See:
+ https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways
+
+ |
+
+
+
+ACMEChallengeSolverHTTP01Ingress
+ (Appears on: ACMEChallengeSolverHTTP01)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ serviceType
+
+
+ Kubernetes core/v1.ServiceType
+
+ |
+
+ (Optional)
+ Optional service type for Kubernetes solver service. Supported values are NodePort or ClusterIP. If unset, defaults to NodePort.
+ |
+
+
+
+ class
+
+ string
+ |
+
+ (Optional)
+ The ingress class to use when creating Ingress resources to solve ACME challenges that use this challenge solver. Only one of ‘class’ or ‘name’ may be specified.
+ |
+
+
+
+ name
+
+ string
+ |
+
+ (Optional)
+ The name of the ingress resource that should have ACME challenge solving routes inserted into it in order to solve HTTP01 challenges. This is typically used in conjunction with ingress controllers like ingress-gce, which maintains a 1:1 mapping between external IPs and ingress resources.
+ |
+
+
+
+ podTemplate
+
+
+ ACMEChallengeSolverHTTP01IngressPodTemplate
+
+ |
+
+ (Optional)
+ Optional pod template used to configure the ACME challenge solver pods used for HTTP01 challenges.
+ |
+
+
+
+ ingressTemplate
+
+
+ ACMEChallengeSolverHTTP01IngressTemplate
+
+ |
+
+ (Optional)
+ Optional ingress template used to configure the ACME challenge solver ingress used for HTTP01 challenges.
+ |
+
+
+
+
+ (Appears on: ACMEChallengeSolverHTTP01IngressTemplate)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ annotations
+
+ map[string]string
+ |
+
+ (Optional)
+ Annotations that should be added to the created ACME HTTP01 solver ingress.
+ |
+
+
+
+ labels
+
+ map[string]string
+ |
+
+ (Optional)
+ Labels that should be added to the created ACME HTTP01 solver ingress.
+ |
+
+
+
+
+ (Appears on: ACMEChallengeSolverHTTP01IngressPodTemplate)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ annotations
+
+ map[string]string
+ |
+
+ (Optional)
+ Annotations that should be added to the create ACME HTTP01 solver pods.
+ |
+
+
+
+ labels
+
+ map[string]string
+ |
+
+ (Optional)
+ Labels that should be added to the created ACME HTTP01 solver pods.
+ |
+
+
+
+ACMEChallengeSolverHTTP01IngressPodSpec
+ (Appears on: ACMEChallengeSolverHTTP01IngressPodTemplate)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ nodeSelector
+
+ map[string]string
+ |
+
+ (Optional)
+ NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node’s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
+ |
+
+
+
+ affinity
+
+
+ Kubernetes core/v1.Affinity
+
+ |
+
+ (Optional)
+ If specified, the pod’s scheduling constraints
+ |
+
+
+
+ tolerations
+
+
+ []Kubernetes core/v1.Toleration
+
+ |
+
+ (Optional)
+ If specified, the pod’s tolerations.
+ |
+
+
+
+ priorityClassName
+
+ string
+ |
+
+ (Optional)
+ If specified, the pod’s priorityClassName.
+ |
+
+
+
+ serviceAccountName
+
+ string
+ |
+
+ (Optional)
+ If specified, the pod’s service account
+ |
+
+
+
+ACMEChallengeSolverHTTP01IngressPodTemplate
+ (Appears on: ACMEChallengeSolverHTTP01Ingress)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ metadata
+
+
+ ACMEChallengeSolverHTTP01IngressPodObjectMeta
+
+ |
+
+ (Optional)
+ ObjectMeta overrides for the pod used to solve HTTP01 challenges. Only the ‘labels’ and ‘annotations’ fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values.
+ |
+
+
+
+ spec
+
+
+ ACMEChallengeSolverHTTP01IngressPodSpec
+
+ |
+
+ (Optional)
+ PodSpec defines overrides for the HTTP01 challenge solver pod. Only the ‘priorityClassName’, ‘nodeSelector’, ‘affinity’, ‘serviceAccountName’ and ‘tolerations’ fields are supported currently. All other fields will be ignored.
+
+
+
+
+
+ nodeSelector
+
+ map[string]string
+ |
+
+ (Optional)
+ NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node’s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
+ |
+
+
+
+ affinity
+
+
+ Kubernetes core/v1.Affinity
+
+ |
+
+ (Optional)
+ If specified, the pod’s scheduling constraints
+ |
+
+
+
+ tolerations
+
+
+ []Kubernetes core/v1.Toleration
+
+ |
+
+ (Optional)
+ If specified, the pod’s tolerations.
+ |
+
+
+
+ priorityClassName
+
+ string
+ |
+
+ (Optional)
+ If specified, the pod’s priorityClassName.
+ |
+
+
+
+ serviceAccountName
+
+ string
+ |
+
+ (Optional)
+ If specified, the pod’s service account
+ |
+
+
+ |
+
+
+
+ACMEChallengeSolverHTTP01IngressTemplate
+ (Appears on: ACMEChallengeSolverHTTP01Ingress)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ metadata
+
+
+ ACMEChallengeSolverHTTP01IngressObjectMeta
+
+ |
+
+ (Optional)
+ ObjectMeta overrides for the ingress used to solve HTTP01 challenges. Only the ‘labels’ and ‘annotations’ fields may be set. If labels or annotations overlap with in-built values, the values here will override the in-built values.
+ |
+
+
+
+ ACMEChallengeType (string alias)
+ (Appears on: ChallengeSpec)
+
+ The type of ACME challenge. Only HTTP-01 and DNS-01 are supported.
+
+
+ACMEExternalAccountBinding
+ (Appears on: ACMEIssuer)
+
+ ACMEExternalAccountBinding is a reference to a CA external account of the ACME server.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ keyID
+
+ string
+ |
+
+ keyID is the ID of the CA key that the External Account is bound to.
+ |
+
+
+
+ keySecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ keySecretRef is a Secret Key Selector referencing a data item in a Kubernetes Secret which holds the symmetric MAC key of the External Account Binding. The key is the index string that is paired with the key data in the Secret and should not be confused with the key data itself, or indeed with the External Account Binding keyID above. The secret key stored in the Secret must be un-padded, base64 URL encoded data.
+ |
+
+
+
+ keyAlgorithm
+
+
+ HMACKeyAlgorithm
+
+ |
+
+ (Optional)
+ Deprecated: keyAlgorithm field exists for historical compatibility reasons and should not be used. The algorithm is now hardcoded to HS256 in golang/x/crypto/acme.
+ |
+
+
+
+ACMEIssuer
+ (Appears on: IssuerConfig)
+
+ ACMEIssuer contains the specification for an ACME issuer. This uses the RFC8555 specification to obtain certificates by completing ‘challenges’ to prove ownership of domain identifiers. Earlier draft versions of the ACME specification are not supported.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ email
+
+ string
+ |
+
+ (Optional)
+ Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered.
+ |
+
+
+
+ server
+
+ string
+ |
+
+ Server is the URL used to access the ACME server’s ‘directory’ endpoint. For example, for Let’s Encrypt’s staging endpoint, you would use: “https://acme-staging-v02.api.letsencrypt.org/directory”. Only ACME v2 endpoints (i.e. RFC 8555) are supported.
+ |
+
+
+
+ preferredChain
+
+ string
+ |
+
+ (Optional)
+ PreferredChain is the chain to use if the ACME server outputs multiple. PreferredChain is no guarantee that this one gets delivered by the ACME endpoint. For example, for Let’s Encrypt’s DST crosssign you would use: “DST Root CA X3” or “ISRG Root X1” for the newer Let’s Encrypt root CA. This value picks the first certificate bundle in the ACME alternative chains that has a certificate with this value as its issuer’s CN
+ |
+
+
+
+ caBundle
+
+ []byte
+ |
+
+ (Optional)
+ Base64-encoded bundle of PEM CAs which can be used to validate the certificate chain presented by the ACME server. Mutually exclusive with SkipTLSVerify; prefer using CABundle to prevent various kinds of security vulnerabilities. If CABundle and SkipTLSVerify are unset, the system certificate bundle inside the container is used to validate the TLS connection.
+ |
+
+
+
+ skipTLSVerify
+
+ bool
+ |
+
+ (Optional)
+ INSECURE: Enables or disables validation of the ACME server TLS certificate. If true, requests to the ACME server will not have the TLS certificate chain validated. Mutually exclusive with CABundle; prefer using CABundle to prevent various kinds of security vulnerabilities. Only enable this option in development environments. If CABundle and SkipTLSVerify are unset, the system certificate bundle inside the container is used to validate the TLS connection. Defaults to false.
+ |
+
+
+
+ externalAccountBinding
+
+
+ ACMEExternalAccountBinding
+
+ |
+
+ (Optional)
+ ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account.
+ |
+
+
+
+ privateKeySecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ PrivateKey is the name of a Kubernetes Secret resource that will be used to store the automatically generated ACME account private key. Optionally, a key may be specified to select a specific entry within the named Secret resource. If key is not specified, a default of tls.key will be used.
+ |
+
+
+
+ solvers
+
+
+ []ACMEChallengeSolver
+
+ |
+
+ (Optional)
+ Solvers is a list of challenge solvers that will be used to solve ACME challenges for the matching domains. Solver configurations must be provided in order to obtain certificates from an ACME server. For more information, see: https://cert-manager.io/docs/configuration/acme/
+ |
+
+
+
+ disableAccountKeyGeneration
+
+ bool
+ |
+
+ (Optional)
+ Enables or disables generating a new ACME account key. If true, the Issuer resource will not request a new account but will expect the account key to be supplied via an existing secret. If false, the cert-manager system will generate a new ACME account key for the Issuer. Defaults to false.
+ |
+
+
+
+ enableDurationFeature
+
+ bool
+ |
+
+ (Optional)
+ Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let’s Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false.
+ |
+
+
+
+ACMEIssuerDNS01ProviderAcmeDNS
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ ACMEIssuerDNS01ProviderAcmeDNS is a structure containing the configuration for ACME-DNS servers
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ host
+
+ string
+ |
+ |
+
+
+
+ accountSecretRef
+
+
+ SecretKeySelector
+
+ |
+ |
+
+
+
+ACMEIssuerDNS01ProviderAkamai
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ ACMEIssuerDNS01ProviderAkamai is a structure containing the DNS configuration for Akamai DNS—Zone Record Management API
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ serviceConsumerDomain
+
+ string
+ |
+ |
+
+
+
+ clientTokenSecretRef
+
+
+ SecretKeySelector
+
+ |
+ |
+
+
+
+ clientSecretSecretRef
+
+
+ SecretKeySelector
+
+ |
+ |
+
+
+
+ accessTokenSecretRef
+
+
+ SecretKeySelector
+
+ |
+ |
+
+
+
+ACMEIssuerDNS01ProviderAzureDNS
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ ACMEIssuerDNS01ProviderAzureDNS is a structure containing the configuration for Azure DNS
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ clientID
+
+ string
+ |
+
+ (Optional)
+ if both this and ClientSecret are left unset MSI will be used
+ |
+
+
+
+ clientSecretSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ (Optional)
+ if both this and ClientID are left unset MSI will be used
+ |
+
+
+
+ subscriptionID
+
+ string
+ |
+
+ ID of the Azure subscription
+ |
+
+
+
+ tenantID
+
+ string
+ |
+
+ (Optional)
+ when specifying ClientID and ClientSecret then this field is also needed
+ |
+
+
+
+ resourceGroupName
+
+ string
+ |
+
+ resource group the DNS zone is located in
+ |
+
+
+
+ hostedZoneName
+
+ string
+ |
+
+ (Optional)
+ name of the DNS zone that should be used
+ |
+
+
+
+ environment
+
+
+ AzureDNSEnvironment
+
+ |
+
+ (Optional)
+ name of the Azure environment (default AzurePublicCloud)
+ |
+
+
+
+ managedIdentity
+
+
+ AzureManagedIdentity
+
+ |
+
+ (Optional)
+ managed identity configuration, can not be used at the same time as clientID, clientSecretSecretRef or tenantID
+ |
+
+
+
+ACMEIssuerDNS01ProviderCloudDNS
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ ACMEIssuerDNS01ProviderCloudDNS is a structure containing the DNS configuration for Google Cloud DNS
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ serviceAccountSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ (Optional)
+ |
+
+
+
+ project
+
+ string
+ |
+ |
+
+
+
+ hostedZoneName
+
+ string
+ |
+
+ (Optional)
+ HostedZoneName is an optional field that tells cert-manager in which Cloud DNS zone the challenge record has to be created. If left empty cert-manager will automatically choose a zone.
+ |
+
+
+
+ACMEIssuerDNS01ProviderCloudflare
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ ACMEIssuerDNS01ProviderCloudflare is a structure containing the DNS configuration for Cloudflare. One of apiKeySecretRef or apiTokenSecretRef must be provided.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ email
+
+ string
+ |
+
+ (Optional)
+ Email of the account, only required when using API key based authentication.
+ |
+
+
+
+ apiKeySecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ (Optional)
+ API key to use to authenticate with Cloudflare. Note: using an API token to authenticate is now the recommended method as it allows greater control of permissions.
+ |
+
+
+
+ apiTokenSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ (Optional)
+ API token used to authenticate with Cloudflare.
+ |
+
+
+
+ACMEIssuerDNS01ProviderDigitalOcean
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ ACMEIssuerDNS01ProviderDigitalOcean is a structure containing the DNS configuration for DigitalOcean Domains
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ tokenSecretRef
+
+
+ SecretKeySelector
+
+ |
+ |
+
+
+
+ACMEIssuerDNS01ProviderRFC2136
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ ACMEIssuerDNS01ProviderRFC2136 is a structure containing the configuration for RFC2136 DNS
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ nameserver
+
+ string
+ |
+
+ The IP address or hostname of an authoritative DNS server supporting RFC2136 in the form host:port. If the host is an IPv6 address it must be enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. This field is required.
+ |
+
+
+
+ tsigSecretSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ (Optional)
+ The name of the secret containing the TSIG value. If tsigKeyName is defined, this field is required.
+ |
+
+
+
+ tsigKeyName
+
+ string
+ |
+
+ (Optional)
+ The TSIG Key name configured in the DNS. If tsigSecretSecretRef is defined, this field is required.
+ |
+
+
+
+ tsigAlgorithm
+
+ string
+ |
+
+ (Optional)
+ The TSIG Algorithm configured in the DNS supporting RFC2136. Used only when tsigSecretSecretRef and tsigKeyName are defined. Supported values are (case-insensitive): HMACMD5 (default), HMACSHA1 , HMACSHA256 or HMACSHA512 .
+ |
+
+
+
+ACMEIssuerDNS01ProviderRoute53
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ ACMEIssuerDNS01ProviderRoute53 is a structure containing the Route 53 configuration for AWS
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ accessKeyID
+
+ string
+ |
+
+ (Optional)
+ The AccessKeyID is used for authentication. Cannot be set when SecretAccessKeyID is set. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
+ |
+
+
+
+ accessKeyIDSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ (Optional)
+ The SecretAccessKey is used for authentication. If set, pull the AWS access key ID from a key within a Kubernetes Secret. Cannot be set when AccessKeyID is set. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
+ |
+
+
+
+ secretAccessKeySecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ (Optional)
+ The SecretAccessKey is used for authentication. If neither the Access Key nor Key ID are set, we fall-back to using env vars, shared credentials file or AWS Instance metadata, see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
+ |
+
+
+
+ role
+
+ string
+ |
+
+ (Optional)
+ Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata
+ |
+
+
+
+ hostedZoneID
+
+ string
+ |
+
+ (Optional)
+ If set, the provider will manage only this zone in Route53 and will not do an lookup using the route53:ListHostedZonesByName api call.
+ |
+
+
+
+ region
+
+ string
+ |
+
+ Always set the region when using AccessKeyID and SecretAccessKey
+ |
+
+
+
+ACMEIssuerDNS01ProviderWebhook
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ ACMEIssuerDNS01ProviderWebhook specifies configuration for a webhook DNS01 provider, including where to POST ChallengePayload resources.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ groupName
+
+ string
+ |
+
+ The API group name that should be used when POSTing ChallengePayload resources to the webhook apiserver. This should be the same as the GroupName specified in the webhook provider implementation.
+ |
+
+
+
+ solverName
+
+ string
+ |
+
+ The name of the solver to use, as defined in the webhook provider implementation. This will typically be the name of the provider, e.g. ‘cloudflare’.
+ |
+
+
+
+ config
+
+
+ Kubernetes apiextensions/v1.JSON
+
+ |
+
+ (Optional)
+ Additional configuration that should be passed to the webhook apiserver when challenges are processed. This can contain arbitrary JSON data. Secret values should not be specified in this stanza. If secret values are needed (e.g. credentials for a DNS service), you should use a SecretKeySelector to reference a Secret resource. For details on the schema of this field, consult the webhook provider implementation’s documentation.
+ |
+
+
+
+ACMEIssuerStatus
+ (Appears on: IssuerStatus)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ uri
+
+ string
+ |
+
+ (Optional)
+ URI is the unique account identifier, which can also be used to retrieve account details from the CA
+ |
+
+
+
+ lastRegisteredEmail
+
+ string
+ |
+
+ (Optional)
+ LastRegisteredEmail is the email associated with the latest registered ACME account, in order to track changes made to registered account associated with the Issuer
+ |
+
+
+
+ AzureDNSEnvironment (string alias)
+ (Appears on: ACMEIssuerDNS01ProviderAzureDNS)
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "AzureChinaCloud"
+ |
+ |
+
+
+
+ "AzureGermanCloud"
+ |
+ |
+
+
+
+ "AzurePublicCloud"
+ |
+ |
+
+
+
+ "AzureUSGovernmentCloud"
+ |
+ |
+
+
+
+AzureManagedIdentity
+ (Appears on: ACMEIssuerDNS01ProviderAzureDNS)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ clientID
+
+ string
+ |
+
+ (Optional)
+ client ID of the managed identity, can not be used at the same time as resourceID
+ |
+
+
+
+ resourceID
+
+ string
+ |
+
+ (Optional)
+ resource ID of the managed identity, can not be used at the same time as clientID
+ |
+
+
+
+ CNAMEStrategy (string alias)
+ (Appears on: ACMEChallengeSolverDNS01)
+
+ CNAMEStrategy configures how the DNS01 provider should handle CNAME records when found in DNS zones. By default, the None strategy will be applied (i.e. do not follow CNAMEs).
+
+CertificateDNSNameSelector
+ (Appears on: ACMEChallengeSolver)
+
+ CertificateDNSNameSelector selects certificates using a label selector, and can optionally select individual DNS names within those certificates. If both MatchLabels and DNSNames are empty, this selector will match all certificates and DNS names within them.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ matchLabels
+
+ map[string]string
+ |
+
+ (Optional)
+ A label selector that is used to refine the set of certificate’s that this challenge solver will apply to.
+ |
+
+
+
+ dnsNames
+
+ []string
+ |
+
+ (Optional)
+ List of DNSNames that this solver will be used to solve. If specified and a match is found, a dnsNames selector will take precedence over a dnsZones selector. If multiple solvers match with the same dnsNames value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected.
+ |
+
+
+
+ dnsZones
+
+ []string
+ |
+
+ (Optional)
+ List of DNSZones that this solver will be used to solve. The most specific DNS zone match specified here will take precedence over other DNS zone matches, so a solver specifying sys.example.com will be selected over one specifying example.com for the domain www.sys.example.com. If multiple solvers match with the same dnsZones value, the solver with the most matching labels in matchLabels will be selected. If neither has more matches, the solver defined earlier in the list will be selected.
+ |
+
+
+
+ChallengeSpec
+ (Appears on: Challenge)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ url
+
+ string
+ |
+
+ The URL of the ACME Challenge resource for this challenge. This can be used to lookup details about the status of this challenge.
+ |
+
+
+
+ authorizationURL
+
+ string
+ |
+
+ The URL to the ACME Authorization resource that this challenge is a part of.
+ |
+
+
+
+ dnsName
+
+ string
+ |
+
+ dnsName is the identifier that this challenge is for, e.g. example.com. If the requested DNSName is a ‘wildcard’, this field MUST be set to the non-wildcard domain, e.g. for *.example.com , it must be example.com .
+ |
+
+
+
+ wildcard
+
+ bool
+ |
+
+ (Optional)
+ wildcard will be true if this challenge is for a wildcard identifier, for example ‘*.example.com’.
+ |
+
+
+
+ type
+
+
+ ACMEChallengeType
+
+ |
+
+ The type of ACME challenge this resource represents. One of “HTTP-01” or “DNS-01”.
+ |
+
+
+
+ token
+
+ string
+ |
+
+ The ACME challenge token for this challenge. This is the raw value returned from the ACME server.
+ |
+
+
+
+ key
+
+ string
+ |
+
+
+ The ACME challenge key for this challenge For HTTP01 challenges, this is the value that must be responded with to complete the HTTP01 challenge in the format:
+ <private key JWK thumbprint>.<key from acme server for challenge> . For DNS01 challenges, this is the base64 encoded SHA256 sum of the
+ <private key JWK thumbprint>.<key from acme server for challenge>
+ text that must be set as the TXT record content.
+
+ |
+
+
+
+ solver
+
+
+ ACMEChallengeSolver
+
+ |
+
+ Contains the domain solving configuration that should be used to solve this challenge resource.
+ |
+
+
+
+ issuerRef
+
+
+ ObjectReference
+
+ |
+
+ References a properly configured ACME-type Issuer which should be used to create this Challenge. If the Issuer does not exist, processing will be retried. If the Issuer is not an ‘ACME’ Issuer, an error will be returned and the Challenge will be marked as failed.
+ |
+
+
+
+ChallengeStatus
+ (Appears on: Challenge)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ processing
+
+ bool
+ |
+
+ (Optional)
+ Used to denote whether this challenge should be processed or not. This field will only be set to true by the ‘scheduling’ component. It will only be set to false by the ‘challenges’ controller, after the challenge has reached a final state or timed out. If this field is set to false, the challenge controller will not take any more action.
+ |
+
+
+
+ presented
+
+ bool
+ |
+
+ (Optional)
+ presented will be set to true if the challenge values for this challenge are currently ‘presented’. This does not imply the self check is passing. Only that the values have been ‘submitted’ for the appropriate challenge mechanism (i.e. the DNS01 TXT record has been presented, or the HTTP01 configuration has been configured).
+ |
+
+
+
+ reason
+
+ string
+ |
+
+ (Optional)
+ Contains human readable information on why the Challenge is in the current state.
+ |
+
+
+
+ state
+
+
+ State
+
+ |
+
+ (Optional)
+ Contains the current ‘state’ of the challenge. If not set, the state of the challenge is unknown.
+ |
+
+
+
+ HMACKeyAlgorithm (string alias)
+ (Appears on: ACMEExternalAccountBinding)
+
+ HMACKeyAlgorithm is the name of a key algorithm used for HMAC encryption
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "HS256"
+ |
+ |
+
+
+
+ "HS384"
+ |
+ |
+
+
+
+ "HS512"
+ |
+ |
+
+
+
+OrderSpec
+ (Appears on: Order)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ request
+
+ []byte
+ |
+
+ Certificate signing request bytes in DER encoding. This will be used when finalizing the order. This field must be set on the order.
+ |
+
+
+
+ issuerRef
+
+
+ ObjectReference
+
+ |
+
+ IssuerRef references a properly configured ACME-type Issuer which should be used to create this Order. If the Issuer does not exist, processing will be retried. If the Issuer is not an ‘ACME’ Issuer, an error will be returned and the Order will be marked as failed.
+ |
+
+
+
+ commonName
+
+ string
+ |
+
+ (Optional)
+ CommonName is the common name as specified on the DER encoded CSR. If specified, this value must also be present in dnsNames or ipAddresses . This field must match the corresponding field on the DER encoded CSR.
+ |
+
+
+
+ dnsNames
+
+ []string
+ |
+
+ (Optional)
+ DNSNames is a list of DNS names that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR.
+ |
+
+
+
+ ipAddresses
+
+ []string
+ |
+
+ (Optional)
+ IPAddresses is a list of IP addresses that should be included as part of the Order validation process. This field must match the corresponding field on the DER encoded CSR.
+ |
+
+
+
+ duration
+
+
+ Kubernetes meta/v1.Duration
+
+ |
+
+ (Optional)
+ Duration is the duration for the not after date for the requested certificate. this is set on order creation as pe the ACME spec.
+ |
+
+
+
+OrderStatus
+ (Appears on: Order)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ url
+
+ string
+ |
+
+ (Optional)
+ URL of the Order. This will initially be empty when the resource is first created. The Order controller will populate this field when the Order is first processed. This field will be immutable after it is initially set.
+ |
+
+
+
+ finalizeURL
+
+ string
+ |
+
+ (Optional)
+ FinalizeURL of the Order. This is used to obtain certificates for this order once it has been completed.
+ |
+
+
+
+ authorizations
+
+
+ []ACMEAuthorization
+
+ |
+
+ (Optional)
+ Authorizations contains data returned from the ACME server on what authorizations must be completed in order to validate the DNS names specified on the Order.
+ |
+
+
+
+ certificate
+
+ []byte
+ |
+
+ (Optional)
+ Certificate is a copy of the PEM encoded certificate for this Order. This field will be populated after the order has been successfully finalized with the ACME server, and the order has transitioned to the ‘valid’ state.
+ |
+
+
+
+ state
+
+
+ State
+
+ |
+
+ (Optional)
+ State contains the current state of this Order resource. States ‘success’ and ‘expired’ are ‘final’
+ |
+
+
+
+ reason
+
+ string
+ |
+
+ (Optional)
+ Reason optionally provides more information about a why the order is in the current state.
+ |
+
+
+
+ failureTime
+
+
+ Kubernetes meta/v1.Time
+
+ |
+
+ (Optional)
+ FailureTime stores the time that this order failed. This is used to influence garbage collection and back-off.
+ |
+
+
+
+ State (string alias)
+ (Appears on: ACMEAuthorization, ChallengeStatus, OrderStatus)
+
+
+ State represents the state of an ACME resource, such as an Order. The possible options here map to the corresponding values in the ACME specification. Full details of these values can be found here: https://tools.ietf.org/html/draft-ietf-acme-acme-15#section-7.1.6
+ Clients utilising this type must also gracefully handle unknown values, as the contents of this enumeration may be added to over time.
+
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "errored"
+ |
+
+ Errored signifies that the ACME resource has errored for some reason. This is a catch-all state, and is used for marking internal cert-manager errors such as validation failures. This is a final state.
+ |
+
+
+
+ "expired"
+ |
+
+ Expired signifies that an ACME resource has expired. If an Order is marked ‘Expired’, one of its validations may have expired or the Order itself. This is a final state.
+ |
+
+
+
+ "invalid"
+ |
+
+ Invalid signifies that an ACME resource is invalid for some reason. If an Order is marked ‘invalid’, one of its validations be have invalid for some reason. This is a final state.
+ |
+
+
+
+ "pending"
+ |
+
+ Pending signifies that an ACME resource is still pending and is not yet ready. If an Order is marked ‘Pending’, the validations for that Order are still in progress. This is a transient state.
+ |
+
+
+
+ "processing"
+ |
+
+ Processing signifies that an ACME resource is being processed by the server. If an Order is marked ‘Processing’, the validations for that Order are currently being processed. This is a transient state.
+ |
+
+
+
+ "ready"
+ |
+
+ Ready signifies that an ACME resource is in a ready state. If an order is ‘ready’, all of its challenges have been completed successfully and the order is ready to be finalized. Once finalized, it will transition to the Valid state. This is a transient state.
+ |
+
+
+
+ ""
+ |
+
+ Unknown is not a real state as part of the ACME spec. It is used to represent an unrecognised value.
+ |
+
+
+
+ "valid"
+ |
+
+ Valid signifies that an ACME resource is in a valid state. If an order is ‘valid’, it has been finalized with the ACME server and the certificate can be retrieved from the ACME server using the certificate URL stored in the Order’s status subresource. This is a final state.
+ |
+
+
+
+
+cert-manager.io/v1
+
+ Package v1 is the v1 version of the API.
+
+Resource Types:
+
+Certificate
+
+ A Certificate resource should be created to ensure an up to date and signed x509 certificate is stored in the Kubernetes Secret resource named in spec.secretName .
+ The stored certificate will be renewed before it expires (as configured by spec.renewBefore ).
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ apiVersion
+
+ string
+ |
+
+ cert-manager.io/v1
+ |
+
+
+
+ kind
+
+ string
+ |
+
+ Certificate
+ |
+
+
+
+ metadata
+
+
+ Kubernetes meta/v1.ObjectMeta
+
+ |
+
+ Refer to the Kubernetes API documentation for the fields of the
+ metadata field.
+ |
+
+
+
+ spec
+
+
+ CertificateSpec
+
+ |
+
+ Desired state of the Certificate resource.
+
+
+
+
+
+ subject
+
+
+ X509Subject
+
+ |
+
+ (Optional)
+ Full X509 name specification (https://golang.org/pkg/crypto/x509/pkix/#Name).
+ |
+
+
+
+ literalSubject
+
+ string
+ |
+
+ (Optional)
+ LiteralSubject is an LDAP formatted string that represents the X.509 Subject field. Use this instead of the Subject field if you need to ensure the correct ordering of the RDN sequence, such as when issuing certs for LDAP authentication. See https://github.com/cert-manager/cert-manager/issues/3203, https://github.com/cert-manager/cert-manager/issues/4424. This field is alpha level and is only supported by cert-manager installations where LiteralCertificateSubject feature gate is enabled on both cert-manager controller and webhook.
+ |
+
+
+
+ commonName
+
+ string
+ |
+
+ (Optional)
+ CommonName is a common name to be used on the Certificate. The CommonName should have a length of 64 characters or fewer to avoid generating invalid CSRs. This value is ignored by TLS clients when any subject alt name is set. This is x509 behaviour: https://tools.ietf.org/html/rfc6125#section-6.4.4
+ |
+
+
+
+ duration
+
+
+ Kubernetes meta/v1.Duration
+
+ |
+
+ (Optional)
+ The requested ‘duration’ (i.e. lifetime) of the Certificate. This option may be ignored/overridden by some issuer types. If unset this defaults to 90 days. Certificate will be renewed either 2⁄3 through its duration or renewBefore period before its expiry, whichever is later. Minimum accepted duration is 1 hour. Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration
+ |
+
+
+
+ renewBefore
+
+
+ Kubernetes meta/v1.Duration
+
+ |
+
+ (Optional)
+
+ How long before the currently issued certificate’s expiry cert-manager should renew the certificate. The default is 2⁄3 of the issued certificate’s duration. Minimum accepted value is 5 minutes. Value must be in units accepted by Go time.ParseDuration
+ https://golang.org/pkg/time/#ParseDuration
+
+ |
+
+
+
+ dnsNames
+
+ []string
+ |
+
+ (Optional)
+ DNSNames is a list of DNS subjectAltNames to be set on the Certificate.
+ |
+
+
+
+ ipAddresses
+
+ []string
+ |
+
+ (Optional)
+ IPAddresses is a list of IP address subjectAltNames to be set on the Certificate.
+ |
+
+
+
+ uris
+
+ []string
+ |
+
+ (Optional)
+ URIs is a list of URI subjectAltNames to be set on the Certificate.
+ |
+
+
+
+ emailAddresses
+
+ []string
+ |
+
+ (Optional)
+ EmailAddresses is a list of email subjectAltNames to be set on the Certificate.
+ |
+
+
+
+ secretName
+
+ string
+ |
+
+ SecretName is the name of the secret resource that will be automatically created and managed by this Certificate resource. It will be populated with a private key and certificate, signed by the denoted issuer.
+ |
+
+
+
+ secretTemplate
+
+
+ CertificateSecretTemplate
+
+ |
+
+ (Optional)
+ SecretTemplate defines annotations and labels to be copied to the Certificate’s Secret. Labels and annotations on the Secret will be changed as they appear on the SecretTemplate when added or removed. SecretTemplate annotations are added in conjunction with, and cannot overwrite, the base set of annotations cert-manager sets on the Certificate’s Secret.
+ |
+
+
+
+ keystores
+
+
+ CertificateKeystores
+
+ |
+
+ (Optional)
+
+ Keystores configures additional keystore output formats stored in the
+ secretName Secret resource.
+
+ |
+
+
+
+ issuerRef
+
+
+ ObjectReference
+
+ |
+
+ IssuerRef is a reference to the issuer for this certificate. If the kind field is not set, or set to Issuer , an Issuer resource with the given name in the same namespace as the Certificate will be used. If the kind field is set to ClusterIssuer , a ClusterIssuer with the provided name will be used. The name field in this stanza is required at all times.
+ |
+
+
+
+ isCA
+
+ bool
+ |
+
+ (Optional)
+ IsCA will mark this Certificate as valid for certificate signing. This will automatically add the cert sign usage to the list of usages .
+ |
+
+
+
+ usages
+
+
+ []KeyUsage
+
+ |
+
+ (Optional)
+ Usages is the set of x509 usages that are requested for the certificate. Defaults to digital signature and key encipherment if not specified.
+ |
+
+
+
+ privateKey
+
+
+ CertificatePrivateKey
+
+ |
+
+ (Optional)
+ Options to control private keys used for the Certificate.
+ |
+
+
+
+ encodeUsagesInRequest
+
+ bool
+ |
+
+ (Optional)
+ EncodeUsagesInRequest controls whether key usages should be present in the CertificateRequest
+ |
+
+
+
+ revisionHistoryLimit
+
+ int32
+ |
+
+ (Optional)
+ revisionHistoryLimit is the maximum number of CertificateRequest revisions that are maintained in the Certificate’s history. Each revision represents a single CertificateRequest created by this Certificate, either when it was created, renewed, or Spec was changed. Revisions will be removed by oldest first if the number of revisions exceeds this number. If set, revisionHistoryLimit must be a value of 1 or greater. If unset (nil ), revisions will not be garbage collected. Default value is nil .
+ |
+
+
+
+ additionalOutputFormats
+
+
+ []CertificateAdditionalOutputFormat
+
+ |
+
+ (Optional)
+
+ AdditionalOutputFormats defines extra output formats of the private key and signed certificate chain to be written to this Certificate’s target Secret. This is an Alpha Feature and is only enabled with the
+ --feature-gates=AdditionalCertificateOutputFormats=true option on both the controller and webhook components.
+
+ |
+
+
+ |
+
+
+
+ status
+
+
+ CertificateStatus
+
+ |
+
+ (Optional)
+ Status of the Certificate. This is set and managed automatically.
+ |
+
+
+
+CertificateRequest
+
+ A CertificateRequest is used to request a signed certificate from one of the configured issuers.
+
+ All fields within the CertificateRequest’s spec are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its status.state
+ field.
+
+ A CertificateRequest is a one-shot resource, meaning it represents a single point in time request for a certificate and cannot be re-used.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ apiVersion
+
+ string
+ |
+
+ cert-manager.io/v1
+ |
+
+
+
+ kind
+
+ string
+ |
+
+ CertificateRequest
+ |
+
+
+
+ metadata
+
+
+ Kubernetes meta/v1.ObjectMeta
+
+ |
+
+ Refer to the Kubernetes API documentation for the fields of the
+ metadata field.
+ |
+
+
+
+ spec
+
+
+ CertificateRequestSpec
+
+ |
+
+ Desired state of the CertificateRequest resource.
+
+
+
+
+
+ duration
+
+
+ Kubernetes meta/v1.Duration
+
+ |
+
+ (Optional)
+ The requested ‘duration’ (i.e. lifetime) of the Certificate. This option may be ignored/overridden by some issuer types.
+ |
+
+
+
+ issuerRef
+
+
+ ObjectReference
+
+ |
+
+ IssuerRef is a reference to the issuer for this CertificateRequest. If the kind field is not set, or set to Issuer , an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the kind field is set to ClusterIssuer , a ClusterIssuer with the provided name will be used. The name field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to cert-manager.io if empty.
+ |
+
+
+
+ request
+
+ []byte
+ |
+
+ The PEM-encoded x509 certificate signing request to be submitted to the CA for signing.
+ |
+
+
+
+ isCA
+
+ bool
+ |
+
+ (Optional)
+ IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the cert sign usage to the list of usages .
+ |
+
+
+
+ usages
+
+
+ []KeyUsage
+
+ |
+
+ (Optional)
+ Usages is the set of x509 usages that are requested for the certificate. If usages are set they SHOULD be encoded inside the CSR spec Defaults to digital signature and key encipherment if not specified.
+ |
+
+
+
+ username
+
+ string
+ |
+
+ (Optional)
+ Username contains the name of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable.
+ |
+
+
+
+ uid
+
+ string
+ |
+
+ (Optional)
+ UID contains the uid of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable.
+ |
+
+
+
+ groups
+
+ []string
+ |
+
+ (Optional)
+ Groups contains group membership of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable.
+ |
+
+
+
+ extra
+
+ map[string][]string
+ |
+
+ (Optional)
+ Extra contains extra attributes of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable.
+ |
+
+
+ |
+
+
+
+ status
+
+
+ CertificateRequestStatus
+
+ |
+
+ (Optional)
+ Status of the CertificateRequest. This is set and managed automatically.
+ |
+
+
+
+ClusterIssuer
+
+ A ClusterIssuer represents a certificate issuing authority which can be referenced as part of issuerRef fields. It is similar to an Issuer, however it is cluster-scoped and therefore can be referenced by resources that exist in any namespace, not just the same namespace as the referent.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ apiVersion
+
+ string
+ |
+
+ cert-manager.io/v1
+ |
+
+
+
+ kind
+
+ string
+ |
+
+ ClusterIssuer
+ |
+
+
+
+ metadata
+
+
+ Kubernetes meta/v1.ObjectMeta
+
+ |
+
+ Refer to the Kubernetes API documentation for the fields of the
+ metadata field.
+ |
+
+
+
+ spec
+
+
+ IssuerSpec
+
+ |
+
+ Desired state of the ClusterIssuer resource.
+
+
+
+
+
+ IssuerConfig
+
+
+ IssuerConfig
+
+ |
+
+ (Members of IssuerConfig are embedded into this type.)
+ |
+
+
+ |
+
+
+
+ status
+
+
+ IssuerStatus
+
+ |
+
+ (Optional)
+ Status of the ClusterIssuer. This is set and managed automatically.
+ |
+
+
+
+Issuer
+
+ An Issuer represents a certificate issuing authority which can be referenced as part of issuerRef fields. It is scoped to a single namespace and can therefore only be referenced by resources within the same namespace.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ apiVersion
+
+ string
+ |
+
+ cert-manager.io/v1
+ |
+
+
+
+ kind
+
+ string
+ |
+
+ Issuer
+ |
+
+
+
+ metadata
+
+
+ Kubernetes meta/v1.ObjectMeta
+
+ |
+
+ Refer to the Kubernetes API documentation for the fields of the
+ metadata field.
+ |
+
+
+
+ spec
+
+
+ IssuerSpec
+
+ |
+
+ Desired state of the Issuer resource.
+
+
+
+
+
+ IssuerConfig
+
+
+ IssuerConfig
+
+ |
+
+ (Members of IssuerConfig are embedded into this type.)
+ |
+
+
+ |
+
+
+
+ status
+
+
+ IssuerStatus
+
+ |
+
+ (Optional)
+ Status of the Issuer. This is set and managed automatically.
+ |
+
+
+
+CAIssuer
+ (Appears on: IssuerConfig)
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ secretName
+
+ string
+ |
+
+ SecretName is the name of the secret used to sign Certificates issued by this Issuer.
+ |
+
+
+
+ crlDistributionPoints
+
+ []string
+ |
+
+ (Optional)
+ The CRL distribution points is an X.509 v3 certificate extension which identifies the location of the CRL from which the revocation of this certificate can be checked. If not set, certificates will be issued without distribution points set.
+ |
+
+
+
+ ocspServers
+
+ []string
+ |
+
+ (Optional)
+ The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate will be issued with no OCSP servers set. For example, an OCSP server URL could be “http://ocsp.int-x3.letsencrypt.org”.
+ |
+
+
+
+
+ (Appears on: CertificateSpec)
+
+ CertificateAdditionalOutputFormat defines an additional output format of a Certificate resource. These contain supplementary data formats of the signed certificate chain and paired private key.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ type
+
+
+ CertificateOutputFormatType
+
+ |
+
+ Type is the name of the format type that should be written to the Certificate’s target Secret.
+ |
+
+
+
+CertificateCondition
+ (Appears on: CertificateStatus)
+
+ CertificateCondition contains condition information for an Certificate.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ type
+
+
+ CertificateConditionType
+
+ |
+
+ Type of the condition, known values are (Ready , Issuing ).
+ |
+
+
+
+ status
+
+
+ ConditionStatus
+
+ |
+
+ Status of the condition, one of (True , False , Unknown ).
+ |
+
+
+
+ lastTransitionTime
+
+
+ Kubernetes meta/v1.Time
+
+ |
+
+ (Optional)
+ LastTransitionTime is the timestamp corresponding to the last status change of this condition.
+ |
+
+
+
+ reason
+
+ string
+ |
+
+ (Optional)
+ Reason is a brief machine readable explanation for the condition’s last transition.
+ |
+
+
+
+ message
+
+ string
+ |
+
+ (Optional)
+ Message is a human readable description of the details of the last transition, complementing reason.
+ |
+
+
+
+ observedGeneration
+
+ int64
+ |
+
+ (Optional)
+ If set, this represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date with respect to the current state of the Certificate.
+ |
+
+
+
+ CertificateConditionType (string alias)
+ (Appears on: CertificateCondition)
+
+ CertificateConditionType represents an Certificate condition value.
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "Issuing"
+ |
+
+
+ A condition added to Certificate resources when an issuance is required. This condition will be automatically added and set to true if: * No keypair data exists in the target Secret * The data stored in the Secret cannot be decoded * The private key and certificate do not have matching public keys * If a CertificateRequest for the current revision exists and the certificate data stored in the Secret does not match the
+ status.certificate on the CertificateRequest. * If no CertificateRequest resource exists for the current revision, the options on the Certificate resource are compared against the x509 data in the Secret, similar to what’s done in earlier versions. If there is a mismatch, an issuance is triggered. This condition may also be added by external API consumers to trigger a re-issuance manually for any other reason.
+
+ It will be removed by the ‘issuing’ controller upon completing issuance.
+ |
+
+
+
+ "Ready"
+ |
+
+ CertificateConditionReady indicates that a certificate is ready for use. This is defined as: - The target secret exists - The target secret contains a certificate that has not expired - The target secret contains a private key valid for the certificate - The commonName and dnsNames attributes match those specified on the Certificate
+ |
+
+
+
+CertificateKeystores
+ (Appears on: CertificateSpec)
+
+ CertificateKeystores configures additional keystore output formats to be created in the Certificate’s output Secret.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ jks
+
+
+ JKSKeystore
+
+ |
+
+ (Optional)
+
+ JKS configures options for storing a JKS keystore in the
+ spec.secretName Secret resource.
+
+ |
+
+
+
+ pkcs12
+
+
+ PKCS12Keystore
+
+ |
+
+ (Optional)
+
+ PKCS12 configures options for storing a PKCS12 keystore in the
+ spec.secretName Secret resource.
+
+ |
+
+
+
+
+ (Appears on: CertificateAdditionalOutputFormat)
+
+
+ CertificateOutputFormatType specifies which additional output formats should be written to the Certificate’s target Secret. Allowed values are DER or CombinedPEM . When Type is set to DER an additional entry key.der will be written to the Secret, containing the binary format of the private key. When Type is set to CombinedPEM an additional entry tls-combined.pem
+ will be written to the Secret, containing the PEM formatted private key and signed certificate chain (tls.key + tls.crt concatenated).
+
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "CombinedPEM"
+ |
+
+
+ CertificateOutputFormatCombinedPEM writes the Certificate’s signed certificate chain and private key, in PEM format, to the
+ tls-combined.pem target Secret Data key. The value at this key will include the private key PEM document, followed by at least one new line character, followed by the chain of signed certificate PEM documents (<private key> + \n + <signed certificate chain> ).
+
+ |
+
+
+
+ "DER"
+ |
+
+ CertificateOutputFormatDER writes the Certificate’s private key in DER binary format to the key.der target Secret Data key.
+ |
+
+
+
+CertificatePrivateKey
+ (Appears on: CertificateSpec)
+
+ CertificatePrivateKey contains configuration options for private keys used by the Certificate controller. This allows control of how private keys are rotated.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ rotationPolicy
+
+
+ PrivateKeyRotationPolicy
+
+ |
+
+ (Optional)
+ RotationPolicy controls how private keys should be regenerated when a re-issuance is being processed. If set to Never, a private key will only be generated if one does not already exist in the target spec.secretName . If one does exists but it does not have the correct algorithm or size, a warning will be raised to await user intervention. If set to Always, a private key matching the specified requirements will be generated whenever a re-issuance occurs. Default is ‘Never’ for backward compatibility.
+ |
+
+
+
+ encoding
+
+
+ PrivateKeyEncoding
+
+ |
+
+ (Optional)
+ The private key cryptography standards (PKCS) encoding for this certificate’s private key to be encoded in. If provided, allowed values are PKCS1 and PKCS8 standing for PKCS#1 and PKCS#8, respectively. Defaults to PKCS1 if not specified.
+ |
+
+
+
+ algorithm
+
+
+ PrivateKeyAlgorithm
+
+ |
+
+ (Optional)
+ Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either RSA ,Ed25519 or ECDSA If algorithm is specified and size is not provided, key size of 256 will be used for ECDSA key algorithm and key size of 2048 will be used for RSA key algorithm. key size is ignored when using the Ed25519 key algorithm.
+ |
+
+
+
+ size
+
+ int
+ |
+
+ (Optional)
+ Size is the key bit size of the corresponding private key for this certificate. If algorithm is set to RSA , valid values are 2048 , 4096 or 8192 , and will default to 2048 if not specified. If algorithm is set to ECDSA , valid values are 256 , 384 or 521 , and will default to 256 if not specified. If algorithm is set to Ed25519 , Size is ignored. No other values are allowed.
+ |
+
+
+
+CertificateRequestCondition
+ (Appears on: CertificateRequestStatus)
+
+ CertificateRequestCondition contains condition information for a CertificateRequest.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ type
+
+
+ CertificateRequestConditionType
+
+ |
+
+ Type of the condition, known values are (Ready , InvalidRequest ,Approved , Denied ).
+ |
+
+
+
+ status
+
+
+ ConditionStatus
+
+ |
+
+ Status of the condition, one of (True , False , Unknown ).
+ |
+
+
+
+ lastTransitionTime
+
+
+ Kubernetes meta/v1.Time
+
+ |
+
+ (Optional)
+ LastTransitionTime is the timestamp corresponding to the last status change of this condition.
+ |
+
+
+
+ reason
+
+ string
+ |
+
+ (Optional)
+ Reason is a brief machine readable explanation for the condition’s last transition.
+ |
+
+
+
+ message
+
+ string
+ |
+
+ (Optional)
+ Message is a human readable description of the details of the last transition, complementing reason.
+ |
+
+
+
+ CertificateRequestConditionType (string alias)
+ (Appears on: CertificateRequestCondition)
+
+ CertificateRequestConditionType represents an Certificate condition value.
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "Approved"
+ |
+
+
+ CertificateRequestConditionApproved indicates that a certificate request is approved and ready for signing. Condition must never have a status of
+ False , and cannot be modified once set. Cannot be set alongside Denied .
+
+ |
+
+
+
+ "Denied"
+ |
+
+
+ CertificateRequestConditionDenied indicates that a certificate request is denied, and must never be signed. Condition must never have a status of
+ False , and cannot be modified once set. Cannot be set alongside Approved .
+
+ |
+
+
+
+ "InvalidRequest"
+ |
+
+ CertificateRequestConditionInvalidRequest indicates that a certificate signer has refused to sign the request due to at least one of the input parameters being invalid. Additional information about why the request was rejected can be found in the reason and message fields.
+ |
+
+
+
+ "Ready"
+ |
+
+ CertificateRequestConditionReady indicates that a certificate is ready for use. This is defined as: - The target certificate exists in CertificateRequest.Status
+ |
+
+
+
+CertificateRequestSpec
+ (Appears on: CertificateRequest)
+
+ CertificateRequestSpec defines the desired state of CertificateRequest
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ duration
+
+
+ Kubernetes meta/v1.Duration
+
+ |
+
+ (Optional)
+ The requested ‘duration’ (i.e. lifetime) of the Certificate. This option may be ignored/overridden by some issuer types.
+ |
+
+
+
+ issuerRef
+
+
+ ObjectReference
+
+ |
+
+ IssuerRef is a reference to the issuer for this CertificateRequest. If the kind field is not set, or set to Issuer , an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the kind field is set to ClusterIssuer , a ClusterIssuer with the provided name will be used. The name field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to cert-manager.io if empty.
+ |
+
+
+
+ request
+
+ []byte
+ |
+
+ The PEM-encoded x509 certificate signing request to be submitted to the CA for signing.
+ |
+
+
+
+ isCA
+
+ bool
+ |
+
+ (Optional)
+ IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the cert sign usage to the list of usages .
+ |
+
+
+
+ usages
+
+
+ []KeyUsage
+
+ |
+
+ (Optional)
+ Usages is the set of x509 usages that are requested for the certificate. If usages are set they SHOULD be encoded inside the CSR spec Defaults to digital signature and key encipherment if not specified.
+ |
+
+
+
+ username
+
+ string
+ |
+
+ (Optional)
+ Username contains the name of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable.
+ |
+
+
+
+ uid
+
+ string
+ |
+
+ (Optional)
+ UID contains the uid of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable.
+ |
+
+
+
+ groups
+
+ []string
+ |
+
+ (Optional)
+ Groups contains group membership of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable.
+ |
+
+
+
+ extra
+
+ map[string][]string
+ |
+
+ (Optional)
+ Extra contains extra attributes of the user that created the CertificateRequest. Populated by the cert-manager webhook on creation and immutable.
+ |
+
+
+
+CertificateRequestStatus
+ (Appears on: CertificateRequest)
+
+ CertificateRequestStatus defines the observed state of CertificateRequest and resulting signed certificate.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ conditions
+
+
+ []CertificateRequestCondition
+
+ |
+
+ (Optional)
+ List of status conditions to indicate the status of a CertificateRequest. Known condition types are Ready and InvalidRequest .
+ |
+
+
+
+ certificate
+
+ []byte
+ |
+
+ (Optional)
+
+ The PEM encoded x509 certificate resulting from the certificate signing request. If not set, the CertificateRequest has either not been completed or has failed. More information on failure can be found by checking the
+ conditions field.
+
+ |
+
+
+
+ ca
+
+ []byte
+ |
+
+ (Optional)
+ The PEM encoded x509 certificate of the signer, also known as the CA (Certificate Authority). This is set on a best-effort basis by different issuers. If not set, the CA is assumed to be unknown/not available.
+ |
+
+
+
+ failureTime
+
+
+ Kubernetes meta/v1.Time
+
+ |
+
+ (Optional)
+ FailureTime stores the time that this CertificateRequest failed. This is used to influence garbage collection and back-off.
+ |
+
+
+
+CertificateSecretTemplate
+ (Appears on: CertificateSpec)
+
+ CertificateSecretTemplate defines the default labels and annotations to be copied to the Kubernetes Secret resource named in CertificateSpec.secretName .
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ annotations
+
+ map[string]string
+ |
+
+ (Optional)
+ Annotations is a key value map to be copied to the target Kubernetes Secret.
+ |
+
+
+
+ labels
+
+ map[string]string
+ |
+
+ (Optional)
+ Labels is a key value map to be copied to the target Kubernetes Secret.
+ |
+
+
+
+CertificateSpec
+ (Appears on: Certificate)
+
+ CertificateSpec defines the desired state of Certificate. A valid Certificate requires at least one of a CommonName, DNSName, or URISAN to be valid.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ subject
+
+
+ X509Subject
+
+ |
+
+ (Optional)
+ Full X509 name specification (https://golang.org/pkg/crypto/x509/pkix/#Name).
+ |
+
+
+
+ literalSubject
+
+ string
+ |
+
+ (Optional)
+ LiteralSubject is an LDAP formatted string that represents the X.509 Subject field. Use this instead of the Subject field if you need to ensure the correct ordering of the RDN sequence, such as when issuing certs for LDAP authentication. See https://github.com/cert-manager/cert-manager/issues/3203, https://github.com/cert-manager/cert-manager/issues/4424. This field is alpha level and is only supported by cert-manager installations where LiteralCertificateSubject feature gate is enabled on both cert-manager controller and webhook.
+ |
+
+
+
+ commonName
+
+ string
+ |
+
+ (Optional)
+ CommonName is a common name to be used on the Certificate. The CommonName should have a length of 64 characters or fewer to avoid generating invalid CSRs. This value is ignored by TLS clients when any subject alt name is set. This is x509 behaviour: https://tools.ietf.org/html/rfc6125#section-6.4.4
+ |
+
+
+
+ duration
+
+
+ Kubernetes meta/v1.Duration
+
+ |
+
+ (Optional)
+ The requested ‘duration’ (i.e. lifetime) of the Certificate. This option may be ignored/overridden by some issuer types. If unset this defaults to 90 days. Certificate will be renewed either 2⁄3 through its duration or renewBefore period before its expiry, whichever is later. Minimum accepted duration is 1 hour. Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration
+ |
+
+
+
+ renewBefore
+
+
+ Kubernetes meta/v1.Duration
+
+ |
+
+ (Optional)
+
+ How long before the currently issued certificate’s expiry cert-manager should renew the certificate. The default is 2⁄3 of the issued certificate’s duration. Minimum accepted value is 5 minutes. Value must be in units accepted by Go time.ParseDuration
+ https://golang.org/pkg/time/#ParseDuration
+
+ |
+
+
+
+ dnsNames
+
+ []string
+ |
+
+ (Optional)
+ DNSNames is a list of DNS subjectAltNames to be set on the Certificate.
+ |
+
+
+
+ ipAddresses
+
+ []string
+ |
+
+ (Optional)
+ IPAddresses is a list of IP address subjectAltNames to be set on the Certificate.
+ |
+
+
+
+ uris
+
+ []string
+ |
+
+ (Optional)
+ URIs is a list of URI subjectAltNames to be set on the Certificate.
+ |
+
+
+
+ emailAddresses
+
+ []string
+ |
+
+ (Optional)
+ EmailAddresses is a list of email subjectAltNames to be set on the Certificate.
+ |
+
+
+
+ secretName
+
+ string
+ |
+
+ SecretName is the name of the secret resource that will be automatically created and managed by this Certificate resource. It will be populated with a private key and certificate, signed by the denoted issuer.
+ |
+
+
+
+ secretTemplate
+
+
+ CertificateSecretTemplate
+
+ |
+
+ (Optional)
+ SecretTemplate defines annotations and labels to be copied to the Certificate’s Secret. Labels and annotations on the Secret will be changed as they appear on the SecretTemplate when added or removed. SecretTemplate annotations are added in conjunction with, and cannot overwrite, the base set of annotations cert-manager sets on the Certificate’s Secret.
+ |
+
+
+
+ keystores
+
+
+ CertificateKeystores
+
+ |
+
+ (Optional)
+
+ Keystores configures additional keystore output formats stored in the
+ secretName Secret resource.
+
+ |
+
+
+
+ issuerRef
+
+
+ ObjectReference
+
+ |
+
+ IssuerRef is a reference to the issuer for this certificate. If the kind field is not set, or set to Issuer , an Issuer resource with the given name in the same namespace as the Certificate will be used. If the kind field is set to ClusterIssuer , a ClusterIssuer with the provided name will be used. The name field in this stanza is required at all times.
+ |
+
+
+
+ isCA
+
+ bool
+ |
+
+ (Optional)
+ IsCA will mark this Certificate as valid for certificate signing. This will automatically add the cert sign usage to the list of usages .
+ |
+
+
+
+ usages
+
+
+ []KeyUsage
+
+ |
+
+ (Optional)
+ Usages is the set of x509 usages that are requested for the certificate. Defaults to digital signature and key encipherment if not specified.
+ |
+
+
+
+ privateKey
+
+
+ CertificatePrivateKey
+
+ |
+
+ (Optional)
+ Options to control private keys used for the Certificate.
+ |
+
+
+
+ encodeUsagesInRequest
+
+ bool
+ |
+
+ (Optional)
+ EncodeUsagesInRequest controls whether key usages should be present in the CertificateRequest
+ |
+
+
+
+ revisionHistoryLimit
+
+ int32
+ |
+
+ (Optional)
+ revisionHistoryLimit is the maximum number of CertificateRequest revisions that are maintained in the Certificate’s history. Each revision represents a single CertificateRequest created by this Certificate, either when it was created, renewed, or Spec was changed. Revisions will be removed by oldest first if the number of revisions exceeds this number. If set, revisionHistoryLimit must be a value of 1 or greater. If unset (nil ), revisions will not be garbage collected. Default value is nil .
+ |
+
+
+
+ additionalOutputFormats
+
+
+ []CertificateAdditionalOutputFormat
+
+ |
+
+ (Optional)
+
+ AdditionalOutputFormats defines extra output formats of the private key and signed certificate chain to be written to this Certificate’s target Secret. This is an Alpha Feature and is only enabled with the
+ --feature-gates=AdditionalCertificateOutputFormats=true option on both the controller and webhook components.
+
+ |
+
+
+
+CertificateStatus
+ (Appears on: Certificate)
+
+ CertificateStatus defines the observed state of Certificate
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ conditions
+
+
+ []CertificateCondition
+
+ |
+
+ (Optional)
+ List of status conditions to indicate the status of certificates. Known condition types are Ready and Issuing .
+ |
+
+
+
+ lastFailureTime
+
+
+ Kubernetes meta/v1.Time
+
+ |
+
+ (Optional)
+ LastFailureTime is the time as recorded by the Certificate controller of the most recent failure to complete a CertificateRequest for this Certificate resource. If set, cert-manager will not re-request another Certificate until 1 hour has elapsed from this time.
+ |
+
+
+
+ notBefore
+
+
+ Kubernetes meta/v1.Time
+
+ |
+
+ (Optional)
+ The time after which the certificate stored in the secret named by this resource in spec.secretName is valid.
+ |
+
+
+
+ notAfter
+
+
+ Kubernetes meta/v1.Time
+
+ |
+
+ (Optional)
+ The expiration time of the certificate stored in the secret named by this resource in spec.secretName .
+ |
+
+
+
+ renewalTime
+
+
+ Kubernetes meta/v1.Time
+
+ |
+
+ (Optional)
+ RenewalTime is the time at which the certificate will be next renewed. If not set, no upcoming renewal is scheduled.
+ |
+
+
+
+ revision
+
+ int
+ |
+
+ (Optional)
+ The current ‘revision’ of the certificate as issued.
+
+ When a CertificateRequest resource is created, it will have the
+ cert-manager.io/certificate-revision set to one greater than the current value of this field.
+
+ Upon issuance, this field will be set to the value of the annotation on the CertificateRequest resource used to issue the certificate.
+ Persisting the value on the CertificateRequest resource allows the certificates controller to know whether a request is part of an old issuance or if it is part of the ongoing revision’s issuance by checking if the revision value in the annotation is greater than this field.
+ |
+
+
+
+ nextPrivateKeySecretName
+
+ string
+ |
+
+ (Optional)
+
+ The name of the Secret resource containing the private key to be used for the next certificate iteration. The keymanager controller will automatically set this field if the
+ Issuing condition is set to True . It will automatically unset this field when the Issuing condition is not set or False.
+
+ |
+
+
+
+ failedIssuanceAttempts
+
+ int
+ |
+
+ (Optional)
+ The number of continuous failed issuance attempts up till now. This field gets removed (if set) on a successful issuance and gets set to 1 if unset and an issuance has failed. If an issuance has failed, the delay till the next issuance will be calculated using formula time.Hour * 2 ^ (failedIssuanceAttempts - 1).
+ |
+
+
+
+GenericIssuer
+
+IssuerCondition
+ (Appears on: IssuerStatus)
+
+ IssuerCondition contains condition information for an Issuer.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ type
+
+
+ IssuerConditionType
+
+ |
+
+ Type of the condition, known values are (Ready ).
+ |
+
+
+
+ status
+
+
+ ConditionStatus
+
+ |
+
+ Status of the condition, one of (True , False , Unknown ).
+ |
+
+
+
+ lastTransitionTime
+
+
+ Kubernetes meta/v1.Time
+
+ |
+
+ (Optional)
+ LastTransitionTime is the timestamp corresponding to the last status change of this condition.
+ |
+
+
+
+ reason
+
+ string
+ |
+
+ (Optional)
+ Reason is a brief machine readable explanation for the condition’s last transition.
+ |
+
+
+
+ message
+
+ string
+ |
+
+ (Optional)
+ Message is a human readable description of the details of the last transition, complementing reason.
+ |
+
+
+
+ observedGeneration
+
+ int64
+ |
+
+ (Optional)
+ If set, this represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.condition[x].observedGeneration is 9, the condition is out of date with respect to the current state of the Issuer.
+ |
+
+
+
+ IssuerConditionType (string alias)
+ (Appears on: IssuerCondition)
+
+ IssuerConditionType represents an Issuer condition value.
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "Ready"
+ |
+
+ IssuerConditionReady represents the fact that a given Issuer condition is in ready state and able to issue certificates. If the status of this condition is False , CertificateRequest controllers should prevent attempts to sign certificates.
+ |
+
+
+
+IssuerConfig
+ (Appears on: IssuerSpec)
+
+ The configuration for the issuer. Only one of these can be set.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ acme
+
+
+ ACMEIssuer
+
+ |
+
+ (Optional)
+ ACME configures this issuer to communicate with a RFC8555 (ACME) server to obtain signed x509 certificates.
+ |
+
+
+
+ ca
+
+
+ CAIssuer
+
+ |
+
+ (Optional)
+ CA configures this issuer to sign certificates using a signing CA keypair stored in a Secret resource. This is used to build internal PKIs that are managed by cert-manager.
+ |
+
+
+
+ vault
+
+
+ VaultIssuer
+
+ |
+
+ (Optional)
+ Vault configures this issuer to sign certificates using a HashiCorp Vault PKI backend.
+ |
+
+
+
+ selfSigned
+
+
+ SelfSignedIssuer
+
+ |
+
+ (Optional)
+ SelfSigned configures this issuer to ‘self sign’ certificates using the private key used to create the CertificateRequest object.
+ |
+
+
+
+ venafi
+
+
+ VenafiIssuer
+
+ |
+
+ (Optional)
+ Venafi configures this issuer to sign certificates using a Venafi TPP or Venafi Cloud policy zone.
+ |
+
+
+
+IssuerSpec
+ (Appears on: ClusterIssuer, Issuer)
+
+ IssuerSpec is the specification of an Issuer. This includes any configuration required for the issuer.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ IssuerConfig
+
+
+ IssuerConfig
+
+ |
+
+ (Members of IssuerConfig are embedded into this type.)
+ |
+
+
+
+IssuerStatus
+ (Appears on: ClusterIssuer, Issuer)
+
+ IssuerStatus contains status information about an Issuer
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ conditions
+
+
+ []IssuerCondition
+
+ |
+
+ (Optional)
+ List of status conditions to indicate the status of a CertificateRequest. Known condition types are Ready .
+ |
+
+
+
+ acme
+
+
+ ACMEIssuerStatus
+
+ |
+
+ (Optional)
+ ACME specific status options. This field should only be set if the Issuer is configured to use an ACME server to issue certificates.
+ |
+
+
+
+JKSKeystore
+ (Appears on: CertificateKeystores)
+
+
+ JKS configures options for storing a JKS keystore in the spec.secretName
+ Secret resource.
+
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ create
+
+ bool
+ |
+
+ Create enables JKS keystore creation for the Certificate. If true, a file named keystore.jks will be created in the target Secret resource, encrypted using the password stored in passwordSecretRef . The keystore file will be updated immediately. A file named truststore.jks will also be created in the target Secret resource, encrypted using the password stored in passwordSecretRef containing the issuing Certificate Authority
+ |
+
+
+
+ passwordSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ PasswordSecretRef is a reference to a key in a Secret resource containing the password used to encrypt the JKS keystore.
+ |
+
+
+
+ KeyUsage (string alias)
+ (Appears on: CertificateRequestSpec, CertificateSpec)
+
+
+ KeyUsage specifies valid usage contexts for keys. See:
+ https://tools.ietf.org/html/rfc5280#section-4.2.1.3
+ https://tools.ietf.org/html/rfc5280#section-4.2.1.12
+
+ Valid KeyUsage values are as follows: “signing”, “digital signature”, “content commitment”, “key encipherment”, “key agreement”, “data encipherment”, “cert sign”, “crl sign”, “encipher only”, “decipher only”, “any”, “server auth”, “client auth”, “code signing”, “email protection”, “s/mime”, “ipsec end system”, “ipsec tunnel”, “ipsec user”, “timestamping”, “ocsp signing”, “microsoft sgc”, “netscape sgc”
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "any"
+ |
+ |
+
+
+
+ "crl sign"
+ |
+ |
+
+
+
+ "cert sign"
+ |
+ |
+
+
+
+ "client auth"
+ |
+ |
+
+
+
+ "code signing"
+ |
+ |
+
+
+
+ "content commitment"
+ |
+ |
+
+
+
+ "data encipherment"
+ |
+ |
+
+
+
+ "decipher only"
+ |
+ |
+
+
+
+ "digital signature"
+ |
+ |
+
+
+
+ "email protection"
+ |
+ |
+
+
+
+ "encipher only"
+ |
+ |
+
+
+
+ "ipsec end system"
+ |
+ |
+
+
+
+ "ipsec tunnel"
+ |
+ |
+
+
+
+ "ipsec user"
+ |
+ |
+
+
+
+ "key agreement"
+ |
+ |
+
+
+
+ "key encipherment"
+ |
+ |
+
+
+
+ "microsoft sgc"
+ |
+ |
+
+
+
+ "netscape sgc"
+ |
+ |
+
+
+
+ "ocsp signing"
+ |
+ |
+
+
+
+ "s/mime"
+ |
+ |
+
+
+
+ "server auth"
+ |
+ |
+
+
+
+ "signing"
+ |
+ |
+
+
+
+ "timestamping"
+ |
+ |
+
+
+
+PKCS12Keystore
+ (Appears on: CertificateKeystores)
+
+
+ PKCS12 configures options for storing a PKCS12 keystore in the
+ spec.secretName Secret resource.
+
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ create
+
+ bool
+ |
+
+ Create enables PKCS12 keystore creation for the Certificate. If true, a file named keystore.p12 will be created in the target Secret resource, encrypted using the password stored in passwordSecretRef . The keystore file will be updated immediately. A file named truststore.p12 will also be created in the target Secret resource, encrypted using the password stored in passwordSecretRef containing the issuing Certificate Authority
+ |
+
+
+
+ passwordSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ PasswordSecretRef is a reference to a key in a Secret resource containing the password used to encrypt the PKCS12 keystore.
+ |
+
+
+
+ PrivateKeyAlgorithm (string alias)
+ (Appears on: CertificatePrivateKey)
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "ECDSA"
+ |
+
+ Denotes the ECDSA private key type.
+ |
+
+
+
+ "Ed25519"
+ |
+
+ Denotes the Ed25519 private key type.
+ |
+
+
+
+ "RSA"
+ |
+
+ Denotes the RSA private key type.
+ |
+
+
+
+ PrivateKeyEncoding (string alias)
+ (Appears on: CertificatePrivateKey)
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "PKCS1"
+ |
+
+ PKCS1 key encoding will produce PEM files that include the type of private key as part of the PEM header, e.g. BEGIN RSA PRIVATE KEY . If the keyAlgorithm is set to ‘ECDSA’, this will produce private keys that use the BEGIN EC PRIVATE KEY header.
+ |
+
+
+
+ "PKCS8"
+ |
+
+
+ PKCS8 key encoding will produce PEM files with the BEGIN PRIVATE KEY
+ header. It encodes the keyAlgorithm of the private key as part of the DER encoded PEM block.
+
+ |
+
+
+
+ PrivateKeyRotationPolicy (string alias)
+ (Appears on: CertificatePrivateKey)
+
+ Denotes how private keys should be generated or sourced when a Certificate is being issued.
+
+SelfSignedIssuer
+ (Appears on: IssuerConfig)
+
+ Configures an issuer to ‘self sign’ certificates using the private key used to create the CertificateRequest object.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ crlDistributionPoints
+
+ []string
+ |
+
+ (Optional)
+ The CRL distribution points is an X.509 v3 certificate extension which identifies the location of the CRL from which the revocation of this certificate can be checked. If not set certificate will be issued without CDP. Values are strings.
+ |
+
+
+
+VaultAppRole
+ (Appears on: VaultAuth)
+
+ VaultAppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ path
+
+ string
+ |
+
+ Path where the App Role authentication backend is mounted in Vault, e.g: “approle”
+ |
+
+
+
+ roleId
+
+ string
+ |
+
+ RoleID configured in the App Role authentication backend when setting up the authentication backend in Vault.
+ |
+
+
+
+ secretRef
+
+
+ SecretKeySelector
+
+ |
+
+ Reference to a key in a Secret that contains the App Role secret used to authenticate with Vault. The key field must be specified and denotes which entry within the Secret resource is used as the app role secret.
+ |
+
+
+
+VaultAuth
+ (Appears on: VaultIssuer)
+
+ Configuration used to authenticate with a Vault server. Only one of tokenSecretRef , appRole or kubernetes may be specified.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ tokenSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ (Optional)
+ TokenSecretRef authenticates with Vault by presenting a token.
+ |
+
+
+
+ appRole
+
+
+ VaultAppRole
+
+ |
+
+ (Optional)
+ AppRole authenticates with Vault using the App Role auth mechanism, with the role and secret stored in a Kubernetes Secret resource.
+ |
+
+
+
+ kubernetes
+
+
+ VaultKubernetesAuth
+
+ |
+
+ (Optional)
+ Kubernetes authenticates with Vault by passing the ServiceAccount token stored in the named Secret resource to the Vault server.
+ |
+
+
+
+VaultIssuer
+ (Appears on: IssuerConfig)
+
+ Configures an issuer to sign certificates using a HashiCorp Vault PKI backend.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ auth
+
+
+ VaultAuth
+
+ |
+
+ Auth configures how cert-manager authenticates with the Vault server.
+ |
+
+
+
+ server
+
+ string
+ |
+
+ Server is the connection address for the Vault server, e.g: “https://vault.example.com:8200”.
+ |
+
+
+
+ path
+
+ string
+ |
+
+ Path is the mount path of the Vault PKI backend’s sign endpoint, e.g: “my_pki_mount/sign/my-role-name”.
+ |
+
+
+
+ namespace
+
+ string
+ |
+
+ (Optional)
+ Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: “ns1” More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces
+ |
+
+
+
+ caBundle
+
+ []byte
+ |
+
+ (Optional)
+ Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by Vault. Only used if using HTTPS to connect to Vault and ignored for HTTP connections. Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection.
+ |
+
+
+
+ caBundleSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ (Optional)
+ Reference to a Secret containing a bundle of PEM-encoded CAs to use when verifying the certificate chain presented by Vault when using HTTPS. Mutually exclusive with CABundle. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection. If no key for the Secret is specified, cert-manager will default to ‘ca.crt’.
+ |
+
+
+
+VaultKubernetesAuth
+ (Appears on: VaultAuth)
+
+ Authenticate against Vault using a Kubernetes ServiceAccount token stored in a Secret.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ mountPath
+
+ string
+ |
+
+ (Optional)
+ The Vault mountPath here is the mount path to use when authenticating with Vault. For example, setting a value to /v1/auth/foo , will use the path /v1/auth/foo/login to authenticate with Vault. If unspecified, the default value “/v1/auth/kubernetes” will be used.
+ |
+
+
+
+ secretRef
+
+
+ SecretKeySelector
+
+ |
+
+ The required Secret field containing a Kubernetes ServiceAccount JWT used for authenticating with Vault. Use of ‘ambient credentials’ is not supported.
+ |
+
+
+
+ role
+
+ string
+ |
+
+ A required field containing the Vault Role to assume. A Role binds a Kubernetes ServiceAccount with a set of Vault policies.
+ |
+
+
+
+VenafiCloud
+ (Appears on: VenafiIssuer)
+
+ VenafiCloud defines connection configuration details for Venafi Cloud
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ url
+
+ string
+ |
+
+ (Optional)
+ URL is the base URL for Venafi Cloud. Defaults to “https://api.venafi.cloud/v1”.
+ |
+
+
+
+ apiTokenSecretRef
+
+
+ SecretKeySelector
+
+ |
+
+ APITokenSecretRef is a secret key selector for the Venafi Cloud API token.
+ |
+
+
+
+VenafiIssuer
+ (Appears on: IssuerConfig)
+
+ Configures an issuer to sign certificates using a Venafi TPP or Cloud policy zone.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ zone
+
+ string
+ |
+
+ Zone is the Venafi Policy Zone to use for this issuer. All requests made to the Venafi platform will be restricted by the named zone policy. This field is required.
+ |
+
+
+
+ tpp
+
+
+ VenafiTPP
+
+ |
+
+ (Optional)
+ TPP specifies Trust Protection Platform configuration settings. Only one of TPP or Cloud may be specified.
+ |
+
+
+
+ cloud
+
+
+ VenafiCloud
+
+ |
+
+ (Optional)
+ Cloud specifies the Venafi cloud configuration settings. Only one of TPP or Cloud may be specified.
+ |
+
+
+
+VenafiTPP
+ (Appears on: VenafiIssuer)
+
+ VenafiTPP defines connection configuration details for a Venafi TPP instance
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ url
+
+ string
+ |
+
+ URL is the base URL for the vedsdk endpoint of the Venafi TPP instance, for example: “https://tpp.example.com/vedsdk”.
+ |
+
+
+
+ credentialsRef
+
+
+ LocalObjectReference
+
+ |
+
+ CredentialsRef is a reference to a Secret containing the username and password for the TPP server. The secret must contain two keys, ‘username’ and ‘password’.
+ |
+
+
+
+ caBundle
+
+ []byte
+ |
+
+ (Optional)
+ Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. If undefined, the certificate bundle in the cert-manager controller container is used to validate the chain.
+ |
+
+
+
+X509Subject
+ (Appears on: CertificateSpec)
+
+ X509Subject Full X509 name specification
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ organizations
+
+ []string
+ |
+
+ (Optional)
+ Organizations to be used on the Certificate.
+ |
+
+
+
+ countries
+
+ []string
+ |
+
+ (Optional)
+ Countries to be used on the Certificate.
+ |
+
+
+
+ organizationalUnits
+
+ []string
+ |
+
+ (Optional)
+ Organizational Units to be used on the Certificate.
+ |
+
+
+
+ localities
+
+ []string
+ |
+
+ (Optional)
+ Cities to be used on the Certificate.
+ |
+
+
+
+ provinces
+
+ []string
+ |
+
+ (Optional)
+ State/Provinces to be used on the Certificate.
+ |
+
+
+
+ streetAddresses
+
+ []string
+ |
+
+ (Optional)
+ Street addresses to be used on the Certificate.
+ |
+
+
+
+ postalCodes
+
+ []string
+ |
+
+ (Optional)
+ Postal codes to be used on the Certificate.
+ |
+
+
+
+ serialNumber
+
+ string
+ |
+
+ (Optional)
+ Serial number to be used on the Certificate.
+ |
+
+
+
+
+
+
+ Package v1 contains meta types for cert-manager APIs
+
+Resource Types:
+
+
+ (Appears on: CertificateCondition, CertificateRequestCondition, IssuerCondition)
+
+ ConditionStatus represents a condition’s status.
+
+
+
+
+ Value |
+ Description |
+
+
+
+
+
+ "False"
+ |
+
+ ConditionFalse represents the fact that a given condition is false
+ |
+
+
+
+ "True"
+ |
+
+ ConditionTrue represents the fact that a given condition is true
+ |
+
+
+
+ "Unknown"
+ |
+
+ ConditionUnknown represents the fact that a given condition is unknown
+ |
+
+
+
+
+ (Appears on: VenafiTPP, SecretKeySelector)
+
+ A reference to an object in the same namespace as the referent. If the referent is a cluster-scoped resource (e.g. a ClusterIssuer), the reference instead refers to the resource with the given name in the configured ‘cluster resource namespace’, which is set as a flag on the controller component (and defaults to the namespace that cert-manager runs in).
+
+
+
+ (Appears on: ChallengeSpec, OrderSpec, CertificateRequestSpec, CertificateSpec)
+
+ ObjectReference is a reference to an object with a given name, kind and group.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ name
+
+ string
+ |
+
+ Name of the resource being referred to.
+ |
+
+
+
+ kind
+
+ string
+ |
+
+ (Optional)
+ Kind of the resource being referred to.
+ |
+
+
+
+ group
+
+ string
+ |
+
+ (Optional)
+ Group of the resource being referred to.
+ |
+
+
+
+
+
+ (Appears on: ACMEExternalAccountBinding, ACMEIssuer, ACMEIssuerDNS01ProviderAcmeDNS, ACMEIssuerDNS01ProviderAkamai, ACMEIssuerDNS01ProviderAzureDNS, ACMEIssuerDNS01ProviderCloudDNS, ACMEIssuerDNS01ProviderCloudflare, ACMEIssuerDNS01ProviderDigitalOcean, ACMEIssuerDNS01ProviderRFC2136,
+ ACMEIssuerDNS01ProviderRoute53, JKSKeystore, PKCS12Keystore, VaultAppRole, VaultAuth, VaultIssuer, VaultKubernetesAuth, VenafiCloud)
+
+
+ A reference to a specific ‘key’ within a Secret resource. In some instances, key is a required field.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ LocalObjectReference
+
+
+ LocalObjectReference
+
+ |
+
+ (Members of LocalObjectReference are embedded into this type.)
+ The name of the Secret resource being referred to.
+ |
+
+
+
+ key
+
+ string
+ |
+
+ (Optional)
+ The key of the entry in the Secret resource’s data field to be used. Some instances of this field may be defaulted, in others it may be required.
+ |
+
+
+
+
+webhook.config.cert-manager.io/v1alpha1
+
+ Package v1alpha1 is the v1alpha1 version of the webhook config API.
+
+Resource Types:
+
+DynamicServingConfig
+ (Appears on: TLSConfig)
+
+ DynamicServingConfig makes the webhook generate a CA and persist it into Secret resources. This CA will be used by all instances of the webhook for signing serving certificates.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ secretNamespace
+
+ string
+ |
+
+ Namespace of the Kubernetes Secret resource containing the TLS certificate used as a CA to sign dynamic serving certificates.
+ |
+
+
+
+ secretName
+
+ string
+ |
+
+ Namespace of the Kubernetes Secret resource containing the TLS certificate used as a CA to sign dynamic serving certificates.
+ |
+
+
+
+ dnsNames
+
+ []string
+ |
+
+ DNSNames that must be present on serving certificates signed by the CA.
+ |
+
+
+
+FilesystemServingConfig
+ (Appears on: TLSConfig)
+
+ FilesystemServingConfig enables using a certificate and private key found on the local filesystem. These files will be periodically polled in case they have changed, and dynamically reloaded.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ certFile
+
+ string
+ |
+
+ Path to a file containing TLS certificate & chain to serve with
+ |
+
+
+
+ keyFile
+
+ string
+ |
+
+ Path to a file containing a TLS private key to server with
+ |
+
+
+
+TLSConfig
+ (Appears on: WebhookConfiguration)
+
+ TLSConfig configures how TLS certificates are sourced for serving. Only one of ‘filesystem’ or ‘dynamic’ may be specified.
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ cipherSuites
+
+ []string
+ |
+
+ cipherSuites is the list of allowed cipher suites for the server. Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants). If not specified, the default for the Go version will be used and may change over time.
+ |
+
+
+
+ minTLSVersion
+
+ string
+ |
+
+ minTLSVersion is the minimum TLS version supported. Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants). If not specified, the default for the Go version will be used and may change over time.
+ |
+
+
+
+ filesystem
+
+
+ FilesystemServingConfig
+
+ |
+
+ Filesystem enables using a certificate and private key found on the local filesystem. These files will be periodically polled in case they have changed, and dynamically reloaded.
+ |
+
+
+
+ dynamic
+
+
+ DynamicServingConfig
+
+ |
+
+ When Dynamic serving is enabled, the webhook will generate a CA used to sign webhook certificates and persist it into a Kubernetes Secret resource (for other replicas of the webhook to consume). It will then generate a certificate in-memory for itself using this CA to serve with. The CAs certificate can then be copied into the appropriate Validating, Mutating and Conversion webhook configuration objects (typically by cainjector).
+ |
+
+
+
+WebhookConfiguration
+
+
+
+
+ Field |
+ Description |
+
+
+
+
+
+ securePort
+
+ int
+ |
+
+ securePort is the port number to listen on for secure TLS connections from the kube-apiserver. Defaults to 6443.
+ |
+
+
+
+ healthzPort
+
+ int
+ |
+
+ healthzPort is the port number to listen on (using plaintext HTTP) for healthz connections. Defaults to 6080.
+ |
+
+
+
+ tlsConfig
+
+
+ TLSConfig
+
+ |
+
+ tlsConfig is used to configure the secure listener’s TLS settings.
+ |
+
+
+
+ kubeConfig
+
+ string
+ |
+
+ kubeConfig is the kubeconfig file used to connect to the Kubernetes apiserver. If not specified, the webhook will attempt to load the in-cluster-config.
+ |
+
+
+
+ apiServerHost
+
+ string
+ |
+
+ apiServerHost is used to override the API server connection address. Deprecated: use kubeConfig instead.
+ |
+
+
+
+ enablePprof
+
+ bool
+ |
+
+ enablePprof configures whether pprof is enabled.
+ |
+
+
+
+ pprofAddress
+
+ string
+ |
+
+ pprofAddress configures the address on which /debug/pprof endpoint will be served if enabled. Defaults to ‘localhost:6060’.
+ |
+
+
+
+ featureGates
+
+ map[string]bool
+ |
+
+ (Optional)
+ featureGates is a map of feature names to bools that enable or disable experimental features. Default: nil
+ |
+
+
+
+
+
+ Generated with gen-crd-api-reference-docs on git commit 7ebb5f515 .
+
diff --git a/content/v1.12-docs/reference/cmctl.md b/content/v1.12-docs/reference/cmctl.md
new file mode 100644
index 00000000000..095c9dfe6e0
--- /dev/null
+++ b/content/v1.12-docs/reference/cmctl.md
@@ -0,0 +1,344 @@
+---
+title: The cert-manager Command Line Tool (cmctl)
+description: |
+ cmctl is a command line tool that can help you manage cert-manager and its resources inside your cluster
+---
+
+`cmctl` is a command line tool that can help you manage cert-manager and its resources inside your cluster.
+
+## Installation
+
+### Homebrew
+
+On Mac or Linux if you have [Homebrew](https://brew.sh) installed, you can
+install `cmctl` with:
+
+```console
+brew install cmctl
+```
+
+This will also install shell completion.
+
+### Manual Installation
+
+You need the `cmctl.tar.gz` file for the platform you're using, these can be
+found on our
+[GitHub releases page](https://github.com/cert-manager/cert-manager/releases).
+In order to use `cmctl` you need its binary to be accessible under
+the name `cmctl` in your `$PATH`.
+Run the following commands to set up the CLI. Replace OS and ARCH with your
+systems equivalents:
+
+```console
+OS=$(go env GOOS); ARCH=$(go env GOARCH); curl -fsSL -o cmctl.tar.gz https://github.com/cert-manager/cert-manager/releases/latest/download/cmctl-$OS-$ARCH.tar.gz
+tar xzf cmctl.tar.gz
+sudo mv cmctl /usr/local/bin
+```
+
+You can run `cmctl help` to test the CLI is set up properly:
+
+```console
+$ cmctl help
+
+cmctl is a CLI tool manage and configure cert-manager resources for Kubernetes
+
+Usage: cmctl [command]
+
+Available Commands:
+ approve Approve a CertificateRequest
+ check Check cert-manager components
+ completion Generate completion scripts for the cert-manager CLI
+ convert Convert cert-manager config files between different API versions
+ create Create cert-manager resources
+ deny Deny a CertificateRequest
+ experimental Interact with experimental features
+ help Help about any command
+ inspect Get details on certificate related resources
+ renew Mark a Certificate for manual renewal
+ status Get details on current status of cert-manager resources
+ upgrade Tools that assist in upgrading cert-manager
+ version Print the cert-manager CLI version and the deployed cert-manager version
+
+Flags:
+ -h, --help help for cmctl
+ --log-flush-frequency duration Maximum number of seconds between log flushes (default 5s)
+
+Use "cmctl [command] --help" for more information about a command.
+```
+
+> There is also a [legacy kubectl plugin](#legacy-kubectl-plugin), but it is no longer recommended
+> because the standalone `cmctl` binary provides better [auto-completion](#completion).
+
+## Commands
+
+### Approve and Deny CertificateRequests
+
+CertificateRequests can be
+[approved or denied](../concepts/certificaterequest.md#approval) using their
+respective cmctl commands:
+
+> **Note**: The internal cert-manager approver may automatically approve all
+> CertificateRequests unless disabled with the flag on the cert-manager-controller
+> `--controllers=*,-certificaterequests-approver`
+
+```bash
+$ cmctl approve -n istio-system mesh-ca --reason "pki-team" --message "this certificate is valid"
+Approved CertificateRequest 'istio-system/mesh-ca'
+```
+
+```bash
+$ cmctl deny -n my-app my-app --reason "example.com" --message "violates policy"
+Denied CertificateRequest 'my-app/my-app'
+```
+
+### Convert
+
+`cmctl convert` can be used to convert cert-manager manifest files between
+different API versions. Both YAML and JSON formats are accepted. The command
+either takes a file name, directory path, or a URL as input. The contents is
+converted into the format of the latest API version known to cert-manager, or
+the one specified by `--output-version` flag.
+
+The default output will be printed to stdout in YAML format. One can use the
+option `-o` to change the output destination.
+
+For example, this will output `cert.yaml` in the latest API version:
+
+```console
+cmctl convert -f cert.yaml
+```
+
+### Create
+
+`cmctl create` can be used to create cert-manager resources manually.
+Sub-commands are available to create different resources:
+
+#### CertificateRequest
+
+To create a cert-manager CertificateRequest, use `cmctl create
+certificaterequest`. The command takes in the name of the CertificateRequest to
+be created, and creates a new CertificateRequest resource based on the YAML
+manifest of a Certificate resource as specified by `--from-certificate-file`
+flag, by generating a private key locally and creating a 'certificate signing
+request' to be submitted to a cert-manager Issuer. The private key will be
+written to a local file, where the default is `.key`, or it can be
+specified using the `--output-key-file` flag.
+
+If you wish to wait for the CertificateRequest to be signed and store the X.509
+certificate in a file, you can set the `--fetch-certificate` flag. The default
+timeout when waiting for the issuance of the certificate is 5 minutes, but can
+be specified with the `--timeout` flag. The default name of the file storing the
+X.509 certificate is `.crt`, you can use the `
+--output-certificate-file` flag to specify otherwise.
+
+Note that the private key and the X.509 certificate are both written to file,
+and are **not** stored inside Kubernetes.
+
+For example this will create a CertificateRequest resource with the name "my-cr"
+based on the cert-manager Certificate described in `my-certificate.yaml` while
+storing the private key and X.509 certificate in `my-cr.key` and `my-cr.crt`
+respectively.
+
+```console
+cmctl create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --timeout 20m
+```
+
+### Renew
+
+`cmctl` allows you to manually trigger a renewal of a specific certificate.
+This can be done either one certificate at a time, using label selectors (`-l app=example`), or with the `--all` flag:
+
+For example, you can renew the certificate `example-com-tls`:
+```console
+$ kubectl get certificate
+NAME READY SECRET AGE
+example-com-tls True example-com-tls 1d
+
+$ cmctl renew example-com-tls
+Manually triggered issuance of Certificate default/example-com-tls
+
+$ kubectl get certificaterequest
+NAME READY AGE
+example-com-tls-tls-8rbv2 False 10s
+```
+
+You can also renew all certificates in a given namespace:
+
+```console
+$ cmctl renew --namespace=app --all
+```
+
+The renew command allows several options to be specified:
+* `--all` renew all Certificates in the given Namespace, or all namespaces when combined with `--all-namespaces`
+* `-A` or `--all-namespaces` mark Certificates across namespaces for renewal
+* `-l` `--selector` allows set a label query to filter on
+as well as `kubectl` like global flags like `--context` and `--namespace`.
+
+### Status Certificate
+
+`cmctl status certificate` outputs the details of the current status of a
+Certificate resource and related resources like CertificateRequest, Secret,
+Issuer, as well as Order and Challenges if it is a ACME Certificate. The
+command outputs information about the resources, including Conditions, Events
+and resource specific fields like Key Usages and Extended Key Usages of the
+Secret or Authorizations of the Order. This will be helpful for troubleshooting
+a Certificate.
+
+The command takes in one argument specifying the name of the Certificate
+resource and the namespace can be specified as usual with the `-n` or
+`--namespace` flag.
+
+This example queries the status of the Certificate named `my-certificate` in
+namespace `my-namespace`.
+
+```console
+cmctl status certificate my-certificate -n my-namespace
+```
+
+### Completion
+
+`cmctl` supports auto-completion for both subcommands as well as suggestions for
+runtime objects.
+
+```console
+$ cmctl approve -n
+default kube-node-lease kube-public kube-system local-path-storage
+```
+
+Completion can be installed for your environment by following the instructions
+for the shell you are using. It currently supports bash, fish, zsh, and
+powershell.
+
+```console
+$ cmctl completion help
+```
+
+---
+
+### Experimental
+`cmctl x` has experimental sub-commands for operations which are currently under
+evaluation to be included into cert-manager proper. The behavior and interface
+of these commands are subject to change or removal in future releases.
+
+
+#### Create
+`cmctl x create` can be used to create cert-manager resources manually.
+Sub-commands are available to create different resources:
+
+##### CertificateSigningRequest
+To create a [CertificateSigningRequest](../usage/kube-csr.md), use
+```console
+cmctl x create csr
+```
+This command takes the name of the CertificateSigningRequest to be created, as
+well as a file containing a Certificate manifest (`-f,
+--from-certificate-file`). This command will generate a private key, based on
+the options of the Certificate, and write it to the local file `.key`, or
+specified by `-k, --output-key-file`.
+
+```bash
+$ cmctl x create csr -f my-cert.yaml my-req
+```
+
+
+
+
+cert-manager **will not** automatically approve CertificateSigningRequests. If
+you are not running a custom approver in your cluster, you will likely need to
+manually approve the CertificateSigningRequest:
+
+```bash
+$ kubectl certificate approve
+```
+
+
+
+This command can also wait for the CertificateSigningRequest to be signed using
+the flag `-w, --fetch-certificate`. Once signed it will write the resulting
+signed certificate to the local file `.crt`, or specified by `-c,
+--output-certificate-file`.
+
+```bash
+$ cmctl x create csr -f my-cert.yaml my-req -w
+```
+
+#### Install
+
+```bash
+cmctl x install
+```
+
+This command makes sure that the required `CustomResourceDefinitions` are installed together with the cert-manager, cainjector and webhook components.
+Under the hood, a procedure similar to the [Helm install procedure](../installation/helm.md#steps) is used.
+
+You can also use `cmctl x install` to customize the installation of cert-manager.
+
+The example below shows how to tune the cert-manager installation by overriding the default Helm values:
+
+```bash
+cmctl x install \
+ --set prometheus.enabled=false \ # Example: disabling prometheus using a Helm parameter
+ --set webhook.timeoutSeconds=4s # Example: changing the wehbook timeout using a Helm parameter
+```
+
+You can find [a full list of the install parameters on cert-manager's ArtifactHub page](https://artifacthub.io/packages/helm/cert-manager/cert-manager#configuration). These are the same parameters that are available when using the Helm chart.
+Once you have deployed cert-manager, you can [verify](../installation/verify.md) the installation.
+
+The CLI also allows the user to output the templated manifest to `stdout`, instead of installing the manifest on the cluster.
+
+```bash
+cmctl x install --dry-run > cert-manager.custom.yaml
+```
+
+#### Uninstall
+
+```bash
+cmctl x uninstall
+```
+
+This command uninstalls any Helm-managed release of cert-manager.
+
+The CRDs will be deleted if you installed cert-manager with the option `--set CRDs=true`.
+
+Most of the features supported by `helm uninstall` are also supported by this command.
+
+Some example uses:
+
+```bash
+cmctl x uninstall
+
+cmctl x uninstall --namespace my-cert-manager
+
+cmctl x uninstall --dry-run
+
+cmctl x uninstall --no-hooks
+```
+
+### Upgrade
+
+Tools that assist in upgrading cert-manager
+
+```bash
+$ cmctl upgrade --help
+```
+##### Migrate API version
+
+This command can be used to prepare a cert-manager installation that was created
+before cert-manager `v1` for upgrading to a cert-manager version `v1.6` or later.
+It ensures that any cert-manager custom resources that may have been stored in etcd at
+a deprecated API version get migrated to `v1`. See [Migrating Deprecated API
+Resources](https://cert-manager.io/docs/installation/upgrading/remove-deprecated-apis) for more context.
+
+```bash
+$ cmctl upgrade migrate-api-version --qps 5 --burst 10
+```
+
+## Legacy kubectl plugin
+
+While the kubectl plugin is supported, it is recommended to use `cmctl` as this enables a better experience via tab auto-completion.
+
+To install the plugin you need the `kubectl-cert-manager.tar.gz` file for the platform you're using,
+these can be found on our [GitHub releases page](https://github.com/cert-manager/cert-manager/releases).
+In order to use the kubectl plugin you need its binary to be accessible under the name `kubectl-cert_manager` in your `$PATH`.
+
+You can run `kubectl cert-manager help` to test that the plugin is set up properly.
diff --git a/content/v1.12-docs/reference/tls-terminology.md b/content/v1.12-docs/reference/tls-terminology.md
new file mode 100644
index 00000000000..23b6df34475
--- /dev/null
+++ b/content/v1.12-docs/reference/tls-terminology.md
@@ -0,0 +1,79 @@
+---
+title: TLS Terminology
+description: |
+ Learn about the TLS terminology used in the cert-manager documentation such as publicly trusted, self-signed, root, intermediate and leaf certificate
+---
+
+Learn about the TLS terminology used in the cert-manager documentation such as `publicly trusted`, `self-signed`, `root`, `intermediate` and `leaf` _certificate_.
+
+## Overview
+
+With TLS being so widely deployed, terminology can sometimes get confused or be used to mean different things, and that reality
+combined with the complexity of TLS can lead to serious misunderstandings and confusion.
+
+For further reference, you might want to check out some relevant RFCs:
+
+- [RFC 5246: TLS 1.2](https://datatracker.ietf.org/doc/html/rfc5246)
+- [RFC 8446: TLS 1.3](https://datatracker.ietf.org/doc/html/rfc8446)
+- [RFC 5280: X.509](https://datatracker.ietf.org/doc/html/rfc5280)
+
+## Definitions
+
+### `publicly trusted`
+
+What does "publicly trusted" mean?
+
+Broadly speaking, a "publicly trusted" certificate is one that you can use on the Internet and expect
+that most reasonably up-to-date computers will be able to verify it using their system trust store.
+
+There isn't a single standard trust store containing certs which are "publicly trusted", but generally most
+of the commonly seen trust stores are similar. An example would be [Mozilla's CA Certificate Program](https://wiki.mozilla.org/CA).
+
+### What does "self-signed" mean? Is my CA self-signed?
+
+Self-signed means exactly what it says; a certificate is self-signed if it is signed by its own private key.
+
+Self-signed is a commonly confused term, however, and is very frequently misused to mean "not publicly trusted". We tend to use terms
+like "private PKI" to denote the situation where an organization might have their own internal CA certificates which wouldn't
+be trusted outside of the organization.
+
+As an example, there are _many_ self-signed certificates in [Mozilla's CA Certificate Program](https://wiki.mozilla.org/CA), but
+all of those certificates would usually be described as "publicly trusted".
+
+Your certificate is self-signed only if it's signed with its own key.
+
+### What's the difference between "root", "intermediate", and "leaf" certificates?
+
+cert-manager uses the following definitions:
+
+#### Root Certificates
+
+Roots are self-signed certificates and almost always marked as CA certificates. They're usually not sent over the wire
+during a TLS handshake because they need to be explicitly trusted in order to be validated.
+
+Roots are sometimes defined as "CA certificates which are explicitly trusted"---which can include certificates which
+aren't self-signed. cert-manager doesn't use this definition.
+
+Changing trust stores to include new roots or remove old ones is a non-trivial task which can take months or years for publicly
+trusted roots. For this reason roots are usually issued with very long lifetimes, often on the order of decades.
+
+#### Intermediate Certificates
+
+Intermediates are CA certificates signed by another CA. Most intermediates will be signed by a root certificate, but it's
+possible to construct longer chains where an intermediate can be signed by another intermediate.
+
+Intermediate certificates are usually issued with a much shorter lifetime than the CA which signed them. On the
+Internet, intermediate certificates are used on network-connected machines for day-to-day issuance so that the
+highly-valuable root certificates can remain entirely offline.
+
+While intermediate certificates can also be explicitly trusted via addition to a trust store, they're usually validated
+by "walking up" the chain and validating signatures until an explicitly trusted self-signed root certificate is found.
+
+#### Leaf Certificates
+
+Leaf certificates are usually used to represent a particular identity, rather than being used to sign other certificates.
+On the Internet leaf certificates usually identify a particular domain, such as `example.com`.
+
+Leaf certificates are sent first in a chain of certificates and represent the end of that chain. They must be sent
+along with any intermediates required to create a chain which can be validated by verifying signatures up to a trusted
+root certificate.
diff --git a/content/v1.12-docs/troubleshooting/README.md b/content/v1.12-docs/troubleshooting/README.md
new file mode 100644
index 00000000000..fff96f16723
--- /dev/null
+++ b/content/v1.12-docs/troubleshooting/README.md
@@ -0,0 +1,116 @@
+---
+title: Troubleshooting
+description: |
+ Learn how to debug common problems with cert-manager
+---
+
+In this section, you will learn troubleshooting techniques that will help you find the root cause if your Certificate fails to be issued or renewed.
+
+This section also includes the following guides:
+
+* [Troubleshooting Problems with ACME / Let's Encrypt Certificates](./acme.md):
+ Learn more about how the ACME issuer works and how to diagnose problems with it.
+* [Troubleshooting Problems with the Webhook](./webhook.md):
+ Learn how to diagnose problems with the cert-manager webhook.
+
+## Overview
+
+When troubleshooting cert-manager your best friend is `kubectl describe`, this will give you information on the resources as well as recent events. It is not advised to use the logs as these are quite verbose and only should be looked at if the following steps do not provide help.
+
+cert-manager consists of multiple custom resources that live inside your Kubernetes cluster, these resources are linked together and are often created by one another. When such an event happens it will be reflected in a Kubernetes event, you can see these per-namespace using `kubectl get event`, or in the output of `kubectl describe` when looking at a single resource.
+
+## Troubleshooting a failed certificate request
+
+There are several resources that are involved in requesting a certificate.
+
+```
+
+ ( +---------+ )
+ ( | Ingress | ) Optional ACME Only!
+ ( +---------+ )
+ | |
+ | +-------------+ +--------------------+ | +-------+ +-----------+
+ |-> | Certificate |----> | CertificateRequest | ----> | | Order | ----> | Challenge |
+ +-------------+ +--------------------+ | +-------+ +-----------+
+ |
+```
+
+The cert-manager flow all starts at a `Certificate` resource, you can create this yourself or your Ingress resource will do this for you if you have the [correct annotations](../usage/ingress.md) set.
+
+### 1. Checking the Certificate resource
+First we have to check if we have a `Certificate` resource created in our namespace. We can get these using `kubectl get certificate`.
+```console
+$ kubectl get certificate
+NAME READY AGE
+example-com-tls False 1h
+```
+
+If none is present and you plan to use the [ingress-shim](../usage/ingress.md): check the ingress annotations more about that is in the [ingress troubleshooting guide](../usage/ingress.md#troubleshooting).
+If you are not using the ingress-shim: check the output of the command you used to create the certificate.
+
+If you see one with ready status `False` you can get more info using `kubectl describe certificate`, if the status is `True` that means that cert-manager has successfully issued a certificate.
+```console
+$ kubectl describe certificate
+[...]
+Status:
+ Conditions:
+ Last Transition Time: 2020-05-15T21:45:22Z
+ Message: Issuing certificate as Secret does not exist
+ Reason: DoesNotExist
+ Status: False
+ Type: Ready
+ Next Private Key Secret Name: example-tls-wtlww
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Issuing 105s cert-manager Issuing certificate as Secret does not exist
+ Normal Generated 105s cert-manager Stored new private key in temporary Secret resource "example-tls-wtlww"
+ Normal Requested 104s cert-manager Created new CertificateRequest resource "example-tls-bw5t9"
+```
+
+Here you will find more info about the current certificate status under `Status` as well as detailed information about what happened to it under `Events`. Both will help you determine the current state of the certificate.
+The last status is `Created new CertificateRequest resource`, it is worth taking a look at in which state `CertificateRequest` is to get more info on why our `Certificate` isn't getting issued.
+
+### 2. Checking the `CertificateRequest`
+The `CertificateRequest` resource represents a CSR in cert-manager and passes this CSR on onto the issuer.
+You can find the name of the `CertificateRequest` in the `Certificate` event log or using `kubectl get certificaterequest`
+
+To get more info we again run `kubectl describe`:
+```console
+$ kubectl describe certificaterequest
+API Version: cert-manager.io/v1
+Kind: CertificateRequest
+Spec:
+ Request: [...]
+ Issuer Ref:
+ Group: cert-manager.io
+ Kind: ClusterIssuer
+ Name: letencrypt-production
+Status:
+ Conditions:
+ Last Transition Time: 2020-05-15T21:45:36Z
+ Message: Waiting on certificate issuance from order example-tls-fqtfg-1165244518: "pending"
+ Reason: Pending
+ Status: False
+ Type: Ready
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal OrderCreated 8m20s cert-manager Created Order resource example-tls-fqtfg-1165244518
+```
+
+Here we will see any issue regarding the Issuer configuration as well as Issuer responses.
+
+### 3. Check the issuer state
+If in the above steps you saw an issuer not ready error you can do the same steps again for (cluster)issuer resources:
+```console
+$ kubectl describe issuer
+$ kubectl describe clusterissuer
+```
+
+These will allow you to get any error messages regarding accounts or network issues with your issuer.
+Troubleshooting ACME issuers is described in more detail in [Troubleshooting Issuing ACME Certificates](./acme.md).
+
+### 4. ACME Troubleshooting
+ACME (e.g. Let's Encrypt) issuers have 2 additional resources inside cert-manager: `Orders` and `Challenges`.
+Troubleshooting these is described in [Troubleshooting Issuing ACME Certificates](./acme.md).
diff --git a/content/v1.12-docs/troubleshooting/acme.md b/content/v1.12-docs/troubleshooting/acme.md
new file mode 100644
index 00000000000..c8b527b1cfd
--- /dev/null
+++ b/content/v1.12-docs/troubleshooting/acme.md
@@ -0,0 +1,226 @@
+---
+title: Troubleshooting Problems with ACME / Let's Encrypt Certificates
+description: |
+ Learn how to diagnose problems if cert-manager fails to renew ACME / Let's Encrypt Certificates.
+---
+
+Learn how to diagnose problems if cert-manager fails to renew ACME / Let's Encrypt Certificates.
+
+## Overview
+
+When requesting ACME certificates, cert-manager will create `Order` and
+`Challenges` to complete the request. As such, there are more resources to
+investigate and debug if there is a problem during the process. You can read
+more about these resources in the [concepts
+pages](../concepts/acme-orders-challenges.md).
+
+Before you start here you should probably take a look at our [general troubleshooting guide](./README.md)
+
+## 1. Troubleshooting (Cluster)Issuers
+
+First of all check if the (Cluster)Issuer you're using is in a ready state:
+```bash
+$ kubectl get issuer
+$ kubectl get clusterissuer
+NAME READY AGE
+letsencrypt True 38m
+letsencrypt-http False 32m
+```
+
+If you see `False` check the status using `kubectl describe`. For example:
+```bash
+$ kubectl describe issuer letsencrypt-http
+$ kubectl describe clusterissuer letsencrypt-http
+Name: letsencrypt
+API Version: cert-manager.io/v1
+Kind: Issuer
+Spec:
+ Acme:
+ Email: cert-manager@example.com
+ Private Key Secret Ref:
+ Name: letsencrypt
+ Server: https://acme-staging-v02.api.letsencrypt.org/directory
+Status:
+ Acme:
+ Conditions:
+ Message: Failed to update ACME account:400 urn:ietf:params:acme:error:invalidEmail: Unable to update account :: invalid contact domain. Contact emails @example.com are forbidden
+ Reason: ErrUpdateACMEAccount
+ Status: False
+ Type: Ready
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Warning ErrUpdateACMEAccount 101s (x3 over 106s) cert-manager Failed to update ACME account:400 urn:ietf:params:acme:error:invalidEmail: Unable to update account :: invalid contact domain. Contact emails @example.com are forbidden
+```
+
+### Common errors
+
+* `Failed to update ACME account:400 urn:ietf:params:acme:error:invalidEmail`: the email you specified in the Issuer configuration isn't valid.
+* `Error initializing issuer: Failed to register ACME account: secrets "acme-key" already exists`: there might be a leftover account from a previous issuer that is no longer valid, you should remove the secret so it can be recreated.
+* `Error accepting challenge: 400 urn:ietf:params:acme:error:malformed: Unable to update challenge :: authorization must be pending`: this suggests that the authorization was not in 'pending' state at a time when cert-manager sent a request to the ACME server to accept the challenge. This may be because the domain validation has already failed and the authorization has been marked as 'invalid'. Check the authorization URL on the status of the `Order` or `Challenge` to see the status of the authorization and any additional information.
+
+## 2. Troubleshooting Orders
+
+When we run a describe on the `CertificateRequest` resource we see that an `Order` that has
+been created:
+
+```bash
+$ kubectl describe certificaterequest example-com-2745722290
+...
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal OrderCreated 5s cert-manager Created Order resource default/example-com-2745722290-439160286
+```
+
+Orders are a request to an ACME instance to issue a certificate.
+By running `kubectl describe order` on a particular order,
+information can be gleaned about failures in the process:
+
+```console
+$ kubectl describe order example-com-2745722290-439160286
+...
+Reason:
+State: pending
+URL: https://acme-v02.api.letsencrypt.org/acme/order/41123272/265506123
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Created 1m cert-manager Created Challenge resource "example-com-2745722290-439160286-0" for domain "test1.example.com"
+ Normal Created 1m cert-manager Created Challenge resource "example-com-2745722290-439160286-1" for domain "test2.example.com"
+```
+
+Here we can see that cert-manager has created two Challenge resources to verify we control specific domains,
+a requirements of the ACME order to obtain a signed certificate.
+
+You can then go on to run
+`kubectl describe challenge example-com-2745722290-439160286-0` to further debug the
+progress of the Order.
+
+Once an Order is successful, you should see an event like the following:
+
+```bash
+$ kubectl describe order example-com-2745722290-439160286
+...
+Reason:
+State: valid
+URL: https://acme-v02.api.letsencrypt.org/acme/order/41123272/265506123
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Created 72s cert-manager Created Challenge resource "example-com-2745722290-439160286-0" for domain "test1.example.com"
+ Normal Created 72s cert-manager Created Challenge resource "example-com-2745722290-439160286-1" for domain "test2.example.com"
+ Normal OrderValid 4s cert-manager Order completed successfully
+```
+
+You can see some additional information about the state of the [ACME authorization](https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.4) that needs to be validated as part of this order using the authorization URL from the status of the `Order`:
+
+```bash
+$ kubectl get order -ojsonpath='{.status.authorizations[x].url}'
+```
+
+If the Order is not completing successfully, you can debug the challenges
+for the Order by running `kubectl describe` on the `Challenge` resource which is described in the following steps.
+
+## 3. Troubleshooting Challenges
+
+In order to determine why an ACME Order is not being finished, we can debug
+using the `Challenge` resources that cert-manager has created.
+
+In order to determine which `Challenge` is failing, you can run
+`kubectl get challenges`:
+
+
+```console
+$ kubectl get challenges
+...
+NAME STATE DOMAIN REASON AGE
+example-com-2745722290-4391602865-0 pending example.com Waiting for dns-01 challenge propagation 22s
+```
+
+This shows that the challenge has been presented using the DNS01 solver
+successfully and now cert-manager is waiting for the 'self check' to pass.
+
+You can get more information about the challenge and it's lifecycle by using `kubectl describe`:
+
+```bash
+$ kubectl describe challenge example-com-2745722290-4391602865-0
+...
+Status:
+ Presented: true
+ Processing: true
+ Reason: Waiting for dns-01 challenge propagation
+ State: pending
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Started 19s cert-manager Challenge scheduled for processing
+ Normal Presented 16s cert-manager Presented challenge using dns-01 challenge mechanism
+```
+
+Progress about the state of each challenge will be recorded either as Events
+or on the Challenge's `status` block (as shown above).
+
+In case of DNS01 you will find any errors from your DNS provider here.
+
+Both HTTP01 and DNS01 go through a "self-check" first before cert-manager presents the challenge to the ACME provider.
+This is done not to overload the ACME provider with failed challenges due to DNS or loadbalancer propagations.
+The status of this can be found in the Status block of the describe:
+```console
+$ kubectl describe challenge
+[...]
+Status:
+ Presented: true
+ Processing: true
+ Reason: Waiting for http-01 challenge propagation: failed to perform self check GET request 'http://example.com/.well-known/acme-challenge/_fgdLz0i3TFiZW4LBjuhjgd5nTOkaMBhxYmTY': Get "http://example.com/.well-known/acme-challenge/_fgdLz0i3TFiZW4LBjuhjgd5nTOkaMBhxYmTY: remote error: tls: handshake failure
+ State: pending
+[...]
+```
+
+In this example our HTTP01 check fails due a network issue.
+You will also see any errors coming from your DNS provider here.
+
+You can also see some additional information about the state of the [ACME authorization](https://datatracker.ietf.org/doc/html/rfc8555#section-7.1.4) that the challenge should validate using the authorization URL on from the status of the `Challenge`:
+
+```bash
+$ kubectl get challenge -ojsonpath='{.spec.authorizationURL}'
+```
+
+### HTTP01 troubleshooting
+First of all check if you can see the challenge URL from the public internet, if this does not work check your Ingress and firewall configuration as well as the service and pod cert-manager created to solve the ACME challenge.
+If this does work check if your cluster can see it too. It is important to test this from inside a Pod. If you get a connection error it is suggested to check the cluster's network configuration.
+If you receive a `tls: handshake failure`, try setting the annotation `cert-manager.io/issue-temporary-certificate: "true"` on the Ingress or Certificate resource. This will issue a temporary self signed certificate for the ingress controller to use before the actual certificate is issued.
+If you still are having issues, there may be an issue with your ingress controller handling multiple resources for the same hostname, in this case, the annotation `acme.cert-manager.io/http01-edit-in-place: "true"` is likely required.
+
+For example when using GKE with the Google Cloud Loadbalancer it is recommended to set:
+```
+cert-manager.io/issue-temporary-certificate: "true"
+acme.cert-manager.io/http01-edit-in-place: "true"
+```
+This will allow the Google Cloud Loadbalancer to propagate a HTTPS endpoint correctly with a temporary certificate, the `http01-edit-in-place` part will prevent GKE from assigning a 2nd IP address for the challenge endpoint.
+
+#### Got 404 status code
+If your challenge self-check fails with a 404 not found error. Make sure to check the following:
+
+* you can access the URL from the public internet
+* the ACME solver pod is up and running
+* use `kubectl describe ingress` to check the status of the HTTP01 solver ingress. (unless you use `acme.cert-manager.io/http01-edit-in-place`, then check the same ingress as your domain)
+
+### DNS01 troubleshooting
+If you see no error events about your DNS provider you can check the following
+Check if you can see the `_acme_challenge.domain` TXT DNS record from the public internet, or in your DNS provider's interface.
+cert-manager will check if a DNS record has been propagated by querying the cluster's DNS solver. If you are able to see it from the public internet but not from inside the cluster you might want to change [the DNS server for self-check](../configuration/acme/dns01/README.md#setting-nameservers-for-dns01-self-check) as some cloud providers overwrite DNS internally.
+
+#### cert-manager identifies the wrong zone for your domain name
+cert-manager by default uses SOA (Start of Authority) records to determine which zone name to use at your DNS provider.
+Some DNS resolvers will filter this information, if this is the case cert-manager cannot determine the zone and it is advised to [change the DNS server for DNS01 self-checks](../configuration/acme/dns01/README.md#setting-nameservers-for-dns01-self-check).
+
+If you use `dnsmasq` as your DNS server, this may occur if you use the [`--filterwin2k` flag](http://www.thekelleys.org.uk/dnsmasq/docs/setup.html).
+In [OpenWRT there is a `filterwin2k` configuration option](https://openwrt.org/docs/guide-user/base-system/dhcp#all_options).
+And in [LuCI there is a "Filter useless" option](https://github.com/openwrt/luci/blob/15757dd5b18f9e00ba3c9b38af4d46702a31fe33/modules/luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js#L217-L219).
+By enabling this flag, `dnsmasq` drops all `SOA` records.
+
+## March 2020 Let's Encrypt CAA Rechecking Bug
+Following the [announcement on March 4](https://community.letsencrypt.org/t/revoking-certain-certificates-on-march-4/114864) Let's Encrypt will be revoking a number of certificates due to a bug in the way they validate CAA records, we have created a tool to analyse your existing cert-manager managed certificates and compare their serial numbers to the publicised list of revoked certificates.
+It's advised that all users of Let's Encrypt & cert-manager run a check using this tool to ensure they do not experience any invalid certificate errors in clusters.
+You can find a copy of the checker tool here: https://github.com/jetstack/letsencrypt-caa-bug-checker.
diff --git a/content/v1.12-docs/troubleshooting/webhook.md b/content/v1.12-docs/troubleshooting/webhook.md
new file mode 100644
index 00000000000..b842dcb9def
--- /dev/null
+++ b/content/v1.12-docs/troubleshooting/webhook.md
@@ -0,0 +1,1071 @@
+---
+title: The Definitive Debugging Guide for the cert-manager Webhook Pod
+description: 'This guide helps you debug communication issues between the Kubernetes API server and the cert-manager webhook Pod.'
+---
+
+> Last verified: 8 Sept 2022
+
+The cert-manager webhook is a pod that runs as part of your cert-manager
+installation. When applying a manifest with `kubectl`, the Kubernetes API server
+calls the cert-manager webhook over TLS to validate your manifests. This guide
+helps you debug communication issues between the Kubernetes API server and the
+cert-manager webhook pod.
+
+The error messages listed in this page are encountered while installing or
+upgrading cert-manager, or shortly after installing or upgrading cert-manager
+when trying to create a Certificate, Issuer, or any other cert-manager custom
+resource.
+
+In the below diagram, we show the common pattern when debugging an issue with
+the cert-manager webhook: when creating a cert-manager custom resource, the API
+server connects over TLS to the cert-manager webhook pod. The red cross
+indicates that the API server fails talking to the webhook.
+
+
+
+The rest of this document presents error messages you may encounter.
+
+## Error: `connect: connection refused`
+
+> This issue was reported in 4 GitHub issues ([#2736](https://github.com/jetstack/cert-manager/issues/2736 "Getting WebHook Connection Refused error when using Azure DevOps Pipelines"), [#3133](https://github.com/jetstack/cert-manager/issues/3133 "Failed calling webhook webhook.cert-manager.io: connect: connection refused"), [#3445](https://github.com/jetstack/cert-manager/issues/3445 "Connection refused for cert-manager-webhook service"), [#4425](https://github.com/cert-manager/cert-manager/issues/4425 "Webhook error")), was reported in 1 GitHub issue in an external project ([`aws-load-balancer-controller#1563`](https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/1563 "Internal error occurred: failed calling webhook webhook.cert-manager.io, no endpoints available")), on Stack Overflow ([`serverfault#1076563`](https://web.archive.org/web/20210903183221/https://serverfault.com/questions/1076563/creating-issuer-for-kubernetes-cert-manager-is-causing-404-and-500-error "Creating issuer for kubernetes cert-manager is causing 404 and 500 error")), and was mentioned in 13 Slack messages that can be listed with the search `in:#cert-manager in:#cert-manager-dev ":443: connect: connection refused"`. This error message can also be found in other projects that are building webhooks ([`kubewarden-controller#110`](https://github.com/kubewarden/kubewarden-controller/issues/110 "Investigate failure on webhooks not ready when installing cert-manager from helm chart: connection refused")).
+
+Shortly after installing or upgrading cert-manager, you may hit this error when
+creating a Certificate, Issuer, or any other cert-manager custom resource. For
+example, creating an Issuer resource with the following command:
+
+```sh
+kubectl apply -f- < 10.96.20.99 (webhook pod) TCP 59466 → 443 [SYN]
+10.96.20.99 (webhook pod) -> 192.168.1.43 (apiserver) TCP 443 → 59466 [RST, ACK]
+```
+
+The `RST` packet is sent by the Linux kernel when nothing is listening to the
+requested port. The `RST` packet can also be returned by one of the TCP hops,
+e.g., a firewall, as detailed in the Stack Overflow page [What can be the
+reasons of connection refused errors?](https://stackoverflow.com/a/2333446/3808537)
+
+Note that firewalls usually don't return an `RST` packet; they usually drop the
+`SYN` packet entirely, and you end up with the error message `i/o timeout` or
+`context deadline exceeded`. If that is the case, continue your investigation
+with the section [Error: `i/o timeout` (connectivity issue)](#io-timeout) and [Error: `context
+deadline exceeded`](#context-deadline-exceeded) respectively.
+
+Let's eliminate the possible causes from the closest to the source of the TCP
+connection (the API server) to its destination (the pod `cert-manager-webhook`).
+
+Let's imagine that the name `cert-manager-webhook.cert-manager.svc` was resolved
+to 10.43.183.232. This is a cluster IP. The control plane node, in which the API
+server process runs, uses its iptables to rewrite the IP destination using the
+pod IP. That might be the first problem: sometimes, no pod IP is associated with
+a given cluster IP because the kubelet doesn't fill in the Endpoint resource
+with pod IPs as long as the readiness probe doesn't work.
+
+Let us first check whether it is a problem with the Endpoint resource:
+
+```sh
+kubectl get endpoints -n cert-manager cert-manager-webhook
+```
+
+A valid output would look like this:
+
+```text
+NAME ENDPOINTS AGE
+cert-manager-webhook 10.244.0.2:10250 27d ✅
+```
+
+If you have this valid output and have the `connect: connection refused`, then
+the issue is deeper in the networking stack. We won't dig into this case, but
+you might want to use `tcpdump` and Wireshark to see whether traffic properly
+flows from the API server to the node's host namespace. The traffic from the
+host namespace to the pod's namespace already works fine since the kubelet was
+already able to reach the readiness endpoint.
+
+Common issues include firewall dropping traffic from the control plane to
+workers; for example, the API server on GKE is only allowed to talk to worker
+nodes (which is where the cert-manager webhook is running) over port
+`10250`. In EKS, your security groups might deny traffic from your control
+plane VPC towards your workers VPC over TCP `10250`.
+
+If you see ``, it indicates that the cert-manager webhook is properly
+running but its readiness endpoint can't be reached:
+
+```text
+NAME ENDPOINTS AGE
+cert-manager-webhook 236d ❌
+```
+
+To fix ``, you will have to check whether the cert-manager-webhook
+deployment is healthy. The endpoints stays at `` while the
+cert-manager-webhook isn't marked as `healthy`.
+
+```sh
+kubectl get pod -n cert-manager -l app.kubernetes.io/name=webhook
+```
+
+You should see that the pod is `Running`, and that the number of containers that
+are ready is `0/1`:
+
+```text
+NAME READY STATUS RESTARTS AGE
+cert-manager-76578c9687-24kmr 0/1 Running 7 (8h ago) 28d ❌
+```
+
+We won't be detailing the case where you get `1/1` and `Running`, since it would
+indicate an inconsistent state in Kubernetes.
+
+Continuing with `0/1`, that means the readiness endpoint isn't answering. When
+that happens, no endpoint is created. The next step is to figure out why the
+readiness endpoint isn't answering. Let us see which port the kubelet is using
+when hitting the readiness endpoint:
+
+```sh
+kubectl -n cert-manager get deploy cert-manager-webhook -oyaml | grep -A5 readiness
+```
+
+In our example, the port that the kubelet will try to hit is 6080:
+
+```yaml
+readinessProbe:
+ failureThreshold: 3
+ httpGet:
+ path: /healthz
+ port: 6080 # ✨
+ scheme: HTTP
+```
+
+Now, let us port-forward to that port and see if `/healthz` works. In a shell
+session, run:
+
+```sh
+kubectl -n cert-manager port-forward deploy/cert-manager-webhook 6080
+```
+
+In another shell session, run:
+
+```sh
+curl -sS --dump-header - 127.0.0.1:6080/healthz
+```
+
+The happy output is:
+
+```http
+HTTP/1.1 200 OK ✅
+Date: Tue, 07 Jun 2022 17:16:56 GMT
+Content-Length: 0
+```
+
+If the readiness endpoint doesn't work, you will see:
+
+```text
+curl: (7) Failed to connect to 127.0.0.1 port 6080 after 0 ms: Connection refused ❌
+```
+
+At this point, verify that the readiness endpoint is configured on that same
+port. Let us see the logs to check that our webhook is listening on 6080 for its
+readiness endpoint:
+
+```console
+$ kubectl logs -n cert-manager -l app.kubernetes.io/name=webhook | head -10
+I0607 webhook.go:129] "msg"="using dynamic certificate generating using CA stored in Secret resource"
+I0607 server.go:133] "msg"="listening for insecure healthz connections" "address"=":6081" ❌
+I0607 server.go:197] "msg"="listening for secure connections" "address"=":10250"
+I0607 dynamic_source.go:267] "msg"="Updated serving TLS certificate"
+...
+```
+
+In the above example, the issue was a misconfiguration of the readiness port. In
+the webhook deployment, the argument `--healthz-port=6081` was mismatched with
+the readiness configuration.
+
+
+
+## Error: `i/o timeout` (connectivity issue)
+
+> This error message was reported 26 times on Slack. To list these messages, do a search with `in:#cert-manager in:#cert-manager-dev "443: i/o timeout"`. The error message was reported in 2 GitHub issues ([#2811](https://github.com/cert-manager/cert-manager/issues/2811 "i/o timeout from apiserver when connecting to webhook on k3s"), [#4073](https://github.com/cert-manager/cert-manager/issues/4073 "Internal error occurred: failed calling webhook"))
+
+```text
+Error from server (InternalError): error when creating "STDIN": Internal error occurred:
+ failed calling webhook "webhook.cert-manager.io": failed to call webhook:
+ Post "https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=10s":
+ dial tcp 10.0.0.69:443: i/o timeout
+```
+
+When the API server tries to talk to the cert-manager webhook, the `SYN` packet
+is never answered, and the connection times out. If we were to run tcpdump
+inside the webhook's net namespace, we would see:
+
+```text
+192.168.1.43 (apiserver) -> 10.0.0.69 (webhook pod) TCP 44772 → 443 [SYN]
+192.168.1.43 (apiserver) -> 10.0.0.69 (webhook pod) TCP [TCP Retransmission] 44772 → 443 [SYN]
+192.168.1.43 (apiserver) -> 10.0.0.69 (webhook pod) TCP [TCP Retransmission] 44772 → 443 [SYN]
+192.168.1.43 (apiserver) -> 10.0.0.69 (webhook pod) TCP [TCP Retransmission] 44772 → 443 [SYN]
+```
+
+This issue is caused by the `SYN` packet being dropped somewhere.
+
+
+
+### Cause 1: GKE Private Cluster
+
+The default Helm configuration should work with GKE private clusters, but
+changing `securePort` might break it.
+
+For context, unlike public GKE clusters where the control plane can freely talk
+to pods over any TCP port, the control plane in private GKE clusters can only
+talk to the pods in worker nodes over TCP port `10250` and `443`. These two open
+ports refer to the `containerPort` inside the pod, not the port called `port` in
+the Service resource.
+
+For it to work, the `containerPort` inside the Deployment must match either
+`10250` or `443`; `containerPort` is configured by the Helm value
+`webhook.securePort`. By default, `webhook.securePort` is set to `10250`.
+
+To see if something is off with the `containerPort`, let us start looking at the
+Service resource:
+
+```sh
+kubectl get svc -n cert-manager cert-manager-webhook -oyaml
+```
+
+Looking at the output, we see that the `targetPort` is set to `"https"`:
+
+```yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: cert-manager-webhook
+spec:
+ ports:
+ - name: https
+ port: 443 # ❌ This port is not the cause.
+ protocol: TCP
+ targetPort: "https" # 🌟 This port might be the cause.
+```
+
+The reason the above `port: 443` can't be the cause is because kube-proxy, which
+also runs on the control plane node, translates the webhook's cluster IP to a
+pod IP, and also translates the above `port: 443` to the value in
+`containerPort`.
+
+To see how what is behind the target port `"https"`, we look at the
+Deployment resource:
+
+```sh
+kubectl get deploy -n cert-manager cert-manager-webhook -oyaml | grep -A3 ports:
+```
+
+The output shows that the `containerPort` is not set to `10250`, meaning that
+a new firewall rule will have to be added in Google Cloud.
+
+```yaml
+ ports:
+ - containerPort: 12345 # 🌟 This port matches neither 10250 nor 443.
+ name: https
+ protocol: TCP
+```
+
+To recap, if the above `containerPort` is something other than `443` or `10250` and
+you prefer not changing `containerPort` to `10250`, you will have to add a
+new firewall rule. You can read the section [Adding a firewall rule in a
+GKE private
+cluster](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#add_firewall_rules)
+in the Google documentation.
+
+For context, the reason we did not default `securePort` to `443` is because
+binding to `443` requires one additional Linux capability
+(`NET_BIND_SERVICE`); on the other side, `10250` doesn't require any
+additional capability.
+
+### Cause 2: EKS on a custom CNI
+
+If you are on EKS and you are using a custom CNI such as Weave or Calico,
+the Kubernetes API server (which is in its own node) might not be able to
+reach the webhook pod. This happens because the control plane cannot be
+configured to run on a custom CNI on EKS, meaning that the CNIs cannot
+enable connectivity between the API server and the pods running in the
+worker nodes.
+
+Supposing that you are using Helm, the workaround is to add the following
+value in your `values.yaml` file:
+
+```yaml
+webhook:
+ hostNetwork: true
+ securePort: 10260
+```
+
+Or if you are using Helm from the command-line, use the following flag:
+
+```sh
+--set webhook.hostNetwork=true --set webhook.securePort=10260
+```
+
+By setting `hostNetwork` to `true`, the webhook pod will be run in the
+host's network namespace. By running in the host's network namespace, the
+webhook pod becomes accessible over the node's IP, which means you will
+work around the fact that kube-apiserver can't reach any pod IPs nor
+cluster IPs.
+
+By setting `securePort` to `10260` instead of relying on the default value
+(which is `10250`), you will prevent a conflict between the webhook and the
+kubelet. The kubelet, which is an agent that runs on every Kubernetes
+worker node and runs directly on the host, uses the port `10250` to
+expose its internal API to kube-apiserver.
+
+To understand how `hostnetwork` and `securePort` interact, we have to look
+at how the TCP connection is established. When the kube-apiserver process
+tries to connect to the webhook pod, kube-proxy (which also runs on control
+plane nodes, even without a CNI) kicks in and translates the webhook's
+cluster IP to the webhook's host IP:
+
+```diagram
+ https://cert-manager-webhook.cert-manager.svc:443/validate
+ |
+ |Step 1: resolve to the cluster IP
+ v
+ https://10.43.103.211:443/validate
+ |
+ |Step 2: send TCP packet
+ v
+ src: 172.28.0.1:43021
+ dst: 10.43.103.211:443
+ |
+ |Step 3: kube-proxy rewrite (cluster IP to host IP)
+ v
+ src: 172.28.0.1:43021
+ dst: 172.28.0.2:10260
+ |
+ | control-plane node
+ | (host IP: 172.28.0.1)
+------------|--------------------------------------------------
+ | (host IP: 172.28.0.2)
+ v worker node
+ +-------------------+
+ | webhook pod |
+ | listens on |
+ | 172.28.0.2:10260 |
+ +-------------------+
+```
+
+The reason `10250` is used as the default `securePort` is because it works
+around another limitation with GKE Private Clusters, as detailed in the
+above section [GKE Private Cluster](#gke-private-cluster).
+
+### Cause 3: Network Policies, Calico
+
+Assuming that you are using the Helm chart and that you are using the
+default value of `webhook.securePort` (which is `10250`), and that you are
+using a network policy controller such as Calico, check that there exists a
+policy allowing traffic from the API server to the webhook pod over TCP
+port `10250`.
+
+### Cause 4: EKS and Security Groups
+
+Assuming that you are using the Helm chart and that you are using the
+default value of `webhook.securePort` (which is `10250`), you might want to
+check that your AWS Security Groups allow TCP traffic over `10250` from the
+control plane's VPC to the workers VPC.
+
+### Other causes
+
+If none of the above causes apply, you will need to figure out why the
+webhook is unreachable.
+
+To debug reachability issues (i.e., packets being dropped), we advise to
+use `tcpdump` along with Wireshark at every TCP hop. You can follow the
+article [Debugging Kubernetes Networking: my `kube-dns` is not
+working!](https://maelvls.dev/debugging-kubernetes-networking/) to learn
+how to use `tcpdump` with Wireshark to debug networking issues.
+
+## Error: `x509: certificate is valid for xxx.internal, not cert-manager-webhook.cert-manager.svc` (EKS with Fargate pods)
+
+```text
+Internal error occurred: failed calling webhook "webhook.cert-manager.io":
+ Post https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=30s:
+ x509: certificate is valid for ip-192-168-xxx-xxx.xxx.compute.internal,
+ not cert-manager-webhook.cert-manager.svc
+```
+
+> This issue was first reported in
+> [#3237](https://github.com/cert-manager/cert-manager/issues/3237 "Can't
+> create an issuer when cert-manager runs on EKS in Fargate pods (AWS)").
+
+This is probably because you are running on EKS with Fargate enabled.
+Fargate creates a microVM per pod, and the VM's kernel is used to run the
+container in its own namespace. The problem is that each microVM gets its
+own kubelet. As for any Kubernetes node, the VM's port `10250` is listened to
+by a kubelet process. And `10250` is also the port that the cert-manager
+webhook listens on.
+
+But that's not a problem: the kubelet process and the cert-manager webhook
+process are running in two separate network namespaces, and ports don't
+clash. That's the case both in traditional Kubernetes nodes, as well as
+inside a Fargate microVM.
+
+The problem arises when the API server tries hitting the Fargate pod: the
+microVM's host net namespace is configured to port-forward every possible port
+for maximum compatibility with traditional pods, as demonstrated in the Stack
+Overflow page [EKS Fargate connect to local kubelet][66445207]. But the port
+`10250` is already used by the microVM's kubelet, so anything hitting this port
+won't be port-forwarded and will hit the kubelet instead.
+
+[66445207]: https://stackoverflow.com/questions/66445207 "EKS Fargate connect to local kubelet"
+
+To sum up, the cert-manager webhook looks healthy and is able to listen to port
+`10250` as per its logs, but the microVM's host does not port-forward `10250` to the
+webhook's net namespace. That's the reason you see a message about an unexpected
+domain showing up when doing the TLS handshake: although the cert-manager
+webhook is properly running, the kubelet is the one responding to the API
+server.
+
+This is a limitation of Fargate's microVMs: the IP of the pod and the IP of the
+node are the same. It gives you the same experience as traditional pods, but it
+poses networking challenges.
+
+To fix the issue, the trick is to change the port the cert-manager webhook is
+listening on. Using Helm, we can use the parameter `webhook.securePort`:
+
+```sh
+helm install \
+ cert-manager jetstack/cert-manager \
+ --namespace cert-manager \
+ --create-namespace \
+ --version v1.8.0 \
+ --set webhook.securePort=10260
+```
+
+## Error: `service "cert-managercert-manager-webhook" not found`
+
+```text
+Error from server (InternalError): error when creating "test-resources.yaml": Internal error occurred:
+ failed calling webhook "webhook.cert-manager.io": failed to call webhook:
+ Post "https://cert-managercert-manager-webhook.cert-manager.svc:443/mutate?timeout=10s":
+ service "cert-managercert-manager-webhook" not found
+```
+
+> This error was reported in 2 GitHub issues ([#3195](https://github.com/jetstack/cert-manager/issues/3195 "service cert-manager-webhook not found"),
+> [#4999](https://github.com/cert-manager/cert-manager/issues/4999 "Verification on 1.7.2 fails (Kubectl apply), service cert-manager-webhook not found")).
+
+We do not know the cause of this error, please comment on one of the GitHub
+issues above if you happen to come across it.
+
+## Error: `no endpoints available for service "cert-manager-webhook"` (OVHCloud)
+
+```text
+Error: INSTALLATION FAILED: Internal error occurred:
+ failed calling webhook "webhook.cert-manager.io":
+ Post https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=30s:
+ no endpoints available for service "cert-manager-webhook"
+```
+
+> This issue was first reported once in Slack
+> ([1](https://kubernetes.slack.com/archives/C4NV3DWUC/p1634118489064400?thread_ts=1592676867.472700&cid=C4NV3DWUC)).
+
+This error is rare and was only seen in OVHcloud managed Kubernetes clusters,
+where the etcd resource quota is quite low. etcd is the database where your
+Kubernetes resources (such as pods and deployments) are stored. OVHCloud limits
+the disk space used by your resources in etcd. When the limit is reached, the
+whole cluster starts behaving erratically and one symptom is that Endpoint
+resources aren't created by the kubelet.
+
+To verify that it is in fact a problem of quota, you should be able to see the
+following messages in your kube-apiserver logs:
+
+```sh
+rpc error: code = Unknown desc = ETCD storage quota exceeded
+rpc error: code = Unknown desc = quota computation: etcdserver: not capable
+rpc error: code = Unknown desc = The OVHcloud storage quota has been reached
+```
+
+The workaround is to remove some resources such as CertificateRequest resources
+to get under the limit, as explained in OVHCloud's [ETCD Quotas error,
+troubleshooting](https://docs.ovh.com/gb/en/kubernetes/etcd-quota-error/) page.
+
+## Error: `x509: certificate has expired or is not yet valid`
+
+> This error message was reported once in Slack
+> ([1](https://kubernetes.slack.com/archives/C4NV3DWUC/p1618579222346800)).
+
+When using `kubectl apply`:
+
+```text
+Internal error occurred: failed calling webhook "webhook.cert-manager.io":
+ Post https://kubernetes.default.svc:443/apis/webhook.cert-manager.io/v1beta1/mutations?timeout=30s:
+ x509: certificate has expired or is not yet valid
+```
+
+> This error message was reported once in Slack
+([1](https://kubernetes.slack.com/archives/C4NV3DWUC/p1618579222346800)).
+
+Please answer to the above Slack message since we are still unsure as to what
+may cause this issue; to get access to the Kubernetes Slack, visit
+[https://slack.k8s.io/](https://slack.k8s.io/).
+
+## Error: `net/http: request canceled while waiting for connection`
+
+```text
+Error from server (InternalError): error when creating "STDIN":
+ Internal error occurred: failed calling webhook "webhook.cert-manager.io":
+ Post https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=30s:
+ net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
+```
+
+> This error message was reported once in Slack
+([1](https://kubernetes.slack.com/archives/C4NV3DWUC/p1632849763397100)).
+
+
+
+## Error: `context deadline exceeded`
+
+> This error message was reported in GitHub issues ([2319](https://github.com/cert-manager/cert-manager/issues/2319 "Documenting context deadline exceeded errors relating to the webhook, on bare metal"), [2706](https://github.com/cert-manager/cert-manager/issues/2706 "") [5189](https://github.com/cert-manager/cert-manager/issues/5189 "Post https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=10s: context deadline exceeded"), [5004](https://github.com/cert-manager/cert-manager/issues/5004 "After installing cert-manager using kubectl, cmctl check api fails with https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=10s: context deadline exceeded")), and once [on Stack Overflow](https://stackoverflow.com/questions/72059332/how-can-i-fix-failed-calling-webhook-webhook-cert-manager-io).
+
+This error appears with cert-manager 0.12 and above when trying to apply an
+Issuer or any other cert-manager custom resource after having installed or
+upgraded cert-manager:
+
+```text
+Error from server (InternalError): error when creating "STDIN":
+ Internal error occurred: failed calling webhook "webhook.cert-manager.io":
+ Post https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=30s:
+ context deadline exceeded
+```
+
+> ℹ️ In older releases of cert-manager (0.11 and below), the webhook relied on
+> the [APIService
+> mechanism](https://kubernetes.io/docs/tasks/extend-kubernetes/setup-extension-api-server/),
+> and the message looked a bit different but the cause was the same:
+>
+> ```text
+> Error from server (InternalError): error when creating "STDIN":
+> Internal error occurred: failed calling webhook "webhook.certmanager.k8s.io":
+> Post https://kubernetes.default.svc:443/apis/webhook.certmanager.k8s.io/v1beta1/mutations?timeout=30s:
+> context deadline exceeded
+> ```
+
+> ℹ️ The message `context deadline exceeded` also appears when using `cmctl
+> check api`. The cause is identical, you can continue reading this section to
+> debug it.
+>
+> ```text
+> Not ready: Internal error occurred: failed calling webhook "webhook.cert-manager.io": failed to call webhook:
+> Post "https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=10s":
+> context deadline exceeded
+> ```
+
+The trouble with the message `context deadline exceeded` is that it obfuscates
+the part of the HTTP connection that timed out. When this message appears, we
+can't tell which part of the HTTP interaction timed out. It might be the DNS
+resolution, the TCP handshake, the TLS handshake, sending the HTTP request or
+receiving the HTTP response.
+
+> ℹ️ For context, the query parameter `?timeout=30s` that you can see in the
+> above error messages is a timeout that the API server decides when calling the
+> webhook. It is often set to 10 or 30 seconds.
+
+The following diagram shows what are the three errors that may be hidden behind
+the all-catching "context deadline exceeded" error message, represented by the
+outer box, that is usually thrown after 30 seconds:
+
+
+
+```diagram
+ context deadline exceeded
+ |
+ 30 seconds |
+ timeout v
+ +-------------------------------------------------------------------------+
+ | |
+ | i/o timeout |
+ | | net/http: TLS handshake timeout |
+ | 10 seconds | | |
+ | timeout v | |
+ |------------+ 30 seconds | net/http: request canceled |
+ |TCP | timeout v while awaiting headers |
+ |handshake +---------------------+ | |
+ |------------| TLS | | |
+ | | handshake +------------+ 10 seconds | |
+ | +---------------------| sending | timeout v |
+ | | request +------------+ |
+ | +------------|receiving |------+ |
+ | |resp. header| recv.| |
+ | +------------+ resp.| |
+ | | body +-----+
+ | +------|other|
+ | |logic|
+ | +-----+
+ +-------------------------------------------------------------------------+
+ <----------> <---------------------------------------------->
+ connectivity webhook-side
+ issue issue
+```
+
+In the rest of the section, we will be trying to trigger one of the three "more
+specific" errors:
+
+- `i/o timeout` is the TCP handshake timeout and comes from
+ [`DialTimeout`](https://pkg.go.dev/net#DialTimeout) in the Kubernetes
+ apiserver. The name resolution may be the cause, but usually, this message
+ appears after the API server sent the `SYN` packet and waited for 10 seconds
+ for the `SYN-ACK` packet to be received from the cert-manager webhook.
+- `net/http: request canceled while waiting for connection (Client.Timeout
+ exceeded while awaiting headers)` is the HTTP response timeout and comes from
+ [here](https://github.com/kubernetes/kubernetes/blob/abba1492f/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go#L96-L101)
+ and is configured to [30
+ seconds](https://github.com/kubernetes/kubernetes/blob/abba1492f/staging/src/k8s.io/apiserver/pkg/util/webhook/webhook.go#L36-L38).
+ The Kubernetes API server already sent the HTTP request is is waiting for the
+ HTTP response headers (e.g., `HTTP/1.1 200 OK`).
+- `net/http: TLS handshake timeout` is when the TCP handshake is done, and the
+ Kubernetes API server sent the initial TLS handshake packet (`ClientHello`)
+ and waited for 10 seconds for the cert-manager webhook to answer with the
+ `ServerHello` packet.
+
+We can sort these three messages in two categories: either it is a connectivity
+issue (`SYN` is dropped), or it is a webhook issue (i.e., the TLS certificate is
+wrong, or the webhook is not returning any HTTP response):
+
+| Timeout message | Category |
+|-----------------------------------------------------|--------------------|
+| `i/o timeout` | connectivity issue |
+| `net/http: TLS handshake timeout` | webhook-side issue |
+| `net/http: request canceled while awaiting headers` | webhook-side issue |
+
+The first step is to rule out a webhook-side issue. In your shell session, run
+the following:
+
+```sh
+kubectl -n cert-manager port-forward deploy/cert-manager-webhook 10250
+```
+
+In another shell session, check that you can reach the webhook:
+
+```sh
+curl -vsS --resolve cert-manager-webhook.cert-manager.svc:10250:127.0.0.1 \
+ --service-name cert-manager-webhook-ca \
+ --cacert <(kubectl -n cert-manager get secret cert-manager-webhook-ca -ojsonpath='{.data.ca\.crt}' | base64 -d) \
+ https://cert-manager-webhook.cert-manager.svc:10250/validate 2>&1 -d@- <<'EOF' | sed '/^* /d; /bytes data]$/d; s/> //; s/< //'
+{"kind":"AdmissionReview","apiVersion":"admission.k8s.io/v1","request":{"requestKind":{"group":"cert-manager.io","version":"v1","kind":"Certificate"},"requestResource":{"group":"cert-manager.io","version":"v1","resource":"certificates"},"name":"foo","namespace":"default","operation":"CREATE","object":{"apiVersion":"cert-manager.io/v1","kind":"Certificate","spec":{"dnsNames":["foo"],"issuerRef":{"group":"cert-manager.io","kind":"Issuer","name":"letsencrypt"},"secretName":"foo","usages":["digital signature"]}}}}
+EOF
+```
+
+The happy output looks like this:
+
+```http
+POST /validate HTTP/1.1
+Host: cert-manager-webhook.cert-manager.svc:10250
+User-Agent: curl/7.83.0
+Accept: */*
+Content-Length: 1299
+Content-Type: application/x-www-form-urlencoded
+
+HTTP/1.1 200 OK
+Date: Wed, 08 Jun 2022 14:52:21 GMT
+Content-Length: 2029
+Content-Type: text/plain; charset=utf-8
+
+...
+"response": {
+ "uid": "",
+ "allowed": true
+}
+```
+
+If the response shows `200 OK`, we can rule out a webhook-side issue. Since the
+initial error message was `context deadline exceeded` and not an apiserver-side
+issue such as `x509: certificate signed by unknown authority` or `x509:
+certificate has expired or is not yet valid`, we can conclude that the problem
+is a connectivity issue: the Kubernetes API server isn't able to establish a TCP
+connection to the cert-manager webhook. Please follow the instructions in the
+section [Error: `i/o timeout` (connectivity issue)](#io-timeout) above to
+continue debugging.
+
+## Error: `net/http: TLS handshake timeout`
+
+> This error message was reported in 1 GitHub issue ([#2602](https://github.com/cert-manager/cert-manager/issues/2602 "Internal error occurred: failed calling webhook webhook.cert-manager.io: Post https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=30s: net/http: TLS handshake timeout")).
+
+```text
+Error from server (InternalError): error when creating "STDIN":
+ Internal error occurred: failed calling webhook "webhook.cert-manager.io":
+ Post https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=30s:
+ net/http: TLS handshake timeout
+```
+
+Looking at the [above diagram](#diagram), this error message indicates that the
+Kubernetes API server successfully established a TCP connection to the pod IP
+associated with the cert-manager webhook. The TLS handshake timeout means that
+the cert-manager webhook process isn't the one ending the TCP connection: there
+is some HTTP proxy in between that is probably waiting for a plain HTTP request
+instead a `ClientHello` packet.
+
+We do not know the cause of this error. Please comment on the above GitHub
+issue if you notice this error.
+
+## Error: `HTTP probe failed with statuscode: 500`
+
+> This error message was reported in 2 GitHub issue ([#3185](https://github.com/cert-manager/cert-manager/issues/3185 "kubectl install cert-manager: Readiness probe failed: HTTP probe failed with statuscode: 500"), [#4557](https://github.com/cert-manager/cert-manager/issues/4557 "kubectl install cert-manager: Readiness probe failed: HTTP probe failed with statuscode: 500")).
+
+The error message is visible as an event on the cert-manager webhook:
+
+```text
+Warning Unhealthy (x13 over 15s) kubelet, node83
+ Readiness probe failed: HTTP probe failed with statuscode: 500
+```
+
+We do not know the cause of this error. Please comment on the above GitHub
+issue if you notice this error.
+
+## Error: `Service Unavailable`
+
+> This error was reported in 1 GitHub issue ([#4281](https://github.com/cert-manager/cert-manager/issues/4281 "Can't deploy Issuer, Service Unavailable"))
+
+```text
+Error from server (InternalError): error when creating "STDIN": Internal error occurred:
+ failed calling webhook "webhook.cert-manager.io":
+ Post "https://my-cert-manager-webhook.default.svc:443/mutate?timeout=10s":
+ Service Unavailable
+```
+
+The above message appears in Kubernetes clusters using the Weave CNI.
+
+We do not know the cause of this error. Please comment on the above GitHub
+issue if you notice this error.
+
+## Error: `failed calling admission webhook: the server is currently unable to handle the request`
+
+> This issue was reported in 4 GitHub issues ([1369](https://github.com/cert-manager/cert-manager/issues/1369 "the server is currently unable to handle the request"), [1425](https://github.com/cert-manager/cert-manager/issues/1425 "Verifying Install: failed calling admission webhook (Azure, GKE private cluster)") [3542](https://github.com/cert-manager/cert-manager/issues/3542 "SSL Certificate Manager has got expired, we need to renew SSL certificate in existing ClusterIssuer Kubernetes Service (AKS)"), [4852](https://github.com/cert-manager/cert-manager/issues/4852 "error: unable to retrieve the complete list of server APIs: webhook.cert-manager.io/v1beta1: the server is currently unable to handle the request (AKS)"))
+
+```text
+Error from server (InternalError): error when creating "test-resources.yaml": Internal error occurred:
+ failed calling admission webhook "issuers.admission.certmanager.k8s.io":
+ the server is currently unable to handle the request
+```
+
+We do not know the cause of this error. Please comment in one of the above
+GitHub issues if you are able to reproduce this error.
+
+## Error: `x509: certificate signed by unknown authority`
+
+> Reported in GitHub issues
+> ([2602](https://github.com/cert-manager/cert-manager/issues/2602#issuecomment-606474055 "x509: certificate signed by unknown authority"))
+
+When installing or upgrading cert-manager and using a namespace that is not
+`cert-manager`:
+
+```text
+Error: UPGRADE FAILED: release core-l7 failed, and has been rolled back due to atomic being set:
+ failed to create resource: conversion webhook for cert-manager.io/v1alpha3, Kind=ClusterIssuer failed:
+ Post https://cert-manager-webhook.core-l7.svc:443/convert?timeout=30s:
+ x509: certificate signed by unknown authority
+```
+
+A very similar error message may show when creating an Issuer or any other
+cert-manager custom resource:
+
+```text
+Internal error occurred: failed calling webhook "webhook.cert-manager.io":
+ Post https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=30s:
+ x509: certificate signed by unknown authority`
+```
+
+With `cmctl install` and `cmctl check api`, you might see the following error
+message:
+
+```text
+2022/06/06 15:36:30 Not ready: the cert-manager webhook CA bundle is not injected yet
+ (Internal error occurred: conversion webhook for cert-manager.io/v1alpha2, Kind=Certificate failed:
+ Post "https://-cert-manager-webhook.cert-manager.svc:443/convert?timeout=30s":
+ x509: certificate signed by unknown authority)
+```
+
+If you are using cert-manager 0.14 and below with Helm, and that you are
+installing in a namespace different from `cert-manager`, the CRD manifest had
+the namespace name `cert-manager` hardcoded. You can see the hardcoded namespace
+in the following annotation:
+
+```sh
+kubectl get crd issuers.cert-manager.io -oyaml | grep inject
+```
+
+You will see the following:
+
+```yaml
+cert-manager.io/inject-ca-from-secret: cert-manager/cert-manager-webhook-ca
+# ^^^^^^^^^^^^
+# hardcoded
+```
+
+> **Note 1:** this bug in the cert-manager Helm chart was [was
+fixed](https://github.com/cert-manager/cert-manager/commit/f33beefc) in
+cert-manager 0.15.
+>
+> **Note 2:** since cert-manager 1.6, this annotation is [no longer
+> used](https://github.com/cert-manager/cert-manager/pull/4841) on the
+> cert-manager CRDs since conversion is no longer needed.
+
+The solution, if you are still using cert-manager 0.14 or below, is to render
+the manifest using `helm template`, then edit the annotation to use the correct
+namespace, and then use `kubectl apply` to install cert-manager.
+
+If you are using cert-manager 1.6 and below, the issue might be due to the
+cainjector being stuck trying to inject the self-signed certificate that the
+cert-manager webhook created and stored in the Secret resource
+`cert-manager-webhook-ca` into the `spec.caBundle` field of the cert-manager
+CRDs. The first step is to check whether the cainjector is running with no
+problem:
+
+```console
+$ kubectl -n cert-manager get pods -l app.kubernetes.io/name=cainjector
+NAME READY STATUS RESTARTS AGE
+cert-manager-cainjector-5c55bb7cb4-6z4cf 1/1 Running 11 (31h ago) 28d
+```
+
+Looking at the logs, you will be able to tell if the leader election worked. It
+can take up to one minute for the leader election work to complete.
+
+```console
+I0608 start.go:126] "starting" version="v1.8.0" revision="e466a521bc5455def8c224599c6edcd37e86410c"
+I0608 leaderelection.go:248] attempting to acquire leader lease kube-system/cert-manager-cainjector-leader-election...
+I0608 leaderelection.go:258] successfully acquired lease kube-system/cert-manager-cainjector-leader-election
+I0608 controller.go:186] cert-manager/secret/customresourcedefinition/controller/controller-for-secret-customresourcedefinition "msg"="Starting Controller"
+I0608 controller.go:186] cert-manager/certificate/customresourcedefinition/controller/controller-for-certificate-customresourcedefinition "msg"="Starting Controller"
+I0608 controller.go:220] cert-manager/secret/customresourcedefinition/controller/controller-for-secret-customresourcedefinition "msg"="Starting workers" "worker count"=1
+I0608 controller.go:220] cert-manager/certificate/customresourcedefinition/controller/controller-for-certificate-customresourcedefinition "msg"="Starting workers" "worker count"=1
+```
+
+The happy output contains lines like this:
+
+```console
+I0608 sources.go:184] cert-manager/secret/customresourcedefinition/generic-inject-reconciler
+ "msg"="Extracting CA from Secret resource" "resource_name"="issuers.cert-manager.io" "secret"="cert-manager/cert-manager-webhook-ca"
+I0608 controller.go:178] cert-manager/secret/customresourcedefinition/generic-inject-reconciler
+ "msg"="updated object" "resource_name"="issuers.cert-manager.io"
+```
+
+Now, look for any message that indicates that the Secret resource that the
+cert-manager webhook created can't be loaded. The two error messages that might
+show up are:
+
+```text
+E0608 sources.go:201] cert-manager/secret/customresourcedefinition/generic-inject-reconciler
+ "msg"="unable to fetch associated secret" "error"="Secret \"cert-manager-webhook-caq\" not found"
+```
+
+The following message indicates that the given CRD has been skipped because the
+annotation is missing. You can ignore these messages:
+
+```text
+I0608 controller.go:156] cert-manager/secret/customresourcedefinition/generic-inject-reconciler
+ "msg"="failed to determine ca data source for injectable" "resource_name"="challenges.acme.cert-manager.io"
+```
+
+If nothing seems wrong with the cainjector logs, you will want to check that the
+`spec.caBundle` field in the validation, mutation, and conversion configurations
+are correct. The Kubernetes API server uses the contents of that field to trust
+the cert-manager webhook. The `caBundle` contains the self-signed CA created by
+the cert-manager webhook when it started.
+
+```console
+$ kubectl get validatingwebhookconfigurations cert-manager-webhook -ojson | jq '.webhooks[].clientConfig'
+{
+ "caBundle": "LS0tLS1...LS0tLS0K",
+ "service": {
+ "name": "cert-manager-webhook",
+ "namespace": "cert-manager",
+ "path": "/validate",
+ "port": 443
+ }
+}
+```
+
+```console
+$ kubectl get mutatingwebhookconfigurations cert-manager-webhook -ojson | jq '.webhooks[].clientConfig'
+{
+ "caBundle": "LS0tLS1...RFLS0tLS0K",
+ "service": {
+ "name": "cert-manager-webhook",
+ "namespace": "cert-manager",
+ "path": "/validate",
+ "port": 443
+ }
+}
+```
+
+Let us see the contents of the `caBundle`:
+
+```console
+$ kubectl get mutatingwebhookconfigurations cert-manager-webhook -ojson \
+ | jq '.webhooks[].clientConfig.caBundle' -r | base64 -d \
+ | openssl x509 -noout -text -in -
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ ee:8f:4f:c8:55:7b:16:76:d8:6a:a2:e5:94:bc:7c:6b
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: CN = cert-manager-webhook-ca
+ Validity
+ Not Before: May 10 16:13:37 2022 GMT
+ Not After : May 10 16:13:37 2023 GMT
+ Subject: CN = cert-manager-webhook-ca
+```
+
+Let us check that the contents of `caBundle` works for connecting to the
+webhook:
+
+```console
+$ kubectl -n cert-manager get secret cert-manager-webhook-ca -ojsonpath='{.data.ca\.crt}' \
+ | base64 -d | openssl x509 -noout -text -in -
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ ee:8f:4f:c8:55:7b:16:76:d8:6a:a2:e5:94:bc:7c:6b
+ Signature Algorithm: ecdsa-with-SHA384
+ Issuer: CN = cert-manager-webhook-ca
+ Validity
+ Not Before: May 10 16:13:37 2022 GMT
+ Not After : May 10 16:13:37 2023 GMT
+ Subject: CN = cert-manager-webhook-ca
+```
+
+Our final test is to try to connect to the webhook using this trust bundle. Let
+us port-forward to the webhook pod:
+
+```sh
+kubectl -n cert-manager port-forward deploy/cert-manager-webhook 10250
+```
+
+In another shell session, send a `/validate` HTTP request with the following
+command:
+
+```sh
+curl -vsS --resolve cert-manager-webhook.cert-manager.svc:10250:127.0.0.1 \
+ --service-name cert-manager-webhook-ca \
+ --cacert <(kubectl get validatingwebhookconfigurations cert-manager-webhook -ojson | jq '.webhooks[].clientConfig.caBundle' -r | base64 -d) \
+ https://cert-manager-webhook.cert-manager.svc:10250/validate 2>&1 -d@- <<'EOF' | sed '/^* /d; /bytes data]$/d; s/> //; s/< //'
+{"kind":"AdmissionReview","apiVersion":"admission.k8s.io/v1","request":{"requestKind":{"group":"cert-manager.io","version":"v1","kind":"Certificate"},"requestResource":{"group":"cert-manager.io","version":"v1","resource":"certificates"},"name":"foo","namespace":"default","operation":"CREATE","object":{"apiVersion":"cert-manager.io/v1","kind":"Certificate","spec":{"dnsNames":["foo"],"issuerRef":{"group":"cert-manager.io","kind":"Issuer","name":"letsencrypt"},"secretName":"foo","usages":["digital signature"]}}}}
+EOF
+```
+
+You should see a successful HTTP request and response:
+
+```http
+POST /validate HTTP/1.1
+Host: cert-manager-webhook.cert-manager.svc:10250
+User-Agent: curl/7.83.0
+Accept: */*
+Content-Length: 1299
+Content-Type: application/x-www-form-urlencoded
+
+HTTP/1.1 200 OK
+Date: Wed, 08 Jun 2022 16:20:45 GMT
+Content-Length: 2029
+Content-Type: text/plain; charset=utf-8
+
+...
+```
+
+## Error: `cluster scoped resource "mutatingwebhookconfigurations/" is managed and access is denied`
+
+> This message was reported in GitHub issue
+> [3717](https://github.com/cert-manager/cert-manager/issues/3717 "Cannot
+> install on GKE autopilot cluster due to mutatingwebhookconfigurations access
+> denied").
+
+While installing cert-manager on GKE Autopilot, you will see the following
+message:
+
+```text
+Error: rendered manifests contain a resource that already exists. Unable to continue with install:
+ could not get information about the resource:
+ mutatingwebhookconfigurations.admissionregistration.k8s.io "cert-manager-webhook" is forbidden:
+ User "XXXX" cannot get resource "mutatingwebhookconfigurations" in API group "admissionregistration.k8s.io" at the cluster scope:
+ GKEAutopilot authz: cluster scoped resource "mutatingwebhookconfigurations/" is managed and access is denied
+```
+
+This error message will appear when using Kubernetes 1.20 and below with GKE
+Autopilot. It is due to a [restriction on mutating admission webhooks in GKE
+Autopilot](https://github.com/cert-manager/cert-manager/issues/3717).
+
+As of October 2021, the "rapid" Autopilot release channel has rolled out version
+1.21 for Kubernetes masters. Installation via the Helm chart may end in an error
+message but cert-manager is reported to be working by some users. Feedback and
+PRs are welcome.
+
+## Error: `the namespace "kube-system" is managed and the request's verb "create" is denied`
+
+When installing cert-manager on GKE Autopilot with Helm, you will see the
+following error message:
+
+```text
+Not ready: the cert-manager webhook CA bundle is not injected yet
+```
+
+After this failure, you should still see the three pods happily running:
+
+```console
+$ kubectl get pods -n cert-manager
+NAME READY STATUS RESTARTS AGE
+cert-manager-76578c9687-24kmr 1/1 Running 0 47m
+cert-manager-cainjector-b7d47f746-4799n 1/1 Running 0 47m
+cert-manager-webhook-7f788c5b6-mspnt 1/1 Running 0 47m
+```
+
+But looking at either of the logs, you will see the following error message:
+
+```text
+E0425 leaderelection.go:334] error initially creating leader election record:
+ leases.coordination.k8s.io is forbidden: User "system:serviceaccount:cert-manager:cert-manager-webhook"
+ cannot create resource "leases" in API group "coordination.k8s.io" in the namespace "kube-system":
+ GKEAutopilot authz: the namespace "kube-system" is managed and the request's verb "create" is denied
+```
+
+That is due to a limitation of GKE Autopilot. It is not possible to create
+resources in the `kube-system` namespace, and cert-manager uses the well-known
+`kube-system` to manage the leader election. To get around the limitation, you
+can tell Helm to use a different namespace for the leader election:
+
+```sh
+helm install cert-manager jetstack/cert-manager --version 1.8.0 \
+ --namespace cert-manager --create-namespace \
+ --set global.leaderElection.namespace=cert-manager
+```
diff --git a/content/v1.12-docs/tutorials/README.md b/content/v1.12-docs/tutorials/README.md
new file mode 100644
index 00000000000..cc839b6b105
--- /dev/null
+++ b/content/v1.12-docs/tutorials/README.md
@@ -0,0 +1,38 @@
+---
+title: Tutorials
+description: 'cert-manager tutorials: Overview'
+---
+
+Step-by-step tutorials are a great way to get started with cert-manager, and we provide a few
+for you to learn from. Take a look!
+
+- [Securing Ingresses with NGINX-Ingress and cert-manager](./acme/nginx-ingress.md): Tutorial for deploying NGINX into your
+ cluster and securing incoming connections with a certificate from Let's Encrypt.
+- [GKE + Ingress + Let's Encrypt](./getting-started-with-cert-manager-on-google-kubernetes-engine-using-lets-encrypt-for-ingress-ssl/README.md):
+ Learn how to deploy cert-manager on Google Kubernetes Engine and how to configure it to get certificates for Ingress, from Let's Encrypt.
+- [AKS + LoadBalancer + Let's Encrypt](getting-started-aks-letsencrypt/README.md):
+ Learn how to deploy cert-manager on Azure Kubernetes Service (AKS) and how to configure it to get certificates for an HTTPS web server, from Let's Encrypt.
+- [Backup and Restore Resources](./backup.md): Backup the cert-manager resources
+ in your cluster and then restore them.
+- [Pomerium Ingress](./acme/pomerium-ingress.md): Tutorial on using the Pomerium Ingress Controller with cert-manager.
+- [Issuing an ACME Certificate using DNS Validation](./acme/dns-validation.md):
+ Tutorial on how to resolve DNS ownership validation using DNS01 challenges.
+- [Issuing an ACME Certificate using HTTP Validation](./acme/http-validation.md):
+ Tutorial on how to resolve DNS ownership validation using HTTP01 challenges.
+- [Migrating from kube-lego](./acme/migrating-from-kube-lego.md): Tutorial on
+ how to migrate from the now deprecated kube-lego project.
+- [Securing an EKS Cluster with Venafi](./venafi/venafi.md): Tutorial for
+ creating an EKS cluster and securing an NGINX deployment with a Venafi issued
+ certificate.
+- [Securing an Istio service mesh with cert-manager](./istio-csr/istio-csr.md): Tutorial for
+ securing an Istio service mesh using a cert-manager issuer.
+- [Syncing Secrets Across Namespaces](./syncing-secrets-across-namespaces.md):
+ Learn how to synchronize Kubernetes Secret resources across namespaces using extensions such as: reflector, kubed and kubernetes-replicator.
+- [Obtaining SSL certificates with the ZeroSSL](./zerossl/zerossl.md): Tutorial describing usage of the ZeroSSL as external ACME server.
+
+### External Tutorials
+
+- A great AWS blog post on using cert-manager for end-to-end encryption in EKS. See [Setting up end-to-end TLS encryption on Amazon EKS](https://aws.amazon.com/blogs/containers/setting-up-end-to-end-tls-encryption-on-amazon-eks-with-the-new-aws-load-balancer-controller/)
+- A full cert-manager installation demo on a GKE Cluster. See [How-To: Automatic SSL Certificate Management for your Kubernetes Application Deployment](https://medium.com/contino-engineering/how-to-automatic-ssl-certificate-management-for-your-kubernetes-application-deployment-94b64dfc9114)
+- cert-manager installation on GKE Cluster using Workload Identity. See [Kubernetes, ingress-nginx, cert-manager & external-dns](https://blog.atomist.com/kubernetes-ingress-nginx-cert-manager-external-dns/)
+- A video tutorial for beginners showing cert-manager in action. See [Free SSL for Kubernetes with cert-manager](https://www.youtube.com/watch?v=hoLUigg4V18)
diff --git a/content/v1.12-docs/tutorials/acme/dns-validation.md b/content/v1.12-docs/tutorials/acme/dns-validation.md
new file mode 100644
index 00000000000..bddf11097bf
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/dns-validation.md
@@ -0,0 +1,169 @@
+---
+title: DNS Validation
+description: 'cert-manager turorials: Issuing an ACME certificate using DNS validation'
+---
+
+## Issuing an ACME certificate using DNS validation
+
+cert-manager can be used to obtain certificates from a CA using the
+[ACME](https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment)
+protocol. The ACME protocol supports various challenge mechanisms which are
+used to prove ownership of a domain so that a valid certificate can be issued
+for that domain.
+
+One such challenge mechanism is DNS01. With a DNS01 challenge, you prove
+ownership of a domain by proving you control its DNS records.
+This is done by creating a TXT record with specific content that proves you
+have control of the domains DNS records.
+
+The following Issuer defines the necessary information to enable DNS validation.
+You can read more about the Issuer resource in the [Issuer
+docs](../../configuration/README.md).
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt-staging
+ namespace: default
+spec:
+ acme:
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ email: user@example.com
+
+ # Name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: letsencrypt-staging
+
+ # ACME DNS-01 provider configurations
+ solvers:
+ # An empty 'selector' means that this solver matches all domains
+ - selector: {}
+ dns01:
+ cloudDNS:
+ # The ID of the GCP project
+ # reference: https://cert-manager.io/docs/tutorials/acme/dns-validation/
+ project: $PROJECT_ID
+ # This is the secret used to access the service account
+ serviceAccountSecretRef:
+ name: clouddns-dns01-solver-svc-acct
+ key: key.json
+
+ # We only use cloudflare to solve challenges for example.org.
+ # Alternative options such as 'matchLabels' and 'dnsZones' can be specified
+ # as part of a solver's selector too.
+ - selector:
+ dnsNames:
+ - example.org
+ dns01:
+ cloudflare:
+ email: my-cloudflare-acc@example.com
+ # !! Remember to create a k8s secret before
+ # kubectl create secret generic cloudflare-api-key-secret
+ apiKeySecretRef:
+ name: cloudflare-api-key-secret
+ key: api-key
+```
+
+
+We have specified the ACME server URL for Let's Encrypt's [staging
+environment](https://letsencrypt.org/docs/staging-environment/). The staging
+environment will not issue trusted certificates but is used to ensure that the
+verification process is working properly before moving to production. Let's
+Encrypt's production environment imposes much stricter [rate
+limits](https://letsencrypt.org/docs/rate-limits/), so to reduce the chance of
+you hitting those limits it is highly recommended to start by using the staging
+environment. To move to production, simply create a new Issuer with the URL set
+to `https://acme-v02.api.letsencrypt.org/directory`.
+
+The first stage of the ACME protocol is for the client to register with the
+ACME server. This phase includes generating an asymmetric key pair which is
+then associated with the email address specified in the Issuer. Make sure to
+change this email address to a valid one that you own. It is commonly used to
+send expiry notices when your certificates are coming up for renewal. The
+generated private key is stored in a Secret named `letsencrypt-staging`.
+
+The `dns01` stanza contains a list of DNS01 providers that can be used to
+solve DNS challenges. Our Issuer defines two providers. This gives us a choice
+of which one to use when obtaining certificates.
+
+More information about the DNS provider configuration, including a list of
+supported providers, can be found [in the DNS01 reference docs](../../configuration/acme/dns01/README.md).
+
+Once we have created the above Issuer we can use it to obtain a certificate.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com
+ namespace: default
+spec:
+ secretName: example-com-tls
+ issuerRef:
+ name: letsencrypt-staging
+ dnsNames:
+ - '*.example.com'
+ - example.com
+ - example.org
+```
+
+The Certificate resource describes our desired certificate and the possible
+methods that can be used to obtain it. You can obtain certificates for wildcard
+domains just like any other. Make sure to wrap wildcard domains with asterisks
+in your YAML resources, to avoid formatting issues. If you specify both
+`example.com` and `*.example.com` on the same Certificate, it will take slightly
+longer to perform validation as each domain will have to be validated one after
+the other. You can learn more about the Certificate resource in the
+[docs](../../usage/README.md). If the certificate is obtained successfully, the
+resulting key pair will be stored in a secret called `example-com-tls` in the
+same namespace as the Certificate.
+
+The certificate will have a common name of `*.example.com` and the [Subject
+Alternative Names
+(SANs)](https://en.wikipedia.org/wiki/Subject_Alternative_Name) will be
+`*.example.com`, `example.com` and `example.org`.
+
+In our Certificate we have referenced the `letsencrypt-staging` Issuer above.
+The Issuer must be in the same namespace as the Certificate. If you want to
+reference a `ClusterIssuer`, which is a cluster-scoped version of an Issuer, you
+must add `kind: ClusterIssuer` to the `issuerRef` stanza.
+
+For more information on `ClusterIssuers`, read the
+[issuer concepts](../../concepts/issuer.md).
+
+The `acme` stanza defines the configuration for our ACME challenges. Here we
+have defined the configuration for our DNS challenges which will be used to
+verify domain ownership. For each domain mentioned in a `dns01` stanza,
+cert-manager will use the provider's credentials from the referenced Issuer to
+create a TXT record called `_acme-challenge`. This record will then be verified
+by the ACME server in order to issue the certificate. Once domain ownership has
+been verified, any cert-manager affected records will be cleaned up.
+
+> Note: It is your responsibility to ensure the selected provider is
+> authoritative for your domain.
+
+After creating the above Certificate, we can check whether it has been obtained
+successfully using `kubectl describe`:
+
+```bash
+$ kubectl describe certificate example-com
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal CreateOrder 57m cert-manager Created new ACME order, attempting validation...
+ Normal DomainVerified 55m cert-manager Domain "*.example.com" verified with "dns-01" validation
+ Normal DomainVerified 55m cert-manager Domain "example.com" verified with "dns-01" validation
+ Normal DomainVerified 55m cert-manager Domain "example.org" verified with "dns-01" validation
+ Normal IssueCert 55m cert-manager Issuing certificate...
+ Normal CertObtained 55m cert-manager Obtained certificate from ACME server
+ Normal CertIssued 55m cert-manager Certificate issued successfully
+```
+
+You can also check whether issuance was successful with `kubectl get secret
+example-com-tls -o yaml`. You should see a base64 encoded signed TLS key pair.
+
+Once our certificate has been obtained, cert-manager will periodically check its
+validity and attempt to renew it if it gets close to expiry. cert-manager
+considers certificates to be close to expiry when the 'Not After' field on the
+certificate is less than the current time plus 30 days.
\ No newline at end of file
diff --git a/content/v1.12-docs/tutorials/acme/example/deployment.yaml b/content/v1.12-docs/tutorials/acme/example/deployment.yaml
new file mode 100644
index 00000000000..d876c66cf99
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/deployment.yaml
@@ -0,0 +1,20 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: kuard
+spec:
+ selector:
+ matchLabels:
+ app: kuard
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: kuard
+ spec:
+ containers:
+ - image: gcr.io/kuar-demo/kuard-amd64:1
+ imagePullPolicy: Always
+ name: kuard
+ ports:
+ - containerPort: 8080
diff --git a/content/v1.12-docs/tutorials/acme/example/ingress-tls-final.yaml b/content/v1.12-docs/tutorials/acme/example/ingress-tls-final.yaml
new file mode 100644
index 00000000000..5c90402c416
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/ingress-tls-final.yaml
@@ -0,0 +1,24 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: kuard
+ annotations:
+ kubernetes.io/ingress.class: "nginx"
+ cert-manager.io/issuer: "letsencrypt-prod"
+
+spec:
+ tls:
+ - hosts:
+ - example.example.com
+ secretName: quickstart-example-tls
+ rules:
+ - host: example.example.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: kuard
+ port:
+ number: 80
diff --git a/content/v1.12-docs/tutorials/acme/example/ingress-tls.yaml b/content/v1.12-docs/tutorials/acme/example/ingress-tls.yaml
new file mode 100644
index 00000000000..f888087d675
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/ingress-tls.yaml
@@ -0,0 +1,24 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: kuard
+ annotations:
+ kubernetes.io/ingress.class: "nginx"
+ cert-manager.io/issuer: "letsencrypt-staging"
+
+spec:
+ tls:
+ - hosts:
+ - example.example.com
+ secretName: quickstart-example-tls
+ rules:
+ - host: example.example.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: kuard
+ port:
+ number: 80
diff --git a/content/v1.12-docs/tutorials/acme/example/ingress.yaml b/content/v1.12-docs/tutorials/acme/example/ingress.yaml
new file mode 100644
index 00000000000..a2b8f8c4bd5
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/ingress.yaml
@@ -0,0 +1,24 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: kuard
+ annotations:
+ kubernetes.io/ingress.class: "nginx"
+ #cert-manager.io/issuer: "letsencrypt-staging"
+
+spec:
+ tls:
+ - hosts:
+ - example.example.com
+ secretName: quickstart-example-tls
+ rules:
+ - host: example.example.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: kuard
+ port:
+ number: 80
diff --git a/content/v1.12-docs/tutorials/acme/example/pomerium-certificates.yaml b/content/v1.12-docs/tutorials/acme/example/pomerium-certificates.yaml
new file mode 100644
index 00000000000..7e07111417d
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/pomerium-certificates.yaml
@@ -0,0 +1,36 @@
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: pomerium-cert
+ namespace: pomerium
+spec:
+ secretName: pomerium-tls
+ issuerRef:
+ name: pomerium-issuer
+ kind: Issuer
+ usages:
+ - server auth
+ - client auth
+ dnsNames:
+ - pomerium-proxy.pomerium.svc.cluster.local
+ - pomerium-authorize.pomerium.svc.cluster.local
+ - pomerium-databroker.pomerium.svc.cluster.local
+ - pomerium-authenticate.pomerium.svc.cluster.local
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: pomerium-redis-cert
+ namespace: pomerium
+spec:
+ secretName: pomerium-redis-tls
+ issuerRef:
+ name: pomerium-issuer
+ kind: Issuer
+ usages:
+ - server auth
+ - client auth
+ dnsNames:
+ - pomerium-redis-master.pomerium.svc.cluster.local
+ - pomerium-redis-headless.pomerium.svc.cluster.local
+ - pomerium-redis-replicas.pomerium.svc.cluster.local
diff --git a/content/v1.12-docs/tutorials/acme/example/pomerium-production-issuer.yaml b/content/v1.12-docs/tutorials/acme/example/pomerium-production-issuer.yaml
new file mode 100644
index 00000000000..d802d4d07f9
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/pomerium-production-issuer.yaml
@@ -0,0 +1,19 @@
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt-prod
+ namespace: pomerium
+spec:
+ acme:
+ # The ACME server URL
+ server: https://acme-v02.api.letsencrypt.org/directory
+ # Email address used for ACME registration
+ email: user@example.com
+ # Name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: letsencrypt-prod
+ # Enable the HTTP-01 challenge provider
+ solvers:
+ - http01:
+ ingress:
+ class: pomerium
\ No newline at end of file
diff --git a/content/v1.12-docs/tutorials/acme/example/pomerium-staging-issuer.yaml b/content/v1.12-docs/tutorials/acme/example/pomerium-staging-issuer.yaml
new file mode 100644
index 00000000000..f7756ed4bbb
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/pomerium-staging-issuer.yaml
@@ -0,0 +1,19 @@
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt-staging
+ namespace: pomerium
+spec:
+ acme:
+ # The ACME server URL
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ # Email address used for ACME registration
+ email: user@example.com
+ # Name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: letsencrypt-staging
+ # Enable the HTTP-01 challenge provider
+ solvers:
+ - http01:
+ ingress:
+ class: pomerium
\ No newline at end of file
diff --git a/content/v1.12-docs/tutorials/acme/example/pomerium-values.yaml b/content/v1.12-docs/tutorials/acme/example/pomerium-values.yaml
new file mode 100644
index 00000000000..2460377547d
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/pomerium-values.yaml
@@ -0,0 +1,39 @@
+authenticate:
+ existingTLSSecret: pomerium-tls
+ idp:
+ provider: "google"
+ clientID: YOUR_CLIENT_ID
+ clientSecret: YOUR_SECRET
+ serviceAccount: YOUR_SERVICE_ACCOUNT
+ ingress:
+ annotations:
+ cert-manager.io/issuer: letsencrypt-staging
+ tls:
+ secretName: authenticate.localhost.pomerium.io-tls
+
+proxy:
+ existingTLSSecret: pomerium-tls
+
+databroker:
+ existingTLSSecret: pomerium-tls
+ storage:
+ clientTLS:
+ existingSecretName: pomerium-redis-tls
+ existingCASecretKey: ca.crt
+
+authorize:
+ existingTLSSecret: pomerium-tls
+
+redis:
+ enabled: true
+ generateTLS: false
+ tls:
+ certificateSecret: pomerium-redis-tls
+
+ingressController:
+ enabled: true
+
+config:
+ rootDomain: localhost.pomerium.io #Change this to your reserved domain space.
+ existingCASecret: pomerium-tls
+ generateTLS: false # On by default, disabled when cert-manager or another solution is in place.
diff --git a/content/v1.12-docs/tutorials/acme/example/production-issuer.yaml b/content/v1.12-docs/tutorials/acme/example/production-issuer.yaml
new file mode 100644
index 00000000000..f7676f2522c
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/production-issuer.yaml
@@ -0,0 +1,18 @@
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt-prod
+spec:
+ acme:
+ # The ACME server URL
+ server: https://acme-v02.api.letsencrypt.org/directory
+ # Email address used for ACME registration
+ email: user@example.com
+ # Name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: letsencrypt-prod
+ # Enable the HTTP-01 challenge provider
+ solvers:
+ - http01:
+ ingress:
+ class: nginx
diff --git a/content/v1.12-docs/tutorials/acme/example/service.yaml b/content/v1.12-docs/tutorials/acme/example/service.yaml
new file mode 100644
index 00000000000..864b481ccb5
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/service.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: kuard
+spec:
+ ports:
+ - port: 80
+ targetPort: 8080
+ protocol: TCP
+ selector:
+ app: kuard
diff --git a/content/v1.12-docs/tutorials/acme/example/staging-issuer.yaml b/content/v1.12-docs/tutorials/acme/example/staging-issuer.yaml
new file mode 100644
index 00000000000..b733952029e
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/example/staging-issuer.yaml
@@ -0,0 +1,18 @@
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt-staging
+spec:
+ acme:
+ # The ACME server URL
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ # Email address used for ACME registration
+ email: user@example.com
+ # Name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: letsencrypt-staging
+ # Enable the HTTP-01 challenge provider
+ solvers:
+ - http01:
+ ingress:
+ class: nginx
diff --git a/content/v1.12-docs/tutorials/acme/http-validation.md b/content/v1.12-docs/tutorials/acme/http-validation.md
new file mode 100644
index 00000000000..d5cda8e658a
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/http-validation.md
@@ -0,0 +1,159 @@
+---
+title: HTTP Validation
+description: 'cert-manager tutorials: Issuing an ACME certificate using HTTP validation'
+---
+
+## Issuing an ACME certificate using HTTP validation
+
+cert-manager can be used to obtain certificates from a CA using the
+[ACME](https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment)
+protocol. The ACME protocol supports various challenge mechanisms which are
+used to prove ownership of a domain so that a valid certificate can be issued
+for that domain.
+
+One such challenge mechanism is the HTTP01 challenge. With a HTTP01 challenge,
+you prove ownership of a domain by ensuring that a particular file is present at
+the domain. It is assumed that you control the domain if you are able to
+publish the given file under a given path.
+
+The following Issuer defines the necessary information to enable HTTP
+validation. You can read more about the Issuer resource in the [Issuer
+docs](../../concepts/issuer.md).
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt-staging
+ namespace: default
+spec:
+ acme:
+ # The ACME server URL
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ # Email address used for ACME registration
+ email: user@example.com
+ # Name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: letsencrypt-staging
+ # Enable the HTTP-01 challenge provider
+ solvers:
+ # An empty 'selector' means that this solver matches all domains
+ - selector: {}
+ http01:
+ ingress:
+ class: nginx
+```
+
+We have specified the ACME server URL for Let's Encrypt's [staging
+environment](https://letsencrypt.org/docs/staging-environment/). The staging
+environment will not issue trusted certificates but is used to ensure that the
+verification process is working properly before moving to production. Let's
+Encrypt's production environment imposes much stricter [rate
+limits](https://letsencrypt.org/docs/rate-limits/), so to reduce the chance of
+you hitting those limits it is highly recommended to start by using the staging
+environment. To move to production, simply create a new Issuer with the URL set
+to `https://acme-v02.api.letsencrypt.org/directory`.
+
+The first stage of the ACME protocol is for the client to register with the
+ACME server. This phase includes generating an asymmetric key pair which is
+then associated with the email address specified in the Issuer. Make sure to
+change this email address to a valid one that you own. It is commonly used to
+send expiry notices when your certificates are coming up for renewal. The
+generated private key is stored in a Secret named `letsencrypt-staging`.
+
+We must provide one or more Solvers for handling the ACME challenge. In this
+case we want to use HTTP validation so we specify an `http01` Solver. We could
+optionally map different domains to use different Solver configurations.
+
+Once we have created the above Issuer we can use it to obtain a certificate.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com
+ namespace: default
+spec:
+ secretName: example-com-tls
+ issuerRef:
+ name: letsencrypt-staging
+ commonName: example.com
+ dnsNames:
+ - www.example.com
+```
+
+The Certificate resource describes our desired certificate and the possible
+methods that can be used to obtain it. You can learn more about the Certificate
+resource in the [docs](../../concepts/certificate.md). If the certificate is
+obtained successfully, the resulting key pair will be stored in a secret called
+`example-com-tls` in the same namespace as the Certificate.
+
+The certificate will have a common name of `example.com` and the [Subject
+Alternative Names
+(SANs)](https://en.wikipedia.org/wiki/Subject_Alternative_Name) will be
+`example.com` and `www.example.com`. Note that only these SANs will be respected
+by TLS clients.
+
+In our Certificate we have referenced the `letsencrypt-staging` Issuer above.
+The Issuer must be in the same namespace as the Certificate. If you want to
+reference a `ClusterIssuer`, which is a cluster-scoped version of an Issuer, you
+must add `kind: ClusterIssuer` to the `issuerRef` stanza.
+
+For more information on `ClusterIssuers`, read the [`ClusterIssuer`
+docs](../../concepts/issuer.md).
+
+The `acme` stanza defines the configuration for our ACME challenges. Here we
+have defined the configuration for our HTTP01 challenges which will be used to
+verify domain ownership. To verify ownership of each domain mentioned in an
+`http01` stanza, cert-manager will create a Pod, Service and Ingress that
+exposes an HTTP endpoint that satisfies the HTTP01 challenge.
+
+The fields `ingress` and `ingressClass` in the `http01` stanza can be used to
+control how cert-manager interacts with Ingress resources:
+
+- If the `ingress` field is specified, then an Ingress resource with the same
+ name in the same namespace as the Certificate must already exist and it will
+ be modified only to add the appropriate rules to solve the challenge.
+ This field is useful for the Google Cloud Loadbalancer ingress controller,
+ as well as a number of others, that assign a single public IP address for
+ each ingress resource.
+ Without manual intervention, creating a new ingress resource would cause any
+ challenges to fail.
+- If the `ingressClass` field is specified, a new ingress resource with a
+ randomly generated name will be created in order to solve the challenge.
+ This new resource will have an annotation with key `kubernetes.io/ingress.class`
+ and value set to the value of the `ingressClass` field.
+ This works for the likes of the NGINX ingress controller.
+- If neither are specified, new ingress resources will be created with a randomly
+ generated name, but they will not have the ingress class annotation set.
+- If both are specified, then the `ingress` field will take precedence.
+
+Once domain ownership has been verified, any cert-manager affected resources will
+be cleaned up or deleted.
+
+> Note: It is your responsibility to point each domain name at the correct IP
+> address for your ingress controller.
+
+After creating the above Certificate, we can check whether it has been obtained
+successfully using `kubectl describe`:
+
+```bash
+$ kubectl describe certificate example-com
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal CreateOrder 57m cert-manager Created new ACME order, attempting validation...
+ Normal DomainVerified 55m cert-manager Domain "example.com" verified with "http-01" validation
+ Normal DomainVerified 55m cert-manager Domain "www.example.com" verified with "http-01" validation
+ Normal IssueCert 55m cert-manager Issuing certificate...
+ Normal CertObtained 55m cert-manager Obtained certificate from ACME server
+ Normal CertIssued 55m cert-manager Certificate issued successfully
+```
+
+You can also check whether issuance was successful with `kubectl get secret
+example-com-tls -o yaml`. You should see a base64 encoded signed TLS key pair.
+
+Once our certificate has been obtained, cert-manager will periodically check its
+validity and attempt to renew it if it gets close to expiry. cert-manager
+considers certificates to be close to expiry when the 'Not After' field on the
+certificate is less than the current time plus 30 days.
\ No newline at end of file
diff --git a/content/v1.12-docs/tutorials/acme/migrating-from-kube-lego.md b/content/v1.12-docs/tutorials/acme/migrating-from-kube-lego.md
new file mode 100644
index 00000000000..89b3ffebc97
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/migrating-from-kube-lego.md
@@ -0,0 +1,232 @@
+---
+title: Migrating from Kube-LEGO
+description: 'cert-manager tutorials: Migrating from kube-lego'
+---
+
+[kube-lego](https://github.com/jetstack/kube-lego) is an older Jetstack project
+for obtaining TLS certificates from Let's Encrypt (or another ACME server).
+
+Since cert-managers release, kube-lego has been gradually deprecated in favor
+of this project. There are a number of key differences between the two:
+
+| Feature | kube-lego | cert-manager |
+|-------------------------------------------|----------------------------------|------------------------|
+| Configuration | Annotations on Ingress resources | CRDs |
+| CAs | ACME | ACME, signing key pair |
+| Kubernetes | `v1.2` - `v1.8` | `v1.7+` |
+| Debugging | Look at logs | Kubernetes Events API |
+| Multi-tenancy | Not supported | Supported |
+| Distinct issuance sources per Certificate | Not supported | Supported |
+| Ingress controller support (ACME) | GCE, NGINX | All |
+
+This guide will walk through how you can safely migrate your kube-lego
+installation to cert-manager, without service interruption.
+
+By the end of the guide, we should have:
+
+1. Scaled down and removed kube-lego
+
+2. Installed cert-manager
+
+3. Migrated ACME private key to cert-manager
+
+4. Created an ACME `ClusterIssuer` using this private key, to issue certificates
+ throughout your cluster
+
+5. Configured cert-manager's [`ingress-shim`](../../usage/ingress.md) to
+ automatically provision Certificate resources for all Ingress resources with
+ the `kubernetes.io/tls-acme: "true"` annotation, using the `ClusterIssuer` we
+ have created
+
+6. Verified that the cert-manager installation is working
+
+
+## 1. Scale down kube-lego
+
+Before we begin deploying cert-manager, it is best we scale our kube-lego
+deployment down to 0 replicas. This will prevent the two controllers
+potentially 'fighting' each other. If you deployed kube-lego using the official
+deployment YAMLs, a command like so should do:
+
+```bash
+$ kubectl scale deployment kube-lego \
+ --namespace kube-lego \
+ --replicas=0
+```
+
+You can then verify your kube-lego pod is no longer running with:
+
+```bash
+$ kubectl get pods --namespace kube-lego
+```
+
+## 2. Deploy cert-manager
+
+cert-manager should be deployed using Helm, according to our official
+[installation guide](../../installation/README.md). No special steps are
+required here. We will return to this deployment at the end of this guide and
+perform an upgrade of some of the CLI flags we deploy cert-manager with however.
+
+Please take extra care to ensure you have configured RBAC correctly when
+deploying Helm and cert-manager - there are some nuances described in our
+deploying document!
+
+## 3. Obtaining your ACME account private key
+
+In order to continue issuing and renewing certificates on your behalf, we need
+to migrate the user account private key that kube-lego has created for you over
+to cert-manager.
+
+Your ACME user account identity is a private key, stored in a secret resource.
+By default, kube-lego will store this key in a secret named `kube-lego-account`
+in the same namespace as your kube-lego Deployment. You may have overridden this
+value when you deploy kube-lego, in which case the secret name to use will be
+the value of the `LEGO_SECRET_NAME` environment variable.
+
+You should download a copy of this secret resource and save it in your local
+directory:
+
+```bash
+$ kubectl get secret kube-lego-account -o yaml \
+ --namespace kube-lego \
+ --export > kube-lego-account.yaml
+```
+
+Once saved, open up this file and change the `metadata.name` field to something
+more relevant to cert-manager. For the rest of this guide, we'll assume you
+chose `letsencrypt-private-key`.
+
+Once done, we need to create this new resource in the `cert-manager` namespace.
+By default, cert-manager stores supporting resources for `ClusterIssuers` in the
+namespace that it is running in, and we used `cert-manager` when deploying
+cert-manager above. You should change this if you have deployed cert-manager
+into a different namespace.
+
+```bash
+$ kubectl create -f kube-lego-account.yaml \
+ --namespace cert-manager
+```
+
+## 4. Creating an ACME `ClusterIssuer` using your old ACME account
+
+We need to create a `ClusterIssuer` which will hold information about the ACME
+account previously registered via kube-lego. In order to do so, we need two more
+pieces of information from our old kube-lego deployment: the server URL of the
+ACME server, and the email address used to register the account.
+
+Both of these bits of information are stored within the kube-lego `ConfigMap`.
+
+To retrieve them, you should be able to `get` the `ConfigMap` using `kubectl`:
+
+```bash
+$ kubectl get configmap kube-lego -o yaml \
+ --namespace kube-lego \
+ --export
+```
+
+Your email address should be shown under the `.data.lego.email` field, and the
+ACME server URL under `.data.lego.url`.
+
+For the purposes of this guide, we will assume the email is
+`user@example.com` and the URL
+`https://acme-staging-v02.api.letsencrypt.org/directory`.
+
+Now that we have migrated our private key to the new Secret resource, as well as
+obtaining our ACME email address and URL, we can create a `ClusterIssuer`
+resource!
+
+Create a file named `cluster-issuer.yaml`:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ # Adjust the name here accordingly
+ name: letsencrypt-staging
+spec:
+ acme:
+ # The ACME server URL
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ # Email address used for ACME registration
+ email: user@example.com
+ # Name of a secret used to store the ACME account private key from step 3
+ privateKeySecretRef:
+ name: letsencrypt-private-key
+ # Enable the HTTP-01 challenge provider
+ solvers:
+ - http01:
+ ingress:
+ class: nginx
+```
+
+We then submit this file to our Kubernetes cluster:
+
+```bash
+$ kubectl create -f cluster-issuer.yaml
+```
+
+You should be able to verify the ACME account has been verified successfully:
+
+```bash
+$ kubectl describe clusterissuer letsencrypt-staging
+...
+Status:
+ Acme:
+ Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/7571319
+ Conditions:
+ Last Transition Time: 2019-01-30T14:52:03Z
+ Message: The ACME account was registered with the ACME server
+ Reason: ACMEAccountRegistered
+ Status: True
+ Type: Ready
+```
+
+## 5. Configuring ingress-shim to use our new `ClusterIssuer` by default
+
+Now that our `ClusterIssuer` is ready to issue certificates, we have one last
+thing to do: we must reconfigure `ingress-shim` (deployed as part of cert-manager)
+to automatically create Certificate resources for all Ingress resources it finds
+with appropriate annotations.
+
+More information on the role of ingress-shim can be found [in the
+docs](../../usage/ingress.md), but for now we can just run a `helm
+upgrade` in order to add a few additional flags. Assuming you've named your
+`ClusterIssuer` `letsencrypt-staging` (as above), run:
+
+```bash
+$ helm upgrade cert-manager \
+ jetstack/cert-manager \
+ --namespace cert-manager \
+ --set ingressShim.defaultIssuerName=letsencrypt-staging \
+ --set ingressShim.defaultIssuerKind=ClusterIssuer
+```
+
+You should see the cert-manager pod be re-created, and once started it should
+automatically create Certificate resources for all of your ingresses that
+previously had kube-lego enabled.
+
+## 6. Verify each ingress now has a corresponding Certificate
+
+Before we finish, we should make sure there is now a Certificate resource for
+each ingress resource you previously enabled kube-lego on.
+
+You should be able to check this by running:
+
+```bash
+$ kubectl get certificates --all-namespaces
+```
+
+There should be an entry for each ingress in your cluster with the kube-lego
+annotation.
+
+We can also verify that cert-manager has 'adopted' the old TLS certificates by
+viewing the logs for cert-manager:
+
+```bash
+$ kubectl logs -n cert-manager -l app=cert-manager -c cert-manager
+...
+I1025 21:54:02.869269 1 sync.go:206] Certificate my-example-certificate scheduled for renewal in 292 hours
+```
+
+Here we can see cert-manager has verified the existing TLS certificate and
+scheduled it to be renewed in 292 hours time.
\ No newline at end of file
diff --git a/content/v1.12-docs/tutorials/acme/nginx-ingress.md b/content/v1.12-docs/tutorials/acme/nginx-ingress.md
new file mode 100644
index 00000000000..9a334f4810a
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/nginx-ingress.md
@@ -0,0 +1,602 @@
+---
+title: Securing NGINX-ingress
+description: 'cert-manager tutorials: Using ingress-nginx to solve an ACME HTTP-01 challenge'
+---
+
+This tutorial will detail how to install and secure ingress to your cluster
+using NGINX.
+
+## Step 1 - Install Helm
+
+> *Skip this section if you have helm installed.*
+
+The easiest way to install `cert-manager` is to use [`Helm`](https://helm.sh), a
+templating and deployment tool for Kubernetes resources.
+
+First, ensure the Helm client is installed following the [Helm installation
+instructions](https://helm.sh/docs/intro/install/).
+
+For example, on MacOS:
+
+```bash
+brew install kubernetes-helm
+```
+
+## Step 2 - Deploy the NGINX Ingress Controller
+
+A [`kubernetes ingress controller`](https://kubernetes.io/docs/concepts/services-networking/ingress) is
+designed to be the access point for HTTP and HTTPS traffic to the software
+running within your cluster. The `ingress-nginx-controller` does this by providing
+an HTTP proxy service supported by your cloud provider's load balancer.
+
+You can get more details about `ingress-nginx` and how it works from the
+[documentation for `ingress-nginx`](https://kubernetes.github.io/ingress-nginx/).
+
+Add the latest helm repository for the ingress-nginx
+
+```bash
+helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
+```
+
+Update the helm repository with the latest charts:
+
+```bash
+$ helm repo update
+Hang tight while we grab the latest from your chart repositories...
+...Skip local chart repository
+...Successfully got an update from the "stable" chart repository
+...Successfully got an update from the "ingress-nginx" chart repository
+...Successfully got an update from the "coreos" chart repository
+Update Complete. ⎈ Happy Helming!⎈
+```
+
+Use `helm` to install an NGINX Ingress controller:
+
+```bash
+$ helm install quickstart ingress-nginx/ingress-nginx
+
+NAME: quickstart
+... lots of output ...
+```
+
+It can take a minute or two for the cloud provider to provide and link a public
+IP address. When it is complete, you can see the external IP address using the
+`kubectl` command:
+
+```bash
+$ kubectl get svc
+NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
+kubernetes ClusterIP 10.0.0.1 443/TCP 13m
+quickstart-ingress-nginx-controller LoadBalancer 10.0.114.241 80:31635/TCP,443:30062/TCP 8m16s
+quickstart-ingress-nginx-controller-admission ClusterIP 10.0.188.24 443/TCP 8m16s
+```
+
+This command shows you all the services in your cluster (in the `default`
+namespace), and any external IP addresses they have. When you first create the
+controller, your cloud provider won't have assigned and allocated an IP address
+through the `LoadBalancer` yet. Until it does, the external IP address for the
+service will be listed as ``.
+
+Your cloud provider may have options for reserving an IP address prior to
+creating the ingress controller and using that IP address rather than assigning
+an IP address from a pool. Read through the documentation from your cloud
+provider on how to arrange that.
+
+## Step 3 - Assign a DNS name
+
+The external IP that is allocated to the ingress-controller is the IP to which
+all incoming traffic should be routed. To enable this, add it to a DNS zone you
+control, for example as `www.example.com`.
+
+This quick-start assumes you know how to assign a DNS entry to an IP address and
+will do so.
+
+## Step 4 - Deploy an Example Service
+
+Your service may have its own chart, or you may be deploying it directly with
+manifests. This quick-start uses manifests to create and expose a sample service.
+The example service uses [`kuard`](https://github.com/kubernetes-up-and-running/kuard),
+a demo application.
+
+The quick-start example uses three manifests for the sample. The first two are a
+sample deployment and an associated service:
+
+```yaml file=./example/deployment.yaml
+```
+
+```yaml file=./example/service.yaml
+```
+
+You can create download and reference these files locally, or you can
+reference them from the GitHub source repository for this documentation.
+To install the example service from the tutorial files straight from GitHub, do
+the following:
+
+```bash
+kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/deployment.yaml
+# expected output: deployment.extensions "kuard" created
+
+kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/service.yaml
+# expected output: service "kuard" created
+```
+
+An [Ingress resource](https://kubernetes.io/docs/concepts/services-networking/ingress/) is
+what Kubernetes uses to expose this example service outside the cluster. You
+will need to download and modify the example manifest to reflect the domain that
+you own or control to complete this example.
+
+A sample ingress you can start with is:
+
+```yaml file=./example/ingress.yaml
+```
+
+You can download the sample manifest from GitHub , edit it, and submit the
+manifest to Kubernetes with the command below. Edit the file in your editor, and once
+it is saved:
+
+```bash
+kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress.yaml
+# expected output: ingress.networking.k8s.io/kuard created
+```
+
+> Note: The ingress example we show above has a `host` definition within it. The
+> `ingress-nginx-controller` will route traffic when the hostname requested
+> matches the definition in the ingress. You *can* deploy an ingress without a
+> `host` definition in the rule, but that pattern isn't usable with a TLS
+> certificate, which expects a fully qualified domain name.
+
+Once it is deployed, you can use the command `kubectl get ingress` to see the status
+ of the ingress:
+
+```text
+NAME HOSTS ADDRESS PORTS AGE
+kuard * 80, 443 17s
+```
+
+It may take a few minutes, depending on your service provider, for the ingress
+to be fully created. When it has been created and linked into place, the
+ingress will show an address as well:
+
+```text
+NAME HOSTS ADDRESS PORTS AGE
+kuard * 203.0.113.2 80 9m
+```
+
+> Note: The IP address on the ingress *may not* match the IP address that the
+> `ingress-nginx-controller` has. This is fine, and is a quirk/implementation detail
+> of the service provider hosting your Kubernetes cluster. Since we are using
+> the `ingress-nginx-controller` instead of any cloud-provider specific ingress
+> backend, use the IP address that was defined and allocated for the
+> `quickstart-ingress-nginx-controller ` `LoadBalancer` resource as the primary access point for
+> your service.
+
+Make sure the service is reachable at the domain name you added above, for
+example `http://www.example.com`. The simplest way is to open a browser
+and enter the name that you set up in DNS, and for which we just added the
+ingress.
+
+You may also use a command line tool like `curl` to check the ingress.
+
+```bash
+$ curl -kivL -H 'Host: www.example.com' 'http://203.0.113.2'
+```
+
+The options on this curl command will provide verbose output, following any
+redirects, show the TLS headers in the output, and not error on insecure
+certificates. With `ingress-nginx-controller`, the service will be available
+with a TLS certificate, but it will be using a self-signed certificate
+provided as a default from the `ingress-nginx-controller`. Browsers will show
+a warning that this is an invalid certificate. This is expected and normal,
+as we have not yet used cert-manager to get a fully trusted certificate
+for our site.
+
+> *Warning*: It is critical to make sure that your ingress is available and
+> responding correctly on the internet. This quick-start example uses Let's
+> Encrypt to provide the certificates, which expects and validates both that the
+> service is available and that during the process of issuing a certificate uses
+> that validation as proof that the request for the domain belongs to someone
+> with sufficient control over the domain.
+
+## Step 5 - Deploy cert-manager
+
+We need to install cert-manager to do the work with Kubernetes to request a
+certificate and respond to the challenge to validate it. We can use Helm or
+plain Kubernetes manifests to install cert-manager.
+
+Since we installed Helm earlier, we'll assume you want to use Helm; follow the
+[Helm guide](../../installation/helm.md). For other methods, read the
+[installation documentation](../../installation/README.md) for cert-manager.
+
+cert-manager mainly uses two different custom Kubernetes resources - known as
+[`CRDs`](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) -
+to configure and control how it operates, as well as to store state. These
+resources are Issuers and Certificates.
+
+### Issuers
+
+An Issuer defines _how_ cert-manager will request TLS certificates. Issuers are
+specific to a single namespace in Kubernetes, but there's also a `ClusterIssuer`
+which is meant to be a cluster-wide version.
+
+Take care to ensure that your Issuers are created in the same namespace as the
+certificates you want to create. You might need to add `-n my-namespace` to your
+`kubectl create` commands.
+
+Your other option is to replace your `Issuers` with `ClusterIssuers`;
+`ClusterIssuer` resources apply across all Ingress resources in your cluster.
+If using a `ClusterIssuer`, remember to update the Ingress annotation `cert-manager.io/issuer` to
+`cert-manager.io/cluster-issuer`.
+
+If you see issues with issuers, follow the [Troubleshooting Issuing ACME Certificates](../../troubleshooting/acme.md) guide.
+
+More information on the differences between `Issuers` and `ClusterIssuers` - including
+when you might choose to use each can be found on [Issuer concepts](../../concepts/issuer.md#namespaces).
+
+### Certificates
+
+Certificates resources allow you to specify the details of the certificate you
+want to request. They reference an issuer to define _how_ they'll be issued.
+
+For more information, see [Certificate concepts](../../concepts/certificate.md).
+
+## Step 6 - Configure a Let's Encrypt Issuer
+
+We'll set up two issuers for Let's Encrypt in this example: staging and production.
+
+The Let's Encrypt production issuer has [very strict rate limits](https://letsencrypt.org/docs/rate-limits/).
+When you're experimenting and learning, it can be very easy to hit those limits. Because of that risk,
+we'll start with the Let's Encrypt staging issuer, and once we're happy that it's working
+we'll switch to the production issuer.
+
+Note that you'll see a warning about untrusted certificates from the staging issuer, but that's totally expected.
+
+Create this definition locally and update the email address to your own. This
+email is required by Let's Encrypt and used to notify you of certificate
+expiration and updates.
+
+```yaml file=./example/staging-issuer.yaml
+```
+
+Once edited, apply the custom resource:
+
+```bash
+kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/staging-issuer.yaml
+# expected output: issuer.cert-manager.io "letsencrypt-staging" created
+```
+
+Also create a production issuer and deploy it. As with the staging issuer, you
+will need to update this example and add in your own email address.
+
+```yaml file=./example/production-issuer.yaml
+```
+
+```bash
+kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/production-issuer.yaml
+# expected output: issuer.cert-manager.io "letsencrypt-prod" created
+```
+
+Both of these issuers are configured to use the [`HTTP01`](../../configuration/acme/http01/README.md) challenge provider.
+
+Check on the status of the issuer after you create it:
+
+```bash
+$ kubectl describe issuer letsencrypt-staging
+Name: letsencrypt-staging
+Namespace: default
+Labels:
+Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"cert-manager.io/v1","kind":"Issuer","metadata":{"annotations":{},"name":"letsencrypt-staging","namespace":"default"},(...)}
+API Version: cert-manager.io/v1
+Kind: Issuer
+Metadata:
+ Cluster Name:
+ Creation Timestamp: 2018-11-17T18:03:54Z
+ Generation: 0
+ Resource Version: 9092
+ Self Link: /apis/cert-manager.io/v1/namespaces/default/issuers/letsencrypt-staging
+ UID: 25b7ae77-ea93-11e8-82f8-42010a8a00b5
+Spec:
+ Acme:
+ Email: email@example.com
+ Private Key Secret Ref:
+ Key:
+ Name: letsencrypt-staging
+ Server: https://acme-staging-v02.api.letsencrypt.org/directory
+ Solvers:
+ Http 01:
+ Ingress:
+ Class: nginx
+Status:
+ Acme:
+ Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/7374163
+ Conditions:
+ Last Transition Time: 2018-11-17T18:04:00Z
+ Message: The ACME account was registered with the ACME server
+ Reason: ACMEAccountRegistered
+ Status: True
+ Type: Ready
+Events:
+```
+
+You should see the issuer listed with a registered account.
+
+## Step 7 - Deploy a TLS Ingress Resource
+
+With all the prerequisite configuration in place, we can now do the pieces to
+request the TLS certificate. There are two primary ways to do this: using
+annotations on the ingress with [`ingress-shim`](../../usage/ingress.md) or
+directly creating a certificate resource.
+
+In this example, we will add annotations to the ingress, and take advantage
+of ingress-shim to have it create the certificate resource on our behalf.
+After creating a certificate, the cert-manager will update or create a ingress
+resource and use that to validate the domain. Once verified and issued,
+cert-manager will create or update the secret defined in the certificate.
+
+> Note: The secret that is used in the ingress should match the secret defined
+> in the certificate. There isn't any explicit checking, so a typo will result
+> in the `ingress-nginx-controller` falling back to its self-signed certificate.
+> In our example, we are using annotations on the ingress (and ingress-shim)
+> which will create the correct secrets on your behalf.
+
+Edit the ingress add the annotations that were commented out in our earlier
+example:
+
+```yaml file=./example/ingress-tls.yaml
+```
+
+and apply it:
+
+```bash
+kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress-tls.yaml
+# expected output: ingress.networking.k8s.io/kuard configured
+```
+
+Cert-manager will read these annotations and use them to create a certificate,
+which you can request and see:
+
+```bash
+$ kubectl get certificate
+NAME READY SECRET AGE
+quickstart-example-tls True quickstart-example-tls 16m
+```
+
+cert-manager reflects the state of the process for every request in the
+certificate object. You can view this information using the
+`kubectl describe` command:
+
+```bash
+$ kubectl describe certificate quickstart-example-tls
+Name: quickstart-example-tls
+Namespace: default
+Labels:
+Annotations:
+API Version: cert-manager.io/v1
+Kind: Certificate
+Metadata:
+ Cluster Name:
+ Creation Timestamp: 2018-11-17T17:58:37Z
+ Generation: 0
+ Owner References:
+ API Version: networking.k8s.io/v1
+ Block Owner Deletion: true
+ Controller: true
+ Kind: Ingress
+ Name: kuard
+ UID: a3e9f935-ea87-11e8-82f8-42010a8a00b5
+ Resource Version: 9295
+ Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tls
+ UID: 68d43400-ea92-11e8-82f8-42010a8a00b5
+Spec:
+ Dns Names:
+ www.example.com
+ Issuer Ref:
+ Kind: Issuer
+ Name: letsencrypt-staging
+ Secret Name: quickstart-example-tls
+Status:
+ Acme:
+ Order:
+ URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/7374163/13665676
+ Conditions:
+ Last Transition Time: 2018-11-17T18:05:57Z
+ Message: Certificate issued successfully
+ Reason: CertIssued
+ Status: True
+ Type: Ready
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal CreateOrder 9m cert-manager Created new ACME order, attempting validation...
+ Normal DomainVerified 8m cert-manager Domain "www.example.com" verified with "http-01" validation
+ Normal IssueCert 8m cert-manager Issuing certificate...
+ Normal CertObtained 7m cert-manager Obtained certificate from ACME server
+ Normal CertIssued 7m cert-manager Certificate issued Successfully
+```
+
+The events associated with this resource and listed at the bottom
+of the `describe` results show the state of the request. In the above
+example the certificate was validated and issued within a couple of minutes.
+
+Once complete, cert-manager will have created a secret with the details of
+the certificate based on the secret used in the ingress resource. You can
+use the describe command as well to see some details:
+
+```bash
+$ kubectl describe secret quickstart-example-tls
+Name: quickstart-example-tls
+Namespace: default
+Labels: cert-manager.io/certificate-name=quickstart-example-tls
+Annotations: cert-manager.io/alt-names=www.example.com
+ cert-manager.io/common-name=www.example.com
+ cert-manager.io/issuer-kind=Issuer
+ cert-manager.io/issuer-name=letsencrypt-staging
+
+Type: kubernetes.io/tls
+
+Data
+====
+tls.crt: 3566 bytes
+tls.key: 1675 bytes
+```
+
+Now that we have confidence that everything is configured correctly, you
+can update the annotations in the ingress to specify the production issuer:
+
+```yaml file=./example/ingress-tls-final.yaml
+```
+
+```bash
+$ kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress-tls-final.yaml
+ingress.networking.k8s.io/kuard configured
+```
+
+You will also need to delete the existing secret, which cert-manager is watching
+and will cause it to reprocess the request with the updated issuer.
+
+```bash
+$ kubectl delete secret quickstart-example-tls
+secret "quickstart-example-tls" deleted
+```
+
+This will start the process to get a new certificate, and using describe
+you can see the status. Once the production certificate has been updated,
+you should see the example KUARD running at your domain with a signed TLS
+certificate.
+
+```bash
+$ kubectl describe certificate quickstart-example-tls
+Name: quickstart-example-tls
+Namespace: default
+Labels:
+Annotations:
+API Version: cert-manager.io/v1
+Kind: Certificate
+Metadata:
+ Cluster Name:
+ Creation Timestamp: 2018-11-17T18:36:48Z
+ Generation: 0
+ Owner References:
+ API Version: networking.k8s.io/v1
+ Block Owner Deletion: true
+ Controller: true
+ Kind: Ingress
+ Name: kuard
+ UID: a3e9f935-ea87-11e8-82f8-42010a8a00b5
+ Resource Version: 283686
+ Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tls
+ UID: bdd93b32-ea97-11e8-82f8-42010a8a00b5
+Spec:
+ Dns Names:
+ www.example.com
+ Issuer Ref:
+ Kind: Issuer
+ Name: letsencrypt-prod
+ Secret Name: quickstart-example-tls
+Status:
+ Conditions:
+ Last Transition Time: 2019-01-09T13:52:05Z
+ Message: Certificate does not exist
+ Reason: NotFound
+ Status: False
+ Type: Ready
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Generated 18s cert-manager Generated new private key
+ Normal OrderCreated 18s cert-manager Created Order resource "quickstart-example-tls-889745041"
+```
+
+You can see the current state of the ACME Order by running `kubectl describe`
+on the Order resource that cert-manager has created for your Certificate:
+
+```bash
+$ kubectl describe order quickstart-example-tls-889745041
+...
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Created 90s cert-manager Created Challenge resource "quickstart-example-tls-889745041-0" for domain "www.example.com"
+```
+
+Here, we can see that cert-manager has created 1 'Challenge' resource to fulfill
+the Order. You can dig into the state of the current ACME challenge by running
+`kubectl describe` on the automatically created Challenge resource:
+
+```bash
+$ kubectl describe challenge quickstart-example-tls-889745041-0
+...
+Status:
+ Presented: true
+ Processing: true
+ Reason: Waiting for http-01 challenge propagation
+ State: pending
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Started 15s cert-manager Challenge scheduled for processing
+ Normal Presented 14s cert-manager Presented challenge using http-01 challenge mechanism
+```
+
+From above, we can see that the challenge has been 'presented' and cert-manager
+is waiting for the challenge record to propagate to the ingress controller.
+You should keep an eye out for new events on the challenge resource, as a
+'success' event should be printed after a minute or so (depending on how fast
+your ingress controller is at updating rules):
+
+```bash
+$ kubectl describe challenge quickstart-example-tls-889745041-0
+...
+Status:
+ Presented: false
+ Processing: false
+ Reason: Successfully authorized domain
+ State: valid
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Started 71s cert-manager Challenge scheduled for processing
+ Normal Presented 70s cert-manager Presented challenge using http-01 challenge mechanism
+ Normal DomainVerified 2s cert-manager Domain "www.example.com" verified with "http-01" validation
+```
+
+> Note: If your challenges are not becoming 'valid' and remain in the 'pending'
+> state (or enter into a 'failed' state), it is likely there is some kind of
+> configuration error. Read the [Challenge resource reference
+> docs](../../reference/api-docs.md#acme.cert-manager.io/v1.Challenge) for more
+> information on debugging failing challenges.
+
+Once the challenge(s) have been completed, their corresponding challenge
+resources will be *deleted*, and the 'Order' will be updated to reflect the
+new state of the Order:
+
+```bash
+$ kubectl describe order quickstart-example-tls-889745041
+...
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Created 90s cert-manager Created Challenge resource "quickstart-example-tls-889745041-0" for domain "www.example.com"
+ Normal OrderValid 16s cert-manager Order completed successfully
+```
+
+Finally, the 'Certificate' resource will be updated to reflect the state of the
+issuance process. If all is well, you should be able to 'describe' the Certificate
+and see something like the below:
+
+```bash
+$ kubectl describe certificate quickstart-example-tls
+Status:
+ Conditions:
+ Last Transition Time: 2019-01-09T13:57:52Z
+ Message: Certificate is up to date and has not expired
+ Reason: Ready
+ Status: True
+ Type: Ready
+ Not After: 2019-04-09T12:57:50Z
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Generated 11m cert-manager Generated new private key
+ Normal OrderCreated 11m cert-manager Created Order resource "quickstart-example-tls-889745041"
+ Normal OrderComplete 10m cert-manager Order "quickstart-example-tls-889745041" completed successfully
+```
diff --git a/content/v1.12-docs/tutorials/acme/pomerium-ingress.md b/content/v1.12-docs/tutorials/acme/pomerium-ingress.md
new file mode 100644
index 00000000000..90447f66af8
--- /dev/null
+++ b/content/v1.12-docs/tutorials/acme/pomerium-ingress.md
@@ -0,0 +1,191 @@
+---
+title: Pomerium Ingress
+description: 'cert-manager tutorials: Solving ACME HTTP-01 challenges using Pomerium ingress'
+---
+
+This tutorial covers installing the [Pomerium Ingress Controller](https://pomerium.com/docs/k8s/ingress.html) and securing it with cert-manager. [Pomerium](https://pomerium.com) is an identity-aware proxy that can also provide a custom ingress controller for your Kubernetes services.
+
+## Prerequisites
+
+1. Install [Kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) and set the context to the cluster you'll be working with.
+
+1. Pomerium connects to an identity provider (**IdP**) to authenticate users. See one of their [guides](https://www.pomerium.com/docs/identity-providers/) to learn how to set up your IdP of choice to provide oauth2 validation.
+
+1. This tutorial assumes you have a domain space reserved for this cluster (such as `*.example.com`). You will need access to DNS for this domain to assign A and CNAME records as needed.
+
+## Install The Pomerium Ingress Controller
+
+1. Install Pomerium to your cluster:
+
+ ```sh
+ kubectl apply -f https://raw.githubusercontent.com/pomerium/ingress-controller/main/deployment.yaml
+ ```
+
+ Define a Secret with your IdP configuration. See Pomerium's [Identity Providers](https://www.pomerium.com/docs/identity-providers) pages for more information specific to your IdP:
+
+ ```yaml
+ apiVersion: v1
+ kind: Secret
+ metadata:
+ name: idp
+ namespace: pomerium
+ type: Opaque
+ stringData:
+ client_id: ${IDP_PROVIDED_CLIENT_ID}
+ client_secret: ${IDP_PROVIDED_CLIENT_SECRET}
+ ```
+
+ Add the secret to the cluster with `kubectl apply -f`.
+
+1. Define the global settings for Pomerium:
+
+ ```yaml
+ apiVersion: ingress.pomerium.io/v1
+ kind: Pomerium
+ metadata:
+ name: global
+ namespace: pomerium
+ spec:
+ secrets: pomerium/bootstrap
+ authenticate:
+ url: https://authenticate.example.com
+ identityProvider:
+ provider: ${YOUR_IdP}
+ secret: pomerium/idp
+ # certificates:
+ # - pomerium/pomerium-proxy-tls
+ ```
+
+ Replace `${YOUR_IdP}` with your identity provider. Apply with `kubectl -f`.
+
+ Note that the last two lines are commented out. They reference a TLS certificate we will create further in the process.
+
+## Install cert-manager
+
+Install cert-manager using any of the methods documented in the [Installation](https://cert-manager.io/docs/installation/) section of the cert-manager docs. The simplest method is to download and apply the provided manifest:
+
+```sh
+kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml
+```
+
+## Configure Let's Encrypt Issuer
+
+For communication between the Ingresses and the internet, we'll want to use certificates signed by a trusted certificate authority like Let's Encrypt. This example creates two Let's Encrypt issuers, one for staging and one for production.
+
+The Let's Encrypt production issuer has [strict rate limits](https://letsencrypt.org/docs/rate-limits/). Before your configuration is finalized you may have to recreate services several times, hitting those limits. It's easy to confuse rate limiting with errors in configuration or operation while building your stack.
+
+Because of this, we will start with the Let's Encrypt staging issuer. Once your configuration is all but finalized, we will switch to a production issuer. Both of these issuers are configured to use the [`HTTP01`](../../configuration/acme/http01/README.md) challenge provider.
+
+1. The following YAML defines a staging certificate issuer. You must update the email address to your own. The `email` field is required by Let's Encrypt and used to notify you of certificate expiration and updates.
+
+ ```yaml file=./example/pomerium-staging-issuer.yaml
+ ```
+
+ You can download and edit the example and apply it with `kubectl apply -f`, or edit, and apply the custom resource in one command:
+
+ ```bash
+ kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/pomerium-staging-issuer.yaml
+ ```
+
+1. Create a production issuer and deploy it. As with the staging issuer, update this example with your own email address:
+
+ ```yaml file=./example/pomerium-production-issuer.yaml
+ ```
+
+ ```bash
+ kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/pomerium-production-issuer.yaml
+ ```
+
+1. You can confirm on the status of the issuers after you create them:
+
+ ```bash
+ kubectl describe issuer -n pomerium letsencrypt-staging
+ kubectl describe issuer -n pomerium letsencrypt-prod
+ ```
+
+ You should see the issuer listed with a registered account.
+
+1. Define a certificate for the Pomerium Proxy service. This should be the only certificate you need to manually define:
+
+ ```yaml
+ apiVersion: cert-manager.io/v1
+ kind: Certificate
+ metadata:
+ name: pomerium-proxy-tls
+ namespace: pomerium
+ spec:
+ dnsNames:
+ - 'authenticate.example.com'
+ issuerRef:
+ kind: Issuer
+ name: letsencrypt-staging
+ secretName: pomerium-proxy-tls
+ ```
+
+ Adjust the `dnsNames` value to match your domain space. The subdomain (`authenticate` in our example) must match the domain used for the callback URL in your IdP configuration. Add the certificate with `kubectl -f`.
+
+1. Uncomment the last two lines of the Pomerium global configuration that reference your newly created certificate, and re-apply to the cluster.
+
+Pomerium should now be installed and running in your cluster. You can verify by going to `https://authenticate.example.com` in your browser. Use `kubectl describe pomerium` to review the status of the Pomerium deployment and see recent events.
+
+## Define a Test Service
+
+To test our new Ingress Controller, we will add the [kuard](https://github.com/kubernetes-up-and-running/kuard) app to our cluster and define an Ingress for it.
+
+1. Define the kuard deployment and associated service:
+
+ ```yaml file=./example/deployment.yaml
+ ```
+
+ ```yaml file=./example/service.yaml
+ ```
+
+ You can download and reference these files locally, or you can reference them from the GitHub source repository for this documentation.
+
+ To install the example service from the tutorial files straight from GitHub:
+
+ ```bash
+ kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/deployment.yaml
+ kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/service.yaml
+ ```
+
+1. Create a new Ingress manifest (`example-ingress.yaml`) for our test service:
+
+ ```yaml
+ apiVersion: networking.k8s.io/v1
+ kind: Ingress
+ metadata:
+ name: kuard
+ annotations:
+ cert-manager.io/issuer: letsencrypt-staging
+ ingress.pomerium.io/policy: '[{"allow":{"and":[{"domain":{"is":"example.com"}}]}}]'
+ spec:
+ ingressClassName: pomerium
+ rules:
+ - host: kuard.example.com
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: kuard
+ port:
+ number: 80
+ tls:
+ - hosts:
+ - kuard.example.com
+ secretName: kuard.example.com-tls
+ ```
+
+ Again, change the references to `example.com` to match your domain space.
+
+1. Apply the Ingress manifest to the cluster:
+
+ ```bash
+ kubectl apply -f example-ingress.yaml
+ ```
+
+The Pomerium Ingress Controller will use cert-manager to automatically provision a certificate from the `letsencrypt-staging` issuer for the route to `kuard.example.com`.
+
+Once you've configured all your application services correctly in the cluster, adjust the issuer for your Ingresses (including the Authenticate service) to use `letsencrypt-prod`.
diff --git a/content/v1.12-docs/tutorials/backup.md b/content/v1.12-docs/tutorials/backup.md
new file mode 100644
index 00000000000..8a1f9f69fa5
--- /dev/null
+++ b/content/v1.12-docs/tutorials/backup.md
@@ -0,0 +1,167 @@
+---
+title: Backup and Restore Resources
+description: 'cert-manager tutorials: Backing up your cert-manager installation'
+---
+
+If you need to uninstall cert-manager, or transfer your installation to a new
+cluster, you can backup all of cert-manager's configuration in order to later
+re-install.
+
+## Backing up cert-manager resource configuration
+
+The following commands will back up the configuration of `cert-manager`
+resources. Doing that might be useful before upgrading `cert-manager`. As
+this backup does not include the `Secrets` containing the X.509
+certificates, restoring to a cluster that does not already have those
+`Secret` objects will result in the certificates being reissued.
+
+### Backup
+
+To backup all of your cert-manager configuration resources, run:
+
+```bash
+kubectl get --all-namespaces -oyaml issuer,clusterissuer,cert > backup.yaml
+```
+
+If you are transferring data to a new cluster, you may also need to copy across
+additional `Secret` resources that are referenced by your configured Issuers, such
+as:
+
+#### CA Issuers
+
+- The root CA `Secret` referenced by `issuer.spec.ca.secretName`
+
+#### Vault Issuers
+
+- The token authentication `Secret` referenced by
+ `issuer.spec.vault.auth.tokenSecretRef`
+- The AppRole configuration `Secret` referenced by
+ `issuer.spec.vault.auth.appRole.secretRef`
+
+#### ACME Issuers
+
+- The ACME account private key `Secret` referenced by `issuer.acme.privateKeySecretRef`
+- Any `Secret`s referenced by DNS providers configured under the
+ `issuer.acme.dns01.providers` and `issuer.acme.solvers.dns01` fields.
+
+### Restore
+
+In order to restore your configuration, you can `kubectl apply` the files
+created above after installing cert-manager, with the exception of the
+`uid` and `resourceVersion` fields that do not need to be restored:
+
+```bash
+kubectl apply -f <(awk '!/^ *(resourceVersion|uid): [^ ]+$/' backup.yaml)
+```
+
+## Full cluster backup and restore
+
+This section refers to backing up and restoring 'all' Kubernetes resources in a
+cluster — including some `cert-manager` ones — for scenarios such as disaster
+recovery, cluster migration etc.
+
+*Note*: We have tested this process on simple Kubernetes test clusters with a limited set of Kubernetes releases. To avoid data loss, please test both the backup and the restore strategy on your own cluster before depending upon it in production. If you encounter any errors, please open a GitHub issue or a PR to document variations on this process for different Kubernetes environments.
+
+### Avoiding unnecessary certificate reissuance
+
+#### Order of restore
+
+If `cert-manager` does not find a Kubernetes `Secret` with an X.509 certificate
+for a `Certificate`, reissuance will be triggered. To avoid unnecessary
+reissuance after a restore, ensure that `Secret`s are restored before
+`Certificate`s. Similarly, `Secret`s should be restored before `Ingress`es if you
+are using [`ingress-shim`](../usage/ingress.md).
+
+#### Excluding some cert-manager resources from backup
+
+`cert-manager` has a number of custom resources that are designed to represent a
+point-in-time operation. An example would be a `CertificateRequest` that
+represents a one-time request for an X.509 certificate. The status of these
+resources can depend on other ephemeral resources (such as a temporary `Secret`
+holding a private key) so `cert-manager` might not be able to correctly recreate
+the state of these resources at a later point.
+
+In most cases backup and restore tools will not restore the statuses of custom resources,
+so including such one-time resources in a backup can result in an unnecessary reissuance
+after a restore as without the status fields `cert-manager` will not be able to tell that,
+for example, an `Order` has already been fulfilled.
+To avoid unnecessary reissuance, we recommend that `Order`s and `Challenge`s are excluded
+from the backup. We also don't recommend backing up `CertificateRequest`s, see [Backing up CertificateRequests](#backing-up-certificaterequests)
+
+### Restoring Ingress Certificates
+
+A `Certificate` created for an `Ingress` via [`ingress-shim`](../usage/ingress.md) will have an [owner
+reference](https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/#owners-and-dependents)
+pointing to the `Ingress` resource. `cert-manager` uses the owner reference to
+verify that the `Certificate` 'belongs' to that `Ingress` and will not attempt to
+create/correct it for an existing `Certificate`. After a full
+cluster recreation, a restored owner reference would probably be incorrect
+(`Ingress` UUID will have changed). The incorrect owner reference could lead
+to a situation where updates to the `Ingress` (i.e a new DNS name) are not
+applied to the `Certificate`.
+
+To avoid this issue, in most cases `Certificate`s created via `ingress-shim`
+can be excluded from the backup. Given that the restore happens
+in the correct order (`Secret` with the X.509 certificate restored before
+the `Ingress`) `cert-manager` will be able to create a new `Certificate`
+for the `Ingress` and determine that the existing `Secret` is for that `Certificate`.
+
+### Velero
+
+We have briefly tested backup and restore with `velero` `v1.5.3` and
+`cert-manager` versions `v1.3.1` and `v1.3.0` as well as `velero` `v1.3.1`
+ and `cert-manager` `v1.1.0`.
+
+ A few potential edge cases:
+
+- Ensure that the backups include `cert-manager` CRDs.
+ For example, we have seen that if `--exclude-namespaces` flag is passed to
+ `velero backup create`, CRDs for which there are no actual resources to be
+ included in the backup might also not be included in backup unless
+ `--include-cluster-resources=true` flag is also passed to the backup command.
+
+- Velero does not restore statuses of custom resources, so you should probably
+ exclude `Order`s, `Challenge`s and `CertificateRequest`s from the backup, see
+ [Excluding some cert-manager resources from backup](#excluding-some-cert-manager-resources-from-backup).
+
+- Velero's [default restore order](https://github.com/vmware-tanzu/velero/blob/main/pkg/cmd/server/server.go#L470)(`Secrets` before `Ingress`es, Custom Resources
+ restored last), should ensure that there is no unnecessary certificate reissuance
+ due to the order of restore operation, see [Order of restore](#order-of-restore).
+
+- When restoring the deployment of `cert-manager` itself, it may be necessary to
+ restore `cert-manager`'s RBAC resources before the rest of the deployment.
+ This is because `cert-manager`'s controller needs to be able to create
+ `Certificate`'s for the `cert-manager`'s webhook before the webhook can become
+ ready. In order to do this, the controller needs the right permissions. Since
+ Velero by default restores pods before RBAC resources, the restore might get
+ stuck waiting for the webhook pod to become ready.
+
+- Velero does not restore owner references, so it may be necessary to exclude
+ `Certificate`s created for `Ingress`es from the backup even when not
+ re-creating the `Ingress` itself. See [Restoring Ingress Certificates](#restoring-ingress-certificates).
+
+## Backing up CertificateRequests
+
+ We no longer recommend including `CertificateRequest` resources in a backup
+ for most scenarios.
+ `CertificateRequest`s are designed to represent a one-time
+ request for an X.509 certificate. Once the request has been fulfilled,
+ `CertificateRequest` can usually be safely deleted[^1]. In most cases (such as when
+ a `CertificateRequest` has been created for a `Certificate`) a new
+ `CertificateRequest` will be created when needed (i.e at a time of a renewal
+ of a `Certificate`).
+ In `v1.3.0` , as part of our work towards [policy
+ implementation](https://github.com/cert-manager/cert-manager/pull/3727) we
+ introduced identity fields for `CertificateRequest` resources where, at a time
+ of creation, `cert-mananager`'s webhook updates `CertificateRequest`'s spec
+ with immutable identity fields, representing the identity of the creator of
+ the `CertificateRequest`.
+ This introduces some extra complexity for backing up
+ and restoring `CertificateRequest`s as the identity of the restorer might
+ differ from that of the original creator and in most cases a restored
+ `CertificateRequest` would likely end up with incorrect state.
+
+ [^1]: there is an edge case where certain changes to `Certificate` spec may not
+ trigger re-issuance if there is no `CertificateRequest` for that
+ `Certificate`. See [documentation on when do certificates get
+ re-issued](../faq/README.md#when-do-certs-get-re-issued).
\ No newline at end of file
diff --git a/content/v1.12-docs/tutorials/getting-started-aks-letsencrypt/README.md b/content/v1.12-docs/tutorials/getting-started-aks-letsencrypt/README.md
new file mode 100644
index 00000000000..f712fa6b7ad
--- /dev/null
+++ b/content/v1.12-docs/tutorials/getting-started-aks-letsencrypt/README.md
@@ -0,0 +1,687 @@
+---
+title: Deploy cert-manager on Azure Kubernetes Service (AKS) and use Let's Encrypt to sign a certificate for an HTTPS website
+description: |
+ Learn how to deploy cert-manager on Azure Kubernetes Service (AKS)
+ and configure it to get a signed certificate from Let's Encrypt for an HTTPS web server,
+ using the DNS-01 protocol and Azure DNS with workload identity federation.
+---
+
+*Last Verified: 10 January 2023*
+
+In this tutorial you will learn how to deploy and configure cert-manager on Azure Kubernetes Service (AKS)
+and how to deploy an HTTPS web server and make it available on the Internet.
+You will learn how to configure cert-manager to get a signed certificate from Let's Encrypt,
+which will allow clients to connect to your HTTPS website securely.
+You will configure cert-manager to use the [Let's Encrypt DNS-01 challenge protocol](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) with Azure DNS,
+using workload identity federation to authenticate to Azure.
+
+> **Microsoft Azure**: A suite of cloud computing services by Microsoft.
+> **Kubernetes**: Runs on your servers. Automates the deployment, scaling, and management of containerized applications.
+> **cert-manager**: Runs in Kubernetes. Obtains TLS / SSL certificates and ensures the certificates are valid and up-to-date.
+> **Let’s Encrypt**: An Internet service. Allows you to generate free short-lived SSL certificates.
+
+# Part 1
+
+In the first part of this tutorial you will learn the basics required to deploy an HTTPS website on an Azure Kubernetes cluster using cert-manager to create the SSL certificate for the web server.
+You will create a DNS domain for your website, create an Azure Kubernetes cluster, install cert-manager, create an SSL certificate and then deploy a web server which responds to HTTPS requests from clients on the Internet.
+But the SSL certificate in part 1 is only for testing purposes.
+
+In part 2 you will learn how to configure cert-manager to use Let's Encrypt and Azure DNS to create a trusted SSL certificate which you can use in production.
+
+## Configure the Azure CLI (`az`)
+
+If your have not already done so, [download and install the Azure CLI (`az`)](https://learn.microsoft.com/en-us/cli/azure/).
+
+Set up the `az` command for interactive use:
+
+```bash
+az init
+```
+
+Log in, if you have not already done so:
+
+```bash
+az login
+```
+
+Set the default resource group and location:
+
+```bash
+export AZURE_DEFAULTS_GROUP=your-resource-group # ❗ Your Azure resource group
+export AZURE_DEFAULTS_LOCATION=eastus2 # ❗ Your Azure location.
+```
+
+> ℹ️ You will need an `az` version `>=2.40.0`. Run `az version` to print the current version.
+>
+> ℹ️ When you run `az init`, choose "Optimize for interaction" when prompted.
+>
+> ℹ️ When you run `az login`, a web browser will be opened at https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize.
+> Continue the login in the web browser and then return to your terminal.
+>>
+> 📖 Read the [Azure Command-Line Interface (CLI) documentation](https://learn.microsoft.com/en-us/cli/azure/).
+>
+> 📖 Read [CLI configuration values and environment variables](https://learn.microsoft.com/en-us/cli/azure/azure-cli-configuration?source=recommendations#cli-configuration-values-and-environment-variables) for more ways to configure the `az` defaults.
+
+## Create a public domain name
+
+In this tutorial you will deploy an HTTPS website with a publicly accessible domain name, so you will need to register a domain unless you already have one.
+You could use any [domain name registrar](https://www.cloudflare.com/en-gb/learning/dns/glossary/what-is-a-domain-name-registrar/) to register a domain name for your site.
+Here we will use a registrar called `Gandi` and register a cheap domain name for the purposes of this tutorial.
+We will use the domain name: `cert-manager-tutorial-22.site` but you should choose your own.
+
+Now that you know your domain name, save it in an environment variable:
+
+```bash
+export DOMAIN_NAME=cert-manager-tutorial-22.site # ❗ Replace this with your own DNS domain name
+```
+
+And add it to Azure DNS as a zone:
+
+```bash
+az network dns zone create --name $DOMAIN_NAME
+```
+
+Log in to the control panel for your domain registrar and set the NS records for your domain to match the DNS names of the Azure [authoritative DNS servers](https://www.cloudflare.com/en-gb/learning/dns/dns-server-types/).
+You can find these by looking for the NS records of your Azure hosted DNS zone:
+
+```bash
+az network dns zone show --name $DOMAIN_NAME --output yaml
+```
+
+You can check that the NS records have been updated using `dig` to "trace" the hierarchy of NS records,
+rather than using your local DNS resolver:
+
+```bash
+dig $DOMAIN_NAME ns +trace +nodnssec
+```
+
+> ⏲ It **may** take more than 1 hour for the NS records to be updated in the parent zone,
+> and it may take some time for the old NS records to be replaced in the caches of DNS resolver servers,
+> if you looked up the DNS name before updating the NS records.
+>
+> 📖 Read [How do I Update My DNS Records?](https://docs.gandi.net/en/domain_names/common_operations/dns_records.html) in the `Gandi.net` docs,
+> or seek the equivalent documentation for your own domain name registrar.
+
+## Create a Kubernetes cluster
+
+To get started, let's create a Kubernetes cluster in Microsoft Azure.
+You will need to pick a name for your cluster.
+Here, we will go with "test-cluster-1".
+Save it in an environment variable:
+
+```bash
+export CLUSTER=test-cluster-1
+```
+
+Now, create the cluster using the following command:
+
+```bash
+az aks create \
+ --name ${CLUSTER} \
+ --node-count 1 \
+ --node-vm-size "Standard_B2s" \
+ --load-balancer-sku basic
+```
+
+Update your `kubectl` config file with the credentials for your new cluster:
+
+```bash
+az aks get-credentials --admin --name "$CLUSTER"
+```
+
+Now check that you can connect to the cluster:
+
+```bash
+kubectl get nodes -o wide
+```
+
+> ⏲ It will take 4-5 minutes to create the cluster.
+>
+> 💵 To minimize your cloud bill, this command creates a 1-node cluster using a
+> low cost virtual machine and load balancer.
+>
+> ⚠️ This cluster is only suitable for learning purposes it is not suitable for production use.
+>
+> 📖 Read [Run Kubernetes in Azure the Cheap Way](https://trstringer.com/cheap-kubernetes-in-azure/) for more cost saving tips.
+>
+
+## Install cert-manager
+
+Now you can install and configure cert-manager.
+
+Install cert-manager using `helm` as follows:
+
+```bash
+helm repo add jetstack https://charts.jetstack.io
+helm repo update
+helm upgrade cert-manager jetstack/cert-manager \
+ --install \
+ --create-namespace \
+ --wait \
+ --namespace cert-manager \
+ --set installCRDs=true
+```
+
+This will create three Deployments and some Services and Pods in a new namespace called `cert-manager`.
+It also installs various cluster scoped supporting resources such as RBAC roles and Custom Resource Definitions.
+
+You can view some of the resources that have been installed as follows:
+
+```bash
+kubectl -n cert-manager get all
+```
+
+And you can explore the Custom Resource Definitions (cert-manager's API) using `kubectl explain`, as follows:
+
+```bash
+kubectl explain Certificate
+kubectl explain CertificateRequest
+kubectl explain Issuer
+```
+
+> 📖 Read about [other ways to install cert-manager](../../installation/README.md).
+>
+> 📖 Read more about [Certificates and Issuers](../../concepts/README.md).
+
+## Create a test ClusterIssuer and a Certificate
+
+Now everything is ready for you to create your first certificate.
+This will be a self-signed certificate but later we'll replace it with a Let's Encrypt signed certificate.
+
+```yaml file=../../../../public/docs/tutorials/getting-started-aks-letsencrypt/clusterissuer-selfsigned.yaml
+```
+🔗 `clusterissuer-selfsigned.yaml`
+
+```bash
+kubectl apply -f clusterissuer-selfsigned.yaml
+```
+
+Then use `envsubst` to substitute your chosen domain name into the following Certificate template:
+
+```yaml file=../../../../public/docs/tutorials/getting-started-aks-letsencrypt/certificate.yaml
+```
+🔗 `certificate.yaml`
+
+```bash
+envsubst < certificate.yaml | kubectl apply -f -
+```
+
+> 🔗 If you don't already have `envsubst` installed you can [download and install a Go implementation of `envsubst`](https://github.com/a8m/envsubst).
+
+Use `cmctl status certificate` to check the status of the Certificate:
+
+```bash
+cmctl status certificate www
+```
+
+If successful, the private key and the signed certificate will be stored in a Secret called `www-tls`.
+You can use `cmctl inspect secret www-tls` to decode the base64 encoded X.509 content of the Secret:
+
+```terminal
+$ cmctl inspect secret www-tls
+...
+Valid for:
+ DNS Names:
+ - www.cert-manager-tutorial-22.site
+ URIs:
+ IP Addresses:
+ Email Addresses:
+ Usages:
+ - digital signature
+ - key encipherment
+ - server auth
+...
+```
+
+## Deploy a sample web server
+
+Now deploy a simple web server which responds to HTTPS requests with "hello world!".
+The SSL / TLS key and certificate are supplied to the web server by using the `www-tls` Secret as a volume
+and by mounting its contents into the file system of the `hello-app` container in the Pod:
+
+```yaml file=../../../../public/docs/tutorials/getting-started-aks-letsencrypt/deployment.yaml
+```
+🔗 `deployment.yaml`
+
+```bash
+kubectl apply -f deployment.yaml
+```
+
+You also need to create a Kubernetes LoadBalancer Service, so that connections from the Internet can be routed to the web server Pod.
+When you create the following Kubernetes Service, an Azure load balancer with an ephemeral public IP address will also be created:
+
+```yaml file=../../../../public/docs/tutorials/getting-started-aks-letsencrypt/service.yaml
+```
+🔗 `service.yaml`
+
+Create a unique DNS name for the LoadBalancer Service and then apply it:
+```bash
+export AZURE_LOADBALANCER_DNS_LABEL_NAME=lb-$(uuidgen) # ❗ The label must start with a lowercase ASCII letter
+envsubst < service.yaml | kubectl apply -f -
+```
+
+Within 2-3 minutes, a load balancer should have been provisioned with a public IP.
+
+```bash
+kubectl get service helloweb
+```
+
+Sample output
+
+```terminal
+$ kubectl get service helloweb
+NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
+helloweb LoadBalancer 10.0.141.1 20.114.151.62 443:30394/TCP 7m15s
+```
+
+The `EXTERNAL-IP` will be different for you and it may be different each time you re-create the LoadBalancer service,
+but it will have a stable DNS host name associated with it
+because you annotated the Service with `azure-dns-label-name`.
+This stable DNS hostname can be used as an alias for your chosen `$DOMAIN_NAME` by creating a [DNS CNAME record](https://www.cloudflare.com/en-gb/learning/dns/dns-records/dns-cname-record/):
+
+```bash
+az network dns record-set cname set-record \
+ --zone-name $DOMAIN_NAME \
+ --cname $AZURE_LOADBALANCER_DNS_LABEL_NAME.$AZURE_DEFAULTS_LOCATION.cloudapp.azure.com \
+ --record-set-name www
+```
+
+Check that `www.$DOMAIN_NAME` now resolves to the ephemeral public IP address of the load balancer:
+
+```terminal
+$ dig www.$DOMAIN_NAME A
+...
+;; QUESTION SECTION:
+;www.cert-manager-tutorial-22.site. IN A
+...
+;; ANSWER SECTION:
+www.cert-manager-tutorial-22.site. 3600 IN CNAME lb-ec8776e1-d067-4d4c-8cce-fdf07ce48260.eastus2.cloudapp.azure.com.
+lb-ec8776e1-d067-4d4c-8cce-fdf07ce48260.eastus2.cloudapp.azure.com. 10 IN A 20.122.27.189
+...
+```
+
+If the DNS is correct and the load balancer is working and the hello world web server is running,
+you should now be able to connect to it using curl or using your web browser:
+
+```bash
+curl --insecure -v https://www.$DOMAIN_NAME
+```
+
+> ⚠️ We used curl's `--insecure` option because it rejects self-signed certificates by default.
+> Later you will learn how to create a trusted certificate signed by Let's Encrypt.
+
+You should see that the certificate has the expected DNS names and that it is self-signed:
+
+```terminal
+...
+* Server certificate:
+* subject: CN=www.cert-manager-tutorial-22.site
+* start date: Jan 4 15:28:30 2023 GMT
+* expire date: Apr 4 15:28:30 2023 GMT
+* issuer: CN=www.cert-manager-tutorial-22.site
+* SSL certificate verify result: self-signed certificate (18), continuing anyway.
+...
+Hello, world!
+Protocol: HTTP/2.0!
+Hostname: helloweb-55cb4cd887-tjlvh
+```
+
+> 📖 Read more about [Using a Service to Expose Your App](https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/).
+>
+> 📖 Read more about [Using a public IP address and DNS label with the Azure Kubernetes Service (AKS) load balancer](https://learn.microsoft.com/en-us/azure/aks/static-ip).
+
+# Part 2
+
+In part 1 you created a test certificate.
+Now you will learn how to configure cert-manager to use Let's Encrypt and Azure DNS to create a trusted certificate which you can use in production.
+You need to prove to Let's Encrypt that you own the domain name of the certificate and one way to do this is to create a special DNS record in that domain.
+This is known as the [DNS-01 challenge type](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge).
+
+cert-manager can create that DNS record for you in by using the Azure DNS API but it needs to authenticate to Azure first,
+and currently the most secure method of authentication is to use [workload identity federation](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview).
+The advantages of this method are that cert-manager will use an ephemeral Kubernetes ServiceAccount Token to authenticate to Azure and the token need not be stored in a Kubernetes Secret.
+
+> ℹ️ cert-manager `>= v1.11.0` supports workload identity federation for ACME (Let's Encrypt) DNS-01 with Azure DNS.
+> Older versions of cert-manager support other authentication mechanisms which are not covered in this tutorial.
+>
+> 📖 Read about [other ways to configure the ACME issuer with Azure DNS](../../configuration/acme/dns01/azuredns.md).
+
+## Install the Azure workload identity features
+
+The workload identity features in Azure AKS are relatively new (at time of writing) and they require some non-default features to be enabled.
+
+Install the [Azure CLI AKS Preview Extension](https://github.com/Azure/azure-cli-extensions/tree/main/src/aks-preview),
+which you will need to configure some advanced workload identity federation features on your AKS cluster.
+
+```bash
+az extension add --name aks-preview
+```
+
+Register the `EnableWorkloadIdentityPreview` feature flag which is required for the AKS cluster in this demo.
+
+```bash
+az feature register --namespace "Microsoft.ContainerService" --name "EnableWorkloadIdentityPreview"
+
+# It takes a few minutes for the status to show Registered. Verify the registration status by using the az feature list command:
+az feature list -o table --query "[?contains(name, 'Microsoft.ContainerService/EnableWorkloadIdentityPreview')].{Name:name,State:properties.state}"
+
+# When ready, refresh the registration of the Microsoft.ContainerService resource provider by using the az provider register command:
+az provider register --namespace Microsoft.ContainerService
+```
+
+> 📖 Read more about [Registering the `EnableWorkloadIdentityPreview` feature flag](https://learn.microsoft.com/en-us/azure/aks/workload-identity-deploy-cluster).
+
+## Reconfigure the cluster
+
+Next enable the workload identity federation features on the cluster that you created earlier:
+
+```bash
+az aks update \
+ --name ${CLUSTER} \
+ --enable-oidc-issuer \
+ --enable-workload-identity # ℹ️ This option is currently only available when using the aks-preview extension.
+```
+
+> 📖 Read [Deploy and configure workload identity on an Azure Kubernetes Service (AKS) cluster](https://learn.microsoft.com/en-us/azure/aks/workload-identity-deploy-cluster) for more information about the `--enable-workload-identity` feature.
+
+## Reconfigure cert-manager
+
+We will label the cert-manager controller Pod and ServiceAccount for the attention of the Azure Workload Identity webhook,
+which will result in the cert-manager controller Pod having an extra volume containing a Kubernetes ServiceAccount token which it will use to authenticate with Azure.
+
+The labels can be configured using the Helm values file below:
+
+```yaml file=../../../../public/docs/tutorials/getting-started-aks-letsencrypt/values.yaml
+```
+🔗 `values.yaml`
+
+```bash
+helm upgrade cert-manager jetstack/cert-manager \
+ --namespace cert-manager \
+ --reuse-values \
+ --values values.yaml
+```
+
+The newly rolled out cert-manager Pod will have some new environment variables set,
+and the Azure workload-identity ServiceAccount token as a projected volume:
+
+```bash
+kubectl describe pod -n cert-manager -l app.kubernetes.io/component=controller
+```
+
+```terminal
+Containers:
+ ...
+ cert-manager-controller:
+ ...
+ Environment:
+ ...
+ AZURE_CLIENT_ID:
+ AZURE_TENANT_ID: f99bd6a4-665c-41cf-aff1-87a89d5c62d4
+ AZURE_FEDERATED_TOKEN_FILE: /var/run/secrets/azure/tokens/azure-identity-token
+ AZURE_AUTHORITY_HOST: https://login.microsoftonline.com/
+ Mounts:
+ /var/run/secrets/azure/tokens from azure-identity-token (ro)
+Volumes:
+ ...
+ azure-identity-token:
+ Type: Projected (a volume that contains injected data from multiple sources)
+ TokenExpirationSeconds: 3600
+```
+
+> 📖 Read about [the role of the Mutating Admission Webhook](https://azure.github.io/azure-workload-identity/docs/installation/mutating-admission-webhook.html) in Azure AD Workload Identity for Kubernetes.
+>
+> 📖 Read about [other values that can be customized in the cert-manager Helm chart](https://artifacthub.io/packages/helm/cert-manager/cert-manager?modal=values).
+
+## Create an Azure Managed Identity
+
+When cert-manager creates a certificate using Let's Encrypt
+it can use DNS records to prove that it controls the DNS domain names in the certificate.
+In order for cert-manager to use the Azure API and manipulate the records in the Azure DNS zone,
+it needs an Azure account and the best type of account to use is called a "Managed Identity".
+This account does not come with a password or an API key and it is designed for use by machines rather than humans.
+
+Choose a managed identity name:
+
+```bash
+export USER_ASSIGNED_IDENTITY_NAME=cert-manager-tutorials-1 # ❗ Replace with your preferred managed identity name
+```
+
+Create the Managed Identity:
+
+```bash
+az identity create --name "${USER_ASSIGNED_IDENTITY_NAME}"
+```
+
+Grant it permission to modify the DNS zone records:
+
+```bash
+export USER_ASSIGNED_IDENTITY_CLIENT_ID=$(az identity show --name "${USER_ASSIGNED_IDENTITY_NAME}" --query 'clientId' -o tsv)
+az role assignment create \
+ --role "DNS Zone Contributor" \
+ --assignee $USER_ASSIGNED_IDENTITY_CLIENT_ID \
+ --scope $(az network dns zone show --name $DOMAIN_NAME -o tsv --query id)
+```
+
+> 📖 Read [What are managed identities for Azure resources?](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview)
+> for an overview of managed identities and their uses.
+>
+> 📖 Read [Azure built-in roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles) to learn about the "DNS Zone Contributor" role.
+
+## Add a federated identity
+
+Now we will configure Azure to trust certain Kubernetes ServiceAccount tokens,
+in particular, the service account tokens from our specific Kubernetes cluster,
+and only tokens which are associated with the cert-manager ServiceAccount.
+cert-manager will authenticate to Azure using an short lived Kubernetes ServiceAccount token,
+and it will be able to impersonate the managed identity that you created in the previous step.
+
+First export the following environment variables containing the name and namespace of the Kubernetes ServiceAccount used by the cert-manager controller:
+
+```bash
+export SERVICE_ACCOUNT_NAME=cert-manager # ℹ️ This is the default Kubernetes ServiceAccount used by the cert-manager controller.
+export SERVICE_ACCOUNT_NAMESPACE=cert-manager # ℹ️ This is the default namespace for cert-manager.
+```
+
+Then configure the managed identity to trust the cert-manager Kubernetes ServiceAccount,
+by supplying its "subject" (the distinguishing name of the Kubernetes ServiceAccount)
+and its "issuer" (a URL at which the JWT signing certificate and other metadata can be downloaded):
+
+```bash
+export SERVICE_ACCOUNT_ISSUER=$(az aks show --resource-group $AZURE_DEFAULTS_GROUP --name $CLUSTER --query "oidcIssuerProfile.issuerUrl" -o tsv)
+az identity federated-credential create \
+ --name "cert-manager" \
+ --identity-name "${USER_ASSIGNED_IDENTITY_NAME}" \
+ --issuer "${SERVICE_ACCOUNT_ISSUER}" \
+ --subject "system:serviceaccount:${SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME}"
+```
+
+> 📖 Read about [Workload identity federation](https://learn.microsoft.com/en-us/azure/active-directory/develop/workload-identity-federation) in the Microsoft identity platform documentation.
+
+
+## Create a ClusterIssuer for Let's Encrypt Staging
+
+A ClusterIssuer is a custom resource which tells cert-manager how to sign a Certificate.
+In this case the ClusterIssuer will be configured to connect to the Let's Encrypt staging server,
+which allows us to test everything without using up our Let's Encrypt certificate quota for the domain name.
+
+Save the following content to a file called `clusterissuer-lets-encrypt-staging.yaml`, change the `email` field to use your email address and apply it:
+
+```yaml file=../../../../public/docs/tutorials/getting-started-aks-letsencrypt/clusterissuer-lets-encrypt-staging.yaml
+```
+🔗 `clusterissuer-lets-encrypt-staging.yaml`
+
+
+As you can see there are some variables in the `clusterissuer-lets-encrypt-staging.yaml` which need to be filled in before we apply it;
+most have been defined earlier in this tutorial but you need to set the following:
+
+```bash
+export EMAIL_ADDRESS= # ❗ Replace this with your email address
+export AZURE_SUBSCRIPTION= # ❗ Replace this with your Azure account name
+```
+
+Now use `envsubst` to fill in the variables and pipe it into `kubectl apply`, as follows:
+
+```bash
+export AZURE_SUBSCRIPTION_ID=$(az account show --name $AZURE_SUBSCRIPTION --query 'id' -o tsv)
+envsubst < clusterissuer-lets-encrypt-staging.yaml | kubectl apply -f -
+```
+
+You can check the status of the ClusterIssuer:
+
+```bash
+kubectl describe clusterissuer letsencrypt-staging
+```
+
+Example output
+
+```console
+Status:
+ Acme:
+ Last Registered Email: firstname.lastname@example.com
+ Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/77882854
+ Conditions:
+ Last Transition Time: 2022-11-29T13:05:33Z
+ Message: The ACME account was registered with the ACME server
+ Observed Generation: 1
+ Reason: ACMEAccountRegistered
+ Status: True
+ Type: Ready
+```
+
+> ℹ️ Let's Encrypt uses the Automatic Certificate Management Environment (ACME) protocol
+> which is why the configuration above is under a key called `acme`.
+>
+> ℹ️ The email address is only used by Let's Encrypt to remind you to renew the certificate after 30 days before expiry. You will only receive this email if something goes wrong when renewing the certificate with cert-manager.
+>
+> ℹ️ The Let's Encrypt production issuer has [very strict rate limits](https://letsencrypt.org/docs/rate-limits/).
+> When you're experimenting and learning, it can be very easy to hit those limits. Because of that risk,
+> we'll start with the Let's Encrypt staging issuer, and once we're happy that it's working
+> we'll switch to the production issuer.
+>
+> 📖 Read more about [configuring the ACME Issuer](../../configuration/acme/README.md).
+>
+
+
+## Re-issue the Certificate using Let's Encrypt
+
+Patch the Certificate to use the staging ClusterIssuer:
+
+```bash
+kubectl patch certificate www --type merge -p '{"spec":{"issuerRef":{"name":"letsencrypt-staging"}}}'
+```
+
+That should trigger cert-manager to renew the certificate:
+Use `cmctl` to check:
+
+```bash
+cmctl status certificate www
+cmctl inspect secret www-tls
+```
+
+And finally, when the new certificate has been issued, you must restart the web server to use it:
+
+```bash
+kubectl rollout restart deployment helloweb
+```
+
+You should once again be able to connect to the website, but this time you will see the Let's Encrypt staging certificate:
+
+```terminal
+$ curl -v --insecure https://www.$DOMAIN_NAME
+...
+* Server certificate:
+* subject: CN=www.cert-manager-tutorial-22.site
+* start date: Jan 5 12:41:14 2023 GMT
+* expire date: Apr 5 12:41:13 2023 GMT
+* issuer: C=US; O=(STAGING) Let's Encrypt; CN=(STAGING) Artificial Apricot R3
+* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
+...
+Hello, world!
+Protocol: HTTP/2.0!
+Hostname: helloweb-9b8bcdd56-6rxm8
+```
+
+> ⚠️ We used curl's `--insecure` option again here because the Let's Encrypt staging issuer creates untrusted certificates.
+> Next you will learn how to create a trusted certificate signed by the Let's Encrypt production issuer.
+
+## Create a production ready certificate
+
+Now that everything is working with the Let's Encrypt staging server, we can switch to the production server and get a trusted certificate.
+
+Create a Let's Encrypt production Issuer by copying the staging ClusterIssuer YAML and modifying the server URL and the names,
+then apply it:
+
+```yaml file=../../../../public/docs/tutorials/getting-started-aks-letsencrypt/clusterissuer-lets-encrypt-production.yaml
+```
+🔗 `clusterissuer-lets-encrypt-production.yaml`
+
+
+```bash
+envsubst < clusterissuer-lets-encrypt-production.yaml | kubectl apply -f -
+```
+
+Check the status of the ClusterIssuer:
+
+```bash
+kubectl describe clusterissuer letsencrypt-production
+```
+
+Patch the Certificate to use the production ClusterIssuer:
+
+```bash
+kubectl patch certificate www --type merge -p '{"spec":{"issuerRef":{"name":"letsencrypt-production"}}}'
+```
+
+That should trigger cert-manager to renew the certificate:
+Use `cmctl` to check:
+
+```bash
+cmctl status certificate www
+cmctl inspect secret www-tls
+```
+
+And finally, when the new certificate has been issued, you must restart the web server to use it:
+
+```bash
+kubectl rollout restart deployment helloweb
+```
+
+Now you should be able to connect to the web server securely, without the `--insecure` flag,
+and if you visit the site in your web browser, it should show a padlock (🔒) symbol next to the URL.
+
+```bash
+curl -v https://www.$DOMAIN_NAME
+```
+
+```terminal
+...
+* Server certificate:
+* subject: CN=cert-manager-tutorial-22.site
+* start date: Nov 30 15:41:40 2022 GMT
+* expire date: Feb 28 15:41:39 2023 GMT
+* subjectAltName: host "www.cert-manager-tutorial-22.site" matched cert's "www.cert-manager-tutorial-22.site"
+* issuer: C=US; O=Let's Encrypt; CN=R3
+* SSL certificate verify ok.
+...
+```
+
+That concludes this tutorial.
+You have learned how to deploy cert-manager on Azure AKS and how to configure it to issue Let's Encrypt signed certificates using the DNS-01 protocol with Azure DNS.
+You have learned about workload identity federation in Azure and learned how to configure cert-manager to authenticate to Azure using a Kubernetes ServiceAccount Token.
+
+## Cleanup
+
+After completing the tutorial you can clean up by deleting the cluster, the domain name and the managed identity, as follows:
+
+```
+az aks delete --name $CLUSTER
+az network dns zone delete --name $DOMAIN_NAME
+az identity delete --name $USER_ASSIGNED_IDENTITY_NAME
+```
+
+## Next Steps
+
+> 📖 Read other [cert-manager tutorials](../README.md) and [getting started guides](../../getting-started/README.md).
+>
+> 📖 Read more about [configuring the cert-manager ACME issuer with Azure DNS](../../configuration/acme/dns01/azuredns.md).
diff --git a/content/v1.12-docs/tutorials/getting-started-with-cert-manager-on-google-kubernetes-engine-using-lets-encrypt-for-ingress-ssl/README.md b/content/v1.12-docs/tutorials/getting-started-with-cert-manager-on-google-kubernetes-engine-using-lets-encrypt-for-ingress-ssl/README.md
new file mode 100644
index 00000000000..80f233aee7d
--- /dev/null
+++ b/content/v1.12-docs/tutorials/getting-started-with-cert-manager-on-google-kubernetes-engine-using-lets-encrypt-for-ingress-ssl/README.md
@@ -0,0 +1,779 @@
+---
+title: Deploy cert-manager on Google Kubernetes Engine (GKE) and create SSL certificates for Ingress using Let's Encrypt
+description: Learn how to deploy cert-manager on Google Kubernetes (GKE) Engine and then configure it to sign SSL certificates using Let's Encrypt
+---
+
+*Last Verified: 15 July 2022*
+
+In this tutorial you will learn how to deploy and configure cert-manager on Google Kubernetes Engine (GKE).
+You will learn how to configure cert-manager to get a signed SSL certificate from Let's Encrypt,
+using an [HTTP-01 challenge](https://letsencrypt.org/docs/challenge-types/#http-01-challenge).
+Finally you will learn how the certificate can be used to serve an HTTPS website with a public domain name.
+
+> **Google Cloud**: A suite of cloud computing services by Google.
+> **Kubernetes**: Runs on your servers. Automates the deployment, scaling, and management of containerized applications.
+> **cert-manager**: Runs in Kubernetes. Obtains TLS / SSL certificates and ensures the certificates are valid and up-to-date.
+> **Let’s Encrypt**: An Internet service. Allows you to generate free short-lived SSL certificates.
+
+First you will create a Kubernetes (GKE) cluster and deploy a sample web server.
+You will then create a public IP address and a public domain name for your website.
+You'll set up Ingress and Google Cloud load balancers so that Internet clients can connect to the web server using HTTP.
+Finally you will use cert-manager to get an SSL certificate from Let's Encrypt
+and configure the load balancer to use that certificate.
+By the end of this tutorial you will be able to connect to your website from the Internet using an `https://` URL.
+
+## Prerequisites
+
+**💻 Google Cloud account**
+
+You will need a Google Cloud account.
+Registration requires a credit card or bank account details.
+Visit the [Get started with Google Cloud](https://cloud.google.com/docs/get-started) page and follow the instructions.
+
+> 💵 If you have never used Google Cloud before, you may be eligible for the
+> [Google Cloud Free
+> Program](https://cloud.google.com/free/docs/gcp-free-tier/#free-trial), which
+> gives you a 90 day trial period that includes $300 in free Cloud Billing
+> credits to explore and evaluate Google Cloud.
+
+**💻 Domain Name**
+
+You will need a domain name and the ability to create DNS records in that domain. We will be getting a $12 domain name from Google Domains. Google Domains is one of the many possible "domain name registrars". NameCheap and GoDaddy are two other well-known registrars.
+
+> 💵 If you prefer not purchasing a domain name, it is also possible to adapt this tutorial to use the IP address to serve your website and for the SSL certificate.
+
+**💻 Software**
+
+
+You will also need to install the following software on your laptop:
+
+1. [gcloud](https://cloud.google.com/sdk/docs/install): A set of tools to create and manage Google Cloud resources.
+2. [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl): The Kubernetes command-line tool which allows you to configure Kubernetes clusters.
+3. [curl](https://everything.curl.dev/get): A command-line tool for connecting to a web server using HTTP and HTTPS.
+
+> ℹ️ Try running `gcloud components install kubectl` to quickly install `kubectl`.
+
+## 0. Configure `gcloud` with a Google Cloud project
+
+If you don't have a Google Cloud account, the command below will create one for you:
+
+```bash
+gcloud init
+```
+
+You will need to answer "yes" to the following question:
+
+```text
+Do you want to configure a default Compute Region and Zone? (Y/n)? Y
+```
+
+After running the command, you will shown the project name, default region, and default zone.
+
+Example output:
+
+```text
+* Commands that require authentication will use firstname.lastname@example.com by default
+* Commands will reference project `your-project` by default
+* Compute Engine commands will use region `europe-west1` by default
+* Compute Engine commands will use zone `europe-west1-b` by default
+```
+
+In this tutorial, we will refer to the name of the project that was selected while running `gcloud init` with the variable `PROJECT`. Where ever you see `$PROJECT` in a command, you need to either (1) replace the variable manually before you execute the command,
+or (2) export the variable in your shell session. This applies to all environment variables that you will encounter in the commands listed in this tutorial.
+
+We will go with option (2), so we need to export the environment variables before continuing using the information that was printed by `gcloud init`:
+
+```bash
+export PROJECT=your-project # Your Google Cloud project ID.
+export REGION=europe-west1 # Your Google Cloud region.
+```
+
+## 1. Create a Kubernetes Cluster
+
+To get started, let's create a Kubernetes cluster in Google Cloud. You will need to pick a name for your cluster. Here, we will go with "test-cluster-1". Let us save it in an environment variable:
+
+```bash
+export CLUSTER=test-cluster-1
+```
+
+Now, create the cluster using the following command:
+
+```bash
+gcloud container clusters create $CLUSTER --preemptible --num-nodes=1
+```
+
+Set up the [Google Kubernetes Engine auth plugin for kubectl](https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke):
+
+```bash
+gcloud components install gke-gcloud-auth-plugin
+export USE_GKE_GCLOUD_AUTH_PLUGIN=True
+gcloud container clusters get-credentials $CLUSTER
+```
+
+Now check that you can connect to the cluster:
+
+```bash
+kubectl get nodes -o wide
+```
+
+> ⏲ It will take 4-5 minutes to create the cluster.
+>
+> 💵 To minimize your cloud bill, this command creates a 1-node cluster using a
+> [preemptible virtual
+> machine](https://cloud.google.com/kubernetes-engine/docs/how-to/preemptible-vms)
+> which is cheaper than a normal virtual machine.
+
+## 2. Deploy a sample web server
+
+We will deploy a very simple web server which responds to HTTP requests with "hello world!".
+
+```bash
+kubectl create deployment web --image=gcr.io/google-samples/hello-app:1.0
+```
+
+We also need to create a Kubernetes Service, so that connections can be routed to the web server Pods:
+
+```bash
+kubectl expose deployment web --port=8080
+```
+
+> ℹ️ These [kubectl imperative commands](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/imperative-command/) are used for readability and brevity.
+> Feel free to use YAML manifests and `kubectl apply -f` instead.
+>
+> ℹ️ The Service created by `kubectl expose` will be of type `ClusterIP` (the default) and this is only reachable by components within the cluster. Later we will create an Ingress which is how we make the service available to clients outside the cluster.
+>
+> 🔰 Read more about [Using a Service to Expose Your App](https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/).
+
+## 3. Create a static external IP address
+
+This tutorial is about creating a public facing HTTPS website with a Let's Encrypt SSL certificate using the HTTP01 challenge mechanism,
+so we need a public IP address so that both Let's Encrypt and other Internet clients can connect to your website.
+
+It is easy to create a public IP address in Google Cloud and later we will associate it with your website domain name and with a Google Cloud load balancer, which will accept HTTP(S) connections from Internet clients and proxy the requests to the web servers running in your cluster.
+
+Create a global static IP address as follows:
+
+```bash
+gcloud compute addresses create web-ip --global
+```
+
+You should see the new IP address listed:
+
+```bash
+gcloud compute addresses list
+```
+
+> ⚠️ You MUST create a `global` IP address because that is a prerequisite of the [External HTTP(S) Load Balancer](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress-xlb) which we will be using in this tutorial.
+>
+> 💵 Global static IP addresses are only available in the Premium network service tier and are more expensive than ephemeral and standard public IP addresses.
+>
+> 🔰 Read more about [Network service tiers in Google Cloud](https://cloud.google.com/network-tiers).
+>
+> 🔰 Read more about [Reserving a static external IP address in Google Cloud](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address).
+
+Finally, we will save the IP address into an environment variable for later use. Display the IP address with the following command:
+
+```bash
+gcloud compute addresses describe web-ip --format='value(address)' --global
+```
+
+Then, copy the output and save it into an environment variable:
+
+```bash
+export IP_ADDRESS=198.51.100.1 # Replace with your IP address
+```
+
+## 4. Create a domain name for your website
+
+You will need a domain name for your website and Let's Encrypt checks your domain before it signs your SSL certificate,
+so the domain name needs to be reachable from the Internet.
+
+We will purchase a cheap domain name using a credit card. Go to https://domains.google.com, and type something in the search box. For the example, we searched for `hello-app.com` because the example container that we will be deploying is called `hello-app`. Most importantly, we make sure to sort the domain names by price:
+
+![](/images/getting-started/screenshot_google-domains_get-a-new-domain.png)
+
+We don't pick `hello-app.com` because it costs $2,800; instead, we go with the one at the top: `heyapp.net`. It looks good! We then click the cart button. On the next screen, you will want to disable the auto-renewal, since we don't want to pay for this domain every year:
+
+![](/images/getting-started/screenshot_google-domains_your-cart.png)
+
+Now that you know your domain name, save it in an environment variable:
+
+```bash
+export DOMAIN_NAME=heyapp.net
+```
+
+Next, you will need to create a new `A` record pointing at the IP address that we created above. Head back to https://domains.google.com/registrar, open your domain (here, `heyapp.net`) and click "DNS" on the left menu. You will see "Custom records". You want to add a new record of type `A` and put the IP address from the previous step into "data". You must leave "Host name" empty because we are configuring the top-level domain name:
+
+![](/images/getting-started/screenshot_google-domains_resource-records.png)
+
+> 🔰 Learn more about [What is a DNS A record? from the Cloudflare DNS tutorial](https://www.cloudflare.com/learning/dns/dns-records/dns-a-record/).
+
+> ℹ️ It is not strictly necessary to create a domain name for your website. You can connect to it using the IP address and later you can create an SSL certificate for the IP address instead of a domain name. If for some reason you can't create a domain name, then feel free to skip this section and adapt the instructions below to use an IP address instead.
+>
+> ℹ️ Every Google Cloud address has an automatically generated reverse DNS name like `51.159.120.34.bc.googleusercontent.com`,
+> but the parent domain `googleusercontent.com` has a CAA record which prevents
+> Let's Encrypt from signing certificates for the sub-domains.
+> See [Certificate Authority Authorization (CAA)](https://letsencrypt.org/docs/caa/) in the Let's Encrypt documentation.
+
+## 5. Create an Ingress
+
+You won't be able to reach your website yet.
+Your web server is running inside your Kubernetes cluster but there is no route or proxy through which Internet clients can connect to it, yet!
+Now we will create a Kubernetes Ingress object and in Google Cloud this will trigger the creation of a various services which together allow Internet clients to reach your web server running inside your Kubernetes cluster.
+
+Initially we are going to create an HTTP (not an HTTPS) Ingress so that we can test the basic connectivity before adding the SSL layer.
+
+Copy the following YAML into a file called `ingress.yaml` and apply it:
+
+```yaml
+# ingress.yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: web-ingress
+ annotations:
+ # This tells Google Cloud to create an External Load Balancer to realize this Ingress
+ kubernetes.io/ingress.class: gce
+ # This enables HTTP connections from Internet clients
+ kubernetes.io/ingress.allow-http: "true"
+ # This tells Google Cloud to associate the External Load Balancer with the static IP which we created earlier
+ kubernetes.io/ingress.global-static-ip-name: web-ip
+spec:
+ defaultBackend:
+ service:
+ name: web
+ port:
+ number: 8080
+```
+
+```bash
+kubectl apply -f ingress.yaml
+```
+
+This will trigger the creation of a Google HTTP(S) loadbalancer associated with the IP address that you created earlier.
+You can watch the progress and the resources that are being created:
+
+```bash
+kubectl describe ingress web-ingress
+```
+
+Within 4-5 minutes all the load balancer components should be ready and you should be able to connect to the DNS name and see the response from the hello-world web server that we deployed earlier:
+
+```
+curl http://$DOMAIN_NAME
+```
+
+Example output:
+
+```console
+Hello, world!
+Version: 1.0.0
+Hostname: web-79d88c97d6-t8hj2
+```
+
+At this point we have a Google load balancer which is forwarding HTTP traffic to the hello-world web server running in a Pod in our cluster.
+
+> ⏲ It may take 4-5 minutes for the load balancer components to be created and
+> configured and for Internet clients to be routed to your web server.
+> Refer to the [Troubleshooting](#troubleshooting) section if it takes longer.
+>
+> 🔰 Read about how to [Use a static IP addresses for HTTP(S) load balancers via Ingress annotation](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress-xlb#static_ip_addresses_for_https_load_balancers).
+>
+> 🔰 Read a [Summary of external Ingress annotations for GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/load-balance-ingress#summary_of_external_ingress_annotations).
+>
+> 🔰 Read about [Troubleshooting Ingress with External HTTP(S) Load Balancing on GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/load-balance-ingress#testing_the).
+>
+> ℹ️ There are two Ingress classes available for GKE Ingress. The `gce` class deploys an external load balancer and the `gce-internal` class deploys an internal load balancer. Ingress resources without a class specified default to `gce`.
+>
+> ⚠️ Contrary to the Kubernetes Ingress documentation, you MUST use the `kubernetes.io/ingress.class` annotation rather than the `Ingress.Spec.IngressClassName` field.
+> See [ingress-gce #1301](https://github.com/kubernetes/ingress-gce/issues/1301#issuecomment-1133356812) and [ingress-gce #1337](https://github.com/kubernetes/ingress-gce/pull/1337).
+
+
+## 6. Install cert-manager
+
+So finally we are ready to start creating an SSL certificate for our website.
+The first thing you need to do is install cert-manager, and we'll install it the easy using `kubectl` as follows:
+
+```
+kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.2/cert-manager.yaml
+```
+
+This will create three Deployments, and a bunch of Services and Pods in a new namespace called `cert-manager`.
+It also installs various cluster scoped supporting resources such as RBAC roles and Custom Resource Definitions.
+
+You can view some of the resources that have been installed as follows:
+
+```bash
+kubectl -n cert-manager get all
+```
+
+And you can explore the Custom Resource Definitions (cert-manager's API) using `kubectl explain`, as follows:
+
+```bash
+kubectl explain Certificate
+kubectl explain CertificateRequest
+kubectl explain Issuer
+```
+
+> 🔰 Read about [other ways to install cert-manager](../../installation).
+>
+> 🔰 Read more about [Certificates and Issuers](../../concepts).
+
+## 7. Create an Issuer for Let's Encrypt Staging
+
+An Issuer is a custom resource which tells cert-manager how to sign a Certificate.
+In this case the Issuer will be configured to connect to the Let's Encrypt staging server,
+which allows us to test everything without using up our Let's Encrypt certificate quota for the domain name.
+
+> ℹ️ Let's Encrypt uses the Automatic Certificate Management Environment (ACME) protocol
+> which is why the configuration below is under a key called `acme`.
+
+Save the following content to a file called `issuer-lets-encrypt-staging.yaml`, change the `email` field to use your email address and apply it:
+
+```yaml
+# issuer-lets-encrypt-staging.yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt-staging
+spec:
+ acme:
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ email: # ❗ Replace this with your email address
+ privateKeySecretRef:
+ name: letsencrypt-staging
+ solvers:
+ - http01:
+ ingress:
+ name: web-ingress
+```
+
+```bash
+kubectl apply -f issuer-lets-encrypt-staging.yaml
+```
+
+> ℹ️ The email address is only used by Let's Encrypt to remind you to renew the certificate after 30 days before expiry. You will only receive this email if something goes wrong when renewing the certificate with cert-manager.
+
+You can check the status of the Issuer:
+
+```bash
+kubectl describe issuers.cert-manager.io letsencrypt-staging
+```
+
+Example output
+
+```console
+Status:
+ Acme:
+ Last Registered Email: firstname.lastname@example.com
+ Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/60706744
+ Conditions:
+ Last Transition Time: 2022-07-13T16:13:25Z
+ Message: The ACME account was registered with the ACME server
+ Observed Generation: 1
+ Reason: ACMEAccountRegistered
+ Status: True
+ Type: Ready
+```
+
+> ℹ️ The Let's Encrypt production issuer has [very strict rate limits](https://letsencrypt.org/docs/rate-limits/).
+> When you're experimenting and learning, it can be very easy to hit those limits. Because of that risk,
+> we'll start with the Let's Encrypt staging issuer, and once we're happy that it's working
+> we'll switch to the production issuer.
+>
+> ⚠️ In the next step you will see a warning about untrusted certificates because
+> we start with the staging issuer, but that's totally expected.
+>
+> 🔰 Read more about [configuring the ACME Issuer](../../configuration/acme).
+
+## 8. Re-configure the Ingress for SSL
+
+Earlier we created an Ingress and saw that we could connect to our web server using HTTP.
+Now we will reconfigure that Ingress for HTTPS.
+
+First a quick hack, to work around a problem with the Google Cloud ingress controller.
+Create an empty Secret for your SSL certificate **before reconfiguring the Ingress** and apply it:
+
+```yaml
+# secret.yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: web-ssl
+type: kubernetes.io/tls
+stringData:
+ tls.key: ""
+ tls.crt: ""
+```
+
+```bash
+kubectl apply -f secret.yaml
+```
+
+> ℹ️ This is a work around for a chicken-and-egg problem, where the ingress-gce
+> controller won't update its forwarding rules unless it can first find the
+> Secret that will eventually contain the SSL certificate. But Let's Encrypt
+> won't sign the SSL certificate until it can get the special
+> `.../.well-known/acme-challenge/...` URL which cert-manager adds to the
+> Ingress and which must then be translated into Google Cloud forwarding rules,
+> by the ingress-gce controller.
+>
+> 🔰 Read more about [Kubernetes Secrets and how to use them](https://kubernetes.io/docs/concepts/configuration/secret/).
+
+Now make the following changes to the Ingress and apply them:
+
+```diff
+--- a/ingress.yaml
++++ b/ingress.yaml
+@@ -7,7 +7,12 @@ metadata:
+ kubernetes.io/ingress.class: gce
+ kubernetes.io/ingress.allow-http: "true"
+ kubernetes.io/ingress.global-static-ip-name: web-ip
++ cert-manager.io/issuer: letsencrypt-staging
+ spec:
++ tls:
++ - secretName: web-ssl
++ hosts:
++ - $DOMAIN_NAME
+ defaultBackend:
+ service:
+ name: web
+```
+
+```
+kubectl apply -f ingress.yaml
+```
+
+This triggers a complex set of operations which may take many minutes to eventually complete.
+Some of these steps take 2-3 minutes and some will initially fail.
+They should all eventually succeed because cert-manager and ingress-gce (the Google Cloud ingress controller) will periodically re-reconcile.
+
+Eventually, When all the pieces are in place, you should be able to
+use curl to check the HTTPS connection to your website:
+
+```bash
+curl -v --insecure https://$DOMAIN_NAME
+```
+
+You should see that the HTTPS connection is established but that the SSL certificate is not trusted;
+that's why you use the `--insecure` flag at this stage
+
+Example output:
+```console
+* Server certificate:
+* subject: CN=www.example.com
+* start date: Jul 14 08:52:29 2022 GMT
+* expire date: Oct 12 08:52:28 2022 GMT
+* issuer: C=US; O=(STAGING) Let's Encrypt; CN=(STAGING) Artificial Apricot R3
+* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
+```
+
+> ⏲ You will have to wait 5-10 minutes for the SSL certificate to be signed and then loaded by the Google Cloud load balancer.
+> Refer to the [Troubleshooting](#troubleshooting) section if it takes longer.
+>
+> ℹ️ Adding the annotation `cert-manager.io/issuer: letsencrypt-staging` marks the Ingress for the attention of the cert-manager `ingress-shim`
+> and causes it to create a new Certificate with a reference to the Issuer that we created earlier.
+>
+> 🔰 Read [Securing Ingress Resources](../../usage/ingress.md) to learn more.
+>
+> 🔰 Read about how to [Specify certificates for your Ingress in GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-multi-ssl#specifying_certificates_for_your_ingress).
+
+## 9. Create a production ready SSL certificate
+
+Now that everything is working with the Let's Encrypt staging server, we can switch to the production server and get a trusted SSL certificate.
+
+Create a Let's Encrypt production Issuer and apply it:
+
+```yaml
+# issuer-lets-encrypt-production.yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: letsencrypt-production
+spec:
+ acme:
+ server: https://acme-v02.api.letsencrypt.org/directory
+ email: # ❗ Replace this with your email address
+ privateKeySecretRef:
+ name: letsencrypt-production
+ solvers:
+ - http01:
+ ingress:
+ name: web-ingress
+```
+
+```bash
+kubectl apply -f issuer-lets-encrypt-production.yaml
+```
+
+Then update the Ingress annotation to use the production Issuer:
+
+```bash
+kubectl annotate ingress web-ingress cert-manager.io/issuer=letsencrypt-production --overwrite
+```
+
+This will trigger cert-manager to get a new SSL certificate signed by the Let's Encrypt production CA and store it to the `web-ssl` Secret.
+Within about 10 minutes, this new certificate will be synced to the Google Cloud load balancer and you will be able to connect to the website using secure HTTPS:
+
+```bash
+curl -v https://$DOMAIN_NAME
+```
+
+Example output:
+```console
+...
+* Server certificate:
+* subject: CN=www.example.com
+* start date: Jul 14 09:44:29 2022 GMT
+* expire date: Oct 12 09:44:28 2022 GMT
+* subjectAltName: host "www.example.com" matched cert's "www.example.com"
+* issuer: C=US; O=Let's Encrypt; CN=R3
+* SSL certificate verify ok.
+...
+Hello, world!
+Version: 1.0.0
+Hostname: web-79d88c97d6-t8hj2
+```
+
+It should also be possible to visit `https://$DOMAIN_NAME` in your web browser, without any errors or warnings.
+
+That concludes the tutorial.
+You now understand how cert-manager integrates with Kubernetes Ingress and cloud Ingress controllers.
+You have learned how to use cert-manager to get free Let's Encrypt SSL certificates.
+And you have seen how the certificates can be used by a cloud based load balancer to terminate SSL connections from Internet clients
+and forward HTTPS requests to a web server running in your Kubernetes cluster.
+
+> 💵 Read the [Clean up](#clean-up) section to learn how to delete all the resources that you created in this tutorial and reduce your cloud bill.
+>
+> 🔰 Read the [Troubleshooting](#troubleshooting) section if you encounter difficulties with the steps described in this tutorial.
+
+## Clean up
+
+After completing the tutorial you can clean up by deleting the cluster and the domain name and the static IP as follows:
+
+```bash
+# Delete the cluster and all the Google Cloud resources related to the Ingress that it contains
+gcloud container clusters delete $CLUSTER
+
+# Delete the domain name
+gcloud dns record-sets delete $DOMAIN_NAME --zone $ZONE --type A
+
+# Delete the static IP address
+gcloud compute addresses delete web-ip --global
+```
+
+## Troubleshooting
+
+When you create or update the Ingress object in this tutorial it triggers a complex set of operations which may take many minutes to eventually complete.
+Some of these steps take 2-3 minutes and some will initially fail but then subsequently succeed when either cert-manager or the Google ingress controller re-reconciles.
+In short, you should allow 5-10 minutes after you create or change the Ingress and you should expect to see some errors and warnings when you run `kubectl describe ingress web-ingress`.
+
+Here's a brief summary of the operations performed by cert-manager and ingress-gce (the Google Cloud Ingress controller):
+
+* cert-manager connects to Let's Encrypt and sends an SSL certificate signing request.
+* Let's Encrypt responds with a "challenge", which is a unique token that cert-manager must make available at a well-known location on the target web site. This proves that you are an administrator of that web site and domain name.
+* cert-manager deploys a Pod containing a temporary web server that serves the Let's Encrypt challenge token.
+* cert-manager reconfigures the Ingress, adding a `rule` to route requests for from Let's Encrypt to that temporary web server.
+* Google Cloud ingress controller reconfigures the external HTTP load balancer with that new rule.
+* Let's Encrypt now connects and receives the expected challenge token and the signs the SSL certificate and returns it to cert-manager.
+* cert-manager stores the signed SSL certificate in the Kubernetes Secret called `web-ssl`.
+* Google Cloud ingress controller uploads the signed certificate and associated private key to a Google Cloud certificate.
+* Google Cloud ingress controller reconfigures the external load balancer to serve the uploaded SSL certificate.
+
+### Check Ingress and associated events
+
+Use `kubectl describe` to view the Ingress configuration and all the associated Events.
+Check that the IP address is correct and that the TLS and Host entries match the domain name that you chose for your website.
+Notice that `ingress-gce` creates an Event for each of the Google Cloud components that it manages.
+And notice that it adds annotations with references to the ID of each of those components.
+cert-manager also creates Events when it reconciles the Ingress object, including details of the Certificate object that it creates for the Ingress.
+
+```console
+$ kubectl describe ingress web-ingress
+Name: web-ingress
+Labels:
+Namespace: default
+Address: 34.120.159.51
+Ingress Class:
+Default backend: web:8080 (10.52.0.13:8080)
+TLS:
+ web-ssl terminates www.example.com
+Rules:
+ Host Path Backends
+ ---- ---- --------
+ * * web:8080 (10.52.0.13:8080)
+Annotations: cert-manager.io/issuer: letsencrypt-staging
+ ingress.kubernetes.io/backends: {"k8s1-01784147-default-web-8080-1647ccd2":"HEALTHY"}
+ ingress.kubernetes.io/forwarding-rule: k8s2-fr-1lt9dzcy-default-web-ingress-yteotwe4
+ ingress.kubernetes.io/https-forwarding-rule: k8s2-fs-1lt9dzcy-default-web-ingress-yteotwe4
+ ingress.kubernetes.io/https-target-proxy: k8s2-ts-1lt9dzcy-default-web-ingress-yteotwe4
+ ingress.kubernetes.io/ssl-cert: k8s2-cr-1lt9dzcy-4gjeakdb9n7k6ls7-a257650b5fefd174
+ ingress.kubernetes.io/target-proxy: k8s2-tp-1lt9dzcy-default-web-ingress-yteotwe4
+ ingress.kubernetes.io/url-map: k8s2-um-1lt9dzcy-default-web-ingress-yteotwe4
+ kubernetes.io/ingress.allow-http: true
+ kubernetes.io/ingress.class: gce
+ kubernetes.io/ingress.global-static-ip-name: web-ip
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal CreateCertificate 28m cert-manager-ingress-shim Successfully created Certificate "web-ssl"
+ Normal Sync 28m loadbalancer-controller UrlMap "k8s2-um-1lt9dzcy-default-web-ingress-yteotwe4" updated
+ Warning Sync 24m (x16 over 28m) loadbalancer-controller Error syncing to GCP: error running load balancer syncing routine: loadbalancer 1lt9dzcy-default-web-ingress-yteotwe4 does not exist: googleapi: Error 404: The resource 'projects/your-project/global/sslCertificates/k8s2-cr-1lt9dzcy-4gjeakdb9n7k6ls7-e3b0c44298fc1c14' was not found, notFound
+ Normal Sync 34s (x16 over 65m) loadbalancer-controller Scheduled for sync
+```
+
+### Use cmctl to show the state of a Certificate and its associated resources
+
+> ℹ️ [Install `cmctl`](../../reference/cmctl.md) if you have not already done so.
+
+When you create a Certificate, cert-manager will create a collection of temporary resources
+which each contain information about the status of certificate signing process.
+You can read more about these in the [Certificate Lifecycle](../../concepts/certificate.md#certificate-lifecycle) section.
+Use the `cmctl status` command to view details of all these resources and all the associated Events and error messages.
+
+You may see some temporary errors, like:
+
+```console
+$ cmctl status certificate web-ssl
+Name: web-ssl
+Namespace: default
+Created at: 2022-07-14T17:30:06+01:00
+Conditions:
+ Ready: False, Reason: MissingData, Message: Issuing certificate as Secret does not contain a private key
+ Issuing: True, Reason: MissingData, Message: Issuing certificate as Secret does not contain a private key
+DNS Names:
+- www.example.com
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Issuing 4m37s cert-manager-certificates-trigger Issuing certificate as Secret does not contain a private key
+ Normal Generated 4m37s cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "web-ssl-8gsqc"
+ Normal Requested 4m37s cert-manager-certificates-request-manager Created new CertificateRequest resource "web-ssl-dblrj"
+Issuer:
+ Name: letsencrypt-staging
+ Kind: Issuer
+ Conditions:
+ Ready: True, Reason: ACMEAccountRegistered, Message: The ACME account was registered with the ACME server
+ Events:
+error: 'tls.crt' of Secret "web-ssl" is not set
+Not Before:
+Not After:
+Renewal Time:
+CertificateRequest:
+ Name: web-ssl-dblrj
+ Namespace: default
+ Conditions:
+ Approved: True, Reason: cert-manager.io, Message: Certificate request has been approved by cert-manager.io
+ Ready: False, Reason: Pending, Message: Waiting on certificate issuance from order default/web-ssl-dblrj-327645514: "pending"
+ Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal cert-manager.io 4m37s cert-manager-certificaterequests-approver Certificate request has been approved by cert-manager.io
+ Normal OrderCreated 4m37s cert-manager-certificaterequests-issuer-acme Created Order resource default/web-ssl-dblrj-327645514
+ Normal OrderPending 4m37s cert-manager-certificaterequests-issuer-acme Waiting on certificate issuance from order default/web-ssl-dblrj-327645514: ""
+Order:
+ Name: web-ssl-dblrj-327645514
+ State: pending, Reason:
+ Authorizations:
+ URL: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/3008789144, Identifier: www.example.com, Initial State: pending, Wildcard: false
+Challenges:
+- Name: web-ssl-dblrj-327645514-2671694319, Type: HTTP-01, Token: TKspp86xMjQzTvMVXWkezEA2sE2GSWjnld5Lt4X13ro, Key: TKspp86xMjQzTvMVXWkezEA2sE2GSWjnld5Lt4X13ro.f4bppCOm-jXasFGMKjpBE5aQlhiQBeTPIs0Lx822xao, State: pending, Reason: Waiting for HTTP-01 challenge propagation: did not get expected response when querying endpoint, expected "TKspp86xMjQzTvMVXWkezEA2sE2GSWjnld5Lt4X13ro.f4bppCOm-jXasFGMKjpBE5aQlhiQBeTPIs0Lx822xao" but got: Hello, world!
+Version: 1... (truncated), Processing: true, Presented: true
+```
+
+This is because cert-manager is performing a preflight check to see if the temporary challenge web server is reachable at the expected URL.
+Initially it will not be reachable, because cert-manager takes some time to deploy the temporary web server and the Ingress controller takes time to set up the new HTTP routing rules.
+Eventually you will see that the Certificate is Ready and signed:
+
+```console
+$ cmctl status certificate web-ssl
+Name: web-ssl
+Namespace: default
+Created at: 2022-07-14T17:30:06+01:00
+Conditions:
+ Ready: True, Reason: Ready, Message: Certificate is up to date and has not expired
+DNS Names:
+- www.example.com
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Issuing 31m cert-manager-certificates-trigger Issuing certificate as Secret does not contain a private key
+ Normal Generated 31m cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "web-ssl-8gsqc"
+ Normal Requested 31m cert-manager-certificates-request-manager Created new CertificateRequest resource "web-ssl-dblrj"
+ Normal Issuing 26m cert-manager-certificates-issuing The certificate has been successfully issued
+Issuer:
+ Name: letsencrypt-staging
+ Kind: Issuer
+ Conditions:
+ Ready: True, Reason: ACMEAccountRegistered, Message: The ACME account was registered with the ACME server
+ Events:
+Secret:
+ Name: web-ssl
+ Issuer Country: US
+ Issuer Organisation: (STAGING) Let's Encrypt
+ Issuer Common Name: (STAGING) Artificial Apricot R3
+ Key Usage: Digital Signature, Key Encipherment
+ Extended Key Usages: Server Authentication, Client Authentication
+ Public Key Algorithm: RSA
+ Signature Algorithm: SHA256-RSA
+ Subject Key ID: a51e3621f5c1138947810f27dce425b33c88cb16
+ Authority Key ID: de727a48df31c3a650df9f8523df57374b5d2e65
+ Serial Number: fa8bb0b603ca2cdbfdfb2872d05ee52cda10
+ Events:
+Not Before: 2022-07-14T16:34:52+01:00
+Not After: 2022-10-12T16:34:51+01:00
+Renewal Time: 2022-09-12T16:34:51+01:00
+```
+
+### Check that the SSL certificate has been copied to Google Cloud
+
+After cert-manager receives the signed Certificate it stores in the `web-ssl` Secret,
+and this in turn triggers the Google Cloud ingress controller to copy that SSL certificate to Google Cloud.
+You can see the certificate using the `gcloud` command, as follows:
+
+```console
+$ gcloud compute ssl-certificates list
+NAME TYPE CREATION_TIMESTAMP EXPIRE_TIME MANAGED_STATUS
+k8s2-cr-1lt9dzcy-4gjeakdb9n7k6ls7-a257650b5fefd174 SELF_MANAGED 2022-07-14T09:37:06.920-07:00 2022-10-12T08:34:51.000-07:00
+```
+
+And you can view its contents and check its attributes as follows:
+
+```console
+$ gcloud compute ssl-certificates describe k8s2-cr-1lt9dzcy-4gjeakdb9n7k6ls7-a257650b5fefd174 --format='value(certificate)' \
+ | openssl x509 -in - -noout -text
+...
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 04:9f:47:f1:cb:25:37:9b:86:a3:ef:bf:2e:77:3b:45:fc:1a
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C = US, O = Let's Encrypt, CN = R3
+ Validity
+ Not Before: Jul 14 17:11:15 2022 GMT
+ Not After : Oct 12 17:11:14 2022 GMT
+ Subject: CN = www.example.com
+```
+
+### Check the Google Cloud forwarding-rules
+
+After you add the TLS stanza to the Ingress object, you should eventually see a forwarding-rule for the SSL connection:
+
+```console
+$ gcloud compute forwarding-rules describe k8s2-fs-1lt9dzcy-default-web-ingress-yteotwe4 --global
+IPAddress: 34.120.159.51
+IPProtocol: TCP
+creationTimestamp: '2022-07-14T09:37:12.362-07:00'
+description: '{"kubernetes.io/ingress-name": "default/web-ingress"}'
+fingerprint: oBTg7dRaIqI=
+id: '2303318464959215831'
+kind: compute#forwardingRule
+labelFingerprint: 42WmSpB8rSM=
+loadBalancingScheme: EXTERNAL
+name: k8s2-fs-1lt9dzcy-default-web-ingress-yteotwe4
+networkTier: PREMIUM
+portRange: 443-443
+selfLink: https://www.googleapis.com/compute/v1/projects/your-project/global/forwardingRules/k8s2-fs-1lt9dzcy-default-web-ingress-yteotwe4
+target: https://www.googleapis.com/compute/v1/projects/your-project/global/targetHttpsProxies/k8s2-ts-1lt9dzcy-default-web-ingress-yteotwe4
+```
diff --git a/content/v1.12-docs/tutorials/istio-csr/example/example-cluster-issuer.yaml b/content/v1.12-docs/tutorials/istio-csr/example/example-cluster-issuer.yaml
new file mode 100644
index 00000000000..cb387c29d73
--- /dev/null
+++ b/content/v1.12-docs/tutorials/istio-csr/example/example-cluster-issuer.yaml
@@ -0,0 +1,46 @@
+# NB: We generally recommend using Issuers rather than ClusterIssuers with istio-csr.
+# Issuers are easier to scope, and therefore easier to reason about in terms of security.
+
+# SelfSigned issuers are useful for creating root certificates
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: selfsigned
+spec:
+ selfSigned: {}
+---
+# Request a self-signed certificate from our ClusterIssuer; this will function as our
+# issuing root certificate when we pass it into a CA ClusterIssuer.
+
+# It's generally fine to issue root certificates like this one with long lifespans;
+# the certificates which istio-csr issues will be much shorter lived.
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: istio-ca
+ namespace: cert-manager
+spec:
+ isCA: true
+ duration: 87600h # 10 years
+ secretName: istio-ca
+ commonName: istio-ca
+ privateKey:
+ algorithm: ECDSA
+ size: 256
+ subject:
+ organizations:
+ - cluster.local
+ - cert-manager
+ issuerRef:
+ name: selfsigned
+ kind: ClusterIssuer
+ group: cert-manager.io
+---
+# Create a CA issuer using our root. This will be the ClusterIssuer which istio-csr will use.
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: istio-ca
+spec:
+ ca:
+ secretName: istio-ca
diff --git a/content/v1.12-docs/tutorials/istio-csr/example/example-issuer.yaml b/content/v1.12-docs/tutorials/istio-csr/example/example-issuer.yaml
new file mode 100644
index 00000000000..4dd383dbcba
--- /dev/null
+++ b/content/v1.12-docs/tutorials/istio-csr/example/example-issuer.yaml
@@ -0,0 +1,45 @@
+# SelfSigned issuers are useful for creating root certificates
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: selfsigned
+ namespace: istio-system
+spec:
+ selfSigned: {}
+---
+# Request a self-signed certificate from our Issuer; this will function as our
+# issuing root certificate when we pass it into a CA Issuer.
+
+# It's generally fine to issue root certificates like this one with long lifespans;
+# the certificates which istio-csr issues will be much shorter lived.
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: istio-ca
+ namespace: istio-system
+spec:
+ isCA: true
+ duration: 87600h # 10 years
+ secretName: istio-ca
+ commonName: istio-ca
+ privateKey:
+ algorithm: ECDSA
+ size: 256
+ subject:
+ organizations:
+ - cluster.local
+ - cert-manager
+ issuerRef:
+ name: selfsigned
+ kind: Issuer
+ group: cert-manager.io
+---
+# Create a CA issuer using our root. This will be the Issuer which istio-csr will use.
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: istio-ca
+ namespace: istio-system
+spec:
+ ca:
+ secretName: istio-ca
diff --git a/content/v1.12-docs/tutorials/istio-csr/example/istio-config-getting-started.yaml b/content/v1.12-docs/tutorials/istio-csr/example/istio-config-getting-started.yaml
new file mode 100644
index 00000000000..b0b6e1ca4c0
--- /dev/null
+++ b/content/v1.12-docs/tutorials/istio-csr/example/istio-config-getting-started.yaml
@@ -0,0 +1,57 @@
+apiVersion: install.istio.io/v1alpha1
+kind: IstioOperator
+metadata:
+ namespace: istio-system
+spec:
+ profile: "demo"
+ hub: gcr.io/istio-release
+ meshConfig:
+ # Change the following line to configure the trust domain of the Istio cluster.
+ trustDomain: cluster.local
+ values:
+ global:
+ # Change certificate provider to cert-manager istio agent for istio agent
+ caAddress: cert-manager-istio-csr.cert-manager.svc:443
+ components:
+ pilot:
+ k8s:
+ env:
+ # Disable istiod CA Sever functionality
+ - name: ENABLE_CA_SERVER
+ value: "false"
+ overlays:
+ - apiVersion: apps/v1
+ kind: Deployment
+ name: istiod
+ patches:
+
+ # Mount istiod serving and webhook certificate from Secret mount
+ - path: spec.template.spec.containers.[name:discovery].args[-1]
+ value: "--tlsCertFile=/etc/cert-manager/tls/tls.crt"
+ - path: spec.template.spec.containers.[name:discovery].args[-1]
+ value: "--tlsKeyFile=/etc/cert-manager/tls/tls.key"
+ - path: spec.template.spec.containers.[name:discovery].args[-1]
+ value: "--caCertFile=/etc/cert-manager/ca/root-cert.pem"
+
+ - path: spec.template.spec.containers.[name:discovery].volumeMounts[-1]
+ value:
+ name: cert-manager
+ mountPath: "/etc/cert-manager/tls"
+ readOnly: true
+ - path: spec.template.spec.containers.[name:discovery].volumeMounts[-1]
+ value:
+ name: ca-root-cert
+ mountPath: "/etc/cert-manager/ca"
+ readOnly: true
+
+ - path: spec.template.spec.volumes[-1]
+ value:
+ name: cert-manager
+ secret:
+ secretName: istiod-tls
+ - path: spec.template.spec.volumes[-1]
+ value:
+ name: ca-root-cert
+ configMap:
+ defaultMode: 420
+ name: istio-ca-root-cert
diff --git a/content/v1.12-docs/tutorials/istio-csr/istio-csr.md b/content/v1.12-docs/tutorials/istio-csr/istio-csr.md
new file mode 100644
index 00000000000..32c5c1ae3e7
--- /dev/null
+++ b/content/v1.12-docs/tutorials/istio-csr/istio-csr.md
@@ -0,0 +1,276 @@
+---
+title: Securing the istio Service Mesh using cert-manager
+description: 'cert-manager tutorials: Securing the istio Service Mesh using cert-manager'
+---
+
+This guide will run through installing and using istio-csr from scratch. We'll use [kind](https://kind.sigs.k8s.io/) to create a new cluster locally in Docker, but this guide should work on any cluster as long as the relevant Istio [Platform Setup](https://istio.io/latest/docs/setup/platform-setup/) has been performed.
+
+Note that if you're following the Platform Setup guide for OpenShift, do not run the `istioctl install` command listed in that guide; we'll run our own command later.
+
+## Initial Setup
+
+You'll need the following tools installed on your machine:
+
+- [istioctl](https://github.com/istio/istio/releases/latest)
+- [kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) and [docker](https://docs.docker.com/get-docker/) (if you're using kind)
+- [helm](https://helm.sh/docs/intro/install/)
+- [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl)
+- [jq](https://stedolan.github.io/jq/download/)
+
+In addition, Istio must not already be installed in your cluster. Installing istio-csr _after_ Istio is not supported.
+
+## Creating the Cluster and Installing cert-manager
+
+Kind will automatically set up kubectl to point to the newly created cluster.
+
+We install cert-manager [using helm](https://cert-manager.io/docs/installation/helm/) here, but if you've got a preferred method you can install in any way.
+
+```console
+kind create cluster --image=docker.io/kindest/node:v1.22.4
+
+# Helm setup
+helm repo add jetstack https://charts.jetstack.io
+helm repo update
+
+# install cert-manager CRDs
+kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.crds.yaml
+
+# install cert-manager; this might take a little time
+helm install cert-manager jetstack/cert-manager \
+ --namespace cert-manager \
+ --create-namespace \
+ --version v1.8.0
+
+# We need this namespace to exist since our cert will be placed there
+kubectl create namespace istio-system
+```
+
+## Create a cert-manager Issuer and Issuing Certificate
+
+An Issuer tells cert-manager how to issue certificates; we'll create a self-signed root CA in our cluster because it's really simple to configure.
+
+The approach of using a locally generated root certificate would work in a production deployment too, but there are also several [other issuers](https://cert-manager.io/docs/configuration/) in cert-manager which could be used. Note that the ACME issuer **will not work**, since it can't add the required fields to issued certificates.
+
+There are also some comments on the [example-issuer](https://github.com/cert-manager/website/blob/master/content/docs/tutorials/istio-csr/example/example-issuer.yaml) providing a little more detail. Note also that this guide only uses `Issuer`s and not `ClusterIssuer`s - using a `ClusterIssuer` isn't a drop-in replacement, and in any case we recommend that production deployments use Issuers for easier access controls and scoping.
+
+```console
+kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/istio-csr/example/example-issuer.yaml
+```
+
+## Export the Root CA to a Local File
+
+While it's possible to configure Istio such that it can automatically "discover" the root CA, this can be dangerous in
+some specific scenarios involving other security holes, enabling [signer hijacking attacks](https://github.com/cert-manager/istio-csr/issues/103#issuecomment-923882792).
+
+As such, we'll export our Root CA and configure Istio later using that static cert.
+
+```console
+# Export our cert from the secret it's stored in, and base64 decode to get the PEM data.
+kubectl get -n istio-system secret istio-ca -ogo-template='{{index .data "tls.crt"}}' | base64 -d > ca.pem
+
+# Out of interest, we can check out what our CA looks like
+openssl x509 -in ca.pem -noout -text
+
+# Add our CA to a secret
+kubectl create secret generic -n cert-manager istio-root-ca --from-file=ca.pem=ca.pem
+```
+
+## Installing istio-csr
+
+istio-csr is best installed via Helm, and it should be simple and quick to install. There
+are a bunch of other configuration options for the helm chart, which you can check out [here](../../projects/istio-csr.md).
+
+```console
+helm repo add jetstack https://charts.jetstack.io
+helm repo update
+
+# We set a few helm template values so we can point at our static root CA
+helm install -n cert-manager cert-manager-istio-csr jetstack/cert-manager-istio-csr \
+ --set "app.tls.rootCAFile=/var/run/secrets/istio-csr/ca.pem" \
+ --set "volumeMounts[0].name=root-ca" \
+ --set "volumeMounts[0].mountPath=/var/run/secrets/istio-csr" \
+ --set "volumes[0].name=root-ca" \
+ --set "volumes[0].secret.secretName=istio-root-ca"
+
+# Check to see that the istio-csr pod is running and ready
+kubectl get pods -n cert-manager
+NAME READY STATUS RESTARTS AGE
+cert-manager-aaaaaaaaaa-11111 1/1 Running 0 9m46s
+cert-manager-cainjector-aaaaaaaaaa-22222 1/1 Running 0 9m46s
+cert-manager-istio-csr-bbbbbbbbbb-00000 1/1 Running 0 63s
+cert-manager-webhook-aaaaaaaaa-33333 1/1 Running 0 9m46s
+```
+
+## Installing Istio
+
+If you're not running on kind, you may need to do some additional [setup tasks](https://istio.io/latest/docs/setup/platform-setup/) before installing Istio.
+
+We use the `istioctl` CLI to install Istio, configured using a custom IstioOperator manifest.
+
+The custom manifest does the following:
+
+- Disables the CA server in istiod,
+- Ensures that Istio workloads request certificates from istio-csr,
+- Ensures that the istiod certificates and keys are mounted from the Certificate created when installing istio-csr.
+
+First we download our demo manifest and then we apply it.
+
+```console
+curl -sSL https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/istio-csr/example/istio-config-getting-started.yaml > istio-install-config.yaml
+```
+
+You may wish to inspect and tweak `istio-install-config.yaml` if you know what you're doing,
+but this manifest should work for example purposes as-is.
+
+If you set a custom `app.tls.trustDomain` when installing istio-csr via helm earlier, you'll need to ensure that
+value is repeated in `istio-install-config.yaml`.
+
+This final command will install Istio; the exact command you need might vary on different platforms,
+and will certainly vary on OpenShift.
+
+```console
+# This takes a little time to complete
+istioctl install -f istio-install-config.yaml
+
+# If you're on OpenShift, you need a different profile:
+# istioctl install --set profile=openshift -f istio-install-config.yaml
+```
+
+You will be prompted for input to confirm your choice of Istio profile:
+
+```console
+This will install the Istio 1.14.1 demo profile with ["Istio core" "Istiod" "Ingress gateways" "Egress gateways"] components into the cluster. Proceed? (y/N)
+```
+
+Confirm your selection by entering `y` into the console to proceed with installation.
+
+## Validating Install
+
+The following steps are option but can be followed to validate everything is hooked correctly:
+
+1. Deploy a sample application & watch for `certificaterequests.cert-manager.io` resources
+2. Verify `cert-manager` logs for new `certificaterequests` and responses
+3. Verify the CA Endpoint being used in a `istio-proxy` sidecar container
+4. Using `istioctl` to fetch the certificate info for the `istio-proxy` container
+
+To see this all in action, lets deploy a very simple sample application from the
+[Istio samples](https://github.com/istio/istio/tree/master/samples/httpbin).
+
+First set some environment variables whose values could be changed if needed:
+
+```shell
+# Set namespace for sample application
+export NAMESPACE=default
+# Set env var for the value of the app label in manifests
+export APP=httpbin
+# Grab the installed version of istio
+export ISTIO_VERSION=$(istioctl version -o json | jq -r '.meshVersion[0].Info.version')
+```
+
+We use the `default` namespace for simplicity, so let's label the namespace for Istio injection:
+
+```shell
+kubectl label namespace $NAMESPACE istio-injection=enabled --overwrite
+```
+
+In a separate terminal you should now follow the logs for `cert-manager`:
+
+```shell
+kubectl logs -n cert-manager $(kubectl get pods -n cert-manager -o jsonpath='{.items..metadata.name}' --selector app=cert-manager) --since 2m -f
+```
+
+In another separate terminal, lets watch the `istio-system` namespace for `certificaterequests`:
+
+```shell
+kubectl get certificaterequests.cert-manager.io -n istio-system -w
+```
+
+Now deploy the sample application `httpbin` in the labeled namespace. Note the use of a
+variable to match the manifest version to your installed Istio version:
+
+```shell
+kubectl apply -n $NAMESPACE -f https://raw.githubusercontent.com/istio/istio/$ISTIO_VERSION/samples/httpbin/httpbin.yaml
+```
+
+You should see something similar to the output here for `certificaterequests`:
+
+```
+NAME APPROVED DENIED READY ISSUER REQUESTOR AGE
+istio-ca-74bnl True True selfsigned system:serviceaccount:cert-manager:cert-manager 2d2h
+istiod-w9zh6 True True istio-ca system:serviceaccount:cert-manager:cert-manager 27m
+istio-csr-8ddcs istio-ca system:serviceaccount:cert-manager:cert-manager-istio-csr 0s
+istio-csr-8ddcs True istio-ca system:serviceaccount:cert-manager:cert-manager-istio-csr 0s
+istio-csr-8ddcs True True istio-ca system:serviceaccount:cert-manager:cert-manager-istio-csr 0s
+istio-csr-8ddcs True True istio-ca system:serviceaccount:cert-manager:cert-manager-istio-csr 0s
+```
+
+The key request being `istio-csr-8ddcs` in our example output. You should then check your
+`cert-manager` log output for two log lines with this request being "Approved" and "Ready":
+
+```
+I0113 16:51:59.186482 1 conditions.go:261] Setting lastTransitionTime for CertificateRequest "istio-csr-8ddcs" condition "Approved" to 2022-01-13 16:51:59.186455713 +0000 UTC m=+3507.098466775
+I0113 16:51:59.258876 1 conditions.go:261] Setting lastTransitionTime for CertificateRequest "istio-csr-8ddcs" condition "Ready" to 2022-01-13 16:51:59.258837897 +0000 UTC m=+3507.170859959
+```
+
+You should now see the application is running with both the application container and the sidecar:
+
+```shell
+~ kubectl get pods -n $NAMESPACE
+NAME READY STATUS RESTARTS AGE
+httpbin-74fb669cc6-559cg 2/2 Running 0 4m
+```
+
+To validate that the `istio-proxy` sidecar container has requested the certificate from the correct
+service, check the container logs:
+
+```shell
+kubectl logs $(kubectl get pod -n $NAMESPACE -o jsonpath="{.items...metadata.name}" --selector app=$APP) -c istio-proxy
+```
+
+You should see some early logs similar to this example:
+
+Istio v1.12 and earlier versions:
+
+```
+2022-01-13T16:51:58.495493Z info CA Endpoint cert-manager-istio-csr.cert-manager.svc:443, provider Citadel
+2022-01-13T16:51:58.495817Z info Using CA cert-manager-istio-csr.cert-manager.svc:443 cert with certs: var/run/secrets/istio/root-cert.pem
+2022-01-13T16:51:58.495941Z info citadelclient Citadel client using custom root cert: cert-manager-istio-csr.cert-manager.svc:443
+```
+
+Istio v1.13+
+
+```
+2022-01-13T16:51:58.495493Z info CA Endpoint cert-manager-istio-csr.cert-manager.svc:443, provider Citadel
+2022-01-13T16:51:58.495817Z info Using CA cert-manager-istio-csr.cert-manager.svc:443 cert with certs: var/run/secrets/istio/root-cert.pem
+2022-01-13T16:51:58.495941Z info citadelclient Citadel client using custom root cert: var/run/secrets/istio/root-cert.pem
+```
+
+Finally we can inspect the certificate being used in memory by Envoy. This one liner should return you the certificate being used:
+
+```shell
+istioctl proxy-config secret $(kubectl get pods -n $NAMESPACE -o jsonpath='{.items..metadata.name}' --selector app=$APP) -o json | jq -r '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | base64 --decode | openssl x509 -text -noout
+```
+
+In particular look for the following sections:
+
+```
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: O=cert-manager, O=cluster.local, CN=istio-ca
+ Validity
+ Not Before: Jan 13 16:51:59 2022 GMT
+ Not After : Jan 13 17:51:59 2022 GMT
+...
+ X509v3 Subject Alternative Name:
+ URI:spiffe://cluster.local/ns/default/sa/httpbin
+```
+
+You should see the relevant Trust Domain inside the Issuer. In the default case, it should be:
+`cluster.local` as above. Note that the SPIFFE URI may be different if you used a different
+namespace or application.
+
+## Clean up
+
+Assuming your running inside kind, you can simply remove the cluster:
+
+```shell
+kind delete cluster
diff --git a/content/v1.12-docs/tutorials/syncing-secrets-across-namespaces.md b/content/v1.12-docs/tutorials/syncing-secrets-across-namespaces.md
new file mode 100644
index 00000000000..95e8a6a5faa
--- /dev/null
+++ b/content/v1.12-docs/tutorials/syncing-secrets-across-namespaces.md
@@ -0,0 +1,143 @@
+---
+title: Syncing Secrets Across Namespaces
+description: |
+ Learn how to synchronize Kubernetes Secret resources across namespaces
+ using extensions such as: reflector, kubed and kubernetes-replicator.
+---
+
+It may be required for multiple components across namespaces to consume the same
+`Secret` that has been created by a single `Certificate`. The recommended way to
+do this is to use extensions such as:
+ - [reflector](https://github.com/emberstack/kubernetes-reflector) with support
+ for auto secret reflection
+ - [kubed](https://github.com/appscode/kubed) with its
+ [secret syncing feature](https://appscode.com/products/kubed/v0.11.0/guides/config-syncer/intra-cluster/)
+ - [kubernetes-replicator](https://github.com/mittwald/kubernetes-replicator) secret replication
+
+## Serving a wildcard to ingress resources in different namespaces (default SSL certificate)
+
+Most ingress controllers, including [ingress-nginx](https://kubernetes.github.io/ingress-nginx/user-guide/tls/#default-ssl-certificate), [Traefik](https://docs.traefik.io/https/tls/#default-certificate), and [Kong](https://docs.konghq.com/2.0.x/configuration/#ssl_cert) support specifying a _single_ certificate to be used for ingress resources which request TLS but do not specify `tls.[].secretName`. This is often referred to as a "default SSL certificate". As long as this is correctly configured, ingress resources in any namespace will be able to use a single wildcard certificate. Wildcard certificates are not supported with HTTP01 validation and require DNS01.
+
+Sample ingress snippet:
+
+```
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+#[...]
+spec:
+ rules:
+ - host: service.example.com
+ #[...]
+ tls:
+ - hosts:
+ - service.example.com
+ #secretName omitted to use default wildcard certificate
+```
+
+
+## Syncing arbitrary secrets across namespaces using extensions
+
+In order for the target Secret to be synced, you can use the `secretTemplate` field
+for annotating the generated secret with the extension specific annotation (See [CertificateSecretTemplate]).
+
+
+### Using `reflector`
+ The example below shows syncing a certificate's secret from the `cert-manager` namespace to multiple namespaces (i.e. `dev`, `staging`, `prod`).
+ Reflector will ensure that any namespace (existing or new) matching the allowed condition (with regex support) will get a copy of the certificate's secret and will keep it up to date.
+ You can also sync other secrets (different name) using `reflector` (consult the extension's [README](https://github.com/emberstack/kubernetes-reflector/blob/main/README.md))
+
+```yaml
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: source
+ namespace: cert-manager
+spec:
+ secretName: source-tls
+ commonName: source
+ issuerRef:
+ name: source-ca
+ kind: Issuer
+ group: cert-manager.io
+ secretTemplate:
+ annotations:
+ reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
+ reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "dev,staging,prod" # Control destination namespaces
+ reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true" # Auto create reflection for matching namespaces
+ reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "dev,staging,prod" # Control auto-reflection namespaces
+```
+
+
+### Using `kubed`
+ The example below shows syncing
+a certificate belonging to the `sandbox` Certificate from the `cert-manager`
+namespace, into the `sandbox` namespace.
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: sandbox
+ labels:
+ cert-manager-tls: sandbox # Define namespace label for kubed
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: sandbox
+ namespace: cert-manager
+spec:
+ secretName: sandbox-tls
+ commonName: sandbox
+ issuerRef:
+ name: sandbox-ca
+ kind: Issuer
+ group: cert-manager.io
+ secretTemplate:
+ annotations:
+ kubed.appscode.com/sync: "cert-manager-tls=sandbox" # Sync certificate to matching namespaces
+```
+
+
+### Using `kubernetes-replicator`
+Replicator supports both push- and pull-based replication. Push-based
+replication will "push out" the TLS secret into namespaces when new ones are
+created, or when the secret changes. Pull-based replication makes it possible
+to create an empty TLS secret in the destination namespace and select a
+"source" resource from which the data is replicated from. The following example
+shows the pull-based approach:
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: source
+ namespace: cert-manager
+spec:
+ secretName: source-tls
+ commonName: source
+ issuerRef:
+ name: source-ca
+ kind: Issuer
+ secretTemplate:
+ annotations:
+ replicator.v1.mittwald.de/replication-allowed: "true" # permit replication
+ replicator.v1.mittwald.de/replication-allowed-namespaces: "dev,test,prod-[0-9]*" # comma separated list of namespaces or regular expressions
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: tls-secret-replica
+ namespace: prod-1
+ annotations:
+ replicator.v1.mittwald.de/replicate-from: cert-manager/source-tls
+type: kubernetes.io/tls
+# Normally, we'd create an empty destination secret, but secrets of type
+# 'kubernetes.io/tls' are treated in a special way and need to have properties
+# data["tls.crt"] and data["tls.key"] to begin with, though they may be empty.
+data:
+ tls.key: ""
+ tls.crt: ""
+```
+
+[CertificateSecretTemplate]: ../reference/api-docs.md#cert-manager.io/v1.CertificateSecretTemplate
diff --git a/content/v1.12-docs/tutorials/venafi/venafi.md b/content/v1.12-docs/tutorials/venafi/venafi.md
new file mode 100644
index 00000000000..505276f626f
--- /dev/null
+++ b/content/v1.12-docs/tutorials/venafi/venafi.md
@@ -0,0 +1,586 @@
+---
+title: Securing Ingresses with Venafi
+description: 'cert-manager tutorials: Securing Ingress using Venafi Issuers'
+---
+
+This guide walks you through how to secure a Kubernetes
+[`Ingress`](https://kubernetes.io/docs/concepts/services-networking/ingress/)
+resource using the Venafi Issuer type.
+
+Whilst stepping through, you will learn how to:
+
+- Create an EKS cluster using [`eksctl`](https://github.com/weaveworks/eksctl)
+- Install cert-manager into the EKS cluster
+- Deploy [`nginx-ingress`](https://github.com/kubernetes/ingress-nginx) to
+ expose applications running in the cluster
+- Configure a Venafi Cloud issuer
+- Configure cert-manager to secure your application traffic
+
+While this guide focuses on EKS as a Kubernetes provisioner and Venafi
+as a Certificate issuer, the steps here should be generally re-usable for other
+Issuer types.
+
+## Prerequisites
+
+- An AWS account
+- `kubectl` installed
+- Access to a publicly registered DNS zone
+- A Venafi Cloud account and API credentials
+
+## Create an EKS cluster
+
+If you already have a running EKS cluster you can skip this step and move onto
+deploying cert-manager.
+
+[`eksctl`](https://eksctl.io/introduction/installation/) is a tool that makes it
+easier to deploy and manage an EKS cluster.
+
+Installation instructions for various platforms can be found in the
+[`eksctl` installation
+instructions](https://eksctl.io/introduction/installation/).
+
+Once installed, you can create a basic cluster by running:
+
+```
+$ eksctl create cluster
+```
+
+This process may take up to 20 minutes to complete. Complete instructions on
+using `eksctl` can be found in the [`eksctl` usage
+section](https://eksctl.io/usage/creating-and-managing-clusters/).
+
+Once your cluster has been created, you should verify that your cluster is
+running correctly by running the following command:
+
+```
+$ kubectl get pods --all-namespaces
+NAME READY STATUS RESTARTS AGE
+aws-node-8xpkp 1/1 Running 0 115s
+aws-node-tflxs 1/1 Running 0 118s
+coredns-694d9447b-66vlp 1/1 Running 0 23s
+coredns-694d9447b-w5bg8 1/1 Running 0 23s
+kube-proxy-4dvpj 1/1 Running 0 115s
+kube-proxy-tpvht 1/1 Running 0 118s
+```
+
+You should see output similar to the above, with all pods in a Running state.
+
+## Installing cert-manager
+
+There are no special requirements to note when installing cert-manager on EKS,
+so the regular [running on
+Kubernetes](../../installation/README.md) guides
+can be used to install cert-manager.
+
+Please walk through the installation guide and return to this step once you
+have validated cert-manager is deployed correctly.
+
+## Installing `ingress-nginx`
+
+A [Kubernetes ingress
+controller](https://eksctl.io/usage/creating-and-managing-clusters/) is designed
+to be the access point for HTTP and HTTPS traffic to the software running within
+your cluster. The [`ingress-nginx`](https://github.com/kubernetes/ingress-nginx)
+controller does this by providing an HTTP proxy service supported by your cloud
+provider's load balancer (in this case, a [Network Load Balancer
+(NLB)](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/introduction.html).
+
+You can get more details about `ingress-nginx` and how it works from the
+[documentation for `ingress-nginx`](https://kubernetes.github.io/ingress-nginx/).
+
+To deploy `ingress-nginx` using an ELB to expose the service, run the following:
+
+Deploy the AWS specific prerequisite manifest
+```bash
+$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.4.0/deploy/static/provider/aws/deploy.yaml
+```
+
+Deploy the 'generic' `ingress-nginx` manifest
+```bash
+$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/aws/deploy.yaml
+```
+
+You may have to wait up to 5 minutes for all the required components in your
+cluster and AWS account to become ready.
+
+You can run the following command to determine the address that Amazon has
+assigned to your NLB:
+
+```bash
+$ kubectl get service -n ingress-nginx
+NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
+ingress-nginx LoadBalancer 10.100.52.175 a8c2870a5a8a311e9a9a10a2e7af57d7-6c2ec8ede48726ab.elb.eu-west-1.amazonaws.com 80:31649/TCP,443:30567/TCP 4m10s
+```
+
+The *EXTERNAL-IP* field may say `` for a while. This indicates the NLB
+is still being created. Retry the command until an *EXTERNAL-IP* has been
+provisioned.
+
+Once the *EXTERNAL-IP* is available, you should run the following command to
+verify that traffic is being correctly routed to `ingress-nginx`:
+
+```
+$ curl http://a8c2870a5a8a311e9a9a10a2e7af57d7-6c2ec8ede48726ab.elb.eu-west-1.amazonaws.com/
+
+404 Not Found
+
+404 Not Found
+ openresty/1.15.8.1
+
+
+```
+
+Whilst the above message would normally indicate an error (the page not being
+found), in this instance it indicates that traffic is being correctly routed to
+the `ingress-nginx` service.
+
+> Note: Although the AWS Application Load Balancer (ALB) is a modern load
+> balancer offered by AWS that can can be provisioned from within EKS, at the
+> time of writing, the
+> [`alb-ingress-controller`](https://github.com/kubernetes-sigs/aws-alb-ingress-controller>)
+> is only capable of serving sites using certificates stored in AWS Certificate
+> Manager (ACM). Version 1.15 of Kubernetes should address multiple bug fixes
+> for this controller and allow for TLS termination support.
+
+## Configure your DNS records
+
+Now that our NLB has been provisioned, we should point our application's DNS
+records at the NLBs address.
+
+Go into your DNS provider's console and set a CNAME record pointing to your
+NLB.
+
+For the purposes of demonstration, we will assume in this guide you have created
+the following DNS entry:
+
+```
+example.com CNAME a8c2870a5a8a311e9a9a10a2e7af57d7-6c2ec8ede48726ab.elb.eu-west-1.amazonaws.com
+```
+
+As you progress through the rest of this tutorial, please replace `example.com`
+with your own registered domain.
+
+## Deploying a demo application
+
+For the purposes of this demo, we provide an example deployment which is a
+simple "hello world" website.
+
+First, create a new namespace that will contain your application:
+
+```bash
+$ kubectl create namespace demo
+namespace/demo created
+```
+
+Save the following YAML into a file named `demo-deployment.yaml`:
+
+```yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: hello-kubernetes
+ namespace: demo
+spec:
+ type: ClusterIP
+ ports:
+ - port: 80
+ targetPort: 8080
+ selector:
+ app: hello-kubernetes
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: hello-kubernetes
+ namespace: demo
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ app: hello-kubernetes
+ template:
+ metadata:
+ labels:
+ app: hello-kubernetes
+ spec:
+ containers:
+ - name: hello-kubernetes
+ image: paulbouwer/hello-kubernetes:1.5
+ resources:
+ requests:
+ cpu: 100m
+ memory: 100Mi
+ ports:
+ - containerPort: 8080
+```
+
+Then run:
+
+```bash
+kubectl apply -n demo -f demo-deployment.yaml
+```
+
+Note that the Service resource we deploy is of type `ClusterIP` and not
+`LoadBalancer`, as we will expose and secure traffic for this service using
+`ingress-nginx` that we deployed earlier.
+
+You should be able to see two Pods and one Service in the `demo` namespace:
+
+```bash
+kubectl get po,svc -n demo
+NAME READY STATUS RESTARTS AGE
+hello-kubernetes-66d45d6dff-m2lnr 1/1 Running 0 7s
+hello-kubernetes-66d45d6dff-qt2kb 1/1 Running 0 7s
+
+NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
+service/hello-kubernetes ClusterIP 10.100.164.58 80/TCP 7s
+```
+
+Note that we have not yet exposed this application to be accessible over the
+internet. We will expose the demo application to the internet in later steps.
+
+## Creating a Venafi Issuer resource
+
+cert-manager supports both Venafi TPP and Venafi Cloud.
+
+Please only follow one of the below sections according to where you want to
+retrieve your Certificates from.
+
+### Venafi TPP
+
+Assuming you already have a Venafi TPP server set up properly, you can create
+a Venafi Issuer resource that can be used to issue certificates.
+
+To do this, you need to make sure you have your TPP *username* and *password*.
+
+In order for cert-manager to be able to authenticate with your Venafi TPP
+server and set up an Issuer resource, you'll need to create a Kubernetes
+Secret containing your username and password:
+
+```bash
+$ kubectl create secret generic \
+ venafi-tpp-secret \
+ --namespace=demo \
+ --from-literal=username='YOUR_TPP_USERNAME_HERE' \
+ --from-literal=password='YOUR_TPP_PASSWORD_HERE'
+```
+
+We must then create a Venafi Issuer resource, which represents a certificate
+authority within Kubernetes.
+
+Save the following YAML into a file named `venafi-issuer.yaml`:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: venafi-issuer
+ namespace: demo
+spec:
+ venafi:
+ zone: "Default" # Set this to the Venafi policy zone you want to use
+ tpp:
+ url: https://venafi-tpp.example.com/vedsdk # Change this to the URL of your TPP instance
+ caBundle:
+ credentialsRef:
+ name: venafi-tpp-secret
+```
+
+Then run:
+
+```bash
+$ kubectl apply -n demo -f venafi-issuer.yaml
+```
+
+When you run the following command, you should see that the Status stanza of
+the output shows that the Issuer is Ready (i.e. has successfully validated
+itself with the Venafi TPP server).
+
+```bash
+$ kubectl describe issuer -n demo venafi-issuer
+
+ Status:
+ Conditions:
+ Last Transition Time: 2019-07-17T15:46:00Z
+ Message: Venafi issuer started
+ Reason: Venafi issuer started
+ Status: True
+ Type: Ready
+ Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Ready 14s cert-manager Verified issuer with Venafi server
+```
+
+### Venafi Cloud
+
+You can sign up for a Venafi Cloud account by visiting the [enrollment
+page](https://www.venafi.com/cloud).
+
+Once registered, you should fetch your API key by clicking your name in the top
+right of the control panel interface.
+
+In order for cert-manager to be able to authenticate with your Venafi Cloud
+account and set up an Issuer resource, you'll need to create a Kubernetes
+Secret containing your API key:
+
+```bash
+$ kubectl create secret generic \
+ venafi-cloud-secret \
+ --namespace=demo \
+ --from-literal=apikey=
+```
+
+We must then create a Venafi Issuer resource, which represents a certificate
+authority within Kubernetes.
+
+Save the following YAML into a file named `venafi-issuer.yaml`:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Issuer
+metadata:
+ name: venafi-issuer
+ namespace: demo
+spec:
+ venafi:
+ zone: "Default" # Set this to the Venafi policy zone you want to use
+ cloud:
+ apiTokenSecretRef:
+ name: venafi-cloud-secret
+ key: apikey
+```
+
+Then run:
+
+```bash
+$ kubectl apply -n demo -f venafi-issuer.yaml
+```
+
+When you run the following command, you should see that the Status stanza of
+the output shows that the Issuer is Ready (i.e. has successfully validated
+itself with the Venafi Cloud service).
+
+```bash
+$ kubectl describe issuer -n demo venafi-issuer
+...
+Status:
+ Conditions:
+ Last Transition Time: 2019-07-17T15:46:00Z
+ Message: Venafi issuer started
+ Reason: Venafi issuer started
+ Status: True
+ Type: Ready
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Ready 14s cert-manager Verified issuer with Venafi server
+```
+
+## Request a Certificate
+
+Now that the Issuer is configured and we have confirmed it has been set up
+correctly, we can begin requesting certificates which can be used by Kubernetes
+applications.
+
+Full information on how to specify and request Certificate resources can be
+found in the [Issuing certificates](../../usage/certificate.md) guide.
+
+For now, we will create a basic X.509 Certificate that is valid for our domain,
+`example.com`:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com-tls
+ namespace: demo
+spec:
+ secretName: example-com-tls
+ dnsNames:
+ - example.com
+ commonName: example.com
+ issuerRef:
+ name: venafi-issuer
+```
+
+Save this YAML into a file named `example-com-tls.yaml` and run:
+
+```bash
+$ kubectl apply -n demo -f example-com-tls.yaml
+```
+
+As long as you've ensured that the zone of your Venafi Cloud account (in our
+example, we use the "Default" zone) has been configured with a CA or contains a
+custom certificate, cert-manager can now take steps to populate the
+`example-com-tls` Secret with a certificate. It does this by identifying itself
+with Venafi Cloud using the API key, then requesting a certificate to match the
+specifications of the Certificate resource that we've created.
+
+You can run `kubectl describe` to check the progress of your Certificate:
+
+```bash
+$ kubectl describe certificate -n demo example-com-tls
+...
+Status:
+ Conditions:
+ Last Transition Time: 2019-07-17T17:43:01Z
+ Message: Certificate is up to date and has not expired
+ Reason: Ready
+ Status: True
+ Type: Ready
+ Not After: 2019-10-15T12:00:00Z
+Events:
+ Type Reason Age From Message
+ ---- ------ ---- ---- -------
+ Normal Issuing 33s cert-manager Requesting new certificate...
+ Normal GenerateKey 33s cert-manager Generated new private key
+ Normal Validate 33s cert-manager Validated certificate request against Venafi zone policy
+ Normal Requesting 33s cert-manager Requesting certificate from Venafi server...
+ Normal Retrieve 15s cert-manager Retrieved certificate from Venafi server
+ Normal CertIssued 15s cert-manager Certificate issued successfully
+```
+
+Once the Certificate has been issued, you should see events similar to above.
+
+You should then be able to see the certificate has been successfully stored in
+the Secret resource:
+
+```bash
+$ kubectl get secret -n demo example-com-tls
+NAME TYPE DATA AGE
+example-com-tls kubernetes.io/tls 3 2m47s
+
+$ kubectl get secret example-com-tls -o 'go-template={{index .data "tls.crt"}}' | \
+ base64 --decode | \
+ openssl x509 -noout -text
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0d:ce:bf:89:04:d4:41:83:f4:4c:32:66:64:fb:60:14
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, O=DigiCert Inc, CN=DigiCert Test SHA2 Intermediate CA-1
+ Validity
+ Not Before: Jul 17 00:00:00 2019 GMT
+ Not After : Oct 15 12:00:00 2019 GMT
+ Subject: C=US, ST=California, L=Palo Alto, O=Venafi Cloud, OU=SerialNumber, CN=example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:ad:2e:66:02:20:c9:b1:6a:00:63:70:4e:22:3c:
+ 45:63:6e:e7:fd:4c:94:7d:75:50:22:a2:01:72:99:
+ 9c:23:04:90:51:85:4d:47:32:e4:8b:ee:b1:ea:09:
+ 1a:de:97:5d:31:05:a2:73:73:4f:06:a3:b2:59:ee:
+ bc:30:f7:26:85:3d:b3:56:e4:c2:97:34:b6:ac:6d:
+ 65:7e:a2:4e:b4:ce:f2:0a:0a:4c:d7:32:d7:5a:18:
+ e8:69:c6:34:28:26:36:ef:c5:bc:ae:ba:ca:d2:46:
+ 3f:d4:61:39:66:8f:19:cc:d6:d6:10:77:af:51:93:
+ 1b:4d:f8:d1:10:19:ab:ac:b3:7b:0b:98:58:29:e6:
+ a9:ac:9f:7a:dc:63:0d:51:f5:bd:9f:f3:03:2e:b3:
+ 2d:2f:00:87:f4:e1:cd:5a:32:c6:d8:fb:49:c4:e7:
+ da:3f:0f:8f:bb:66:94:28:5d:99:fe:7c:f0:17:1b:
+ fd:3e:ed:dd:36:bf:8e:62:60:0c:85:7f:76:74:4b:
+ 37:d9:c2:e8:74:49:04:bf:f1:83:81:cc:4f:9b:f3:
+ 40:97:d4:dc:b6:d3:2d:dc:73:18:93:48:a5:8f:6c:
+ 57:7f:ec:62:c0:bc:c2:b0:e9:0a:51:2d:c4:b6:87:
+ 68:96:87:f8:9a:86:3c:6a:f1:01:ca:57:c4:07:e7:
+ b0:51
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Authority Key Identifier:
+ keyid:D6:4D:F9:39:60:6C:73:C3:22:F5:AD:30:0C:2F:A0:D5:CA:75:4A:2A
+
+ X509v3 Subject Key Identifier:
+ A3:B3:47:2C:41:5E:9C:B2:27:97:57:14:A4:2E:BA:8C:93:E7:01:65
+ X509v3 Subject Alternative Name:
+ DNS:example.com
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://crl3.digicert.com/DigiCertTestSHA2IntermediateCA1.crl
+
+ Full Name:
+ URI:http://crl4.digicert.com/DigiCertTestSHA2IntermediateCA1.crl
+
+ X509v3 Certificate Policies:
+ Policy: 2.16.840.1.114412.1.1
+ CPS: https://www.digicert.com/CPS
+
+ Authority Information Access:
+ OCSP - URI:http://ocsp.digicert.com
+ CA Issuers - URI:http://cacerts.test.digicert.com/DigiCertTestSHA2IntermediateCA1.crt
+
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ Signature Algorithm: sha256WithRSAEncryption
+ ae:d4:9c:8a:66:19:9e:7d:12:b7:05:c2:b6:33:b3:9c:a5:40:
+ 47:ab:34:8d:1b:0f:51:96:de:e9:46:5a:e4:16:10:43:56:bf:
+ fa:f8:64:f4:cb:53:39:5b:45:ca:7f:15:d9:59:25:21:23:c4:
+ 4d:dc:a7:f7:83:21:d2:3f:a8:0a:26:f4:ef:fa:1b:2b:7d:97:
+ 7e:28:f3:ca:cd:b2:c4:92:f3:92:27:7f:e0:f1:ac:d6:db:4c:
+ 10:8a:f8:6f:09:bb:b3:4f:19:06:aa:bb:74:1c:e0:51:42:f6:
+ 8c:7d:77:f7:80:a4:03:ab:a9:ae:ae:2b:89:17:af:2f:eb:f7:
+ 3d:61:7c:dd:e1:5d:d2:5a:c5:6a:f6:c8:92:4c:0a:b5:75:d1:
+ dd:39:f2:a7:a2:10:8c:6d:bf:ca:08:ad:b9:a9:df:e3:59:8f:
+ 64:16:3c:7e:8a:6e:27:fc:49:d7:06:f0:bd:94:15:f2:fd:0f:
+ 94:8a:b8:73:67:73:53:22:df:9d:36:e9:34:f9:2a:68:00:59:
+ 78:6d:2d:8f:a0:0f:13:af:bd:b3:aa:8c:37:c4:22:cf:23:fb:
+ 56:bc:4e:55:ae:3a:0a:e6:3e:b1:1a:22:71:7b:08:b8:00:41:
+ 14:26:f6:9b:9b:72:3f:eb:dc:dd:1b:db:a8:20:fd:54:75:ae:
+ 25:7f:80:e6
+```
+
+In the next step, we'll configure your application to actually use this new
+Certificate resource.
+
+## Exposing and securing your application
+
+Now that we have issued a Certificate, we can expose our application using a
+Kubernetes Ingress resource.
+
+Create a file named `application-ingress.yaml` and save the following in it,
+replacing `example.com` with your own domain name:
+
+```yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: frontend-ingress
+ namespace: demo
+ annotations:
+ kubernetes.io/ingress.class: "nginx"
+spec:
+ tls:
+ - hosts:
+ - example.com
+ secretName: example-com-tls
+ rules:
+ - host: example.com
+ http:
+ paths:
+ - path: /
+ pathType: Exact
+ backend:
+ service:
+ name: kuard
+ port:
+ number: 80
+```
+
+You can then apply this resource with:
+
+```bash
+$ kubectl apply -n demo -f application-ingress.yaml
+```
+
+Once this has been created, you should be able to visit your application at the
+configured URL, here `example.com`!
+
+Navigate to the address in your web browser and you should see the certificate
+obtained via Venafi being used to secure application traffic.
diff --git a/content/v1.12-docs/tutorials/zerossl/zerossl.md b/content/v1.12-docs/tutorials/zerossl/zerossl.md
new file mode 100644
index 00000000000..e10d997ec91
--- /dev/null
+++ b/content/v1.12-docs/tutorials/zerossl/zerossl.md
@@ -0,0 +1,180 @@
+---
+title: "Securing Ingresses with ZeroSSL"
+linkTitle: "Securing Ingresses with ZeroSSL"
+---
+
+# The ZeroSSL
+
+This guide walks you through how to secure a Kubernetes [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) resource using the ZeroSSL Issuer type.
+
+The ZeroSSL just like Let's Encrypt and its competitors allows to create free 90 days certificates. All is need is to create account at https://zerossl.com/. After that go to developer section and generate `EAB Credentials for ACME Clients`. You will need it later.
+
+
+`Please note!` \
+EAB credentials are not stored in your account, please make sure to note them somewhere. Each click on "Generate" will create a new set of credentials. Even if you create multiple credentials, all of them will remain functional.
+
+
+
+# Prerequisites
+
+- An AWS account
+- kubectl installed
+- Access to a publicly registered DNS zone
+- Kubernetes cluster, you can use AWS EKS
+- [ingress-nginx](https://kubernetes.github.io/ingress-nginx/) deployed and working inside cluster
+
+
+# Tutorial scenario:
+
+## Installing cert-manager
+
+Make sure you use cert-manager `1.8.2+`/`1.7.3+`. See [link](https://github.com/cert-manager/cert-manager/pull/5226) for more details.
+
+Please walk through the installation guide and return to this step once you
+have validated cert-manager is deployed correctly. Follow steps under [running on
+Kubernetes](../../installation/helm.md) to install in k8s.
+
+In order to automatically switch to the ZeroSSL we recommend setting default shim by adding the following configuration to values file.
+
+```yaml
+ingressShim:
+ defaultIssuerName: "zerossl-production"
+ defaultIssuerKind: "ClusterIssuer"
+
+installCRDs: true
+```
+
+Install it using helm:
+```
+helm upgrade --install --namespace cert-manager --version v1.8.2 cert-manager jetstack/cert-manager -f values.yaml
+```
+
+## Configure your DNS records
+
+The best way to manage DNS using AWS is by using Route53. Create AWS account with permissions to modify Route53 rules.
+
+## EAB secret
+Once you will get your credentials first step is to create seed with secrets. They are responsible for authenticating with your ZeroSSL account.
+
+```bash
+$ kubectl create secret generic \
+ zero-ssl-eabsecret \
+ --namespace=cert-manager \
+ --from-literal=secret='YOUR_ZEROSSL_EAB_HMAC_KEY'
+```
+
+### Another way of creating secret.
+
+Encode it in base64 first.
+```bash
+echo -n "YOUR_ZEROSSL_EAB_HMAC_KEY" | base64 -w 0
+```
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: zero-ssl-eabsecret
+data:
+ secret: YOUR_ENCODED_ZEROSSL_EAB_HMAC_KEY
+```
+```bash
+kubectl apply -f zero-ssl-eabsecret.yaml -n cert-manager
+```
+
+## Cluster issuer
+Then we must create the `ZeroSSL` `ClusterIssuer`, let's call it `zerossl-production`. In our case we are using AWS. See pre-conditions to provision all required elements.
+
+```yaml
+apiVersion: cert-manager.io/v1alpha2
+kind: ClusterIssuer
+metadata:
+ name: zerossl-production
+spec:
+ acme:
+ # ZeroSSL ACME server
+ server: https://acme.zerossl.com/v2/DV90
+ email: dummy-email@yopmail.com
+
+ # name of a secret used to store the ACME account private key
+ privateKeySecretRef:
+ name: zerossl-prod
+
+ # for each cert-manager new EAB credencials are required
+ externalAccountBinding:
+ keyID: YOUR_ZEROSSL_EAB_KEY_ID
+ keySecretRef:
+ name: zero-ssl-eabsecret
+ key: secret
+ keyAlgorithm: HS256
+
+ # ACME DNS-01 provider configurations to verify domain
+ solvers:
+ - selector: {}
+ dns01:
+ route53:
+ region: us-west-2
+ # optional if ambient credentials are available; see ambient credentials documentation
+ # see Route53 for >0 issue "letsencrypt.org" and change to >0 issue "sectigo.com"
+ accessKeyID: ACCESS_KEY_ID
+ secretAccessKeySecretRef:
+ name: route53-credentials-secret
+ key: secret-access-key
+
+```
+
+### Then run:
+
+```bash
+$ kubectl apply -n cert-manager -f zerossl-production.yaml
+```
+
+```bash
+$ kubectl describe Clusterissuer zerossl-prod
+
+Status:
+ Acme:
+ Last Registered Email: dummy-email@yopmail.com
+ Uri: https://acme.zerossl.com/v2/DV90/account/tXXX_NwSv15rlS_XXXX
+ Conditions:
+ Last Transition Time: 2021-09-09T17:03:26Z
+ Message: The ACME account was registered with the ACME server
+ Reason: ACMEAccountRegistered
+ Status: True
+ Type: Ready
+```
+
+### Please note!
+If this step failed and the ACME account is not registered please check if secrets in `zero-ssl-eabsecret` are correct.
+
+## Request a ingress certificate
+
+
+```yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: test-ingress
+ namespace: default
+spec:
+ rules:
+ - host: test.example.com
+ tls:
+ - secretName: secret-tls
+
+```
+
+Apply test-ingress:
+
+```bash
+kubectl apply -f ingress.yaml
+```
+
+You are set! Check your ingress.
+```bash
+kubectl describe ingress test-ingress -n default
+# check if tls is terminated using secret-tls
+
+openssl s_client -showcerts -connect test.example.com:443
+# verify server certificate and its chain
+```
diff --git a/content/v1.12-docs/usage/README.md b/content/v1.12-docs/usage/README.md
new file mode 100644
index 00000000000..b0d93801a94
--- /dev/null
+++ b/content/v1.12-docs/usage/README.md
@@ -0,0 +1,31 @@
+---
+title: Issuing Certificates
+description: 'cert-manager usage: Overview'
+---
+
+Once an [`Issuer`](../configuration/README.md) has been configured, you're ready to issue your first certificate!
+
+There are several use cases and methods for requesting certificates through cert-manager:
+
+- [Certificate Resources](./certificate.md): The simplest and most common method for
+ requesting signed certificates.
+- [Securing Ingress Resources](./ingress.md): A method to secure ingress resources
+ in your cluster.
+- [Securing OpenFaaS functions](https://docs.openfaas.com/reference/ssl/kubernetes-with-cert-manager/):
+ Secure your OpenFaaS services using cert-manager.
+- [Integration with Garden](https://docs.garden.io/guides/cert-manager-integration): Garden is a
+ developer tool for developing Kubernetes applications which has first class
+ support for integrating cert-manager.
+- [Securing Knative](https://knative.dev/docs/serving/using-auto-tls/): Secure
+ your Knative services with trusted HTTPS certificates.
+- [Enable mTLS on Pods with CSI](./csi.md): Using the cert-manager CSI
+ driver to provide unique keys and certificates that share the lifecycle of
+ pods.
+- [Securing Istio Gateway](https://istio.io/docs/tasks/traffic-management/ingress/ingress-certmgr/):
+ Secure your Istio Gateway in Kubernetes using cert-manager.
+- [Securing Istio Service Mesh](./istio.md): Using the cert-manager
+ [Istio](https://istio.io) integration, secure the mTLS PKI for each pod
+ through cert-manager managed certificates.
+- [Policy for cert-manager certificates](./approver-policy.md): Manage
+ what cert-manager certificates are able to be signed or rejected through
+ custom resource defined policy.
diff --git a/content/v1.12-docs/usage/approver-policy.md b/content/v1.12-docs/usage/approver-policy.md
new file mode 100644
index 00000000000..b712d04b7f3
--- /dev/null
+++ b/content/v1.12-docs/usage/approver-policy.md
@@ -0,0 +1,14 @@
+---
+title: Policy for cert-manager certificates
+description: 'cert-manager usage: approver-policy'
+---
+
+cert-manager [CertificateRequests](../concepts/certificaterequest.md) can be
+rejected from being signed by using the [approval
+API](../concepts/certificaterequest.md#approval).
+[approver-policy](https://github.com/cert-manager/approver-policy) is a
+cert-manager project that enables you to write policy to automatically manage
+this approval mechanism.
+
+Please read the [project page](../projects/approver-policy/README.md) for more
+information on how to install and use approver-policy.
diff --git a/content/v1.12-docs/usage/certificate.md b/content/v1.12-docs/usage/certificate.md
new file mode 100644
index 00000000000..17792853bfc
--- /dev/null
+++ b/content/v1.12-docs/usage/certificate.md
@@ -0,0 +1,368 @@
+---
+title: Certificate Resources
+description: 'cert-manager usage: Certificates'
+---
+
+In cert-manager, the [`Certificate`](../concepts/certificate.md) resource
+represents a human readable definition of a certificate request that is to be
+honored by an issuer which is to be kept up-to-date. This is the usual way that
+you will interact with cert-manager to request signed certificates.
+
+In order to issue any certificates, you'll need to configure an
+[`Issuer`](../configuration/README.md) or [`ClusterIssuer`](../configuration/README.md)
+resource first.
+
+## Creating Certificate Resources
+
+A `Certificate` resource specifies fields that are used to generate certificate
+signing requests which are then fulfilled by the issuer type you have
+referenced. `Certificates` specify which issuer they want to obtain the
+certificate from by specifying the `certificate.spec.issuerRef` field.
+
+A `Certificate` resource, for the `example.com` and `www.example.com` DNS names,
+`spiffe://cluster.local/ns/sandbox/sa/example` URI Subject Alternative Name,
+that is valid for 90 days and renews 15 days before expiry is below. It contains
+an exhaustive list of all options a `Certificate` resource may have however only
+a subset of fields are required as labelled.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com
+ namespace: sandbox
+spec:
+ # Secret names are always required.
+ secretName: example-com-tls
+
+ # secretTemplate is optional. If set, these annotations and labels will be
+ # copied to the Secret named example-com-tls. These labels and annotations will
+ # be re-reconciled if the Certificate's secretTemplate changes. secretTemplate
+ # is also enforced, so relevant label and annotation changes on the Secret by a
+ # third party will be overwriten by cert-manager to match the secretTemplate.
+ secretTemplate:
+ annotations:
+ my-secret-annotation-1: "foo"
+ my-secret-annotation-2: "bar"
+ labels:
+ my-secret-label: foo
+
+ duration: 2160h # 90d
+ renewBefore: 360h # 15d
+ subject:
+ organizations:
+ - jetstack
+ # The use of the common name field has been deprecated since 2000 and is
+ # discouraged from being used.
+ commonName: example.com
+ isCA: false
+ privateKey:
+ algorithm: RSA
+ encoding: PKCS1
+ size: 2048
+ usages:
+ - server auth
+ - client auth
+ # At least one of a DNS Name, URI, or IP address is required.
+ dnsNames:
+ - example.com
+ - www.example.com
+ uris:
+ - spiffe://cluster.local/ns/sandbox/sa/example
+ ipAddresses:
+ - 192.168.0.5
+ # Issuer references are always required.
+ issuerRef:
+ name: ca-issuer
+ # We can reference ClusterIssuers by changing the kind here.
+ # The default value is Issuer (i.e. a locally namespaced Issuer)
+ kind: Issuer
+ # This is optional since cert-manager will default to this value however
+ # if you are using an external issuer, change this to that issuer group.
+ group: cert-manager.io
+```
+
+The signed certificate will be stored in a `Secret` resource named
+`example-com-tls` in the same namespace as the `Certificate` once the issuer has
+successfully issued the requested certificate.
+
+If `secretTemplate` is present, annotations and labels set in this property
+will be copied over to `example-com-tls` secret. Both properties are optional.
+
+The `Certificate` will be issued using the issuer named `ca-issuer` in the
+`sandbox` namespace (the same namespace as the `Certificate` resource).
+
+> Note: If you want to create an `Issuer` that can be referenced by
+> `Certificate` resources in _all_ namespaces, you should create a
+> [`ClusterIssuer`](../concepts/issuer.md#namespaces) resource and set the
+> `certificate.spec.issuerRef.kind` field to `ClusterIssuer`.
+
+> Note: The `renewBefore` and `duration` fields must be specified using a [Go
+> `time.Duration`](https://golang.org/pkg/time/#ParseDuration) string format,
+> which does not allow the `d` (days) suffix. You must specify these values
+> using `s`, `m`, and `h` suffixes instead. Failing to do so without installing
+> the [`webhook component`](../concepts/webhook.md) can prevent cert-manager
+> from functioning correctly
+> [`#1269`](https://github.com/cert-manager/cert-manager/issues/1269).
+
+> Note: Take care when setting the `renewBefore` field to be very close to the
+> `duration` as this can lead to a renewal loop, where the `Certificate` is always
+> in the renewal period. Some `Issuers` set the `notBefore` field on their
+> issued X.509 certificates before the issue time to fix clock-skew issues,
+> leading to the working duration of a certificate to be less than the full
+> duration of the certificate. For example, Let's Encrypt sets it to be one hour
+> before issue time, so the actual _working duration_ of the certificate is 89
+> days, 23 hours (the _full duration_ remains 90 days).
+
+A full list of the fields supported on the Certificate resource can be found in
+the [API reference documentation](../reference/api-docs.md#cert-manager.io/v1.CertificateSpec).
+
+X.509 key usages and extended key usages
+
+cert-manager supports requesting certificates that have a number of [custom key
+usages](https://tools.ietf.org/html/rfc5280#section-4.2.1.3) and [extended key
+usages](https://tools.ietf.org/html/rfc5280#section-4.2.1.12). Although
+cert-manager will attempt to honor this request, some issuers will remove, add
+defaults, or otherwise completely ignore the request.
+The `CA` and `SelfSigned` `Issuer` will always return certificates matching the usages you have requested.
+
+Unless any number of usages has been set, cert-manager will set the default
+requested usages of `digital signature`, `key encipherment`, and `server auth`.
+cert-manager will not attempt to request a new certificate if the current
+certificate does not match the current key usage set.
+
+An exhaustive list of supported key usages can be found in the [API reference
+documentation](../reference/api-docs.md#cert-manager.io/v1.KeyUsage).
+
+Temporary Certificates while Issuing
+
+When requesting certificates [using the ingress-shim](./ingress.md), the
+component `ingress-gce`, if used, requires that a temporary certificate is
+present while waiting for the issuance of a signed certificate when serving. To
+facilitate this, if the following annotation:
+
+ ```yaml
+ cert-manager.io/issue-temporary-certificate: "true"
+ ```
+
+is present on the certificate, a self-signed temporary certificate will be
+present on the `Secret` until it is overwritten once the signed certificate has
+been issued.
+
+Adding the following annotation on an ingress will automatically set "issue-temporary-certificate" on the certificate:
+
+ ```yaml
+ acme.cert-manager.io/http01-edit-in-place: "true"
+ ```
+
+Rotation of the private key
+
+By default, the private key won't be rotated automatically. Using the setting
+`rotationPolicy: Always`, the private key Secret associated with a Certificate
+object can be configured to be rotated as soon as an action triggers the
+reissuance of the Certificate object (see
+[Actions that will trigger a rotation of the private key](#actions-triggering-private-key-rotation) below).
+
+With `rotationPolicy: Always`, cert-manager waits until the Certificate
+object is correctly signed before overwriting the `tls.key` file in the
+Secret.
+
+With this setting, you can expect **no downtime** if your application can detect
+changes to the mounted `tls.crt` and `tls.key` and reload them gracefully or
+automatically restart.
+
+If your application only loads the private key and signed certificate once
+at start up, the new certificate won't immediately be served by your
+application, and you will want to either manually restart your pod with
+`kubectl rollout restart`, or automate the action by running
+[wave](https://github.com/wave-k8s/wave). Wave is a Secret controller that
+makes sure deployments get restarted whenever a mounted Secret changes.
+
+
+
+Re-use of private keys
+
+Some issuers, like the built-in [Venafi
+issuer](../configuration/venafi.md), may disallow re-using private keys.
+If this is the case, you must explicitly configure the `rotationPolicy:
+Always` setting for each of your Certificate objects accordingly.
+
+
+
+In the following example, the certificate has been set with
+`rotationPolicy: Always`:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+spec:
+ secretName: my-cert-tls
+ privateKey:
+ rotationPolicy: Always # 🔰 Here.
+```
+
+Actions that will trigger a rotation of the private key
+
+Setting the `rotationPolicy: Always` won't rotate the private key immediately.
+In order to rotate the private key, the certificate objects must be reissued. A
+certificate object is reissued under the following circumstances:
+
+- when the X.509 certificate is nearing expiry, which is when the Certificate's
+ `status.renewalTime` is reached;
+- when a change is made to one of the following fields on the Certificate's
+ spec: `commonName`, `dnsNames`, `ipAddresses`, `uris`, `emailAddresses`,
+ `subject`, `isCA`, `usages`, `duration` or `issuerRef`;
+- when a reissuance is manually triggered with the following:
+ ```sh
+ cmctl renew cert-1
+ ```
+ Note that the above command requires [cmctl](../reference/cmctl.md#renew).
+
+
+
+**❌** Deleting the Secret resource associated with a Certificate resource is
+**not a recommended solution** for manually rotating the private key. The
+recommended way to manually rotate the private key is to trigger the reissuance
+of the Certificate resource with the following command (requires
+[`cmctl`](../reference/cmctl.md#renew)):
+
+```sh
+cmctl renew cert-1
+```
+
+
+
+### The `rotationPolicy` setting
+
+The possible values for `rotationPolicy` are:
+
+| Value | Description |
+| ---------------------- | ------------------------------------------------------------- |
+| `Never` (default) | cert-manager reuses the existing private key on each issuance |
+| `Always` (recommended) | cert-manager regenerates a new private key on each issuance |
+
+With `rotationPolicy: Never`, a private key is only generated if one does not
+already exist in the target Secret resource (using the `tls.key` key). All
+further issuances will re-use this private key. This is the default in order to
+maintain compatibility with previous releases.
+
+With `rotationPolicy: Always`, a new private key will be generated each time an
+action triggers the reissuance of the certificate object (see [Actions that will
+trigger a rotation of the private key](#actions-triggering-private-key-rotation)
+above). Note that if the private key secret already exists when creating the
+certificate object, the existing private key will not be used, since the
+rotation mechanism also includes the initial issuance.
+
+
+
+👉 We recommend that you configure `rotationPolicy: Always` on your Certificate
+resources. Rotating both the certificate and the private key simultaneously
+prevents the risk of issuing a certificate with an exposed private key. Another
+benefit to renewing the private key regularly is to let you be confident that
+the private key rotation can be done in case of emergency. More generally, it is
+a good practice to be rotating the keys as often as possible, reducing the risk
+associated with compromised keys.
+
+
+
+## Cleaning up Secrets when Certificates are deleted
+
+By default, cert-manager does not delete the `Secret` resource containing the signed certificate when the corresponding `Certificate` resource is deleted.
+This means that deleting a `Certificate` won't take down any services that are currently relying on that certificate, but the certificate will no longer be renewed.
+The `Secret` needs to be manually deleted if it is no longer needed.
+
+If you would prefer the `Secret` to be deleted automatically when the `Certificate` is deleted, you need to configure your installation to pass the `--enable-certificate-owner-ref` flag to the controller.
+
+## Renewal
+
+cert-manager will automatically renew `Certificate`s. It will calculate _when_ to renew a `Certificate` based on the issued X.509 certificate's duration and a 'renewBefore' value which specifies _how long_ before expiry a certificate should be renewed.
+
+`spec.duration` and `spec.renewBefore` fields on a `Certificate` can be used to specify an X.509 certificate's duration and a 'renewBefore' value. Default value for `spec.duration` is 90 days. Some issuers might be configured to only issue certificates with a set duration, so the actual duration may be different.
+Minimum value for `spec.duration` is 1 hour and minimum value for `spec.renewBefore` is 5 minutes.
+It is also required that `spec.duration` > `spec.renewBefore`.
+
+Once an X.509 certificate has been issued, cert-manager will calculate the renewal time for the `Certificate`. By default this will be 2/3 through the X.509 certificate's duration. If `spec.renewBefore` has been set, it will be `spec.renewBefore` amount of time before expiry. cert-manager will set `Certificate`'s `status.RenewalTime` to the time when the renewal will be attempted.
+
+## Additional Certificate Output Formats
+
+
+
+⛔️ The additional certificate output formats feature is currently in an
+_experimental_ alpha state, and is subject to breaking changes or complete
+removal in future releases. This feature is only enabled by adding it to the
+`--feature-gates` flag on the cert-manager controller and webhook components:
+
+```bash
+--feature-gates=AdditionalCertificateOutputFormats=true
+```
+
+
+
+`additionalOutputFormats` is a field on the Certificate `spec` that allows
+specifying additional supplementary formats of issued certificates and their
+private key. There are currently two supported additional output formats:
+`CombinedPEM` and `DER`. Both output formats can be specified on the same
+Certificate.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+spec:
+ ...
+ secretName: my-cert-tls
+ additionalOutputFormats:
+ - type: CombinedPEM
+ - type: DER
+
+# Results in:
+
+apiVersion: v1
+kind: Secret
+metadata:
+ name: my-cert-tls
+type: kubernetes.io/tls
+data:
+ ca.crt:
+ tls.key:
+ tls.crt:
+ tls-combined.pem:
+ key.der:
+```
+
+#### `CombinedPEM`
+
+The `CombinedPEM` type will create a new key entry in the resulting
+Certificate's Secret `tls-combined.pem`. This entry will contain the PEM encoded
+private key, followed by at least one new line character, followed by the PEM
+encoded signed certificate chain-
+
+```text
+ + "\n" +
+```
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: my-cert-tls
+type: kubernetes.io/tls
+data:
+ tls-combined.pem:
+ ...
+```
+
+#### `DER`
+
+The `DER` type will create a new key entry in the resulting Certificate's Secret
+`key.der`. This entry will contain the DER binary format of the private key.
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: my-cert-tls
+type: kubernetes.io/tls
+data:
+ key.der:
+ ...
+```
diff --git a/content/v1.12-docs/usage/csi.md b/content/v1.12-docs/usage/csi.md
new file mode 100644
index 00000000000..5e1a6124b0b
--- /dev/null
+++ b/content/v1.12-docs/usage/csi.md
@@ -0,0 +1,85 @@
+---
+title: CSI Driver
+description: 'cert-manager usage: CSI driver'
+---
+
+## Enabling mTLS of Pods using the cert-manager CSI Driver
+
+A [Container Storage Interface (CSI)
+driver](../projects/csi-driver.md) has been created to
+facilitate mTLS of Pods running inside your cluster through use of cert-manager.
+Using this driver will ensure that the private key and corresponding signed
+certificate will be unique to each Pod and will be stored on disk to the node
+that the Pod is scheduled to. The life cycle of the certificate key pair matches
+that of the Pod meaning that they will be created at Pod creation, and destroyed
+during termination. This driver also handles renewal on live certificates on the
+fly.
+
+A [CSI
+driver](https://github.com/container-storage-interface/spec/blob/master/spec.md)
+is a storage plugin that is deployed into your Kubernetes cluster that can
+honor volume requests specified on Pods, just like those enabled by default such as
+the `Secret`, `ConfigMap`, or `hostPath` volume drivers. In the case of the cert-manager
+CSI driver, it makes use of the ephemeral volume type, made beta as of
+[`v1.16`](https://kubernetes.io/docs/concepts/storage/volumes/#csi-ephemeral-volumes)
+and as such will only work from the Kubernetes version `v1.16`. An ephemeral
+volumes means that the volume is created and destroyed as the Pod is created and
+terminated, as well as specifying the volume attributes, without the need of a
+`PersistentVolume`. This gives the feature of not only having unique
+certificates and keys per Pod, where the private key never leaves the hosts
+node, but that the desired certificate for that Pod template can be defined in
+line with the deployment spec.
+
+> **Warning**: Use of the CSI driver is mostly intended for supporting a PKI of
+> your cluster and facilitating mTLS, and as such, a private Certificate
+> Authority issuer should be used - CA, Vault, and perhaps Venafi, or other
+> external issuers. It is *not* recommended to use public Certificate
+> Authorities, for example Let's Encrypt, which hold strict rate limits on the
+> number of certificates that can be issued for a single domain. Like Pods,
+> these certificate key pairs are designed to be non-immutable and can be
+> created and destroyed at any time during normal operation.
+
+## How Does it Work?
+
+The CSI specification is a protocol and standard for building storage drivers
+for container orchestration platforms with the intention that a single driver
+may be ported across multiple platforms and outlines a consistent specification
+to how drivers should behave from an infrastructure perspective. Since
+cert-manager is designed to only be run with a Kubernetes cluster, so too does
+the cert-manager CSI driver.
+
+The driver should be deployed as a
+[DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/)
+which means a single instance of the driver may be run on each node. The driver
+will not work when running multiple instances on a single node. The set of nodes
+that the driver runs on can be restricted using the
+[`nodeSelector`](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/)
+in its Pod template.
+
+When a Pod is scheduled to a node with a cert-manager CSI volume specified, the
+[`Kubelet`](https://kubernetes.io/docs/concepts/overview/components/#kubelet)
+running on that node will send a `NodePublishVolume` call to the driver on that
+node, containing that Pods information as well as the attributes detailed from
+the in-line volume attributes. From this, the driver will generate a private key
+as well as a certificate request based upon that key using information built
+from the volume attributes. The driver will create a `CertificateRequest`
+resource in the same namespace in the Pod that, if valid, cert-manager will
+return a signed certificate.
+
+The resulting signed certificate and generated key will be written to that
+node's file system to be mounted to the Pods file system. Since the driver needs
+access to the nodes file system it must be made privileged. Once mounted, the
+Pod will begin execution with the unique private key and certificate available in
+its file system, as defined by its mount path.
+
+By default, the driver will keep track of certificates created in order to
+monitor when they should be marked for renewal. When this happens, the driver
+will request for a new signed certificate, and when successful, will simply
+overwrite the existing certificate in path.
+
+When the Pod is marked for termination, the `NodeUnpublishVolume` call is made
+to the node's driver which in turn destroys the certificate and key from the
+nodes file system.
+
+The CSI driver is able to recover its full state in the event the its Pod being
+terminated.
diff --git a/content/v1.12-docs/usage/gateway.md b/content/v1.12-docs/usage/gateway.md
new file mode 100644
index 00000000000..9aa05cf1a17
--- /dev/null
+++ b/content/v1.12-docs/usage/gateway.md
@@ -0,0 +1,402 @@
+---
+title: Securing gateway.networking.k8s.io Gateway Resources
+description: 'cert-manager usage: Kubernetes Gateways'
+---
+
+**FEATURE STATE**: cert-manager 1.5 [alpha]
+
+
+
+📌 This page focuses on automatically creating Certificate resources by
+annotating Kubernetes Gateway resource. If you are looking for using an ACME Issuer along
+with HTTP-01 challenges using the Kubernetes Gateway API, see [ACME
+HTTP-01](../configuration/acme/http01/README.md).
+
+
+
+
+
+🚧 cert-manager 1.8+ is tested with v1alpha2 Kubernetes Gateway API. It should also work
+with v1beta1 because of resource conversion, but has not been tested with it.
+
+
+
+cert-manager can generate TLS certificates for Gateway resources. This is
+configured by adding annotations to a Gateway and is similar to the process for
+[Securing Ingress Resources](../usage/ingress.md).
+
+The Gateway resource is part of the [Gateway API][gwapi], a set of CRDs that you
+install on your Kubernetes cluster and which provide various improvements over
+the Ingress API.
+
+[gwapi]: https://gateway-api.sigs.k8s.io
+
+The Gateway resource holds the TLS configuration, as illustrated in the
+following diagram (source: https://gateway-api.sigs.k8s.io):
+
+![Gateway vs. HTTPRoute](/images/gateway-roles.png)
+
+
+
+📌 This feature requires the installation of the [Gateway API bundle](https://gateway-api.sigs.k8s.io/guides/#installing-a-gateway-controller) and passing a
+feature flag to the cert-manager controller.
+
+To install v1.5.1 Gateway API bundle (Gateway CRDs and webhook), run the following command:
+
+```sh
+kubectl apply -f "https://github.com/kubernetes-sigs/gateway-api/releases/download/v0.5.1/standard-install.yaml"
+```
+
+To enable the feature in cert-manager, turn on the `GatewayAPI` feature gate:
+
+- If you are using Helm:
+
+ ```sh
+ helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager \
+ --set "extraArgs={--feature-gates=ExperimentalGatewayAPISupport=true}"
+ ```
+
+- If you are using the raw cert-manager manifests, add the following flag to the
+ cert-manager controller Deployment:
+
+ ```yaml
+ args:
+ - --feature-gates=ExperimentalGatewayAPISupport=true
+ ```
+
+The Gateway API CRDs should either be installed before cert-manager starts or
+the cert-manager Deployment should be restarted after installing the Gateway API
+CRDs. This is important because some of the cert-manager components only perform
+the Gateway API check on startup. You can restart cert-manager with the
+following command:
+
+```sh
+kubectl rollout restart deployment cert-manager -n cert-manager
+```
+
+
+
+The annotations `cert-manager.io/issuer` or `cert-manager.io/cluster-issuer`
+tell cert-manager to create a Certificate for a Gateway. For example, the
+following Gateway will trigger the creation of a Certificate with the name
+`example-com-tls`:
+
+```yaml
+apiVersion: gateway.networking.k8s.io/v1alpha2
+kind: Gateway
+metadata:
+ name: example
+ annotations:
+ cert-manager.io/issuer: foo
+spec:
+ gatewayClassName: foo
+ listeners:
+ - name: http
+ hostname: example.com
+ port: 443
+ protocol: HTTPS
+ allowedRoutes:
+ namespaces:
+ from: All
+ tls:
+ mode: Terminate
+ certificateRefs:
+ - name: example-com-tls
+```
+
+A few moments later, cert-manager will create a Certificate. The Certificate is
+named after the Secret name `example-com-tls`. The `dnsNames` field is set with
+the `hostname` field from the Gateway spec.
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com-tls
+spec:
+ issuerRef:
+ name: my-issuer
+ kind: Issuer
+ group: cert-manager.io
+ dnsNames:
+ - example.com # ✅ Copied from the `hostname` field.
+ secretName: example-com-tls
+```
+
+
+
+🚧 this mechanism can only be used to create Secrets in the same namespace as the `Gateway`, see [`cert-manager#5610`](https://github.com/cert-manager/cert-manager/issues/5610)
+
+
+
+## Use cases
+
+### Generate TLS certs for selected TLS blocks
+
+cert-manager skips any listener block that cannot be used for generating a
+Certificate. For a listener block to be used for creating a Certificate, it must
+meet the following requirements:
+
+| Field | Requirement |
+|--------------------------------|-------------------------------------------------------------|
+| `tls.hostname` | Must not be empty. |
+| `tls.mode` | Must be set to `Terminate`. `Passthrough` is not supported. |
+| `tls.certificateRef.name` | Cannot be left empty. |
+| `tls.certificateRef.kind` | If specified, must be set to `Secret`. |
+| `tls.certificateRef.group` | If specified, must be set to `core`. |
+| `tls.certificateRef.namespace` | If specified, must be the same as the `Gateway`. |
+
+In the following example, the first four listener blocks will not be used to
+generate Certificate resources:
+
+```yaml
+apiVersion: gateway.networking.k8s.io/v1alpha2
+kind: Gateway
+metadata:
+ name: my-gateway
+ namespace: default
+ annotations:
+ cert-manager.io/issuer: my-issuer
+spec:
+ listeners:
+ # ❌ Missing "tls" block, the following listener is skipped.
+ - hostname: example.com
+
+ # ❌ Missing "hostname", the following listener is skipped.
+ - tls:
+ certificateRefs:
+ - name: example-com-tls
+ kind: Secret"
+ group: core
+
+ # ❌ "mode: Passthrough" is not supported, the following listener is skipped.
+ - hostname: example.com
+ tls:
+ mode: Passthrough
+ certificateRefs:
+ - name: example-com-tls
+ kind: Secret
+ group: core
+
+ # ❌ Cross-namespace secret references are not supported, the following listener is skipped.
+ - hostname: foo.example.com
+ port: 443
+ protocol: HTTPS
+ allowedRoutes:
+ namespaces:
+ from: All
+ tls:
+ mode: Terminate
+ certificateRefs:
+ - name: example-com-tls
+ kind: Secret
+ group: core
+ namespace: other-namespace
+
+ # ✅ The following listener is valid.
+ - hostname: foo.example.com # ✅ Required.
+ port: 443
+ protocol: HTTPS
+ allowedRoutes:
+ namespaces:
+ from: All
+ tls:
+ mode: Terminate # ✅ Required. "Terminate" is the only supported mode.
+ certificateRefs:
+ - name: example-com-tls # ✅ Required.
+ kind: Secret # ✅ Required. "Secret" is the only valid value.
+ group: core # ✅ Required. "core" is the only valid value.
+```
+
+cert-manager has skipped over the first four listener blocks and has created a
+single Certificate named `example-com-tls` for the last listener block:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com-tls
+spec:
+ issuerRef:
+ name: my-issuer
+ kind: Issuer
+ group: cert-manager.io
+ dnsNames:
+ - foo.example.com
+ secretName: example-com-tls
+```
+
+### Two listeners with the same Secret name
+
+The same Secret name can be re-used in multiple TLS blocks, regardless of the
+hostname. Let us imagine that you have these two listeners:
+
+```yaml
+apiVersion: gateway.networking.k8s.io/v1alpha2
+kind: Gateway
+metadata:
+ name: example
+ annotations:
+ cert-manager.io/issuer: my-issuer
+spec:
+ gatewayClassName: foo
+ listeners:
+ # Listener 1.
+ - hostname: example.com
+ port: 443
+ protocol: HTTPS
+ routes:
+ kind: HTTPRoute
+ parentRefs:
+ - name: example
+ kind: Gateway
+ tls:
+ mode: Terminate
+ certificateRefs:
+ - name: example-com-tls
+ kind: Secret
+ group: core
+
+ # Listener 2: Same Secret name as Listener 1, with a different hostname.
+ - hostname: *.example.com
+ port: 443
+ protocol: HTTPS
+ routes:
+ kind: HTTPRoute
+ parentRefs:
+ - name: example
+ kind: Gateway
+ tls:
+ mode: Terminate
+ certificateRefs:
+ - name: example-com-tls
+ kind: Secret
+ group: core
+
+ # Listener 3: also same Secret name, except the hostname is also the same.
+ - hostname: *.example.com
+ port: 8443
+ protocol: HTTPS
+ routes:
+ kind: HTTPRoute
+ parentRefs:
+ - name: example
+ kind: Gateway
+ tls:
+ mode: Terminate
+ certificateRefs:
+ - name: example-com-tls
+ kind: Secret
+ group: core
+
+ # Listener 4: different Secret name.
+ - hostname: site.org
+ port: 443
+ protocol: HTTPS
+ routes:
+ kind: HTTPRoute
+ parentRefs:
+ - name: example
+ kind: Gateway
+ tls:
+ mode: Terminate
+ certificateRefs:
+ - name: site-org-tls
+ kind: Secret
+ group: core
+```
+
+cert-manager will create two Certificates since two Secret names are used:
+`example-com-tls` and `site-org-tls`. Note the Certificate's `dnsNames` contains
+a single occurrence of `*.example.com ` for both listener 2 and 3 (the
+`hostname` values are de-duplicated).
+
+The two Certificates look like this:
+
+```yaml
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: example-com-tls
+spec:
+ issuerRef:
+ name: my-issuer
+ kind: Issuer
+ group: cert-manager.io
+ dnsNames:
+ - example.com # From listener 1.
+ - *.example.com # From listener 2 and 3.
+ secretName: example-com-tls
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: site-org-tls
+spec:
+ issuerRef:
+ name: my-issuer
+ kind: Issuer
+ group: cert-manager.io
+ dnsNames:
+ - site.org # From listener 4.
+ secretName: site-org-tls
+```
+
+## Supported Annotations
+
+If you are migrating to Gateway resources from Ingress resources, be aware that
+there are some differences between [the annotations for Ingress resources](./ingress.md#supported-annotations)
+versus the annotations for Gateway resources.
+
+The Gateway resource supports the following annotations for generating
+Certificate resources:
+
+- `cert-manager.io/issuer`: the name of an Issuer to acquire the certificate
+ required for this Gateway. The Issuer _must_ be in the same namespace as the
+ Gateway resource.
+
+- `cert-manager.io/cluster-issuer`: the name of a ClusterIssuer to acquire the
+ Certificate required for this Gateway. It does not matter which namespace your
+ Gateway resides, as `ClusterIssuers` are non-namespaced resources.
+
+- `cert-manager.io/issuer-kind`: the kind of the external issuer resource, for
+ example `AWSPCACIssuer`. This is only necessary for out-of-tree issuers.
+
+- `cert-manager.io/issuer-group`: the API group of the external issuer
+ controller, for example `awspca.cert-manager.io`. This is only necessary for
+ out-of-tree issuers.
+
+- `cert-manager.io/common-name`: (optional) this annotation allows you to
+ configure `spec.commonName` for the Certificate to be generated.
+
+- ` cert-manager.io/duration`: (optional) this annotation allows you to
+ configure `spec.duration` field for the Certificate to be generated.
+
+- `cert-manager.io/renew-before`: (optional) this annotation allows you to
+ configure `spec.renewBefore` field for the Certificate to be generated.
+
+- `cert-manager.io/usages`: (optional) this annotation allows you to configure
+ `spec.usages` field for the Certificate to be generated. Pass a string with
+ comma-separated values i.e "key agreement,digital signature, server auth"
+
+- `cert-manager.io/revision-history-limit`: (optional) this annotation allows you to
+ configure `spec.revisionHistoryLimit` field to limit the number of CertificateRequests to be kept for a Certificate.
+ Minimum value is 1. If unset all CertificateRequests will be kept.
+
+- `cert-manager.io/private-key-algorithm`: (optional) this annotation allows you to
+ configure `spec.privateKey.algorithm` field to set the algorithm for private key generation for a Certificate.
+ Valid values are `RSA`, `ECDSA` and `Ed25519`. If unset an algorithm `RSA` will be used.
+
+- `cert-manager.io/private-key-encoding`: (optional) this annotation allows you to
+ configure `spec.privateKey.encoding` field to set the encoding for private key generation for a Certificate.
+ Valid values are `PKCS1` and `PKCS8`. If unset an algorithm `PKCS1` will be used.
+
+- `cert-manager.io/private-key-size`: (optional) this annotation allows you to
+ configure `spec.privateKey.size` field to set the size of the private key for a Certificate.
+ If algorithm is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified.
+ If algorithm is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified.
+ If algorithm is set to `Ed25519`, size is ignored.
+
+- `cert-manager.io/private-key-rotation-policy`: (optional) this annotation allows you to
+ configure `spec.privateKey.rotationPolicy` field to set the rotation policy of the private key for a Certificate.
+ Valid values are `Never` and `Always`. If unset a rotation policy `Never` will be used.
diff --git a/content/v1.12-docs/usage/ingress.md b/content/v1.12-docs/usage/ingress.md
new file mode 100644
index 00000000000..e70c77390f5
--- /dev/null
+++ b/content/v1.12-docs/usage/ingress.md
@@ -0,0 +1,175 @@
+---
+title: Securing Ingress Resources
+description: 'cert-manager usage: Kubernetes Ingress'
+---
+
+A common use-case for cert-manager is requesting TLS signed certificates to
+secure your ingress resources. This can be done by simply adding annotations to
+your `Ingress` resources and cert-manager will facilitate creating the
+`Certificate` resource for you. A small sub-component of cert-manager,
+ingress-shim, is responsible for this.
+
+## How It Works
+
+The sub-component ingress-shim watches `Ingress` resources across your cluster.
+If it observes an `Ingress` with annotations described in the [Supported
+Annotations](#supported-annotations) section, it will ensure a `Certificate`
+resource with the name provided in the `tls.secretName` field and configured as
+described on the `Ingress` exists in the `Ingress`'s namespace. For example:
+
+```yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ annotations:
+ # add an annotation indicating the issuer to use.
+ cert-manager.io/cluster-issuer: nameOfClusterIssuer
+ name: myIngress
+ namespace: myIngress
+spec:
+ rules:
+ - host: example.com
+ http:
+ paths:
+ - pathType: Prefix
+ path: /
+ backend:
+ service:
+ name: myservice
+ port:
+ number: 80
+ tls: # < placing a host in the TLS config will determine what ends up in the cert's subjectAltNames
+ - hosts:
+ - example.com
+ secretName: myingress-cert # < cert-manager will store the created certificate in this secret.
+```
+
+## Supported Annotations
+
+You can specify the following annotations on Ingress resources in order to
+trigger Certificate resources to be automatically created:
+
+- `cert-manager.io/issuer`: the name of the issuer that should issue the certificate
+ required for this Ingress.
+
+ > ⚠️ This annotation does _not_ assume a namespace scoped issuer. It will
+ default to cert-manager.io Issuer, however in case of external issuer types,
+ this should be used for both namespaced and cluster scoped issuer types.
+
+ > ⚠️ If a namespace scoped issuer is used then the issuer *must* be in
+ the same namespace as the Ingress resource.
+
+- `cert-manager.io/cluster-issuer`: the name of a cert-manager.io ClusterIssuer
+ to acquire the certificate required for this Ingress. It does not matter which
+ namespace your Ingress resides, as ClusterIssuers are non-namespaced
+ resources.
+
+ > ⚠️ This annotation is a shortcut to refer to to
+ cert-manager.io ClusterIssuer without having to specify group and kind. It is
+ _not_ intended to be used to specify an external cluster-scoped issuer- please
+ use `cert-manager.io/issuer` annotation for those.
+
+- `cert-manager.io/issuer-kind`: the kind of the external issuer resource, for
+ example `AWSPCAIssuer`. This is only necessary for out-of-tree issuers.
+
+- `cert-manager.io/issuer-group`: the API group of the external issuer
+ controller, for example `awspca.cert-manager.io`. This is only necessary for
+ out-of-tree issuers.
+
+- `kubernetes.io/tls-acme: "true"`: this annotation requires additional
+ configuration of the ingress-shim [see below](#optional-configuration).
+ Namely, a default Issuer must be specified as arguments to the ingress-shim
+ container.
+
+- `acme.cert-manager.io/http01-ingress-class`: this annotation allows you to
+ configure the ingress class that will be used to solve challenges for this
+ ingress. Customizing this is useful when you are trying to secure internal
+ services, and need to solve challenges using a different ingress class to that
+ of the ingress. If not specified and the `acme-http01-edit-in-place` annotation
+ is not set, this defaults to the ingress class defined in the Issuer resource.
+
+- `acme.cert-manager.io/http01-edit-in-place: "true"`: this controls whether the
+ ingress is modified 'in-place', or a new one is created specifically for the
+ HTTP01 challenge. If present, and set to "true", the existing ingress will be
+ modified. Any other value, or the absence of the annotation assumes "false".
+ This annotation will also add the annotation
+ `"cert-manager.io/issue-temporary-certificate": "true"` onto created
+ certificates which will cause a [temporary
+ certificate](./certificate.md#temporary-certificates-whilst-issuing) to be set
+ on the resulting Secret until the final signed certificate has been returned.
+ This is useful for keeping compatibility with the `ingress-gce` component.
+
+- `cert-manager.io/common-name`: (optional) this annotation allows you to
+ configure `spec.commonName` for the Certificate to be generated.
+
+- ` cert-manager.io/duration`: (optional) this annotation allows you to
+ configure `spec.duration` field for the Certificate to be generated.
+
+- `cert-manager.io/renew-before`: (optional) this annotation allows you to
+ configure `spec.renewBefore` field for the Certificate to be generated.
+
+- `cert-manager.io/usages`: (optional) this annotation allows you to configure
+ `spec.usages` field for the Certificate to be generated. Pass a string with
+ comma-separated values i.e "key agreement,digital signature, server auth"
+
+- `cert-manager.io/revision-history-limit`: (optional) this annotation allows you to
+ configure `spec.revisionHistoryLimit` field to limit the number of CertificateRequests to be kept for a Certificate.
+ Minimum value is 1. If unset all CertificateRequests will be kept.
+
+- `cert-manager.io/private-key-algorithm`: (optional) this annotation allows you to
+ configure `spec.privateKey.algorithm` field to set the algorithm for private key generation for a Certificate.
+ Valid values are `RSA`, `ECDSA` and `Ed25519`. If unset an algorithm `RSA` will be used.
+
+- `cert-manager.io/private-key-encoding`: (optional) this annotation allows you to
+ configure `spec.privateKey.encoding` field to set the encoding for private key generation for a Certificate.
+ Valid values are `PKCS1` and `PKCS8`. If unset an algorithm `PKCS1` will be used.
+
+- `cert-manager.io/private-key-size`: (optional) this annotation allows you to
+ configure `spec.privateKey.size` field to set the size of the private key for a Certificate.
+ If algorithm is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified.
+ If algorithm is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified.
+ If algorithm is set to `Ed25519`, size is ignored.
+
+- `cert-manager.io/private-key-rotation-policy`: (optional) this annotation allows you to
+ configure `spec.privateKey.rotationPolicy` field to set the rotation policy of the private key for a Certificate.
+ Valid values are `Never` and `Always`. If unset a rotation policy `Never` will be used.
+
+
+## Optional Configuration
+
+The ingress-shim sub-component is deployed automatically as part of
+installation.
+
+If you would like to use the old
+[kube-lego](https://github.com/jetstack/kube-lego) `kubernetes.io/tls-acme:
+"true"` annotation for fully automated TLS, you will need to configure a default
+`Issuer` when deploying cert-manager. This can be done by adding the following
+`--set` when deploying using Helm:
+
+```bash
+ --set ingressShim.defaultIssuerName=letsencrypt-prod \
+ --set ingressShim.defaultIssuerKind=ClusterIssuer \
+ --set ingressShim.defaultIssuerGroup=cert-manager.io
+```
+
+Or by adding the following arguments to the cert-manager deployment
+`podTemplate` container arguments.
+
+```
+ - --default-issuer-name=letsencrypt-prod
+ - --default-issuer-kind=ClusterIssuer
+ - --default-issuer-group=cert-manager.io
+```
+
+In the above example, cert-manager will create `Certificate` resources that
+reference the `ClusterIssuer` `letsencrypt-prod` for all Ingresses that have a
+`kubernetes.io/tls-acme: "true"` annotation.
+
+Issuers configured via annotations have a preference over the default issuer. If a default issuer is configured via CLI flags and a `cert-manager.io/cluster-issuer` or `cert-manager.io/issuer` annotation also has been added to an Ingress, the created `Certificate` will refer to the issuer configured via annotation.
+
+For more information on deploying cert-manager, read the [installation
+guide](../installation/README.md).
+
+## Troubleshooting
+
+If you do not see a `Certificate` resource being created after applying the ingress-shim annotations check that at least `cert-manager.io/issuer` or `cert-manager.io/cluster-issuer` is set. If you want to use `kubernetes.io/tls-acme: "true"` make sure to have checked all steps above and you might want to look for errors in the cert-manager pod logs if not resolved.
\ No newline at end of file
diff --git a/content/v1.12-docs/usage/istio.md b/content/v1.12-docs/usage/istio.md
new file mode 100644
index 00000000000..86149ae22b4
--- /dev/null
+++ b/content/v1.12-docs/usage/istio.md
@@ -0,0 +1,17 @@
+---
+title: Securing Istio Service Mesh
+description: 'cert-manager usage: Istio and istio-csr'
+---
+
+cert-manager can be integrated with [Istio](https://istio.io) using the project
+[istio-csr](https://github.com/cert-manager/istio-csr). istio-csr will deploy an
+agent that is responsible for receiving certificate signing requests for all
+members of the Istio mesh, and signing them through cert-manager.
+
+[istio-csr](https://github.com/cert-manager/istio-csr) will sign all control
+plane and workload certificates via your chosen cert-manager Issuer.
+
+---
+
+Please follow the instructions for installing and using istio-csr on the
+[project page](../projects/istio-csr.md).
diff --git a/content/v1.12-docs/usage/kube-csr.md b/content/v1.12-docs/usage/kube-csr.md
new file mode 100644
index 00000000000..f6abb93f74a
--- /dev/null
+++ b/content/v1.12-docs/usage/kube-csr.md
@@ -0,0 +1,166 @@
+---
+title: Kubernetes CertificateSigningRequests
+description: 'cert-manager usage: Kubernetes CertificateSigningRequest resources'
+---
+
+Kubernetes has an in-built
+[CertificateSigningRequest](https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/)
+resource. This resource is similar to the cert-manager
+[CertificateRequest](../concepts/certificaterequest.md) in that it is used to
+request an X.509 signed certificate from a referenced Certificate Authority
+(CA).
+
+Using this resource may be useful for users who are using an application that
+supports this resource, but not the cert-manager CertificateRequest resource,
+and they still wish for certificates to be signed through cert-manager.
+
+CertificateSigningRequests reference a `SignerName` or signer as the entity it
+wishes to sign its request from. For cert-manager, a signer can be mapped to
+either an [Issuer or ClusterIssuer](../configuration/README.md).
+
+#### Feature State
+
+This feature is currently in an _experimental_ state, and its behavior is
+subject to change in further releases.
+
+
+
+⛔️ This feature is only enabled by adding it to the `--feature-gates` flag on
+the cert-manager controller:
+
+```bash
+--feature-gates=ExperimentalCertificateSigningRequestControllers=true
+```
+
+Which can be added using Helm:
+
+```bash
+$ helm install \
+ cert-manager jetstack/cert-manager \
+ --namespace cert-manager \
+ --create-namespace \
+ --set featureGates="ExperimentalCertificateSigningRequestControllers=true" \
+ # --set installCRDs=true
+```
+
+> Note: cert-manager supports signing CertificateSigningRequests
+> using all [internal Issuers](../configuration/README.md).
+
+> Note: cert-manager _does not_ automatically approve CertificateSigningRequests
+> that reference a cert-manager [Issuer](../configuration/README.md). Please refer to
+> the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/#request-signing-process)
+> for the request process of CertificateSigningRequests.
+
+
+
+
+
+## Signer Name
+
+CertificateSigningRequests contain a
+[`spec.signerName`](https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/#request-signing-process)
+field to reference a CA to sign the request. cert-manager Issuers or
+ClusterIssuers are referenced in the following form:
+
+```
+.cert-manager.io/.
+```
+
+For example, a namespaced Issuer in the namespace `sandbox` with the name
+`my-issuer` would be referenced via:
+
+```yaml
+ signerName: issuers.cert-manager.io/sandbox.my-issuer
+```
+
+A ClusterIssuer with the name `my-cluster-issuer` would be referenced via:
+
+```yaml
+ signerName: clusterissuers.cert-manager.io/my-cluster-issuer
+```
+
+### Referencing Namespaced Issuers
+
+Unlike CertificateRequests, CertificateSigningRequests are cluster scoped
+resources. To prevent users from requesting certificates from a namespaced
+Issuer in a namespace that they otherwise would not have access to, cert-manager
+performs a
+[SubjectAccessReview](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#checking-api-access).
+This review ensures that the requesting user has the permission to `reference`
+the `signers` resource in the given namespace. The name should be either the
+name of the Issuer, or `"*"` to reference all Issuers in that namespace.
+
+An example Role to give permissions to reference Issuers in the `sandbox`
+namespace would look like the following:
+
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: cert-manager-referencer:my-issuer
+ namespace: sandbox
+rules:
+- apiGroups: ["cert-manager.io"]
+ resources: ["signers"]
+ verbs: ["reference"]
+ resourceNames:
+ - "my-issuer" # To give permission to _only_ reference Issuers with the name 'my-issuer'
+ - "*" # To give permission to reference Issuers with any name in this namespace
+```
+
+## Annotations
+
+To keep feature parity with CertificateRequests, annotations are used to store
+values that do not exist as `spec` or `status` fields on the
+CertificateSigningRequest resource. These fields are either set by the
+_requester_ or by the _signer_ as labelled below.
+
+Requester annotations:
+
+- `experimental.cert-manager.io/request-duration`: **Set by the requester**. Accepts
+ a [Go time duration](https://golang.org/pkg/time/#ParseDuration) string
+ specifying the requested certificate duration. Defaults to 90 days. Some
+ signers such as Venafi or ACME typically _do not_ allow requesting a
+ duration.
+
+- `experimental.cert-manager.io/request-is-ca`: **Set by the requester**. If set to
+ `"true"`, will request for a CA certificate.
+
+- `experimental.cert-manager.io/private-key-secret-name`: **Set by the
+ requester**. Required only for the SelfSigned signer. Used to reference a
+ Secret which contains the PEM encoded private key of the requester's X.509
+ certificate signing request at key `tls.key`. Used to sign the requester's
+ request.
+
+- `venafi.experimental.cert-manager.io/custom-fields`: **Set by the
+ requester**. Optional for only the Venafi signer. Used for adding custom
+ fields to the Venafi request. This will only work with Venafi TPP `v19.3`
+ and higher. The value is a JSON array with objects containing the name and
+ value keys, for example:
+ ```
+ venafi.experimental.cert-manager.io/custom-fields: |-
+ [
+ {"name": "field-name", "value": "field value"},
+ {"name": "field-name-2", "value": "field value 2"}
+ ]
+ ```
+
+Signer annotations:
+
+- `venafi.experimental.cert-manager.io/pickup-id`: **Set by the signer**. Only
+ used for the Venafi signer. Used to record the Venafi Pickup ID of a
+ certificate signing request that has been submitted to the Venafi API for
+ collection during issuance.
+
+## Usage
+
+CertificateSigningRequests can be manually created using
+[cmctl](../reference/cmctl.md#experimental).
+This command takes a manifest file containing a
+[Certificate](../usage/certificate.md) resource as input. This generates a
+private key and creates a CertificateSigningRequest. CertificateSigningRequests
+are not approved by default, so you will likely need to approve it manually:
+
+```bash
+$ kubectl certificate approve
+```
diff --git a/content/v1.12-docs/usage/prometheus-metrics.md b/content/v1.12-docs/usage/prometheus-metrics.md
new file mode 100644
index 00000000000..968ce2077db
--- /dev/null
+++ b/content/v1.12-docs/usage/prometheus-metrics.md
@@ -0,0 +1,69 @@
+---
+title: Prometheus Metrics
+description: 'cert-manager usage: Prometheus metrics'
+---
+
+To help with operations and insights into cert-manager activities, cert-manager exposes metrics in the [Prometheus](https://prometheus.io/) format from the controller component. These are available at the standard `/metrics` path of the controller component's configured HTTP port.
+
+## Scraping Metrics
+
+How metrics are scraped will depend how you're operating your Prometheus server(s). These examples presume the [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator) is being used to run Prometheus, and configure Pod or Service Monitor CRDs.
+
+### Helm
+
+If you're deploying cert-manager with helm, a `ServiceMonitor` resource can be configured. This configuration should enable metric scraping, and the configuration can be further tweaked as described in the [Helm configuration documentation](https://github.com/cert-manager/cert-manager/blob/master/deploy/charts/cert-manager/README.template.md#configuration).
+
+```yaml
+prometheus:
+ enabled: true
+ servicemonitor:
+ enabled: true
+```
+
+### Regular Manifests
+
+If you're not using helm to deploy cert-manager and instead using the provided regular YAML manifests, this example `PodMonitor` and deployment patch should be all you need to start ingesting cert-manager metrics.
+
+1. [Apply the following patch](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/#use-a-strategic-merge-patch-to-update-a-deployment) to your cert-manager deployment
+
+```yaml
+spec:
+ template:
+ spec:
+ containers:
+ - name: cert-manager-controller
+ ports:
+ - containerPort: 9402
+ name: http
+ protocol: TCP
+```
+
+2. Create the following `PodMonitor`
+
+```yaml
+apiVersion: monitoring.coreos.com/v1
+kind: PodMonitor
+metadata:
+ name: cert-manager
+ namespace: cert-manager
+ labels:
+ app: cert-manager
+ app.kubernetes.io/name: cert-manager
+ app.kubernetes.io/instance: cert-manager
+ app.kubernetes.io/component: "controller"
+spec:
+ jobLabel: app.kubernetes.io/name
+ selector:
+ matchLabels:
+ app: cert-manager
+ app.kubernetes.io/name: cert-manager
+ app.kubernetes.io/instance: cert-manager
+ app.kubernetes.io/component: "controller"
+ podMetricsEndpoints:
+ - port: http
+ honorLabels: true
+```
+
+## Monitoring Mixin
+
+Monitoring mixins are a way to bundle common alerts, rules, and dashboards for an application in a configurable and extensible way, using the Jsonnet data templating language. A cert-manager monitoring mixin can be found here https://gitlab.com/uneeq-oss/cert-manager-mixin. Documentation on usage can be found with the `cert-manager-mixin` project.
From afa13bfe84fbb55b6f76f1594050e33f1a407112 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Valais?=
Date: Fri, 19 May 2023 17:59:52 +0200
Subject: [PATCH 052/264] post-release 1.12: bump 1.11 -> 1.12 in gen script
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Maël Valais
---
scripts/gendocs/generate-new-import-path-docs | 1 +
1 file changed, 1 insertion(+)
diff --git a/scripts/gendocs/generate-new-import-path-docs b/scripts/gendocs/generate-new-import-path-docs
index fc5a97361b4..09620e5dc4c 100755
--- a/scripts/gendocs/generate-new-import-path-docs
+++ b/scripts/gendocs/generate-new-import-path-docs
@@ -153,6 +153,7 @@ LATEST_VERSION="v1.12-docs"
#genversionwithcli "release-1.8" "v1.8-docs"
#genversionwithcli "release-1.9" "v1.9-docs"
#genversionwithcli "release-1.10" "v1.10-docs"
+#genversionwithcli "release-1.11" "v1.11-docs"
genversionwithcli "release-1.12" "$LATEST_VERSION"
From 9c565534beec93eaff9df95e9064236ad53a8a53 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABl=20Valais?=
Date: Fri, 19 May 2023 18:23:46 +0200
Subject: [PATCH 053/264] post-release 1.12: run ./scripts/gendocs/generate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Maël Valais
---
content/docs/reference/api-docs.md | 22 ++++-
content/v1.12-docs/reference/api-docs.md | 106 +++++++++++++++++++++--
2 files changed, 116 insertions(+), 12 deletions(-)
diff --git a/content/docs/reference/api-docs.md b/content/docs/reference/api-docs.md
index 4943e086a69..f098ef7b0b2 100644
--- a/content/docs/reference/api-docs.md
+++ b/content/docs/reference/api-docs.md
@@ -815,7 +815,7 @@ description: >-
|
(Optional)
- The name of the ingress resource that should have ACME challenge solving routes inserted into it in order to solve HTTP01 challenges. This is typically used in conjunction with ingress controllers like ingress-gce, which maintains a 1:1 mapping between external IPs and ingress resources.
+ The name of the ingress resource that should have ACME challenge solving routes inserted into it in order to solve HTTP01 challenges. This is typically used in conjunction with ingress controllers like ingress-gce, which maintains a 1:1 mapping between external IPs and ingress resources. Only one of class , name or ingressClassName may be specified.
|