OpenID Connect (OIDC) identity and OAuth 2.0 provider with pluggable connectors
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

8.2 KiB

Dex Enhancement Proposal (DEP) 2812 - 2023-02-03 - Token Exchange

Table of Contents

Summary

RFC 8693 specifies a new OAuth2 grant_type of urn:ietf:params:oauth:grant-type:token-exchange. Using this grant type, when clients start an authentication flow with Dex, in lieu of being redirected to their upstream IDP for authentication on demand, clients can present an independently obtained, valid token from their IDP to Dex. This is primarily useful in fully automated environments with job/machine identities, where there is no human in the loop to handle browser-based login flows. This DEP proposes to implement the new grant type for Dex.

Context

I believe the context for all of these are similar: a downstream project using Dex as its only IDP wants to grant access to programmatic clients without issuing long lived API tokens.

Examples of downstream issues:

Other related Dex issues:

More broadly, this fits into recent movements to issue machine identities:

and granting access to resources based on trusting federated identities:

An initial attempt is at #2806

Motivation

Goals/Pain

The goal is to allow programmatic access to Dex-protected resources without the use of static/long-lived secret tokens (API keys, username/password) or web-based redirect flows. Such scenarios are common in CI/CD workflows, and in general automation of common tasks.

Non-goals

Proposal

User Experience

Clients can make POST requests with application/x-www-form-urlencoded parameters as specified by RFC 8693 to Dex's /token endpoint. If successful, an access token will be returned, allowing direct authentication with Dex. No refresh tokens will be issued, perform a new exchange (possibly with refreshed upstream tokens) to obtain a new access token.

The request parameters from RFC 8693 Section 2.1:

  • grant_type: REQUIRED - urn:ietf:params:oauth:grant-type:token-exchange
  • resource: OPTIONAL - the audience in the issued Dex token
  • audience: REQUIRED (RFC OPTIONAL) - the connector to verify the provided token against
  • scope: OPTIONAL - the scope in the issued Dex token
  • requested_token_type: OPTIONAL - one of urn:ietf:params:oauth:token-type:access_token or urn:ietf:params:oauth:token-type:id_token, defaulting to access token
  • subject_token: REQUIRED - the token issued by the upstream IDP
  • subject_token_type: REQUIRED - urn:ietf:params:oauth:token-type:id_token or urn:ietf:params:oauth:token-type:access_token if getUserInfo is true.
  • actor_token: OPTIONAL - unused
  • actor_token_type: OPTIONAL - unused

The response parameters from RFC 8693 Section 2.2:

  • access_token: the issued token, the field is called access_token for legacy reasons
  • issued_token_type: the actual type of the issued token
  • token_type: the value Bearer
  • expires_in: validity lifetime in seconds
  • scope: the requested scope
  • refresh_token: unused

The connector only needs to be configured with an issuer, no client ID / client secrets are necessary

connectors:
- type: oidc
  id: my-platform
  name: My Platform
  config:
    issuer: https://oidc.my-platform.example/

We expose a global and connector setting, allowedGrantTypes: []string defaulting to all implemented types.

Implementation Details/Notes/Constraints

  • Connectors expose a new interface TokenIdentity that will verify the given token and return the associated identity. A Dex access/id token is then minted for the given identity.

  • actor_token and actor_token_type are "MUST ... if the actor token is present, also perform the appropriate validation procedures for its indicated token type". We will ignore these fields for the initial implementation.

Risks and Mitigations

With token exchanges (sometimes known as identity impersonation), is they allow for easier lateral movement if an attacker gains access to an upstream token. We limit the potential impact by not issuing refresh tokens, preventing persistent access. Combined with short token lifetimes, it should limit the period of time between authentication to upstream IDPs. Additionally, a new allowedGrantTypes would allow for disabling exchanges if the functionality isn't needed.

Alternatives

  • Continue to use static keys - this is a secret management nightmare and quite painful when client storage of keys is breached

Future Improvements

  • Other connectors may wish to implement the same capability under Oauth
  • The password connector could be switch to support this new endpoint, submitting passwords as access tokens, allowing for multiple password connectors to be configured
  • The audience field could be made optional if there is a single connector or the id token is inspected for issuer url
  • The actor_token and actor_token_type can be checked / validated if a suitable usecase is determined.
  • A policy language like cel or rego as mentioned on #1635 Connector Middleware would allow for stronger assertions of the provided identity against requested resource access.