Skip to main content

Certificate policy engine

The policy engine puts project-scoped guardrails on certificate issuance and renewal. A request that violates the policy is rejected synchronously — nothing is created, no job is enqueued — with HTTP 422 and a structured list of violations.

Configure under Settings → Certificate Policy.

What the policy enforces

Each rule is optional; an empty rule allows everything. All configured rules are checked and every violation is returned (not just the first).

RuleFieldBehaviourViolation code
Allowed key typesallowed_key_typesKey type must be in the list (ECDSA P-256/P-384, RSA 2048/3072/4096).policy_key_type
Allowed issuer typesallowed_issuer_typesIssuer must be acme and/or msca.policy_issuer_type
Allowed issuer IDsallowed_issuer_idsOnly the listed ACME accounts / MSCA connections may issue.policy_issuer_id
SAN allow patternssan_rules.allowed_patternsEvery domain must match at least one glob.policy_san_allowed
SAN deny patternssan_rules.deny_patternsNo domain may match any glob. Deny overrides allow.policy_san_denied
Max SAN countsan_rules.max_san_countCap on domains per certificate (0 = no limit).policy_san_count
Naming conventionnaming_patternCertificate name must match the regex.policy_naming
Require auto-renewrequire_auto_renewCertificate must have auto-renew enabled.policy_auto_renew
note

on_violation currently supports only reject; a require approval mode is shown in the UI as coming soon. A require_distribution field is persisted but not yet enforced.

One policy per project

Each project has at most one policy (a singleton document). The Enabled switch turns enforcement on and off without deleting the rules; deleting the policy removes all guardrails. Saves are versioned — concurrent edits are rejected on version conflict.

Enforcement points

Evaluation is synchronous inside the certificate service, before the certificate is saved or a job is enqueued:

  • Issue — both ACME and MSCA creation paths.
  • Renew — manual/API renewal re-evaluates the certificate's current name, key type, issuer, domains, and auto-renew flag. A certificate that was compliant at issue time can fail renewal after the policy is tightened.

On violation the API responds 422 Unprocessable Entity:

{
"error": "policy_violation",
"message": "certificate policy violated: 2 rule(s)",
"violations": [
{ "code": "policy_key_type", "field": "key_type",
"message": "Key type RSA-2048 is not allowed. Allowed: ECDSA-P256" },
{ "code": "policy_san_denied", "field": "domains",
"message": "Domain internal.local matches deny pattern *.local" }
]
}

Interaction with approvals

For users who issue directly (Admins/Owners, or when approvals are off), the policy rejects the request before any approval question arises. Two caveats when the approval workflow is enabled for issuance:

  • An operator's issue request is stored as awaiting_approval without policy evaluation, and executing the approved request enqueues the issuance job without re-evaluating. Reviewers should check requests against the policy manually.
  • Approved renew requests do run through the renewal path, so they are policy-checked at execution time.

Glob and regex semantics

SAN patterns are label-by-label globs, case-insensitive. * matches exactly one DNS label — it does not cross dots, and label counts must match:

PatternMatchesDoes not match
*.example.comapi.example.comexample.com, a.b.example.com
*.*.example.coma.b.example.comapi.example.com
example.comexample.com onlyany subdomain
*.internal (deny)db.internaldb.corp.internal

The naming convention is a standard regex tested against the certificate name (not its domains), e.g. ^(prod|stage)-[a-z0-9-]+$. An invalid regex itself produces a policy_naming_error violation rather than silently passing.

Live test fields

The Settings → Certificate Policy form includes two inline testers that evaluate as you type, using the same matching logic as the backend:

  • Domain test (under SAN rules) — shows Denied — matches <pattern>, Allowed — matches <pattern>, Not allowed — does not match any allowed pattern, or No restrictions.
  • Name test (under naming convention) — shows Matches pattern / Does not match pattern for the regex.

Use them to sanity-check patterns before saving; nothing is sent to the server.

Cache TTL

Policies are cached in the API process for 60 seconds (including the "no policy" result). After saving, editing, or deleting a policy, allow up to a minute before enforcement reflects the change on issuance and renewal requests.

API

Project-scoped; reading requires Operator, writing requires Admin:

GET /api/v1/projects/{projectId}/certificate-policy
PUT /api/v1/projects/{projectId}/certificate-policy
DELETE /api/v1/projects/{projectId}/certificate-policy

There is no server-side test endpoint — the live testers run in the browser.

See also