Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .spelling
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ goroutine
gosec
hardcodes
hardcoded
hairpinning
healthz
honour
hostname
Expand Down
63 changes: 63 additions & 0 deletions content/docs/configuration/acme/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,69 @@ Solvers come in the form of [`dns01`](./dns01/README.md) and
these solver types, visit their respective documentation -
[DNS01](./dns01/README.md), [HTTP01](./http01/README.md).

### Skip the self-check with `waitInsteadOfSelfCheck`

> ℹ️ This feature is available in cert-manager `>= v1.21.0`.

The `waitInsteadOfSelfCheck` solver option skips cert-manager's own
[self-check](../../concepts/acme-orders-challenges.md#challenge-lifecycle)
and instead waits a configured duration after presentation before asking the
ACME server to validate the challenge.

You can set this field on either an `http01` or `dns01` solver entry.

This is aimed at environments such as:

- NAT loopback limitations, where cert-manager cannot reach the public address that the
ACME server can reach;
- split-horizon DNS, where cert-manager resolves a different address than the
ACME server does; or
- public/private ingress topologies where cert-manager only sees the internal
path but the ACME server validates against the external path.

The behavior when `waitInsteadOfSelfCheck` is set is:

- cert-manager presents the challenge as usual;
- cert-manager records the time of first presentation in `status.presentedAt`;
- cert-manager skips its own self-check; and

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: adding a DNS01 example (or a short mention of the equivalent YAML) would help readers who are in a split-horizon DNS scenario. The current text says the field works on either solver type, but the example only shows HTTP01. A comment like # or under dns01: instead of http01: next to waitInsteadOfSelfCheck: 30s in the code block would be a low-effort addition.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — added a YAML comment in the example noting dns01: as an alternative in 777bd7d.

- once the configured duration has elapsed since `status.presentedAt`,
cert-manager asks the ACME server to validate the challenge.

For example:

```yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
email: user@example.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: example-issuer-account-key
solvers:
- http01:
ingress:
ingressClassName: nginx-public
# or use dns01: instead of http01: for split-horizon DNS scenarios
waitInsteadOfSelfCheck: 30s
```

This is an advanced escape hatch for cases where cert-manager cannot directly

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted in the code review of the implementation PR, setting waitInsteadOfSelfCheck: 0s causes cert-manager to accept the challenge on the first reconcile after presentation — with no self-check and no wait — because the deadline is PresentedAt + 0 = PresentedAt, which is always in the past. This may be intentional for users who want a pure bypass, but it is not mentioned anywhere in the docs.

If the implementation PR adds a validation marker to reject zero/negative durations, this becomes moot. Otherwise, consider adding a brief note here, e.g.:

Setting this field to 0s skips the self-check and accepts immediately after presentation.

Users who write waitInsteadOfSelfCheck: 0s expecting some kind of no-op would be surprised to find their challenges accepted without any check.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was already addressed in the existing text (lines 138–143) which documents the 0 value behaviour and notes that negative durations are rejected by the validating webhook.

observe the same validation path as the ACME server.

Choose the delay conservatively. If it is too short, the ACME server may still
start validation before your solver resources are reachable. If it is too long,
certificate issuance will wait longer than necessary.

A value of `0` is permitted: cert-manager skips the self-check and asks the ACME
server to validate immediately after presentation. In this case cert-manager
relies on the ACME server's own validation retries
([RFC 8555 section 8.2](https://www.rfc-editor.org/rfc/rfc8555#section-8.2)) to
succeed once the challenge has propagated. Negative durations are rejected by the
validating webhook.

### ACME Certificate Profiles

> ℹ️ This feature is available in cert-manager `>= v1.18.0`.
Expand Down
15 changes: 13 additions & 2 deletions content/docs/releases/release-notes/release-notes-1.21.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,18 @@ cert-manager v1.21 includes:

## Major Themes

### TODO
### Skip the self-check with `waitInsteadOfSelfCheck`

cert-manager 1.21 adds the `waitInsteadOfSelfCheck` solver option for ACME
HTTP01 and DNS01 challenges. When set, cert-manager skips its own self-check
and instead waits the configured duration after presentation before asking the
ACME server to validate. This is an escape hatch for environments where
cert-manager cannot reliably observe the same validation path as the ACME
server, such as split-horizon DNS or NAT loopback (or hairpinning).

See [Skip the self-check with
`waitInsteadOfSelfCheck`](../../configuration/acme/README.md#skip-the-self-check-with-waitinsteadofselfcheck)
for configuration details.

## Community

Expand Down Expand Up @@ -41,7 +52,7 @@ And finally, thanks to the cert-manager steering committee for their feedback in

### Feature

TODO
- Add the `waitInsteadOfSelfCheck` solver option for ACME HTTP01 and DNS01 challenges, allowing cert-manager to skip its own self-check and ask the ACME server to validate after a configured wait. See the [ACME issuer documentation](../../configuration/acme/README.md#skip-the-self-check-with-waitinsteadofselfcheck) for configuration details.

### Documentation

Expand Down
12 changes: 12 additions & 0 deletions content/docs/troubleshooting/acme.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,18 @@ $ kubectl get challenge <challenge-name> -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 the ACME server can reach the challenge URL from the public internet but
cert-manager's [self-check](../concepts/acme-orders-challenges.md#challenge-lifecycle) cannot, you may be in one of the environments
mentioned on the [ACME configuration](../configuration/acme/README.md) page:
NAT loopback limitations, split-horizon DNS, or a public/private ingress split.
The [`waitInsteadOfSelfCheck`](../configuration/acme/README.md#skip-the-self-check-with-waitinsteadofselfcheck)
solver option skips the self-check entirely and instead waits a configured
duration after presentation before asking the ACME server to validate.

A similar issue can also affect DNS01 if cert-manager can only query internal
DNS views while the ACME server validates against the public TXT record.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DNS01 paragraph inserted immediately before this line (207–208) leaves If this does work check if your cluster can see it too. as a non-sequitur. That sentence was originally the continuation of the opening HTTP01 paragraph (First of all check if you can see the challenge URL from the public internet…), but after the insertion it reads as a follow-on to the DNS01 note.

Suggested fix: add a blank line between line 207 and this line so that If this does work… clearly starts a new paragraph and the reader understands this refers back to the challenge URL visibility check, not the DNS01 scenario:

 A similar issue can also affect DNS01 if cert-manager can only query internal
 DNS views while the ACME server validates against the public TXT record.
+
 If this does work check if your cluster can see it too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — added a blank line in 777bd7d.

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.
Expand Down