From 79cc863b5e0692fe0eeb1f32d9a17e228f33eea0 Mon Sep 17 00:00:00 2001 From: Jonathan Collinge Date: Sat, 24 May 2025 10:00:01 +0100 Subject: [PATCH 1/6] Add Sentry JWT OIDC Proposal Signed-off-by: Jonathan Collinge --- 20250524-R-sentry-jwt-oidc.md | 88 +++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 20250524-R-sentry-jwt-oidc.md diff --git a/20250524-R-sentry-jwt-oidc.md b/20250524-R-sentry-jwt-oidc.md new file mode 100644 index 0000000..59c8035 --- /dev/null +++ b/20250524-R-sentry-jwt-oidc.md @@ -0,0 +1,88 @@ +# Sentry JWT and OIDC Support for Workload Identity + +* Author(s): Joni Collige +* State: Implemented +* Updated: 2025-05-24 + +## Overview + +This proposal adds support for configuring Dapr Sentry to issue JWTs as an additional credential alongside the existing x.509 certificate. The JWT will be signed with a configurable key and algorithm, and a JWKS endpoint will be provided for trust distribution. Optionally, Sentry can host a partial OIDC discovery server to allow third-party identity providers to federate trust using the `.well-known/openid-configuration` and `jwks.json` endpoints. The JWT will be returned in the existing `SignCertificate` response, requiring no API changes. This enables Dapr workloads to use JWTs for federated cloud credentials and infrastructure access. + +* Areas affected: Dapr Sentry, Dapr runtime, Dapr components +* Proposed: Add JWT and OIDC support to Sentry, with configuration for signing keys, algorithms, JWKS, and OIDC server options + +## Background + +Dapr currently issues x.509 SVIDs for workload identity using SPIFFE. Many cloud providers and third-party systems only support federated authentication using JWTs and OIDC discovery endpoints. +Supporting JWTs in Sentry enables Dapr workloads to: +- Use JWTs as credentials for identity provider federation + +This proposal addresses the need for flexible, standards-based workload identity in Dapr, improving security and interoperability for cloud-native and hybrid environments. + +## Related Items + +### Related proposals +- [20231024-CIR-trust-distribution.md](20231024-CIR-trust-distribution.md): Trust bundle and CA distribution + +### Related issues + +## Expectations and alternatives + +* In scope: + - Sentry issues JWTs as workload credentials, signed with configurable key/algorithm + - JWKS endpoint for trust distribution + - Optional OIDC discovery server + - Audience claim configurable per app ID (default: trust domain) + - JWT rotation mechanism +* Not in scope: + - Full OIDC authorization flows (only discovery and JWKS endpoints) + - Custom claims beyond audience, issuer, and standard fields +* Alternatives considered: + - Only supporting x.509: limits interoperability with cloud and OIDC systems + - External JWT/OIDC proxy: adds operational complexity, not integrated with Sentry +* Trade-offs: + - Adds complexity to Sentry configuration and deployment + - Exposes unauthenticated endpoints (user must secure as needed) +* Advantages: + - Enables modern, federated identity scenarios + - No breaking changes to existing APIs +* Disadvantages: + - More configuration required for Sentry + - Responsibility for endpoint security is on the user + +## Implementation Details + +### Design + +- Sentry configuration extended to accept JWT signing key, algorithm, and JWKS (or auto-generate if not provided) +- JWT issued alongside x.509 SVID in `SignCertificate` response +- Audience claim set from app ID configuration (default: trust domain) +- JWKS endpoint served for public key distribution +- Optional OIDC discovery server serves `.well-known/openid-configuration` and `jwks.json` endpoints +- OIDC server exposed via Kubernetes Service; user responsible for external exposure and protection +- JWT rotation uses same mechanism as x.509 rotation +- Implementation extends existing SPIFFE package to support JWT-SVIDs +- daprd runtime and components can use JWT for cloud federation via token provider + +### Feature lifecycle outline + +* Expectations: Feature is opt-in, backward compatible, and does not affect existing x.509 flows +* Compatibility guarantees: No breaking changes to Sentry or workload APIs +* Deprecation/co-existence: x.509 and JWT can be issued together; no deprecation +* Feature flags: Enable/disable JWT and OIDC server via Sentry configuration + +### Acceptance Criteria + +* Sentry issues valid JWTs with correct claims and signatures +* JWKS endpoint serves correct public keys +* OIDC discovery endpoint is standards-compliant +* JWTs can be used for cloud provider federation +* No regression in x.509 SVID issuance or trust distribution + +## Completion Checklist + +* Code changes in Sentry for JWT/OIDC support +* Configuration and documentation updates +* Tests for JWT issuance, JWKS, and OIDC endpoints +* SDK/component changes to consume JWT as credential (Azure) + From 128e01c112e06b0f17568a4a3f62d8a327d341f7 Mon Sep 17 00:00:00 2001 From: Jonathan Collinge Date: Sat, 24 May 2025 11:34:17 +0100 Subject: [PATCH 2/6] Add Sentry JWT OIDC Proposal Signed-off-by: Jonathan Collinge --- 20250524-R-sentry-jwt-oidc.md | 150 ++++++++++++++++++++++------------ 1 file changed, 100 insertions(+), 50 deletions(-) diff --git a/20250524-R-sentry-jwt-oidc.md b/20250524-R-sentry-jwt-oidc.md index 59c8035..22e699a 100644 --- a/20250524-R-sentry-jwt-oidc.md +++ b/20250524-R-sentry-jwt-oidc.md @@ -6,83 +6,133 @@ ## Overview -This proposal adds support for configuring Dapr Sentry to issue JWTs as an additional credential alongside the existing x.509 certificate. The JWT will be signed with a configurable key and algorithm, and a JWKS endpoint will be provided for trust distribution. Optionally, Sentry can host a partial OIDC discovery server to allow third-party identity providers to federate trust using the `.well-known/openid-configuration` and `jwks.json` endpoints. The JWT will be returned in the existing `SignCertificate` response, requiring no API changes. This enables Dapr workloads to use JWTs for federated cloud credentials and infrastructure access. - -* Areas affected: Dapr Sentry, Dapr runtime, Dapr components -* Proposed: Add JWT and OIDC support to Sentry, with configuration for signing keys, algorithms, JWKS, and OIDC server options +This proposal introduces support for Dapr Sentry to issue JWTs as an additional credential alongside x.509 certificates. JWTs are signed with a configurable key and algorithm, and a JWKS endpoint is provided for trust distribution. Optionally, Sentry can host a minimal OIDC discovery server, exposing `.well-known/openid-configuration` and `jwks.json` endpoints for third-party trust federation. JWTs are returned in the existing `SignCertificate` response, requiring no API changes. This enables Dapr workloads to use JWTs for federated cloud credentials and infrastructure access. ## Background -Dapr currently issues x.509 SVIDs for workload identity using SPIFFE. Many cloud providers and third-party systems only support federated authentication using JWTs and OIDC discovery endpoints. -Supporting JWTs in Sentry enables Dapr workloads to: -- Use JWTs as credentials for identity provider federation - -This proposal addresses the need for flexible, standards-based workload identity in Dapr, improving security and interoperability for cloud-native and hybrid environments. +Dapr currently uses x.509 SVIDs for workload identity via SPIFFE. However, many cloud providers and third-party systems require JWTs and OIDC discovery for federated authentication. Adding JWT support to Sentry enables Dapr workloads to participate in these modern identity flows, improving interoperability and security in cloud-native and hybrid environments. ## Related Items ### Related proposals - [20231024-CIR-trust-distribution.md](20231024-CIR-trust-distribution.md): Trust bundle and CA distribution -### Related issues - ## Expectations and alternatives -* In scope: - - Sentry issues JWTs as workload credentials, signed with configurable key/algorithm - - JWKS endpoint for trust distribution - - Optional OIDC discovery server - - Audience claim configurable per app ID (default: trust domain) - - JWT rotation mechanism -* Not in scope: - - Full OIDC authorization flows (only discovery and JWKS endpoints) - - Custom claims beyond audience, issuer, and standard fields -* Alternatives considered: - - Only supporting x.509: limits interoperability with cloud and OIDC systems - - External JWT/OIDC proxy: adds operational complexity, not integrated with Sentry -* Trade-offs: - - Adds complexity to Sentry configuration and deployment - - Exposes unauthenticated endpoints (user must secure as needed) -* Advantages: - - Enables modern, federated identity scenarios - - No breaking changes to existing APIs -* Disadvantages: - - More configuration required for Sentry - - Responsibility for endpoint security is on the user +**In scope:** +- Sentry issues JWTs as workload credentials, signed with configurable key/algorithm +- JWKS endpoint for trust distribution +- Optional OIDC discovery server +- Audience claim configurable per app ID (default: trust domain) +- JWT rotation mechanism + +**Not in scope:** +- Full OIDC authorization flows (only discovery and JWKS endpoints) +- Custom claims beyond audience, issuer, and standard fields + +**Alternatives considered:** +- Only supporting x.509: limits interoperability with cloud and OIDC systems +- External JWT/OIDC proxy: adds operational complexity, not integrated with Sentry + +**Trade-offs:** +- Increases Sentry configuration and deployment complexity +- Exposes unauthenticated endpoints (user must secure as needed) + +**Advantages:** +- Enables federated identity scenarios and cloud provider integration +- No breaking changes to existing APIs + +**Disadvantages:** +- Additional configuration required for Sentry +- Endpoint security is the user's responsibility ## Implementation Details ### Design -- Sentry configuration extended to accept JWT signing key, algorithm, and JWKS (or auto-generate if not provided) +- Sentry configuration extended for JWT signing key, algorithm, JWKS (auto-generated if not provided) - JWT issued alongside x.509 SVID in `SignCertificate` response - Audience claim set from app ID configuration (default: trust domain) -- JWKS endpoint served for public key distribution -- Optional OIDC discovery server serves `.well-known/openid-configuration` and `jwks.json` endpoints -- OIDC server exposed via Kubernetes Service; user responsible for external exposure and protection +- JWKS endpoint for public key distribution +- Optional OIDC discovery server serves `.well-known/openid-configuration` and `jwks.json` +- OIDC server exposed via Kubernetes Service (user responsible for exposure and protection) - JWT rotation uses same mechanism as x.509 rotation -- Implementation extends existing SPIFFE package to support JWT-SVIDs +- SPIFFE package extended to support JWT-SVIDs - daprd runtime and components can use JWT for cloud federation via token provider +#### Proposed SignCertificateResponse + +```go +// SignCertificateResponse is returned by Sentry's SignCertificate API. +type SignCertificateResponse struct { + // Existing x.509 SVID fields + WorkloadCertificate []byte + TrustChainCertificates [][]byte + ValidUntil *timestamppb.Timestamp + + // JWT token for authentication. Always provided by Sentry if configured to issue JWTs. + Jwt *string +} +``` + +#### Proposed token provider for components-contrib + +```go +// Token provider function to retrieve JWT from SPIFFE context +tokenProvider := func(ctx context.Context) (string, error) { + // New method on spiffecontext to fetch JWT SVID + tknSource, ok := spiffecontext.JWTFrom(ctx) + if !ok { + return "", fmt.Errorf("failed to get JWT SVID source from context") + } + jwt, err := tknSource.FetchJWTSVID(ctx, jwtsvid.Params{ + Audience: AzureADTokenExchangeAudience, + }) + if err != nil { + return "", fmt.Errorf("failed to get JWT SVID: %w", err) + } + return jwt.Marshal(), nil +} +``` + +### Proposed Sentry Configuration Flags + +**JWT-related flags:** +- `--jwt-enabled` (bool): Enable JWT token issuance by Sentry +- `--jwt-key-filename` (string): JWT signing key filename +- `--jwks-filename` (string): JWKS (JSON Web Key Set) filename +- `--jwt-issuer` (string): Issuer value for JWT tokens (no issuer if empty) +- `--jwt-signing-algorithm` (string): Algorithm for JWT signing, must be supported by signing key +- `--jwt-key-id` (string): Key ID (kid) for JWT signing + +**OIDC-related flags:** +- `--oidc-http-port` (int): Port for the OIDC HTTP server (disabled if 0) +- `--oidc-jwks-uri` (string): Custom URI for external JWKS access +- `--oidc-path-prefix` (string): Path prefix for all OIDC HTTP endpoints +- `--oidc-domains` (string slice): Allowed domains for OIDC HTTP endpoint requests +- `--oidc-tls-cert-file` (string): TLS certificate file for OIDC HTTP server (required if enabled) +- `--oidc-tls-key-file` (string): TLS key file for OIDC HTTP server (required if enabled) +- `--oidc-tls-insecure` (bool): Serve OIDC HTTP without TLS + ### Feature lifecycle outline -* Expectations: Feature is opt-in, backward compatible, and does not affect existing x.509 flows -* Compatibility guarantees: No breaking changes to Sentry or workload APIs -* Deprecation/co-existence: x.509 and JWT can be issued together; no deprecation -* Feature flags: Enable/disable JWT and OIDC server via Sentry configuration +- Feature is opt-in, backward compatible, and does not affect existing x.509 flows +- No breaking changes to Sentry or workload APIs +- x.509 and JWT can be issued together; no deprecation +- Feature flags enable/disable JWT and OIDC server ### Acceptance Criteria -* Sentry issues valid JWTs with correct claims and signatures -* JWKS endpoint serves correct public keys -* OIDC discovery endpoint is standards-compliant -* JWTs can be used for cloud provider federation -* No regression in x.509 SVID issuance or trust distribution +- Sentry issues valid JWTs with correct claims and signatures +- JWKS endpoint serves correct public keys +- OIDC discovery endpoint is standards-compliant +- JWTs can be used for cloud provider federation +- No regression in x.509 SVID issuance or trust distribution ## Completion Checklist -* Code changes in Sentry for JWT/OIDC support -* Configuration and documentation updates -* Tests for JWT issuance, JWKS, and OIDC endpoints -* SDK/component changes to consume JWT as credential (Azure) +- Code changes in Sentry for JWT/OIDC support +- Configuration and documentation updates +- Tests for JWT issuance, JWKS, and OIDC endpoints +- SDK/component changes to consume JWT as credential From e8fd21e6b562eaa0ed80672592000a22019665c6 Mon Sep 17 00:00:00 2001 From: Joni Collinge Date: Sun, 25 May 2025 07:48:54 +0100 Subject: [PATCH 3/6] Update 20250524-R-sentry-jwt-oidc.md Co-authored-by: Josh van Leeuwen Signed-off-by: Joni Collinge --- 20250524-R-sentry-jwt-oidc.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/20250524-R-sentry-jwt-oidc.md b/20250524-R-sentry-jwt-oidc.md index 22e699a..75e71f6 100644 --- a/20250524-R-sentry-jwt-oidc.md +++ b/20250524-R-sentry-jwt-oidc.md @@ -110,9 +110,9 @@ tokenProvider := func(ctx context.Context) (string, error) { - `--oidc-jwks-uri` (string): Custom URI for external JWKS access - `--oidc-path-prefix` (string): Path prefix for all OIDC HTTP endpoints - `--oidc-domains` (string slice): Allowed domains for OIDC HTTP endpoint requests -- `--oidc-tls-cert-file` (string): TLS certificate file for OIDC HTTP server (required if enabled) -- `--oidc-tls-key-file` (string): TLS key file for OIDC HTTP server (required if enabled) -- `--oidc-tls-insecure` (bool): Serve OIDC HTTP without TLS +- `--oidc-server-tls-cert-file` (string): TLS certificate file for OIDC HTTP server (required if enabled) +- `--oidc-server-tls-key-file` (string): TLS key file for OIDC HTTP server (required if enabled) +- `--oidc-server-tls-enable` (bool): Serve OIDC HTTP with TLS ### Feature lifecycle outline From 408ac38d4d472f253631cd386fcb6e5f6415ffef Mon Sep 17 00:00:00 2001 From: Jonathan Collinge Date: Sun, 25 May 2025 08:42:33 +0100 Subject: [PATCH 4/6] Feedback Signed-off-by: Jonathan Collinge --- 20250524-R-sentry-jwt-oidc.md | 47 ++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/20250524-R-sentry-jwt-oidc.md b/20250524-R-sentry-jwt-oidc.md index 75e71f6..384b86c 100644 --- a/20250524-R-sentry-jwt-oidc.md +++ b/20250524-R-sentry-jwt-oidc.md @@ -95,24 +95,47 @@ tokenProvider := func(ctx context.Context) (string, error) { } ``` +### Proposed Configuration + +Audiences will be read by Sentry from the app's configuration, allowing each application to specify its own audience claim for the JWT. If not specified, the default audience will be the trust domain. + +```go +// ConfigurationSpec is the spec for a configuration. +type ConfigurationSpec struct { + // Existing fields... + + // +optional + AccessControlSpec *AccessControlSpec `json:"accessControl,omitempty"` +} + +// AccessControlSpec is the spec object in ConfigurationSpec. +type AccessControlSpec struct { + // Existing fields... + + // +optional + Audiences []string `json:"audiences,omitempty" yaml:"audiences,omitempty"` +} +``` + ### Proposed Sentry Configuration Flags **JWT-related flags:** -- `--jwt-enabled` (bool): Enable JWT token issuance by Sentry -- `--jwt-key-filename` (string): JWT signing key filename -- `--jwks-filename` (string): JWKS (JSON Web Key Set) filename +- `--jwt-enabled` (bool): Enable JWT token issuance by Sentry (default: `false`) +- `--jwt-key-filename` (string): JWT signing key filename (default: `jwt.key`) +- `--jwks-filename` (string): JWKS (JSON Web Key Set) filename (default: `jwks.json`) - `--jwt-issuer` (string): Issuer value for JWT tokens (no issuer if empty) -- `--jwt-signing-algorithm` (string): Algorithm for JWT signing, must be supported by signing key -- `--jwt-key-id` (string): Key ID (kid) for JWT signing +- `--jwt-signing-algorithm` (string): Algorithm for JWT signing, must be supported by signing key. (default: `RS256`, options: https://github.com/lestrrat-go/jwx/blob/3430caec7d1283f2f95de5e065aed1eaba47bc32/jwa/signature_gen.go#L18) +- `--jwt-key-id` (string): Key ID (kid) for JWT signing (default: base64 encoded SHA-256 of the key) **OIDC-related flags:** -- `--oidc-http-port` (int): Port for the OIDC HTTP server (disabled if 0) -- `--oidc-jwks-uri` (string): Custom URI for external JWKS access -- `--oidc-path-prefix` (string): Path prefix for all OIDC HTTP endpoints -- `--oidc-domains` (string slice): Allowed domains for OIDC HTTP endpoint requests -- `--oidc-server-tls-cert-file` (string): TLS certificate file for OIDC HTTP server (required if enabled) -- `--oidc-server-tls-key-file` (string): TLS key file for OIDC HTTP server (required if enabled) -- `--oidc-server-tls-enable` (bool): Serve OIDC HTTP with TLS +- `--oidc-server-listen-port` (int): Port for the OIDC HTTP server (0 for random, `nil` for disabled) +- `--oidc-server-listen-address` (string): Address for the OIDC HTTP server (default: `localhost`) +- `--oidc-server-tls-enable` (bool): Serve OIDC HTTP with TLS (default: `true`) +- `--oidc-server-tls-cert-file` (string): TLS certificate file for OIDC HTTP server (required if `oidc-server-tls-enable` enabled) +- `--oidc-server-tls-key-file` (string): TLS key file for OIDC HTTP server (required if `oidc-server-tls-enable` enabled) +- `--oidc-jwks-uri` (string): Custom URI for external JWKS access (default: `nil`) +- `--oidc-path-prefix` (string): Path prefix for all OIDC HTTP endpoints (default: `nil`) +- `--oidc-domains` (string slice): Allowed domains for OIDC HTTP endpoint requests (default: `nil`) ### Feature lifecycle outline From dd0d63bee1578ccb885b96430db3d4e06cf4b056 Mon Sep 17 00:00:00 2001 From: Jonathan Collinge Date: Sun, 25 May 2025 09:46:49 +0100 Subject: [PATCH 5/6] Feedback Signed-off-by: Jonathan Collinge --- 20250524-R-sentry-jwt-oidc.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/20250524-R-sentry-jwt-oidc.md b/20250524-R-sentry-jwt-oidc.md index 384b86c..70bd02e 100644 --- a/20250524-R-sentry-jwt-oidc.md +++ b/20250524-R-sentry-jwt-oidc.md @@ -137,6 +137,14 @@ type AccessControlSpec struct { - `--oidc-path-prefix` (string): Path prefix for all OIDC HTTP endpoints (default: `nil`) - `--oidc-domains` (string slice): Allowed domains for OIDC HTTP endpoint requests (default: `nil`) +### Propose Key Management + +If no signing key or JWKS is provided, Sentry will automatically generate a new RSA key and JWKS on startup. The JWKS will be served at the `/jwks.json` endpoint, and the JWT signing key will be used for issuing JWTs. +The existing mechanism for generating x.509 certificates will be extended to support the generation of the JWT signing key and JWKS. The generated signing key will use the RS256 algorithm by default as this is the most widely supported and avoids incompatibility issues when federating with cloud providers and third-party systems. +The user can also provide a pre-generated signing key and JWKS file, which Sentry will use instead of generating them. +The JWKS can be used to verify JWTs signed by multiple keys but Sentry can only sign JWTs with one key at a time. It is the user's responsibility to manage key rotation and ensure the JWKS is updated accordingly. +In order to rotate the JWT signing key in a backward-compatible way, the user must provide a JWKS that contains the public keys of any previously used signing keys and the new key. This allows clients to verify old JWTs against previous keys and new JWTs against the new key. + ### Feature lifecycle outline - Feature is opt-in, backward compatible, and does not affect existing x.509 flows From f60255f779e3a56de5068362a8cda793f006ad6f Mon Sep 17 00:00:00 2001 From: Joni Collinge Date: Sun, 25 May 2025 10:32:10 +0100 Subject: [PATCH 6/6] Update 20250524-R-sentry-jwt-oidc.md Signed-off-by: Joni Collinge --- 20250524-R-sentry-jwt-oidc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/20250524-R-sentry-jwt-oidc.md b/20250524-R-sentry-jwt-oidc.md index 70bd02e..c03b37f 100644 --- a/20250524-R-sentry-jwt-oidc.md +++ b/20250524-R-sentry-jwt-oidc.md @@ -1,6 +1,6 @@ # Sentry JWT and OIDC Support for Workload Identity -* Author(s): Joni Collige +* Author(s): Joni Collinge * State: Implemented * Updated: 2025-05-24