Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

PKI Certificates

Run an internal CA, issue certificates, manage CSRs and trust anchors. For ACME and public cert issuance, see ACME. For the conceptual model, see PKI.

Base path: /v1/pki/

Create an internal CA#

Start with a root:

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
curl -X POST https://scaivault.scailabs.ai/v1/pki/ca \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "acme-root",
    "common_name": "Acme Root CA",
    "ca_type": "root",
    "key_type": "ec",
    "key_size": 256,
    "validity_days": 3650
  }'
python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
resp = httpx.post(
    "https://scaivault.scailabs.ai/v1/pki/ca",
    headers={"Authorization": f"Bearer {os.environ['SCAIVAULT_TOKEN']}"},
    json={
        "name": "acme-root",
        "common_name": "Acme Root CA",
        "ca_type": "root",
        "key_type": "ec",
        "key_size": 256,
        "validity_days": 3650,
    },
)
typescript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const resp = await fetch("https://scaivault.scailabs.ai/v1/pki/ca", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SCAIVAULT_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "acme-root",
    common_name: "Acme Root CA",
    ca_type: "root",
    key_type: "ec",
    key_size: 256,
    validity_days: 3650,
  }),
});

Response:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "id": "ca_root_abc",
  "name": "acme-root",
  "common_name": "Acme Root CA",
  "ca_type": "root",
  "key_type": "ec",
  "key_size": 256,
  "valid_from": "2026-04-23T14:00:00Z",
  "valid_until": "2036-04-20T14:00:00Z",
  "is_active": true,
  "certificates_issued": 0,
  "created_at": "2026-04-23T14:00:00Z"
}

Then an intermediate:

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
curl -X POST https://scaivault.scailabs.ai/v1/pki/ca \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "acme-mtls-intermediate",
    "common_name": "Acme mTLS Intermediate",
    "ca_type": "intermediate",
    "parent_ca_id": "ca_root_abc",
    "key_type": "ec",
    "key_size": 256,
    "validity_days": 1825
  }'

Fields#

Field Required Description
name Yes Tenant-unique
common_name Yes Subject CN
ca_type Yes root or intermediate
parent_ca_id For intermediates Parent CA ID
key_type No rsa (default) or ec
key_size No 2048/4096 for RSA; 256/384 for EC
validity_days No Default 3650 for roots, 1825 for intermediates

Get CA certificate in PEM#

bash
1
2
curl -H "Authorization: Bearer $TOKEN" \
     https://scaivault.scailabs.ai/v1/pki/ca/ca_root_abc/certificate

Response:

json
1
2
3
{
  "certificate_pem": "-----BEGIN CERTIFICATE-----\n..."
}

Distribute this to your clients as a trust root.

Create a PKI role#

A role constrains issuance: what domains, what key types, what TTL.

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
curl -X POST https://scaivault.scailabs.ai/v1/pki/roles \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "svc-mtls",
    "ca_id": "ca_intermediate_mtls",
    "allowed_domains": ["*.svc.cluster.local", "*.internal"],
    "allow_subdomains": true,
    "allow_ip_sans": true,
    "max_ttl": "720h",
    "key_type": "ec",
    "key_bits": 256,
    "require_cn": true
  }'

Role fields#

Field Description
ca_id Which CA signs certs for this role
allowed_domains Allow-list of domain patterns
allow_subdomains Whether *.allowed-domain.com is OK
allow_ip_sans Allow IP SANs
max_ttl Cap on requested TTL
key_type, key_bits Required key type for issued certs
require_cn Reject CSRs without a CN

Issue a certificate#

bash
1
2
3
4
5
6
7
8
9
curl -X POST https://scaivault.scailabs.ai/v1/pki/issue/svc-mtls \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "common_name": "billing.svc.cluster.local",
    "alt_names": ["billing-api.svc.cluster.local"],
    "ip_sans": ["10.0.5.100"],
    "ttl": "168h"
  }'

Response (201 Created):

json
1
2
3
4
5
6
7
{
  "certificate": "-----BEGIN CERTIFICATE-----\n...",
  "private_key": "-----BEGIN EC PRIVATE KEY-----\n...",
  "ca_chain": ["-----BEGIN CERTIFICATE-----\n..."],
  "serial_number": "1A:2B:3C:4D:5E:6F:...",
  "not_after": "2026-04-30T14:00:00Z"
}

The private key is returned exactly once. Save it securely — ScaiVault doesn't keep a plaintext copy by default. If the role is configured with store_private_keys: true, you can retrieve it later via POST /v1/pki/certificates/{id}/private-key.

Sign a CSR#

When a peer generates their own key, they send you a CSR. Sign it directly:

bash
1
2
3
4
5
6
7
curl -X POST https://scaivault.scailabs.ai/v1/pki/sign/svc-mtls \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "csr_pem": "-----BEGIN CERTIFICATE REQUEST-----\n...",
    "ttl": "168h"
  }'

Response contains certificate, ca_chain, serial_number, not_after — no private key.

CSR workflow (with approval)#

For CSRs that need human review before signing:

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 1. Import the CSR
curl -X POST https://scaivault.scailabs.ai/v1/pki/csr/import \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"csr_pem": "-----BEGIN CERTIFICATE REQUEST-----\n..."}'
# → {"id": "csr_abc", "status": "pending", ...}

# 2. Review what was requested
curl -H "Authorization: Bearer $TOKEN" \
     https://scaivault.scailabs.ai/v1/pki/csr/csr_abc

# 3. Approve or reject
curl -X POST https://scaivault.scailabs.ai/v1/pki/csr/csr_abc/approve \
  -H "Authorization: Bearer $TOKEN"

# 4. Sign against a CA
curl -X POST https://scaivault.scailabs.ai/v1/pki/csr/csr_abc/sign \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ca_id": "ca_intermediate_mtls", "validity_days": 90}'

Alternatively, generate the CSR in ScaiVault itself (private key stays in the vault):

bash
1
2
3
4
5
6
7
8
9
curl -X POST https://scaivault.scailabs.ai/v1/pki/csr \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": {"common_name": "billing.svc.cluster.local"},
    "san_dns": ["billing-api.svc.cluster.local"],
    "key_type": "ec",
    "key_size": 256
  }'

Reject a CSR with reason:

bash
1
2
3
4
curl -X POST https://scaivault.scailabs.ai/v1/pki/csr/csr_abc/reject \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason": "CN not in allowed scope"}'

List issued certificates#

bash
1
2
curl -H "Authorization: Bearer $TOKEN" \
     "https://scaivault.scailabs.ai/v1/pki/certificates?ca_id=ca_intermediate_mtls&expiring_within=30d"

Response:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "data": [
    {
      "id": "cert_abc",
      "common_name": "billing.svc.cluster.local",
      "issuer_ca_id": "ca_intermediate_mtls",
      "serial_number": "1A:2B:...",
      "valid_from": "2026-04-23T14:00:00Z",
      "valid_until": "2026-04-30T14:00:00Z",
      "is_revoked": false
    }
  ],
  "cursor": null,
  "has_more": false
}

Validate a certificate chain#

bash
1
2
3
4
5
6
7
8
curl -X POST https://scaivault.scailabs.ai/v1/pki/certificates/validate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "certificate_pem": "-----BEGIN CERTIFICATE-----\n...",
    "chain_pem": "-----BEGIN CERTIFICATE-----\n...",
    "check_revocation": true
  }'

Response:

json
1
2
3
4
5
6
7
{
  "valid": true,
  "chain_valid": true,
  "not_expired": true,
  "not_revoked": true,
  "trusted_anchor": "trust_anchor_xyz"
}

Revoke a certificate#

bash
1
2
3
4
curl -X POST https://scaivault.scailabs.ai/v1/pki/revoke \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"serial_number": "1A:2B:3C:...", "reason": "key_compromise"}'

Reasons (RFC 5280): unspecified, key_compromise, ca_compromise, affiliation_changed, superseded, cessation_of_operation, certificate_hold, privilege_withdrawn, aa_compromise.

CRL#

Get the current CRL for a CA:

bash
1
curl https://scaivault.scailabs.ai/v1/pki/ca/ca_intermediate_mtls/crl

Returns application/pkix-crl (DER) or PEM depending on Accept header.

Force immediate regeneration (default is hourly):

bash
1
2
curl -X POST https://scaivault.scailabs.ai/v1/pki/ca/ca_intermediate_mtls/crl \
  -H "Authorization: Bearer $TOKEN"

Trust anchors#

Register an external CA certificate you want to trust:

bash
1
2
3
4
5
6
7
curl -X POST https://scaivault.scailabs.ai/v1/pki/trust-anchors \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "vendor-xyz-root",
    "certificate_pem": "-----BEGIN CERTIFICATE-----\n..."
  }'

List and delete:

bash
1
2
curl -H "Authorization: Bearer $TOKEN" https://scaivault.scailabs.ai/v1/pki/trust-anchors
curl -X DELETE -H "Authorization: Bearer $TOKEN" https://scaivault.scailabs.ai/v1/pki/trust-anchors/trust_anchor_xyz

Trust anchors are consulted by POST /v1/pki/certificates/validate.

Renew a certificate#

bash
1
2
3
4
curl -X POST https://scaivault.scailabs.ai/v1/pki/certificates/cert_abc/renew \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ttl": "168h"}'

Issues a new cert with the same subject and SANs, returns the new PEM + key. The old cert stays valid until its not_after.

Import an existing certificate#

For certificates issued elsewhere that you want to track in ScaiVault:

bash
1
2
3
4
5
6
7
8
curl -X POST https://scaivault.scailabs.ai/v1/pki/certificates/import \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "certificate_pem": "-----BEGIN CERTIFICATE-----\n...",
    "private_key_pem": "-----BEGIN PRIVATE KEY-----\n...",
    "chain_pem": "-----BEGIN CERTIFICATE-----\n..."
  }'

What's next#

  • ACME — public certificates from Let's Encrypt et al.
  • PKI — conceptual model.
  • PKI Reference — all endpoints.
Updated 2026-05-17 13:26:50 View source (.md) rev 2