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

Dynamic Secrets

A dynamic secret is a credential that ScaiVault generates on demand, for a specific caller, with a short lifetime. When the lifetime expires, ScaiVault automatically revokes it at the source. Compared to static credentials stored in a secret, dynamic secrets drastically reduce blast radius: if one leaks, it's valid for minutes, not months.

The mental model#

A static secret:

sequenceDiagram participant App participant SV as ScaiVault App->>SV: read app/db/password SV-->>App: "xyz..." Note over SV: same password for everyone<br/>rotates quarterly

A dynamic secret:

sequenceDiagram participant App participant SV as ScaiVault participant DB as Postgres App->>SV: POST /dynamic/engines/.../creds/readonly SV->>DB: CREATE ROLE v_readonly_abc PASSWORD ... DB-->>SV: ok SV-->>App: lease (username, password, 1h TTL) Note over App,DB: app uses creds for 1h Note over SV: 1h later SV->>DB: DROP ROLE v_readonly_abc DB-->>SV: ok

Every caller gets their own short-lived credential. ScaiVault handles creation on the source system (CREATE USER, IAM policy, SSH cert) and revocation when the lease expires.

Pieces#

  • Engine. A configuration pointing at a specific backend (a Postgres server, an AWS account, a GCP project). Has connection info and root credentials.
  • Role. A recipe for what kind of credential to generate from an engine. Names the permissions (SELECT ON public.*), constraints (max TTL), and any templated statements.
  • Lease. The result of generating credentials. Has an ID, a TTL, and the credential itself (username, password, token, etc.).

Supported engines#

Engine Generates Typical TTL
database.postgresql DB user with GRANT/REVOKE 1–8h
database.mysql DB user 1–8h
database.mongodb DB user 1–8h
database.redis Redis ACL user 1–8h
aws IAM access key or assumed role 15min–12h
azure Service principal 1–8h
gcp Service account key or impersonated token 1h–3h
ssh Signed SSH cert or one-time password 5min–1h
custom Whatever you script Your call

Creating an engine#

An engine needs root credentials for the target system. Those credentials are stored in ScaiVault itself — typically at a path protected by a narrow policy so only the engine machinery can read them.

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
curl -X POST https://scaivault.scailabs.ai/v1/dynamic/engines \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "support-db",
    "type": "database",
    "config": {
      "plugin": "postgresql",
      "connection_url": "postgresql://{{username}}:{{password}}@db.internal:5432/support",
      "root_credentials_path": "infra/db/support/root"
    },
    "default_ttl": "1h",
    "max_ttl": "24h"
  }'

root_credentials_path points at another secret in ScaiVault. On startup, the engine reads that secret and substitutes it into connection_url. You can rotate the root creds the same way you rotate any secret — including on a rotation policy.

Defining a role#

A role says: "when someone asks for credentials from this engine with this role name, run these statements."

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
curl -X POST https://scaivault.scailabs.ai/v1/dynamic/engines/support-db/roles \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "readonly",
    "creation_statements": [
      "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '\''{{password}}'\'' VALID UNTIL '\''{{expiration}}'\''",
      "GRANT USAGE ON SCHEMA public TO \"{{name}}\"",
      "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\""
    ],
    "revocation_statements": [
      "REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM \"{{name}}\"",
      "DROP ROLE IF EXISTS \"{{name}}\""
    ],
    "default_ttl": "1h",
    "max_ttl": "8h"
  }'

Template variables:

  • {{name}} — auto-generated username (e.g. v_readonly_a1b2c3d4).
  • {{password}} — auto-generated password.
  • {{expiration}} — the lease expiration in Postgres timestamp format.

Generating credentials#

An application with dynamic:generate on this engine asks for a credential:

bash
1
2
3
4
curl -X POST https://scaivault.scailabs.ai/v1/dynamic/engines/support-db/creds/readonly \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ttl": "2h"}'

Response:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "lease_id": "lease_abc123xyz",
  "data": {
    "username": "v_readonly_a1b2c3d4",
    "password": "kX9#mP2$vL5@nQ8&wR3!",
    "connection_url": "postgresql://v_readonly_a1b2c3d4:...@db.internal:5432/support"
  },
  "lease_duration": "2h",
  "renewable": true,
  "expires_at": "2026-04-23T22:00:00Z"
}

ScaiVault:

  1. Picks a username (v_<role>_<random>).
  2. Generates a random password.
  3. Connects to Postgres as root, runs the creation statements.
  4. Issues a lease with ID lease_abc123xyz.
  5. Returns the credential to you.

The lease is yours for 2 hours. After that, ScaiVault connects back and runs the revocation statements — the user disappears from Postgres.

Lease lifecycle#

stateDiagram-v2 [*] --> Active: POST /creds/{role} Active --> Active: renew (within max_ttl) Active --> Revoked: DELETE lease Active --> Expired: TTL elapsed Revoked --> [*]: revocation_statements run Expired --> [*]: revocation_statements run

Renew. Extend the lease without changing the credential:

bash
1
2
3
4
curl -X POST https://scaivault.scailabs.ai/v1/dynamic/leases/lease_abc123/renew \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"increment": "1h"}'

Can't extend past max_ttl. After that, you must generate a new credential.

Revoke. Force immediate revocation (the credential stops working instantly):

bash
1
2
curl -X DELETE https://scaivault.scailabs.ai/v1/dynamic/leases/lease_abc123 \
  -H "Authorization: Bearer $TOKEN"

Revoke by prefix. Bulk revoke during an incident — every lease for a compromised engine, or every lease issued by a specific role:

bash
1
2
3
4
curl -X POST https://scaivault.scailabs.ai/v1/dynamic/leases/revoke-prefix \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"prefix": "lease_db_", "engine": "support-db"}'

Using dynamic credentials in practice#

The idiomatic pattern:

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import httpx, time

def with_db_credential(func):
    def wrapper(*args, **kwargs):
        # Ask for a fresh lease
        resp = httpx.post(
            "https://scaivault.scailabs.ai/v1/dynamic/engines/support-db/creds/readonly",
            headers={"Authorization": f"Bearer {TOKEN}"},
            json={"ttl": "2h"},
        )
        lease = resp.json()
        try:
            return func(lease["data"], *args, **kwargs)
        finally:
            httpx.delete(
                f"https://scaivault.scailabs.ai/v1/dynamic/leases/{lease['lease_id']}",
                headers={"Authorization": f"Bearer {TOKEN}"},
            )
    return wrapper

@with_db_credential
def run_report(creds):
    # creds["username"], creds["password"], creds["connection_url"]
    # use them to connect and run your query
    ...

For longer-lived workers, renew before expiration instead of regenerating.

AWS, Azure, GCP engines#

AWS: ScaiVault assumes a role or creates IAM users. Configure the engine with a role ARN or an IAM user with the iam:CreateAccessKey permission. Dynamic creds are short-lived IAM keys or STS tokens.

json
1
2
3
4
5
6
7
8
{
  "name": "prod-aws",
  "type": "aws",
  "config": {
    "region": "us-east-1",
    "root_credentials_path": "infra/aws/prod/admin"
  }
}

Azure / GCP: analogous. Roles specify Azure RBAC roles or GCP IAM roles.

SSH engine#

Generates signed SSH certificates or one-time passwords for SSH logins. Pairs well with an SSH CA trust on your hosts.

bash
1
2
3
4
5
6
7
8
curl -X POST https://scaivault.scailabs.ai/v1/dynamic/engines/ssh-prod/creds/operator \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "alice",
    "public_key": "ssh-ed25519 AAAA...",
    "ttl": "30m"
  }'

Returns a signed OpenSSH certificate valid for 30 minutes.

What's next#

Updated 2026-05-17 14:36:05 View source (.md) rev 6