Skip to main content

Declare a secret by manifest

Available

Deployed and supported. The fields and commands described here are stable within version v1alpha1.

With an SSMSecret manifest, the secret is part of the description of your tenant, like your Apps: it is created when the manifest is applied, its rotation is declared in the spec, and it is deleted with the manifest. The value, however, never goes through Git: the platform generates it, or you set it with sng secret set.

Prerequisites​

  • The CLI configured to apply manifests: cluster and tenant chosen (sng config use-cluster, sng tenant use). See The validate, plan, apply cycle.
  • The right to apply manifests in your tenant (policy readwrite or admin).
  • No particular right on secrets is needed to declare: the platform creates the secret for you. To read the generated value, you need ssm:read.

1. Declare a secret with a generated value​

sng secret create db-password --length 24 --rotation 30
secret "db-password" declared in tenant acme-dev: …

acme-dev is the current tenant of your sng configuration. The command produced a manifest and applied it, exactly like sng apply:

db-password.yml
apiVersion: ssm.stackngo.io/v1alpha1
kind: SSMSecret
metadata:
name: db-password
spec:
length: 24
rotateDays: 30

To write it yourself and keep it in your repository, add --dry-run: the manifest is printed without being applied.

sng secret create db-password --length 24 --rotation 30 --dry-run > secrets/db-password.yml
sng apply secrets/db-password.yml

sng template gen SSMSecret db-password produces the same skeleton, with comments.

Less than a minute after the apply, the secret has a value:

sng secret describe db-password
{
"name": "db-password",
"keys": ["value"],
"version_id": "1",
"rotation_enabled": true,
"rotation_days": 30,
"next_rotation_date": "2026-11-06T10:02:17Z",
"version_stages": { "current": "1" }
}

2. Declare a secret whose value you set​

When the value comes from elsewhere (a provider's API key, the password of an external service), declare the secret empty with --length 0, then set the value:

sng secret create smtp-password --length 0 --description "Mot de passe SMTP Mailjet"
secret "smtp-password" declared in tenant acme-dev: …
set its value with: sng secret set smtp-password
sng secret set smtp-password --from-file ./smtp-password

As long as the value is not set, the secret exists but is pending: an App that references it does not start that service (see Inject a secret into an App). As soon as you run set, it becomes active; the manifest status follows within 10 minutes.

3. Choose the shape of the generated value​

sng secret create api-key --length 40 --contains letters,numbers
FlagRoleDefault
--length Nlength of the generated value; 0 = declared empty16
--rotation Nrenewal every N days; 0 = never; requires --length > 00
--containsclasses: letters, numbers, symbols (aliases letter, alpha, number, digit, symbol, punctuation); requires --length > 0all
--descriptionfree text, visible in sng secret describeempty
--dry-runprints the manifest without applying it—

The manifest vocabulary is deliberately simpler than that of sng secret set: no separate lower/upper, no --exclude-chars. If you need these settings, set the value with set (--length 0 in the manifest), or arm the rotation with set --rotation rather than with rotateDays.

4. What is never overwritten​

The manifest describes how to produce a value, not the value. Consequences:

  • Reapplying the manifest never changes an existing value, nor do the platform's regular checks.
  • If you had already run sng secret set db-password before declaring the secret, the declaration adopts that value and does not regenerate it.
  • Changing length or contains afterwards does not change the current value: only the first generation and future rotations take it into account. To change the value now: sng secret rotate db-password --length 40.
  • rotateDays is the only thing that replaces the value, and it does so whatever its origin. Do not put rotateDays on a secret whose value comes from an external service.

5. Make the secret usable by a static site or a notification channel​

By default, a secret is only made available to the Apps that reference it. A static site (credentialsSecretRef, tlsSecretRef) or a notification channel (urlSecretRef, webhookSecretRef) also reads a secret of your tenant, but no App references it: declare it with materialize: true.

secrets/slack-webhook.yml
apiVersion: ssm.stackngo.io/v1alpha1
kind: SSMSecret
metadata:
name: slack-webhook
spec:
length: 0 # the value comes from Slack: you set it with sng secret set
materialize: true # usable by your static sites and notification channels
sng apply secrets/slack-webhook.yml
printf '%s' 'https://hooks.slack.com/services/T000/B000/XXXX' > /tmp/slack-url
sng secret set slack-webhook --from-file /tmp/slack-url
rm /tmp/slack-url

What you get:

  • as soon as the secret has a value, it is usable under its name (slack-webhook) and with its keys (value for a single value, your keys for a secret set with --data) by the static sites and notification channels of the tenant, within 10 minutes at most;
  • each new version, rotation included, reaches them within 5 minutes;
  • a secret already set with sng secret set is adopted the same way: declare an SSMSecret of the same name with length: 0 and materialize: true, the existing value is kept.

If another secret of the same name already exists in your tenant (that of a registry robot or of an SSO application, for example), it is never overwritten: the SSMSecret goes to Error with the message the value could not be made available to the other resources of the tenant. Choose another name.

6. Delete​

sng kind delete SSMSecret db-password

The manifest is removed from your tenant and the secret is deleted with it, in less than a minute. The secret is no longer listed or readable.

Deletion destroys no version: sng secret restore db-password puts the secret back into service with all its versions, and a later sng secret set db-password recreates it under the same name (see Versions and restore).

Do not delete the secret from underneath

sng secret delete db-password on a secret declared by manifest leaves the manifest in place, and it does not become active again on its own. Delete the manifest, or, if you want to keep the secret, restore it with sng secret restore db-password.

Verification​

sng kind get SSMSecret db-password # the applied manifest, then its state as comments
sng secret describe db-password # the created secret: version_id ≥ 1, rotation if rotateDays > 0

sng kind get shows the stored manifest, followed by its state (# status:: phase Pending, Active or Error, and the message). sng secret describe confirms that the secret has a value: version_id: "1" (or more) and, where applicable, rotation_enabled, rotation_days, next_rotation_date. A secret declared empty responds version_id: "0" until you run set. If describe responds secret not found several minutes after the apply, the declaration failed: see "If it doesn't work" below.

If it doesn't work​

What you seeCauseFix
apply refuses: "rotateDays needs a generated value (length > 0)"rotateDays on a secret declared emptyGive a length > 0, or remove rotateDays
apply refuses a length, a rotateDays or a classValue out of bounds (see below)Fix the value
sng secret describe responds version_id: "0"Secret declared empty, awaiting its valuesng secret set NAME
secret not found several minutes after the applyThe declaration was refused, often by a tenant policy ("forbidden by the tenant policies")Check sng tenant policy list; do not contradict the managed policies for secrets
The secret does not come back after sng secret deleteThe secret was deleted without its manifestsng secret restore NAME, or delete the manifest
Error: the value could not be made available to the other resources of the tenantmaterialize: true and another secret of the same name already exists in the tenantRename the SSMSecret
Static site or notification channel: secret not foundThe secret is not declared with materialize: true, or has no value yetDeclare an SSMSecret with materialize: true, set the value, then give the site or channel time to read it again (up to 15 minutes for a channel)

Going further​

  • The platform does not see your values: for a declared secret, it can only have a value generated, never set one of its choosing or read it back. Leave in place the managed policies reserved for secrets (visible in sng tenant policy list): if one of your policies detaches or contradicts them, your SSMSecret resources switch to Error "forbidden by the tenant policies".
  • Class vocabulary: letters in the manifest becomes lower + upper in the generation policy, numbers becomes number, symbols becomes symbol. The value contains at least one character of each selected class.
  • Validation: at apply time, the API rejects a rotateDays > 0 with length: 0 ("rotateDays needs a generated value (length > 0)"), a length outside 0–4096, a rotateDays outside 0–3650, an unknown class, a description longer than 1024 characters.
  • Delays: a pending secret (Pending) is rechecked every 10 minutes, an active secret (Active) every 6 hours, and one minute after each rotation deadline.
  • A secret referenced by an App before being declared is created pending automatically (without a manifest). You can then declare it with SSMSecret: the declaration adopts the existing secret.

See also​