detached fda3c2b

ci-oidc.md RawHistoryFolder

CI: OIDC

ermite is an OpenID Connect provider for its jobs, like GitHub. A job exchanges a short-lived ID token for cloud or Vault credentials instead of storing a long-lived secret.

permissions:
  id-token: write

Works with core.getIDToken(), aws-actions/configure-aws-credentials, hashicorp/vault-action (method: jwt).

Requirements

  • A trusted run (see CI trust). Agent runs get no token.
  • id-token: write in permissions:.
  • ERMITE_SECRETS_KEY set on the server.

Otherwise the action fails as on GitHub without the permission.

Endpoints

Issuer <ERMITE_PUBLIC_URL>/-/oidc
Discovery /-/oidc/.well-known/openid-configuration
Keys /-/oidc/.well-known/jwks

The relying party must reach the issuer. AWS, Azure and GCP need it on the public Internet; a private server works with a relying party on the same network, such as Vault.

Token

  • RS256, valid 5 minutes, GitHub's claims (sub, repository, ref, sha, job_workflow_ref, environment, …), runner_environment: self-hosted.
  • sub:
    • repo:<owner>/<repo>:environment:<name> for a job with an environment
    • repo:<owner>/<repo>:pull_request for pull_request and pull_request_target
    • repo:<owner>/<repo>:ref:<ref> otherwise
  • Default aud: <ERMITE_PUBLIC_URL>/<owner>. getIDToken(audience) picks another.

Key rotation

ermite oidc rotate-key

The previous key stays in the JWKS for 24 hours.

Vault example

vault auth enable jwt
vault write auth/jwt/config \
  oidc_discovery_url="https://git.example.com/-/oidc" \
  bound_issuer="https://git.example.com/-/oidc"
vault write auth/jwt/role/deploy role_type=jwt user_claim=sub \
  bound_audiences="https://git.example.com/owner" \
  bound_claims_type=glob bound_claims='{"sub":"repo:owner/proj:ref:refs/heads/main"}' \
  policies=deploy ttl=10m
source
1# CI: OIDC
2
3ermite is an OpenID Connect provider for its jobs, like GitHub. A job exchanges a short-lived ID token for cloud or Vault credentials instead of storing a long-lived secret.
4
5```yaml
6permissions:
7  id-token: write
8```
9
10Works with `core.getIDToken()`, `aws-actions/configure-aws-credentials`, `hashicorp/vault-action` (`method: jwt`).
11
12## Requirements
13
14- A **trusted** run (see [CI trust](ci.md#trust)). Agent runs get no token.
15- `id-token: write` in `permissions:`.
16- `ERMITE_SECRETS_KEY` set on the server.
17
18Otherwise the action fails as on GitHub without the permission.
19
20## Endpoints
21
22| | |
23|---|---|
24| Issuer | `<ERMITE_PUBLIC_URL>/-/oidc` |
25| Discovery | `/-/oidc/.well-known/openid-configuration` |
26| Keys | `/-/oidc/.well-known/jwks` |
27
28The relying party must reach the issuer. AWS, Azure and GCP need it on the public Internet; a private server works with a relying party on the same network, such as Vault.
29
30## Token
31
32- RS256, valid 5 minutes, GitHub's claims (`sub`, `repository`, `ref`, `sha`, `job_workflow_ref`, `environment`, …), `runner_environment: self-hosted`.
33- `sub`:
34  - `repo:<owner>/<repo>:environment:<name>` for a job with an environment
35  - `repo:<owner>/<repo>:pull_request` for `pull_request` and `pull_request_target`
36  - `repo:<owner>/<repo>:ref:<ref>` otherwise
37- Default `aud`: `<ERMITE_PUBLIC_URL>/<owner>`. `getIDToken(audience)` picks another.
38
39## Key rotation
40
41```sh
42ermite oidc rotate-key
43```
44
45The previous key stays in the JWKS for 24 hours.
46
47## Vault example
48
49```sh
50vault auth enable jwt
51vault write auth/jwt/config \
52  oidc_discovery_url="https://git.example.com/-/oidc" \
53  bound_issuer="https://git.example.com/-/oidc"
54vault write auth/jwt/role/deploy role_type=jwt user_claim=sub \
55  bound_audiences="https://git.example.com/owner" \
56  bound_claims_type=glob bound_claims='{"sub":"repo:owner/proj:ref:refs/heads/main"}' \
57  policies=deploy ttl=10m
58```

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 45

↑↓ moveenter openesc close