# OIDC Workload Attestation How the `oidc-attestor` plugin identifies workloads via OIDC tokens. ## Flow ``` Workload SPIRE Agent oidc-attestor OIDC Provider | | | | | FetchX509SVID | | | |----------------->| | | | | Attest(pid=1234) | | | |------------------->| | | | | GET /.well-known/ | | | | openid-configuration| | | |-------------------->| | | | JWKS endpoint | | | |<--------------------| | | | | | | | Read token from | | | | /var/run/secrets/ | | | | oidc/token | | | | | | | | Verify signature | | | | via JWKS | | | | | | | Selectors | | | |<-------------------| | | X509-SVID | | | |<-----------------| | | ``` ## Token Discovery The plugin discovers the workload's OIDC token via a configurable path. In Kubernetes, the token is typically projected into the pod filesystem: ```yaml # Pod spec volumes: - name: oidc-token projected: sources: - serviceAccountToken: audience: spire expirationSeconds: 3600 path: token containers: - name: app volumeMounts: - name: oidc-token mountPath: /var/run/secrets/oidc readOnly: true ``` Plugin configuration: ```hcl WorkloadAttestor "guildhouse_oidc" { plugin_cmd = "/opt/spire/plugins/oidc-attestor" plugin_data { issuer = "https://keycloak.guildhouse.example.org/realms/platform" audience = "spire" token_path = "/var/run/secrets/oidc/token" } } ``` ## Token Verification 1. Plugin reads the JWT from the configured path. 2. Fetches the OIDC discovery document from `{issuer}/.well-known/openid-configuration`. 3. Retrieves the JWKS from the `jwks_uri` in the discovery document. 4. Verifies the JWT signature using the matching key from the JWKS. 5. Validates standard claims: `iss` matches configured issuer, `aud` includes configured audience, `exp` is in the future. ## Selector Output The plugin returns selectors that SPIRE uses to match workloads against registration entries: | Selector | Source Claim | Example | |----------|-------------|---------| | `oidc_attestor:iss:` | `iss` | `oidc_attestor:iss:https://keycloak.example.org/realms/platform` | | `oidc_attestor:sub:` | `sub` | `oidc_attestor:sub:f47ac10b-58cc-4372-a567-0e02b2c3d479` | | `oidc_attestor:email:` | `email` | `oidc_attestor:email:operator@guildhouse.coop` | | `oidc_attestor:group:` | `groups[]` | `oidc_attestor:group:platform-engineers` | ## Registration Entry Matching To grant an SVID to workloads authenticated via OIDC: ```bash spire-server entry create \ -spiffeID spiffe://guildhouse.io/ns/prod/sa/web-server \ -parentID spiffe://guildhouse.io/spire/agent/k8s_psat/guildhouse/... \ -selector oidc_attestor:sub:f47ac10b-58cc-4372-a567-0e02b2c3d479 ``` Multiple selectors can be combined (AND logic): ```bash spire-server entry create \ -spiffeID spiffe://guildhouse.io/ns/prod/sa/admin-tool \ -parentID spiffe://guildhouse.io/spire/agent/k8s_psat/guildhouse/... \ -selector oidc_attestor:iss:https://keycloak.example.org/realms/platform \ -selector oidc_attestor:group:platform-engineers ``` ## JWKS Caching The plugin caches JWKS responses for the duration specified by the `Cache-Control` header (or 5 minutes if not present). This avoids hitting the OIDC provider on every attestation.