Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt

Use this file to discover all available pages before exploring further.

Roles and issuance

A role is the issuance template applied when you mint a leaf cert under a root. It answers: “what’s a leaf allowed to claim, and for how long?” The role is what enforces the difference between a CA that hands out anything and a CA that’s safe to delegate.

What a role controls

FieldWhat it does
allowed_domainsGlob list of CN / SAN values the leaf may claim. ['*.example.com', 'api.internal'] — only these.
allow_subdomainsIf true, *.allowed-domain (e.g. foo.bar.example.com under *.example.com) is permitted. If false, only exact matches.
allow_wildcardsIf true, the leaf itself can be a wildcard cert (*.example.com). If false, only concrete hostnames.
default_ttl_secondsDefault validity when the caller doesn’t specify. Default 30 days.
max_ttl_secondsHard ceiling per-issue. Default 90 days.
key_algorithmForced to ecdsa-p256 in v1.
The maximum effective TTL is min(role.max_ttl, intermediate.not_after - now). A leaf can’t outlive the intermediate that signed it.

Creating a role

curl -X POST https://api.knoxcall.com/admin/pki/roots/corp/roles \
  -H "Authorization: Bearer $KC_ADMIN_JWT" \
  -H "X-Tenant-ID: $TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "role_name": "internal-services",
    "allowed_domains": ["*.internal.example.com", "*.svc.cluster.local"],
    "allow_subdomains": true,
    "allow_wildcards": false,
    "max_ttl_seconds": 604800,
    "default_ttl_seconds": 86400
  }'
This says: leaves under internal-services can claim any host under *.internal.example.com or *.svc.cluster.local, can’t be wildcards themselves, and live at most 7 days (24h by default).

Issuing a leaf

curl -X POST https://api.knoxcall.com/admin/pki/roots/corp/issue/internal-services \
  -H "Authorization: Bearer $KC_ADMIN_JWT" \
  -H "X-Tenant-ID: $TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": { "common_name": "auth-svc.internal.example.com" },
    "san_dns": ["auth-svc.internal.example.com", "auth-svc.svc.cluster.local"],
    "ttl_seconds": 86400
  }'
# Response:
# {
#   "serial_hex": "...",
#   "cert_pem": "-----BEGIN CERTIFICATE-----...",
#   "private_key_pem": "-----BEGIN EC PRIVATE KEY-----...",
#   "ca_chain_pem": "...",
#   "not_after": "2026-04-27T..."
# }
The private_key_pem is shown once. KnoxCall doesn’t keep it. Save it next to the cert in whatever your service expects (Kubernetes secret, file mount, etc) — you can’t fetch it again. The ca_chain_pem includes the intermediate so clients can validate without a separate fetch.

Subject DN inheritance

Leaves inherit org-level Subject DN fields (Organization, Country, Province, Locality) from the root if you don’t supply them on the issue call. CN and SAN come from the request. This keeps “issued by Acme Inc, in California” consistent across every leaf without repeating it on every call. You can override any field per-issue if you really need to.

Validation rules at issue time

KnoxCall rejects an issuance request when:
  • The CN or any SAN doesn’t match allowed_domains (subject to the allow_subdomains / allow_wildcards flags).
  • The requested TTL exceeds role.max_ttl_seconds.
  • The requested TTL would push not_after past the intermediate’s expiry. (Effective ceiling is min(role.max_ttl, intermediate.not_after - now).)
  • The intermediate is retired and no successor has been minted yet — surface as a 409 so the caller can retry.

Revocation

To revoke a leaf:
curl -X POST https://api.knoxcall.com/admin/pki/roots/corp/revoke \
  -H "Authorization: Bearer $KC_ADMIN_JWT" \
  -H "X-Tenant-ID: $TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{ "serial_hex": "<serial>", "reason": "key_leaked" }'
The cert lands in the CRL (GET /admin/pki/roots/corp/crl). With short TTLs, most certs age out before a CRL pull catches them — revocation is a fast kill switch, not the primary expiration mechanism.

What KnoxCall doesn’t do (yet)

  • OCSP responder — only CRLs at v1.
  • DER-encoded CRL — text format only at v1; consumers that strictly require DER need a follow-up.
  • Non-EC algorithms — RSA / Ed25519 are roadmap.
  • CSR-based issuance — the keypair is generated server-side and the private key is returned to the caller. CSR support is on the list.

Quick rules of thumb

  • Pick short default TTLs (24–48h). Issuance is cheap; renewal is a curl.
  • Use separate roots for different trust domains (corp vs iot vs web). They have separate root certs, so a leak in one doesn’t compromise the others.
  • Use separate roles within a root for different scopes — e.g. read-only-services (allow_subdomains=false) vs infra-services (allow_subdomains=true).
  • The customer’s trust store only ever needs the root PEM. Re-installing it across the fleet is the expensive operation; rotating intermediates and leaves is invisible.

See also