Vaultic
Integrations

Rotation providers

How server-side rotation execution works, and every provider (postgres, mysql, redis, aws-iam, generic-webhook, cloudflare, gitlab).

secrets rotate --provider <name> hands the new-value computation off to a rotation plugin instead of you typing one in. Run vaultic rotation-providers to list every available plugin and its description.

Where rotation actually runs

The CLI itself never connects directly to the external system being rotated (a customer's database, a payment provider, a cloud IAM service, ...) — only the Vaultic server does. "Rotate the credential" and "store the new value" are two separate steps:

Reveal the current value

The CLI reveals the secret's current value via the API.

Execute the rotation, server-side

The CLI calls the rotate-execute endpoint with the provider name, current value, and any provider-specific options (--role, --admin-conn-string, etc.). The server connects to the target system and performs the actual rotation there.

Store the result

The CLI stores the returned value via the ordinary rotate flow — see Secrets rotation for the grace window and webhook that applies here.

The upshot: only the Vaultic server needs network access and credentials to reach a target database (or other external system) — not every machine that happens to run the CLI. Rotation execution is authorized and audit-logged the same way any other write to a secret is (secret.rotation_executed in the audit log, alongside secret.rotated for the storage step).

postgres, mysql, and redis all connect to a customer-supplied host, so they share two env vars on the server:

Env varDefaultPurpose
ROTATION_ALLOWED_HOSTS(none)Comma-separated hostnames exempt from the public-IP check below — for scratch/dev/self-hosted targets that only resolve internally
ROTATION_CONNECTION_TIMEOUT_MS5000Connection timeout for the rotation attempt

Every target host is checked against assertPublicHostname (the same SSRF guard used for outbound webhooks) unless it's in ROTATION_ALLOWED_HOSTS — a rotation secret's connection string can't be used to reach internal infrastructure or the cloud metadata endpoint.

postgres

Treats the secret's current value as a postgres://user:password@host:port/db connection string. The server connects (with the current value, or --admin-conn-string for different credentials — e.g. a superuser), runs ALTER ROLE "<role>" WITH PASSWORD '<new>', and returns an updated connection string with the new password. Single-user rotation — there's no create-a-second-role dance, just an in-place password change.

vaultic secrets rotate DB_URL --provider postgres --admin-conn-string "$DB_ADMIN_URL"
FlagDescription
--role <name>Role to rotate (default: username parsed from the connection string)
--admin-conn-string <url>Connect with different credentials than the value being rotated
--new-password <value>Use this password instead of a random 32-byte base64url one

Role names are validated against ^[A-Za-z_][A-Za-z0-9_]*$; only postgres:///postgresql:// connection strings are accepted.

mysql

The same idea as postgres, for MySQL: treats the current value as a mysql://user:password@host:port/db connection string and runs ALTER USER 'user'@'host' IDENTIFIED BY '<new>'. Single-user rotation, no blue/green account pair. MySQL accounts are 'user'@'host' pairs, not just a username — the host part defaults to % (the common "app user connecting from anywhere" grant) and can be overridden.

vaultic secrets rotate DB_URL --provider mysql --option host=10.0.%.%
FlagDescription
--role <name>User to rotate (default: username parsed from the connection string)
--option host=<pattern>The '@host' part of the account (default %)
--admin-conn-string <url>Connect with different credentials than the value being rotated
--new-password <value>Use this password instead of a random 32-byte base64url one

redis

Treats the current value as a redis://[user:]password@host:port connection string (rediss:// for TLS) and runs ACL SETUSER <user> resetpass ><new> — requires Redis 6+ ACLs. resetpass clears every previously-set password on the user before adding the new one; the account's other ACL rules (key patterns, command permissions) are untouched. A connection string with no explicit username (the legacy requirepass-only form) rotates the built-in default user.

vaultic secrets rotate REDIS_URL --provider redis
FlagDescription
--role <name>ACL username to rotate (default: username parsed from the connection string, or default)
--admin-conn-string <url>Connect with different credentials than the value being rotated
--new-password <value>Use this password instead of a random password

aws-iam

Rotates an AWS IAM access key: creates a new key, verifies it authenticates (GetUser), then deletes the old one — the standard two-key dance. This one's different from the database providers above in one respect: it doesn't take a customer host at all, and it uses the secret's own current credentials to talk to AWS, the same self-service shape as postgres/mysql rotating their own password. Give the IAM user a policy scoped to iam:CreateAccessKey/iam:DeleteAccessKey/iam:GetUser on arn:aws:iam::*:user/${aws:username} (or equivalent) so it can manage its own keys.

Treats the secret's current value as JSON: {"accessKeyId":"...","secretAccessKey":"..."} — the new value is stored in the same shape.

vaultic secrets rotate AWS_KEY --provider aws-iam --option region=eu-west-1
FlagDescription
--option region=<region>AWS region for the IAM calls (default us-east-1; IAM is a global service, but the SDK still needs one)

If verification fails, the newly-created key is deleted and the original key is left untouched — rotation never leaves the account with zero working keys. If the final delete-the-old-key step fails, rotation still succeeds (the new key is already confirmed working), and the summary returned calls out the orphaned key so it can be cleaned up by hand.

generic-webhook

The escape hatch for anything without a rotation API. Vaultic generates a new value (or uses one you supply), HMAC-signs it with the same scheme as outbound webhook deliveries, and POSTs { secretKey, newValue } to an endpoint you run. That endpoint applies the new value to whatever system it fronts and responds with a 2xx status; Vaultic then stores the same value it sent.

vaultic secrets rotate API_KEY --provider generic-webhook \
  --option endpoint=https://example.com/rotate-hook \
  --option secret="$ROTATE_HOOK_SECRET"
FlagDescription
--option endpoint=<url>Your endpoint (required)
--option secret=<value>HMAC secret — signs the request body into an x-vaultic-signature: sha256=... header, same as webhook deliveries
--option newValue=<value>Use this value instead of a randomly generated one

Unlike ordinary webhook event dispatch (fire-and-forget, single attempt, a failure just recorded in the delivery log), this call is synchronous — the caller is waiting on the new value — so a failed attempt is retried with backoff (up to 3 attempts total) before rotation fails outright. The endpoint is checked with the same SSRF guard as every other outbound webhook, including across redirects.

cloudflare

Rolls a Cloudflare API token to a new value in place via PUT /user/tokens/:id/value — the token's scopes, resources, and policies are untouched, only the secret value changes. No create/verify/delete dance needed; Cloudflare's API does the swap atomically. Self-service: the token authenticates its own roll request.

Treats the secret's current value as JSON: {"tokenId":"...","value":"..."} — the new value is stored in the same shape.

vaultic secrets rotate CF_TOKEN --provider cloudflare

Talks to Cloudflare's own fixed API host (api.cloudflare.com), not a customer-supplied one, so — like aws-iam — there's no ROTATION_ALLOWED_HOSTS involvement here.

gitlab

Rotates a GitLab personal access token via POST /personal_access_tokens/self/rotate — authenticated with the token being rotated, it invalidates that token and returns a fresh one with the same scopes. Self-service, same shape as cloudflare/aws-iam.

Treats the secret's current value as the raw PAT (no JSON wrapping needed).

vaultic secrets rotate GITLAB_PAT --provider gitlab \
  --option gitlabUrl=https://gitlab.example.com \
  --option expiresAt=2027-01-01
FlagDescription
--option gitlabUrl=<url>GitLab instance base URL (default https://gitlab.com)
--option expiresAt=<YYYY-MM-DD>New expiry for the rotated token (optional)

Unlike cloudflare/aws-iam, the target host here is customer-supplied (self-hosted GitLab is common), so this goes through the same SSRF-guarded, redirect-following fetch as outbound webhooks and generic-webhook rotation — not the ROTATION_ALLOWED_HOSTS path postgres/mysql/redis use.

Other providers

GitHub personal access token rotation (fine-grained or classic) was considered and left out: GitHub's API has no endpoint to create a new PAT — only list and revoke — so there's no "new value" a plugin could actually produce. That's a GitHub API gap, not a Vaultic limitation — gitlab above rotates real PATs precisely because GitLab exposes the endpoint GitHub doesn't. A rotation reminder (--remind-every, see Secrets rotation) plus a manual regeneration flow is the honest answer for GitHub today.

On this page