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

# Profiles

> Named certificate shapes that hosts can request from the broker.

A profile defines a kind of certificate the broker may issue. Profile names are referenced by hosts (in policy) and by the agent (in `agent.yml`'s `certificates[].profile`).

```yaml theme={null}
profiles:
  public_edge_main:
    type: wildcard
    dns_names:
      - "*.example.com"
    acme:
      challenge: dns-01
      credentials: cloudflare/example-com
    renew_before: 720h

  api_san:
    type: multi_san
    dns_names:
      - api.example.com
      - api-v2.example.com
    acme:
      challenge: http-01
```

## Fields

| Field              | Type                          | Required            | Notes                                                       |
| ------------------ | ----------------------------- | ------------------- | ----------------------------------------------------------- |
| `type`             | enum: `wildcard`, `multi_san` | yes                 |                                                             |
| `dns_names`        | string\[]                     | yes                 | Allowed DNS names. Non-empty.                               |
| `acme.challenge`   | enum: `dns-01`, `http-01`     | yes                 | Wildcard profiles require `dns-01`.                         |
| `acme.credentials` | string                        | for `dns-01`        | Secret reference resolved by the broker's secrets provider. |
| `renew_before`     | duration                      | no (default `720h`) | When the broker considers a cached cert "due" for renewal.  |

The schema rejects unknown fields per profile (`additionalProperties: false`).

## `type: wildcard`

For `*.zone` certificates.

* `dns_names` must contain exactly one entry of the form `*.<zone>`.
* `acme.challenge` must be `dns-01` (Let's Encrypt does not allow `http-01` for wildcards).
* `acme.credentials` is required and resolves to your DNS provider credential.

The agent's CSR must request a SAN whose host label sits under the same wildcard zone.

```yaml theme={null}
public_edge_main:
  type: wildcard
  dns_names:
    - "*.example.com"
  acme:
    challenge: dns-01
    credentials: cloudflare/example-com
```

## `type: multi_san`

For certificates with a fixed list of SANs.

* `dns_names` lists every SAN the profile may include.
* `acme.challenge` may be `dns-01` or `http-01`.
* `acme.credentials` is required for `dns-01`.
* The agent's CSR SANs must be a subset of `dns_names`.

```yaml theme={null}
api_san:
  type: multi_san
  dns_names:
    - api.example.com
    - api-v2.example.com
  acme:
    challenge: http-01
```

## `renew_before`

This is the **broker-side** renewal window. When an agent asks for a cached certificate and the cache entry is within `renew_before` of expiry, the broker requests a fresh certificate from ACME instead of returning the cached one. Agents have their own `renew_before` in `agent.yml` — they should be roughly equal to avoid an agent asking too late.

Common values: `720h` (30 days) for 90-day Let's Encrypt certificates.

## Credential references

The `acme.credentials` string is opaque to the policy compiler. It is interpreted by the configured secrets provider in `broker.yml`:

| Provider            | Interpretation of `acme.credentials` |
| ------------------- | ------------------------------------ |
| `env`               | Environment variable name.           |
| `file`              | Path to a file on the broker.        |
| `vault` / `openbao` | Vault path under `mount_path`.       |

See [Secrets providers](/configuration/secrets) and [Vault and OpenBao secrets](/guides/vault-secrets).
