Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vale/styles/config/vocabularies/DependencyTrack/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ Webex
[Mm]isconfiguration
[Mm]isconfigured
[Mm]ixeway
[Mm]ulticast
[Nn]amespaced?
[Nn]amespaces
[Nn]amespacing
Expand Down Expand Up @@ -181,6 +182,8 @@ cutover
eDirectory
keysets?
keytool
kubeadm
kubelet
npm
px
sAMAccountName
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/concepts/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ nav:
- About projects: projects.md
- About tags: tags.md
- About access control: access-control.md
- About workload identity federation: workload-identity-federation.md
- About vulnerability data sources: about-vulnerability-data-sources.md
- About KEV data sources: about-kev-data-sources.md
- About vulnerability findings: vulnerability-findings.md
Expand Down
33 changes: 26 additions & 7 deletions docs/concepts/access-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Four types of users exist:
| Managed User | A local account created and managed within Dependency-Track. |
| LDAP User | Authenticated via an external LDAP directory. See [Configuring LDAP](../guides/administration/configuring-ldap.md). |
| OIDC User | Authenticated via an OpenID Connect identity provider. See [Configuring OIDC](../guides/administration/configuring-oidc.md). |
| Service Account | A non-human account for automation. Authenticates with its own API keys. Available in 5.2.0 and later. See [Service accounts](#service-accounts). |
| Service Account | A non-human account for automation. Authenticates with its own API keys, or through workload identity federation. Available in 5.2.0 and later. See [Service accounts](#service-accounts). |

All user types share the same permission model. The authentication mechanism determines
how the system verifies a user's identity, not what they can access.
Expand All @@ -33,10 +33,19 @@ A service account is the identity of a CI pipeline, scanner, script, or other
automated tool. Like any other user, it holds permissions directly or through
team membership, and appears in team member lists.

A service account can't log in. It authenticates with API keys that it owns.
Each request made with such a key acts as the service account, so audit records
show its username. Suspending a service account stops all its API keys from working
until you lift the suspension. Deleting it also deletes its API keys.
A service account can't log in. It authenticates in one of two ways:

* **Workload identity federation.** The workload exchanges a short-lived token
issued by its own platform, such as GitHub Actions, GitLab CI, Kubernetes, or
SPIFFE, for a session of the service account. See
[About workload identity federation](workload-identity-federation.md).
* **API keys** that the service account owns. Each request made with such a key
acts as the service account.

Either way, audit records show the service account's username. Suspending a service
account stops all its API keys and blocks new token exchanges, until you lift the
suspension. It also ends sessions created through federation at once. Deleting the
account also deletes its API keys and its workload identity bindings.

Service account usernames always start with `svc:`, for example `svc:ci-pipeline`.
No other user can have a username with that prefix. This prevents a service account
Expand All @@ -49,6 +58,13 @@ Compared to team API keys, service accounts:
* Give each automated tool a distinct identity, even when tools share a team.
* Take permissions directly, so narrowing one tool's permissions doesn't need a dedicated team.
* Support suspension, which blocks access without deleting API keys.
* Can authenticate without any stored credential, through workload identity federation.

!!! tip "The intended path for automation"

Service accounts combined with [workload identity federation](workload-identity-federation.md)
are the strategic replacement for teams that exist only to hold a long-lived API key.
Team API keys remain supported. Start new integrations on service accounts.

## Teams

Expand All @@ -65,8 +81,9 @@ exceptions that don't justify a dedicated team.

Team API keys belong to a team and carry the same permissions as that team. They authenticate
automated access (CI/CD pipelines, integrations) without associating requests with a
specific identity. In 5.2.0 and later, [service accounts](#service-accounts) offer an
alternative with their own identity and permissions.
specific identity. In 5.2.0 and later, [service accounts](#service-accounts) supersede them:
they carry their own identity and permissions, and can authenticate without a stored
credential at all.

Deleting a team also deletes its API keys and any project access assignments
made through it. It keeps projects, user accounts, and API keys owned by service
Expand Down Expand Up @@ -205,5 +222,7 @@ and holders of `PORTFOLIO_ACCESS_CONTROL_BYPASS` until one is assigned.

* [Permissions reference](../reference/permissions.md) for the full permissions table
and default teams.
* [About workload identity federation](workload-identity-federation.md) for how
service accounts authenticate without stored credentials.
* [About projects](projects.md) for how Dependency-Track models
projects, hierarchies, and collection projects.
101 changes: 101 additions & 0 deletions docs/concepts/workload-identity-federation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# About workload identity federation

!!! note "Available in 5.2.0 and later"

Earlier versions authenticate automation with team API keys only.

Workload identity federation lets a workload authenticate to Dependency-Track with a token
that its own platform issued, instead of an API key that someone created and stored.
A GitHub Actions job, a GitLab CI job, a Kubernetes pod, or a SPIFFE workload already holds a short-lived,
signed token that states its identity. Dependency-Track verifies that token and,
if it matches a rule an administrator configured, hands back a session for a [service account](access-control.md#service-accounts).

The workload stores no Dependency-Track credential.

## Why it exists

An API key is a static secret with a long life. Someone creates it, copies it into a CI system,
and has to remember to delete it when it leaks and to rotate it before it expires.
Nothing about the key says which pipeline uses it, and a key that escapes the pipeline keeps
working from anywhere until a human notices.

A platform token has none of those properties. It exists for minutes, it names the exact repository,
branch, namespace, or workload that received it, and nobody can mint one outside that context.

Service accounts and workload identity federation together are the intended replacement for
automation that runs on team API keys:

* The **service account** gives the automation an identity of its own, with its own permissions and its own audit trail.
* **Workload identity federation** gives that identity a credential nobody has to store.

## How an exchange works

```mermaid
sequenceDiagram
participant W as Workload<br/>(CI job, k8s pod)
participant P as Platform<br/>(GitHub, GitLab, Kubernetes, SPIRE)
participant D as Dependency-Track

W->>P: Request a token for audience X
P-->>W: Signed token (sub, aud, exp, ...)
W->>D: Exchange token, naming a provider and a service account
D->>P: Fetch the issuer's public signing keys
D->>D: Verify signature, issuer, audience, expiry
D->>D: Match subject and condition against the bindings<br/>of that service account
D-->>W: Session token for the service account
W->>D: Upload a BOM with the session token
```

The workload names both the provider and the service account it wants to act as.

## Providers and bindings

A **workload identity provider** says which issuer to trust. It holds the issuer,
the audience that tokens must carry, where the issuer's public signing keys come from,
and how long the sessions it creates last. Providers are instance-wide and only administrators manage them.

A **workload identity binding** says which subject of that provider may act as which service account.
It belongs to a service account, names a provider, and matches a subject, either exactly or by prefix.
An optional condition, written in [CEL](../reference/cel-expressions.md),
narrows the match further by looking at any claim in the token.

Bindings can't point at a human user.

### Subjects and conditions

A binding needs a subject even when it carries a condition, and the reason is the shape of shared issuers.
GitHub and GitLab.com issue tokens to anyone with an account, and let the requester choose the audience.
The audience isolates nothing there. Only the subject names the organization,
so a binding that matched on the condition alone would be open to every other tenant of that platform.

Conditions exist because platforms don't put everything into the subject.
[GitLab CI](https://docs.gitlab.com/ci/secrets/id_token_authentication/), for example,
keeps the deployment environment in a separate claim, out of reach of a subject prefix.

A condition is part of the security boundary, in that one that matches more tokens than intended
lets more workloads act as the service account.

## The resulting session

The exchange returns the same kind of opaque session token that the login endpoints issue,
carrying all permissions of the service account.

The session lasts for the provider's configured lifetime, which can't exceed 24 hours.
The subject token proves the workload's identity at the moment of the exchange,
and short platform tokens make that gap deliberate.

[GitLab CI](https://docs.gitlab.com/ci/secrets/id_token_authentication/) and
[SPIRE](https://spiffe.io/docs/latest/deploying/spire_server/) issue tokens that expire after five minutes by default,
and a CI job that uploads a BOM and waits for its analysis takes longer than that.

A session outlives the token it came from, so deleting a binding or a provider doesn't end
sessions already created. Suspending the service account does, at once.

## Further reading

* [Configuring workload identity federation](../guides/administration/configuring-workload-identity-federation.md)
for the procedure and per-platform configuration.
* [Workload identity reference](../reference/workload-identity.md) for subject matching
rules, the condition environment, and token requirements.
* [About access control](access-control.md#service-accounts) for how service accounts relate
to users, teams, and permissions.
1 change: 1 addition & 0 deletions docs/guides/administration/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ nav:
- configuring-observability.md
- configuring-ldap.md
- configuring-oidc.md
- configuring-workload-identity-federation.md
- managing-notification-templates.md
- debugging-notifications.md
- configuring-project-retention.md
Expand Down
Loading
Loading