secrets.sa-saopaulo-1.basaltic.sh.
Metadata and value
Two endpoints, two IAM actions, and why reading the value is the audited
one.
Versions
Rotation without losing what came before.
Delete and restore
The recovery window, and the one thing repeating a delete will not do.
Your own KMS key
What binding a secret to a customer-managed key actually changes.
Creating a secret
201 and the secret is at version 1.
base64, 1 byte – 64 KiB
Values travel base64-encoded so arbitrary binary payloads survive JSON
intact. Anything larger than 64 KiB belongs in a bucket, with
the secret holding the reference and the credentials to fetch it — not
crammed inline.
unique per account
Matches
^[a-zA-Z0-9][a-zA-Z0-9._/-]{0,255}$. Slashes are allowed, which is
why prod/api/stripe-key works — and because the CRN is built from the name,
a path convention becomes directly policy-able:
crn:secrets:sa-saopaulo-1:my-account:secret/prod/*.The value is a separate endpoint
Describing a secret and reading it are different operations with different permissions.GET /v1/secrets/{id}
Name, description, tags, current version number, which KMS key it is bound
to, deletion state. Never the value. Guarded by
secrets:DescribeSecret.GET /v1/secrets/{id}/value
The decrypted plaintext, base64-encoded. Guarded by the separate,
narrower
secrets:GetSecretValue.secrets:DescribeSecret across everything and still
be unable to read a single value.
Every plaintext read is recorded, successful or not. A denied read, a
probe for an id the caller does not own, and a decrypt that failed are all
written to the audit trail with the error code that stopped them — that set
is exactly what a review is looking for, and it would be invisible if only
successes were logged.
?version=N to read a specific version instead of the current one.
Versions
?version=. That is
what makes rotation safe — you publish the new value, let consumers pick it up,
and still have the old one to fall back to.
GET /v1/secrets/{secret_id}/versions lists version metadata, highest first.
Each entry carries created_by, the CRN of the principal that wrote it
(crn:iam:::user/<id> or crn:iam:::service-account/<id>), so you can see who
rotated what.
Version metadata never includes ciphertext.
GET .../value is the only route
that produces plaintext, and it is the only one that needs
secrets:GetSecretValue.Deleting and restoring
DELETE /v1/secrets/{secret_id} does not delete anything immediately. It moves
the secret into a recovery window and returns deleted_at and
scheduled_purge_at. Once scheduled_purge_at passes, the secret and every
version are removed for good.
86400 – 2592000, default 604800
1 to 30 days, defaulting to 7. Set it at creation to give a secret its own
default, or pass it on the delete call to override it for that deletion.
GET /v1/secrets/{id}still describes it, so you can see the purge date.- Reading or writing the value is refused with
409 SECRET_DELETED. - Updating metadata is refused the same way.
- It is hidden from
GET /v1/secretsunless you passinclude_deleted=true.
POST /v1/secrets/{secret_id}/restore cancels the purge and puts the secret
back. Restoring one that was never deleted is a harmless no-op.
Deleting frees the secret’s quota straight away, so you can create a
replacement without waiting out the window. Restoring has to take that quota
back, which means a restore can fail with
403 QUOTA_EXCEEDED if your
account has since filled the slot. Free one before restoring.Encrypting under your own key
By default a secret’s versions are encrypted under a platform-managed key. Passkms_key_id at creation to use one of your own KMS keys instead:
enabled, and pinned to
encrypt_decrypt.
What it changes
Binding a secret to your key does not change the API surface —value reads
and writes look identical. What changes is that the key becomes a control you
hold:
- Disable the key and reads start failing with
409 KMS_KEY_DISABLED. That error travels to you as itself, not as a500— the key state is yours, and re-enabling the key restores reads. - Schedule the key for deletion and reads fail with
409 KMS_KEY_PENDING_DELETIONfor the whole window. - Let that window elapse and every version of every secret under that key is permanently unreadable. The ciphertext is still in the database; nothing can open it.
The binding is fixed for the life of the secret.
kms_key_id is accepted
only on create, and PATCH edits just description and tags — moving a
secret to a different key means re-wrapping every version, so create a new
secret and retire the old one instead.Versions are bound to their secret
Whichever key is used, the ciphertext of every version is sealed with the secret’s account and secret id as encryption context. A stored blob therefore only decrypts as the version of the secret it was written for — it cannot be lifted out of the database and replayed as the value of a different secret, even one encrypted under the same key.Secrets the platform owns
Some secrets are created by a service that then reads the value back and acts on it — a managed database’s generated user password, for instance. Those come back withmanaged: true.
You can read them and you can delete them. PUT-style writes are refused with
403 SECRET_PLATFORM_MANAGED:
POST .../value— overwriting the value would not change whatever the value describes, it would make the two disagree, turning a credential the platform trusts into customer-supplied bytes.PATCH /v1/secrets/{id}— including tags, because tags feed the conditions IAM policies are written against. Retagging a secret the platform reads back would let a caller move it in and out of the scope of their own policies.
Controlling access
Every operation checks a distinct IAM action. Operations on a specific secret are authorized against that secret’s CRN, with the secret’s tags available as condition context.
One service reading exactly the secrets under its own path prefix:
secrets:ListSecrets is authorized against the collection rather than
against individual secrets, so restricting it by CRN or tag has no effect.
Scope secrets:GetSecretValue — that is the grant that matters.deny guardrail survives a broad allow.
Errors
Next
KMS
Creating the key a secret can be bound to, and what disabling it does.
Writing policies
Scoping
secrets:GetSecretValue to a path prefix or a tag.API reference
Every secrets operation, with request and response schemas.
Authentication
Signing requests to a regional endpoint.