Examples

Configuration examples.

goca is configured as documents: the create-CA form is the POST /v1/cas body, and every other object is a versioned resource behind one uniform API. The console holds each document in a split view — the form on one side, the same document as YAML or JSON on the other — so every example on this page is also exactly what you would click together in the console.

YAML or JSON — the same document

The control below switches every example between the two. They are one document in two representations, not two features: the API speaks JSON, so the JSON view is the literal request body, and the YAML view is that same document in the form the console's code pane holds it — and the form a reviewed change lives in before it is applied. Comments are a YAML-only luxury, so nothing on this page hides inside one: whatever is worth saying is said in the prose beside the block.

These examples target the current build

Verified against the product manual on 2026-08-17. Where a field is stored but not yet enforced (for example an endpoint's sourceRanges), the example leaves it out rather than pretending. Free — download on request.

ECC issuing CA (ECDSA P-384)

One POST /v1/cas creates the CA, and the optional spec block sets labels, path length, CRL cadence and the publication URLs at creation time — before the first certificate can be issued without them.

POST /v1/cas

YAML

name: ica-tls
commonName: ACME TLS Issuing CA G1
algorithm: ecdsa-p384
validityYears: 10
issuerRef: acme-root
spec:
  labels:
    family: tls
    env: prod
  constraints:
    pathLen: 0
  crl:
    full:
      interval: 24h
      validity: 72h
    onRevocation: immediate
  publication:
    baseUrl: http://pki.acme.example
  rollover:
    mode: manual

JSON

{
  "name": "ica-tls",
  "commonName": "ACME TLS Issuing CA G1",
  "algorithm": "ecdsa-p384",
  "validityYears": 10,
  "issuerRef": "acme-root",
  "spec": {
    "labels": {
      "family": "tls",
      "env": "prod"
    },
    "constraints": {
      "pathLen": 0
    },
    "crl": {
      "full": {
        "interval": "24h",
        "validity": "72h"
      },
      "onRevocation": "immediate"
    },
    "publication": {
      "baseUrl": "http://pki.acme.example"
    },
    "rollover": {
      "mode": "manual"
    }
  }
}

Key generation is executed by keysvc in the selected custody — the management process never receives a CA private key.

Post-quantum root CA (SLH-DSA)

No issuerRef means a self-signed root; slh-dsa-sha2-192s is the manual's conservative PQC root choice (ECDSA P-384 the classical one).

POST /v1/cas

YAML

name: root-pqc
commonName: Example Root CA G1
organization: Example
algorithm: slh-dsa-sha2-192s
validityYears: 20

JSON

{
  "name": "root-pqc",
  "commonName": "Example Root CA G1",
  "organization": "Example",
  "algorithm": "slh-dsa-sha2-192s",
  "validityYears": 20
}

For production hierarchies, prefer running CA creation as a ceremony (plan → quorum approval → execute); the direct API path creates immediately and is fine for evaluation.

ACME endpoint (RFC 8555)

An AcmeEndpoint document publishes a directory at https://<head>/acme/<name>/directory; allowed templates are advertised as ACME profiles, registration defaults to external account binding, and order retention lives on the endpoint because the endpoint is what produced the orders. The config API wraps every document in a spec field; the console's code pane shows what is inside it.

PUT /v1/config/resources/AcmeEndpoint/web

YAML

spec:
  enabled: true
  defaultTemplate: tls-server-ecdsa
  templates: [tls-server-ecdsa, tls-server-pqc]
  registration:
    mode: eab-required
  challenges: [http-01, dns-01]
  retention:
    orders: 720h

JSON

{
  "spec": {
    "enabled": true,
    "defaultTemplate": "tls-server-ecdsa",
    "templates": ["tls-server-ecdsa", "tls-server-pqc"],
    "registration": {
      "mode": "eab-required"
    },
    "challenges": ["http-01", "dns-01"],
    "retention": {
      "orders": "720h"
    }
  }
}

Endpoint lint requires automatic approval on the bound templates — ACME clients expect prompt order completion. Set GOCA_ACME_BASE_URL to the external origin clients use.

TLS server template → CA binding

Which CA issues under a template is declared on the template (issuerRef) — endpoints bind a template and the CA follows, so the binding is maintained in exactly one place; the seeded TLS server templates ship unbound by design, so the first save picks the CA. When the same profile must issue from several CAs, derive instead of copying: derivedFrom names the master, and issuerRef is the only thing a derived document is allowed to change.

POST /v1/templates

YAML

name: tls-server-pqc-dev
document:
  derivedFrom: tls-server-pqc
  issuerRef: ica-tls-dev

JSON

{
  "name": "tls-server-pqc-dev",
  "document": {
    "derivedFrom": "tls-server-pqc",
    "issuerRef": "ica-tls-dev"
  }
}

Those two fields are the derived template's entire document — anything else is rejected ("edit the master instead"). The save carries the name beside it: in the console the name is the field above the editor and the code pane holds only the document half; over the API the two travel in one body. A derived template mirrors the master's latest version at resolution time. Known caveat in the current build: derived templates carry a registered defect (build-gap register CA-011) — check the register before relying on them.

YubiKey PIV as a PKCS#11 module

A Pkcs11Module document names the vendor library, the token and a PIN reference — never the PIN itself; this exact custody path is verified on real YubiKey hardware. presenceRequired: true is the touch policy: unattended signing is refused, not retried.

PUT /v1/config/resources/Pkcs11Module/yubikey-piv

YAML

spec:
  displayName: YubiKey PIV
  library: /usr/lib/x86_64-linux-gnu/libykcs11.so
  tokenLabel: "YubiKey PIV #19923655"
  keyLabelPrefix: goca-
  presenceRequired: true
  login:
    mode: pin
    pinRef: secret:hsm-pin

JSON

{
  "spec": {
    "displayName": "YubiKey PIV",
    "library": "/usr/lib/x86_64-linux-gnu/libykcs11.so",
    "tokenLabel": "YubiKey PIV #19923655",
    "keyLabelPrefix": "goca-",
    "presenceRequired": true,
    "login": {
      "mode": "pin",
      "pinRef": "secret:hsm-pin"
    }
  }
}

pinRef is a reference — the document is versioned, returned verbatim by GET and copied into the audit chain, so a PIN typed there is a PIN published. Note the quotes on tokenLabel: a # after a space starts a YAML comment, so a label carrying one has to be quoted. A YubiKey PIV applet permits one session, so serve it from exactly one keysvc (bind the module to a site only that keysvc proves, or name it in that keysvc's GOCA_PKCS11_MODULE allowlist). A touch-policy key suits an offline root, not an issuing CA with scheduled CRLs.

AWS KMS provider

A KmsProvider document names the region and an auth mode. instance-role — IRSA, an ECS task role or an EC2 instance profile — stores no credential anywhere and is the production choice; GOCA_KMS_PROVIDER on keysvc selects the document.

PUT /v1/config/resources/KmsProvider/aws-prod

YAML

spec:
  provider: aws-kms
  region: eu-central-1
  auth:
    mode: instance-role

JSON

{
  "spec": {
    "provider": "aws-kms",
    "region": "eu-central-1",
    "auth": {
      "mode": "instance-role"
    }
  }
}

Off AWS compute there is no instance role, so the same document names a static key instead: the key ID inline, because it is an identifier that rides in every signed request, and the secret access key by reference — never the value.

PUT /v1/config/resources/KmsProvider/aws-onprem

YAML

spec:
  provider: aws-kms
  region: eu-central-1
  auth:
    mode: access-key
    accessKeyId: AKIAIOSFODNN7EXAMPLE
    secretAccessKeyRef: secret:aws-kms-secret

JSON

{
  "spec": {
    "provider": "aws-kms",
    "region": "eu-central-1",
    "auth": {
      "mode": "access-key",
      "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
      "secretAccessKeyRef": "secret:aws-kms-secret"
    }
  }
}

AKIAIOSFODNN7EXAMPLE is AWS's own documentation placeholder, not a live key. AWS and Google Cloud KMS are built and accepted by the validator, but the console's provider editor currently offers Azure only — apply an AWS or GCP document through the API as above. A PQC (ML-DSA/SLH-DSA) CA on any cloud provider uses kms-wrapped custody; strict kms on AWS signs classical algorithms up to P-521.

MFA policy and four-eyes approval

The MFA floor is compiled in — system-admin always requires a second factor and no document can turn that off; an MfaPolicy may only add roles.

PUT /v1/config/resources/MfaPolicy/default

YAML

spec:
  requiredRoles: [system-admin, ca-officer]

JSON

{
  "spec": {
    "requiredRoles": ["system-admin", "ca-officer"]
  }
}

Multi-person approval counts people including the proposer, so four eyes is people: 2. Turning it on is a command rather than a document, so it has no YAML view in the console and none here:

POST /v1/approval/enable

JSON

{
  "people": 2,
  "scope": "security"
}

JSON only — a command, not a versioned document.

Enablement refuses until at least people + 1 administrators are eligible, and once it is on you cannot turn it off alone — only a full quorum, or the break-glass cards. Deleting the approval state turns the control on, not off.

Try them against a running instance.

The fifteen-minute Docker Compose quickstart gives you a CA these documents can be applied to.

Request a download link Quickstart

Free — download on request.