Skip to content

STS roles should support multiple trusted OIDC providers, each with their own audience and subject conditions #152

@alukach

Description

@alukach

Context

PR #132 adds the /.sts token-exchange endpoint. Role trust policies come from multistore::types::RoleConfig, which currently models trust as:

pub trusted_oidc_issuers: Vec<String>,      // N issuers
pub required_audience: Option<String>,      // but ONE audience, shared across all of them
pub subject_conditions: Vec<String>,        // and ONE set of sub conditions, shared too

A role can trust multiple OIDC issuers, but the aud and sub constraints apply uniformly across all of them — and required_audience only holds a single value.

Problem

We will definitely want multiple OIDC providers to be able to assume the same role, each with its own audience and subject conditions. In AWS IAM this is the norm: a role's trust policy can contain multiple statements, one per federated provider, each with its own aud/sub conditions. For example, a single product role trusted by both:

  • source.coop web flow (Ory): aud = the web app's OAuth client_id, sub = the Ory user id
  • GitHub Actions OIDC (token.actions.githubusercontent.com): aud = a custom audience, sub matching repo:<org>/<repo>:ref:refs/heads/main

With the current shape this is unrepresentable: an audience valid for one issuer is wrong for the other, and subject patterns for Ory user ids vs GitHub repo: subjects can't be scoped to their issuer.

Proposal

Restructure role trust as a list of per-provider entries, e.g.:

pub struct TrustedProvider {
    pub issuer: String,
    pub audiences: Vec<String>,          // also fixes the single-client_id limitation
    pub subject_conditions: Vec<String>, // glob patterns, scoped to this issuer
}

pub struct RoleConfig {
    // ...
    pub trusted_providers: Vec<TrustedProvider>,
}

Token exchange validates the subject token against the entry matching its iss, then enforces that entry's aud/sub conditions.

Dependencies

  • The type and its enforcement live upstream in the multistore / multistore-sts crates (RoleConfig, JWKS validation), so this needs a crate release first, then adoption here (src/sts.rs builds the _default role; AUTH_AUDIENCE would become that role's first trusted-provider audience).
  • Related: the role registry is currently a single hardcoded _default role (see TODO in src/sts.rs); per-role trust config becomes most useful once roles are served from the Source Cooperative API.

Spun out of review feedback on #132 (finding 1: audience restriction).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions