pki
A private certificate authority per tenant, in the style of AWS Private CA, step-ca or a SPIFFE server.
A private certificate authority per tenant, in the style of AWS Private CA, step-ca or a SPIFFE server. It issues
X.509 certificates for mutual TLS, internal HTTPS and workload identity (SPIFFE X.509-SVIDs). Authorities sign with KMS
keys pinned to one version. Every name a certificate carries is decided by policy on its own. iam.pki serves CRLs,
trust bundles and certificate verification to servers. The repository guide is docs/private-ca.md.
Deciding names
Policies cannot require that every entry of a list matches, so issuing evaluates iam:pki:issue on
iam/pki/{authorityId} once for the common name and once for each subject alternative name. The certificate is issued
only if every decision allows it. Each decision sees resource.name, resource.nameType (commonName, dns,
wildcard, uri, ip or email), resource.usage, resource.validitySeconds, resource.keyType and the
authority's resource.authorityId, resource.authorityName, resource.authorityType and resource.trustDomain.
Names are decided in the canonical form that is signed. A wildcard DNS name is its own name type, so allowing DNS names
does not allow wildcard certificates. Names must also fit the name constraints (permitted) of the issuing authority
and every authority above it, whoever asks.
| Method | What it does | Access |
|---|---|---|
bundle | The tenant's active root certificates as one PEM bundle: what relying parties trust. Intermediates travel in each server's chain. | Credential |
createAuthority | Creates a root (self-signed) or an intermediate authority (signed by parentId in the same tenant), with a new KMS signing key (keySpec, default ecc-p256) or an existing one (keyId) whose current version is pinned. Either way the key becomes managed by the authority (managedBy: 'pki'), and the keys API refuses to use it directly. | Credential |
crl | The authority's current certificate revocation list as PEM, rebuilt after revocations and at least every 12 hours. | Credential |
getAuthority | One authority: subject, type, parent, KMS key and pinned version, certificate, validity, state, trust domain, name constraints and leaf limits. | Credential |
getCertificate | One certificate by serial number (hexadecimal, colons allowed). | Credential |
issueCertificate | Issues a certificate for the key in a PEM PKCS#10 request (csr). The request must be signed by its own key, which proves the requester holds the private key. Names come from the request unless commonName, dnsNames, uris, ipAddresses or emails are given. usage is both (default), server or client. Validity defaults to the authority's defaultValiditySeconds, is capped at its maxValiditySeconds, and never outlasts the authority. Returns certificatePem, chainPem, rootPem, serialNumber, notBefore, notAfter and fingerprint. | Credential |
listAuthorities | The tenant's authorities the caller may read, oldest first. | Credential |
listCertificates | Certificates the caller may read, newest first, filtered by authorityId, status (valid, revoked, expired) or identityId. | Credential |
requestCertificate | A workload certificate (SPIFFE X.509-SVID) for the caller's own identity. Its only name is spiffe://{trustDomain}/{user|service|agent}/{identityId}, it has an empty subject, and it is valid for one hour by default. For user sessions and API keys acting in their own right. | Credential |
revokeCertificate | Revokes a certificate with a reason (unspecified, keyCompromise, caCompromise, affiliationChanged, superseded, cessationOfOperation or privilegeWithdrawn). It fails verification at once and appears on the next CRL. Revoking a subordinate authority's certificate revokes that authority too. | Credential |
updateAuthority | Disables or re-enables an authority (state), and changes maxValiditySeconds, defaultValiditySeconds or crlUrl (null clears it) for future certificates. A disabled authority issues nothing, and what it issued fails verification until it is active again. | Credential |
bundle
The tenant's active root certificates as one PEM bundle: what relying parties trust. Intermediates travel in each server's chain.
- Permission:
iam:pki:read(per authority).
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/bundle" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.pki.bundle(
credential: CredentialInput,
input: { tenantId: string },
): Promise<{ pem: string; authorities: number }>createAuthority
Creates a root (self-signed) or an intermediate authority (signed by parentId in the same tenant), with a new KMS signing key (keySpec, default ecc-p256) or an existing one (keyId) whose current version is pinned. Either way the key becomes managed by the authority (managedBy: 'pki'), and the keys API refuses to use it directly.
Used inPrivate CA
- Permission:
iam:pki:createoniam/pkiwith recent authentication;iam:pki:updateon the parent for an intermediate;iam:kms:signon an existing key. - Audited as:
iam:pki:create(metadata:authorityId,name,type,keyId,serialNumber,parentId). - Errors:
INVALID_INPUTfor a missingsubject.commonName, an invalid key spec, or a path length the chain does not allow;CONFLICTfor a name in use or a trust domain another tenant has;KEY_MANAGEDfor a key another authority or profile manages;AUTHORITY_UNAVAILABLEwhen the parent chain is not active;LIMIT_EXCEEDEDpast 50 authorities;RECENT_AUTH_REQUIRED.
const issuing = await iam.api.pki.createAuthority(admin, {
tenantId,
name: 'Acme Workloads',
parentId: root.id,
subject: { commonName: 'Acme Workload CA' },
trustDomain: 'acme.internal',
permitted: { dnsNames: ['internal'], uriHosts: ['acme.internal'] },
});A AuthorityCreateInput object:
Prop
Type
A AuthoritySummary object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/createAuthority" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"name": "<name>",
"subject": {}
}'iam.api.pki.createAuthority(
credential: CredentialInput,
input: AuthorityCreateInput,
): Promise<AuthoritySummary>crl
The authority's current certificate revocation list as PEM, rebuilt after revocations and at least every 12 hours.
- Permission:
iam:pki:read. Relying parties fetch the same CRL without a credential throughiam.pki.crlResponse.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/crl" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"authorityId": "<authorityId>"
}'iam.api.pki.crl(
credential: CredentialInput,
input: { tenantId: string; authorityId: string },
): Promise<{ pem: string; crlNumber: number; thisUpdate: number; nextUpdate: number }>getAuthority
One authority: subject, type, parent, KMS key and pinned version, certificate, validity, state, trust domain, name constraints and leaf limits.
- Permission:
iam:pki:read.
Prop
Type
A AuthoritySummary object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/getAuthority" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"authorityId": "<authorityId>"
}'iam.api.pki.getAuthority(
credential: CredentialInput,
input: { tenantId: string; authorityId: string },
): Promise<AuthoritySummary>getCertificate
One certificate by serial number (hexadecimal, colons allowed).
- Permission:
iam:pki:readon its authority.
Prop
Type
A CertificateSummary object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/getCertificate" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"serialNumber": "<serialNumber>"
}'iam.api.pki.getCertificate(
credential: CredentialInput,
input: { tenantId: string; serialNumber: string },
): Promise<CertificateSummary>issueCertificate
Issues a certificate for the key in a PEM PKCS#10 request (csr). The request must be signed by its own key, which proves the requester holds the private key. Names come from the request unless commonName, dnsNames, uris, ipAddresses or emails are given. usage is both (default), server or client. Validity defaults to the authority's defaultValiditySeconds, is capped at its maxValiditySeconds, and never outlasts the authority. Returns certificatePem, chainPem, rootPem, serialNumber, notBefore, notAfter and fingerprint.
Used inPrivate CA
- Permission:
iam:pki:issuefor every name on the certificate. - Audited as:
iam:pki:issue(metadata:serialNumber,names,notAfter,usage). - Errors:
INVALID_CSRfor a malformed or unsigned request or an unsupported key;NAME_NOT_PERMITTEDfor a name outside the name constraints or a SPIFFE ID outside the trust domain;INVALID_INPUTfor a certificate with no names, two URIs beside a SPIFFE ID, or a validity beyond the maximum;AUTHORITY_UNAVAILABLE;KEY_STATE_INVALIDwhen the authority's KMS key is disabled.
A CertificateIssueInput object:
Prop
Type
A IssuedCertificate object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/issueCertificate" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"authorityId": "<authorityId>",
"csr": "<csr>"
}'iam.api.pki.issueCertificate(
credential: CredentialInput,
input: CertificateIssueInput,
): Promise<IssuedCertificate>listAuthorities
The tenant's authorities the caller may read, oldest first.
- Permission:
iam:pki:read, evaluated for each authority.
Prop
Type
An array of AuthoritySummary.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/listAuthorities" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.pki.listAuthorities(
credential: CredentialInput,
input: { tenantId: string },
): Promise<AuthoritySummary[]>listCertificates
Certificates the caller may read, newest first, filtered by authorityId, status (valid, revoked, expired) or identityId.
- Permission:
iam:pki:readon each certificate's authority.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/listCertificates" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.pki.listCertificates(
credential: CredentialInput,
input: {
tenantId: string;
authorityId?: string;
status?: 'valid' | 'revoked' | 'expired';
identityId?: string;
limit?: number;
offset?: number;
},
): Promise<{ certificates: CertificateSummary[]; total: number }>requestCertificate
A workload certificate (SPIFFE X.509-SVID) for the caller's own identity. Its only name is spiffe://{trustDomain}/{user|service|agent}/{identityId}, it has an empty subject, and it is valid for one hour by default. For user sessions and API keys acting in their own right.
Used inPrivate CA
- Permission:
iam:pki:requeston the authority;resource.nameis the SPIFFE ID andresource.identityKindthe caller's kind. - Audited as:
iam:pki:request(metadata:serialNumber,spiffeId,notAfter). - Errors:
INVALID_INPUTwhen the authority has no trust domain;ACCESS_DENIEDfor assumed roles, session tokens, delegated sessions and impersonation.
Prop
Type
A IssuedCertificate object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/requestCertificate" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"authorityId": "<authorityId>",
"csr": "<csr>"
}'iam.api.pki.requestCertificate(
credential: CredentialInput,
input: {
tenantId: string;
authorityId: string;
csr: string;
validitySeconds?: number;
},
): Promise<IssuedCertificate>revokeCertificate
Revokes a certificate with a reason (unspecified, keyCompromise, caCompromise, affiliationChanged, superseded, cessationOfOperation or privilegeWithdrawn). It fails verification at once and appears on the next CRL. Revoking a subordinate authority's certificate revokes that authority too.
- Permission:
iam:pki:revokeon the issuing authority. - Audited as:
iam:pki:revoke(metadata:serialNumber,reason,subordinateId). - Errors:
CONFLICTwhen already revoked.
Prop
Type
A CertificateSummary object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/revokeCertificate" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"serialNumber": "<serialNumber>"
}'iam.api.pki.revokeCertificate(
credential: CredentialInput,
input: { tenantId: string; serialNumber: string; reason?: RevocationReason },
): Promise<CertificateSummary>updateAuthority
Disables or re-enables an authority (state), and changes maxValiditySeconds, defaultValiditySeconds or crlUrl (null clears it) for future certificates. A disabled authority issues nothing, and what it issued fails verification until it is active again.
- Permission:
iam:pki:update. - Errors:
AUTHORITY_UNAVAILABLEfor a revoked authority.
Prop
Type
A AuthoritySummary object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/pki/updateAuthority" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"authorityId": "<authorityId>"
}'iam.api.pki.updateAuthority(
credential: CredentialInput,
input: {
tenantId: string;
authorityId: string;
state?: 'active' | 'disabled';
maxValiditySeconds?: number;
defaultValiditySeconds?: number;
crlUrl?: string | null;
},
): Promise<AuthoritySummary>Better IAM is created by Sean Filimon
Last updated