Deploy without a secret (OIDC)
Being rolled out. The interface described here is the one of the next release: it may still change, and may not be enabled on your tenant yet.
GitLab CI and GitHub Actions hand each job a short-lived OIDC token, which says "this job belongs to this project, on this branch". StackNGO exchanges it for a tenant session. Result: no secret to store, nothing to rotate.
You declare which pipelines you trust with an OIDC trust (IAMOIDCTrust),
then you attach a policy to it, exactly as for a user.
Prerequisites
- An administrator session on the tenant (
sng tenant use acme). - The CI project and its deployment branch.
1. Declare the trust
# GitLab: pipelines of the protected branch main of the project acme/infra
sng tenant oidc create gitlab-deploy \
--gitlab-project acme/infra --ref main \
--claim project_id=4242 --claim ref_protected=true
# GitHub: workflows of the repository acme/infra on main
sng tenant oidc create github-deploy \
--github-repo acme/infra --ref main \
--claim repository_id=123456789
OIDC trust "gitlab-deploy" created in tenant "acme" (pending: applied in a few minutes)
subject: project_path:acme/infra:ref_type:branch:ref:main
next: sng tenant policy attach POLICY --oidc-trust gitlab-deploy
| Flag | Effect |
|---|---|
--gitlab-project GROUP/PROJECT | Issuer https://gitlab.com (or --gitlab-url), subject project_path:GROUP/PROJECT:ref_type:branch:ref:REF |
--github-repo ORG/REPO | Issuer https://token.actions.githubusercontent.com, subject repo:ORG/REPO:ref:refs/heads/REF |
--ref REF | Trusted branch (main by default, * = all) |
--claim KEY=V1,V2 | Additional required claims; AND between keys, OR between values |
--max-session 15m | Duration of the sessions opened by this trust, from 5m to 1h (default 1h) |
--issuer, --audience, --subject | For any issuer, without helpers |
-f FILE | An IAMOIDCTrust manifest or its spec, in YAML or JSON (- = standard input) |
A project path can be renamed and then reused by someone else. project_id
(GitLab) and repository_id (GitHub) never change: always add them as --claim.
The trust is active a few minutes later (STATUS switches to applied):
sng tenant oidc list
NAME ISSUER SUBJECT STATUS
gitlab-deploy https://gitlab.com project_path:acme/infra:ref_type:branch:ref:main applied
sng tenant oidc get gitlab-deploy details the trust. Once the trust is applied, the
discovery line says whether the issuer answered: ok, or failed: <cause> (check the
issuer URL; the check is made again at each token exchange). An issuer of the platform itself
is refused at creation (issuer "…" is reserved to the platform).
2. Give it rights
A trust grants nothing by itself.
sng tenant policy attach readwrite --oidc-trust gitlab-deploy
readwrite is enough for sng apply. For a custom policy (for example deploy:* without
ssm:read), see Policies. Give the pipeline the
bare minimum.
3. Use it in the pipeline
The CLI detects the job token and opens the session on its own, in memory. You just need to tell it which tenant.
| Variable | Role |
|---|---|
STNG_TENANT | Target tenant (required) |
STNG_OIDC_TOKEN | OIDC token of the job (GitLab id_tokens) |
STNG_OIDC_TOKEN_FILE | Same, in a file |
STNG_OIDC_AUDIENCE | GitHub only: audience to request (default: the API URL) |
STNG_OIDC_TRUST | Name of the trust to use if several trusts of the tenant could match |
Under GitHub Actions, the CLI directly uses ACTIONS_ID_TOKEN_REQUEST_URL and
ACTIONS_ID_TOKEN_REQUEST_TOKEN provided by the runner (with permissions: id-token: write).
An expired session is reopened by requesting a token from the CI again; nothing is written to disk.
Complete pipelines are in GitLab CI and GitHub Actions.
Persistent runner
If several commands must share a stored session (persistent runner,
scripts outside sng), sng sso login --oidc exchanges the token once and stores the
session in the runner's configuration file:
OIDC session saved: tenant acme (token from STNG_OIDC_TOKEN, expires in 900s)
What the trust requires
For a job to open a session, a trust of the target tenant must match on all points:
| Trust field | Condition |
|---|---|
issuer | The token comes from this issuer (GitLab, GitHub or the one you specify) |
audiences | The token's aud is in the list (by default: the API URL) |
subject | The sub matches the pattern (* allowed, at least 8 literal characters before the first *) |
claims | Each listed claim has one of the expected values |
maxSessionDuration | Bounds the session, whatever the token duration |
The session obtained has the principal oidc:<tenant>/<trust>: this is what you see in
sng tenant policy principals and in the logs.
Troubleshooting
| Symptom | Cause and fix |
|---|---|
no CI OIDC token: set STNG_OIDC_TOKEN … | The job does not expose a token: add id_tokens (GitLab) or permissions: id-token: write (GitHub) |
OIDC: tenant required: set STNG_TENANT … | STNG_TENANT missing |
invalid identity token | No trust matches, or several do: compare iss, aud, sub displayed by the CLI with sng tenant oidc get, or set STNG_OIDC_TRUST |
jeton OIDC du CI expiré | The token provided by variable expired during the job: rerun, or lengthen its duration on the CI side |
forbidden (no policy of this tenant allows it: see sng tenant policy list) | The session is open, but the policy attached to the trust does not allow this action |
Delete a trust
sng tenant oidc delete gitlab-deploy
Already opened sessions remain valid until they expire (at most
maxSessionDuration).