Set duration for how long the certificate should live and renewBefore for how long before expiry cert-manager should renew. Write both in hours, because the day suffix is not allowed, and keep renewBefore well short of duration. If it sits too close, the certificate is permanently inside its renewal window and reissues in a loop.
What the fields mean
cert-manager represents a requested certificate as a Certificate resource. From it, cert-manager generates a private key and a CertificateRequest, gets a signed certificate from the referenced issuer, and stores the result in a Secret. It renews before expiry, and reissues if asked.
Its documentation says it calculates when to renew from the issued certificate's duration and a renewBefore value. You can use spec.duration with spec.renewBefore, or spec.renewBeforePercentage. The default duration is 90 days.
Write the units correctly
The renewBefore and duration fields use Go duration strings, and the documentation notes this format does not allow a d suffix for days. Use h, m or s. An example from the documentation uses 2160h for 90 days and 360h for 15 days.
Writing values with the wrong unit without the webhook component installed can prevent cert-manager from functioning correctly, according to the same note.
spec:
duration: 2160h # 90 days
renewBefore: 360h # 15 days
The renewal loop
The documentation warns: take care when setting renewBefore very close to duration, because that can create a loop where the Certificate is always in its renewal period. It also explains why the margin is tighter than it looks. Some issuers set notBefore earlier than the issue time to cover clock skew, so the working duration is shorter than the full duration. Its example is Let's Encrypt, which sets notBefore one hour before issue time, leaving a working duration of 89 days and 23 hours on a certificate whose full duration is 90 days.
Keep a generous gap between the two values and check the actual certificate lifetime rather than trusting the request.
Choosing values
| Issued lifetime | Reasonable renewBefore | Reasoning |
|---|---|---|
| 90 days | 30 days (720h) | Matches the one third of lifetime guideline from ACME operators |
| 45 days | 15 days (360h) | Same one third rule |
| Under 10 days | About half the lifetime | Short certificates need proportionally more slack |
The one third and half lifetime guidance comes from the Let's Encrypt integration guide. The rule of thumb is to leave enough time for several failed attempts and a human response.
Verify after changing
- Apply the change and read the Certificate status for the next renewal time.
- Compare the renewal time with the notAfter value of the issued certificate.
- Confirm only one reissue occurs in the window, by watching the Secret revision.
- Make sure pods pick up the new Secret. See why subPath mounts miss renewals.
Where Safeguard fits
Safeguard does not replace cert-manager. It offers SBOM and dependency scanning, and policy gates that can check manifests in pull requests before they land. Try the free scan at gold.safeguard.sh/scan.
Quick check
Can I write renewBefore as 15d?
No. The documentation says the format does not allow a day suffix. Use hours, such as 360h.
What is the default duration?
90 days, according to the Certificate resource documentation.
Can I use a percentage instead?
Yes. The spec.renewBeforePercentage field is supported alongside spec.renewBefore.
Sources
Last reviewed: 19 October 2026.