> ## Documentation Index
> Fetch the complete documentation index at: https://docs.celum.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Certificates

> cert-manager and the five issuer types — which issuer actually signs your TLS, how to pin it, and why a certificate can sit Pending forever.

Every TLS story on this platform ends at one question: **which ClusterIssuer signs it.** A published route, a Gateway listener, a promoted VM, Grafana behind the shared Gateway — each asks cert-manager for a certificate and names an issuer in the request. Get that name wrong and nothing errors: the `Certificate` simply waits, forever, for an issuer that does not exist.

cert-manager arrives with the **Certificates** step of [platform onboarding](https://docs.celum.io/get-started/platform-onboarding.md), which installs it and creates the supervisor's first issuer. The per-supervisor **Certificates** page manages the rest.

## Before an issuer can work

**The supervisor needs a domain.** Certificate names are derived from it, so a supervisor with no domain attached issues nothing and says nothing about why — see [Register a supervisor](https://docs.celum.io/get-started/register-a-supervisor.md). This is the most common cause of a certificate that never appears.

## Five issuer types

The step asks what kind of trust you have, not which fields to fill:

| Type | What it is | What it needs |
| - | - | - |
| **Appliance CA** | the appliance's OpenBao signs each request under the appliance CA; the CA key never enters the cluster | the Secret Store step done, `VAULT_ADDR` and the bootstrap credential on the backend, `VAULT_BOOTSTRAP_ALLOW` covering this supervisor, and a domain or a zone declared in the DNS Publishing step |
| **Let's Encrypt** | ACME with a **DNS-01** challenge, so wildcard names work and nothing has to be reachable from the internet | a DNS provider credential and an ACME contact address |
| **Self-signed** | cert-manager signs its own | nothing |
| **CA import** | your own CA key and certificate, imported | the key pair |
| **AD CS** | Active Directory Certificate Services, via its own issuer kind | the AD CS endpoint and credentials |

The last two are why the rest of this page exists: they produce issuers with **different names and even a different kind** (`ClusterAdcsIssuer` rather than `ClusterIssuer`), and everything downstream has to name the right one.

## Which issuer actually signs — three rules

When something asks for a certificate without naming an issuer, Celum resolves one in this order:

**1. A pinned default, if you set one**

An annotation on the issuer itself — `k8s-gate.nuvira.dev/default-cluster-issuer` — set from the **star** on the Certificates page. It survives restarts and travels with the cluster, because it lives on the resource it governs rather than in Celum's database. Pinning one clears the flag from every other issuer: there is exactly one default.

**2. Otherwise, whatever is deployed**

Detected from the issuer resources actually present — AD CS, then ACME, then self-signed or imported CA.

**3. Otherwise, nothing**

No issuer is deployed, so there is **no answer**, and the resolution says so rather than offering a name.

The status shows which rule answered — **pinned** or **auto** — deliberately. Telling an operator an issuer was detected when they pinned it sends them to the wrong page to change it.

> [!WARNING]
>
> **That third rule used to return a guess, and the guess was permanent.**
>
> Every request path used to fall back to the name `letsencrypt-prod`. On any supervisor that later chose a CA, self-signed or AD CS issuer, that name referred to an issuer which would never exist — and the requests went out anyway.
>
> Measured on one supervisor: the shared Gateway was stamped with the guess **before** the Certificates step ran, the operator then installed a CA issuer, and all four platform hostnames sat on `Referenced "ClusterIssuer" not found` **for a day**. Every HTTPS listener showed `InvalidCertificateRef` while HTTP redirected into a port that answered nothing.
>
> It was permanent because the Gateway's issuer annotation is written once, when the listener is created, and never re-derived. **Install the Certificates step before you publish anything**, and if you have a Gateway that predates your issuer, re-apply it so the annotation is rewritten.

## Managing issuers day-2

The Certificates page lists every issuer with its Ready condition, the **default** badge, and a star to pin or unpin it. Add, edit and delete issuers of any of the five types. The wizard creates the first issuer, and this page manages all the others.

> [tab] Dashboard
>
> The supervisor's **Certificates** page.

> [tab] API
>
> `GET .../certs/issuers` lists the issuers, with `default` on each row. `POST .../certs/issuers` adds an issuer, or edits the one its `issuerName` names, and returns `202` with the steps it applied. `POST .../certs/issuers/{issuer}/default` pins or unpins an issuer, and `DELETE .../certs/issuers/{issuer}` removes one. `GET .../certs/certificates` lists the certificates themselves. All of them need `certs:Install`, except the reads.

> [tab] MCP
>
> `list_cluster_issuers` and `get_certificates` read issuers and certificates; `preview_certificate_reissue` lists, and `reissue_certificates` moves, the certificates Celum minted that are not on the default issuer. **Issuers cannot be created, edited, pinned or deleted through the assistant.**

### Editing an issuer

The pencil on an issuer's row opens **Edit issuer**. **Save changes** applies the issuer again with the values you changed and keeps everything else.

**What you cannot change.** The name and the type are locked. To change either one, delete the issuer and add it again. Only the dashboard enforces this. The API checks neither: a `POST` applies whatever `issuerType` you send under that name.

**What you can change**, per type:

| Type | You can change | An empty field keeps |
| - | - | - |
| Let's Encrypt | **Account email**, **ACME server** (`prod` or `staging`), **DNS-01 provider**, and the API token for that provider | the stored token |
| Self-signed | nothing. **Save changes** applies the issuer and its root again | — |
| CA import | **CA certificate (PEM)** and **CA private key (PEM)**, both together | the stored key pair |
| AD CS | **Enrollment URL**, **Certificate template**, **Skip TLS verification**, **CA bundle (optional)**, and **Username** and **Password** together | the stored username and password |
| Appliance CA (Celum appliance only) | nothing | — |

If you paste only half of a pair, Celum keeps the stored pair. This applies to the CA key pair and to the AD CS username and password. An AD CS issuer's **CA bundle** is not a secret: the form opens with the bundle the issuer holds, and saving with the field cleared removes it. An issuer edited before Celum 1.296 may have lost its bundle that way; if it stopped issuing, paste the bundle again. If you switch the **DNS-01 provider**, paste the token for the new provider. The form does not require it when you edit, and without it the issuer works only if a token for that provider is already stored.

> [!WARNING]
>
> **Credentials belong to the supervisor, not to one issuer.** On one supervisor, all Let's Encrypt issuers that use GoDaddy share one token Secret, and all that use Cloudflare share another. All AD CS issuers share one credential. Every CA-import and self-signed issuer signs with the same key pair, `cert-manager-ca-keypair`. If you rotate a credential on one issuer, you rotate it for all of them.

> [!WARNING]
>
> **On a Celum appliance, saving an issuer of any other type deletes the Appliance CA issuer.** This applies to new and to edited issuers. Celum removes `celum-appliance`, because issuer detection would otherwise keep choosing it over the type you just saved.

Edit only the issuers that Celum created. The form reads only the types above. An issuer of any other kind opens as Let's Encrypt, and saving it applies a Let's Encrypt issuer under that name.

## Certificates that outlive their cluster

A published guest route mints its certificate **on the supervisor**, because guest clusters carry no cert-manager of their own. When the guest is deleted, the certificate is not: on one supervisor that left dozens behind, several wedged mid-issuance and all of them indistinguishable in the list from the platform's own.

A background sweep finds them, and the page offers a purge. It is a sweep rather than a step in the delete path because a guest can vanish five ways — topology delete, flat delete, a GitOps prune that happens later in Flux, a project teardown, or someone's `kubectl` — and only a sweep covers all five. Kubernetes owner references cannot do it for free: an owner may not cross namespaces, and these certificates live in cert-manager's.

## What commonly goes wrong

| Symptom | Cause |
| - | - |
| A `Certificate` sits Pending and nothing is logged | it names an issuer that does not exist. Check which issuer is active, and what the Gateway's annotation actually says |
| No certificates are issued at all, anywhere | the supervisor has no domain attached, so nothing derives a name |
| HTTPS fails on a listener created before the issuer | the annotation was written once and is now wrong. Re-apply the Gateway |
| The wrong issuer signs new certificates | another issuer is pinned, or auto-detection prefers a type you did not expect. Pin the one you want |
| Certificates for clusters that no longer exist | guest-route certificates outlive their cluster. Purge the orphans |
| An issuer will not become Ready | for ACME, the DNS-01 credential; for AD CS, the endpoint. The issuer's own condition carries the reason |

## Related

> [card] [Platform onboarding](https://docs.celum.io/get-started/platform-onboarding.md)
>
> The step that installs cert-manager and creates the first issuer.

> [card] [Publish it on a public name](https://docs.celum.io/get-started/publish-it.md)
>
> Where an issuer is consumed — routes, listeners and TLS.

> [card] [Gateways & Routes](https://docs.celum.io/networking/gateways-and-routes.md)
>
> Listener TLS and the annotation this page is about.

> [card] [Register a supervisor](https://docs.celum.io/get-started/register-a-supervisor.md)
>
> Where the domain comes from.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.