mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-06-05 22:44:17 +00:00
December 2025 Improvements - Azure AD, Internal Networks, Startup Race Condition (#100)
* Allow internal IPs for OIDC configuration via extra flag. Addresses issue #97 * Allow for internal IPs in OIDC configuration. Addresses issue #97. * feat: Add allowPrivateIPAddresses config option for internal networks Adds a new configuration option `allowPrivateIPAddresses` that allows OIDC provider URLs to use private IP addresses (10.x.x.x, 172.16-31.x.x, 192.168.x.x). This is useful for internal deployments where Keycloak or other OIDC providers run on private networks without DNS resolution. Security considerations: - Loopback addresses (127.0.0.1, localhost, ::1) remain blocked - Link-local addresses (169.254.x.x) remain blocked - Default is false (secure by default) Fixes #97 * feat: Support non-email user identifiers for Azure AD Add userIdentifierClaim configuration option to support Azure AD users without email addresses. This allows using alternative JWT claims like "sub", "oid", "upn", or "preferred_username" for user identification. - Default behavior uses "email" claim (backward compatible) - Falls back to "sub" claim if configured claim is missing - allowedUsers matches against the configured claim value - allowedUserDomains only applies when using email-based identification Fixes #95 * Race condition on traefik pod startup When the plugin initializes and calls GetMetadataWithRecovery(): 1. Checks cache first (if metadata is cached, returns immediately) 2. Creates a retry executor with startup-optimized settings (10 attempts, 1s delays) 3. Attempts to fetch metadata from the OIDC provider 4. If the fetch fails with a retryable error (connection refused, EOF, TLS/certificate errors, Traefik default cert), it waits and retries 5. After 10 attempts or on a non-retryable error, returns the error This allows the plugin to handle the race condition where: - Traefik initializes the plugin before routes are established - Traefik serves its default certificate before loading real ones - The OIDC provider pod isn't fully ready yet Fixes issue #90 * Race condition on traefik pod startup When the plugin initializes and calls GetMetadataWithRecovery(): 1. Checks cache first (if metadata is cached, returns immediately) 2. Creates a retry executor with startup-optimized settings (10 attempts, 1s delays) 3. Attempts to fetch metadata from the OIDC provider 4. If the fetch fails with a retryable error (connection refused, EOF, TLS/certificate errors, Traefik default cert), it waits and retries 5. After 10 attempts or on a non-retryable error, returns the error This allows the plugin to handle the race condition where: - Traefik initializes the plugin before routes are established - Traefik serves its default certificate before loading real ones - The OIDC provider pod isn't fully ready yet Fixes issue #90 * Headers too big and 431 responses Added new option `minimalHeaders` to reduce the size of forwarded headers from the auth middleware to backend services. - When minimalHeaders: false (default): All headers are forwarded as before - X-Forwarded-User (always set) - X-Auth-Request-Redirect - X-Auth-Request-User - X-Auth-Request-Token (the large ID token) - X-User-Groups, X-User-Roles (if configured) - When minimalHeaders: true: Reduces header overhead - X-Forwarded-User (always set) - X-User-Groups, X-User-Roles (still forwarded if configured) - Custom templated headers (still processed) - Skipped: X-Auth-Request-Token, X-Auth-Request-User, X-Auth-Request-Redirect Fixes issues #64 and #86
This commit is contained in:
+53
@@ -127,10 +127,63 @@ type Config struct {
|
||||
// Default: "groups"
|
||||
GroupClaimName string `json:"groupClaimName,omitempty"`
|
||||
|
||||
// UserIdentifierClaim specifies the JWT claim to use as the user identifier.
|
||||
// This allows authentication for users without email addresses (e.g., Azure AD service accounts).
|
||||
//
|
||||
// Examples:
|
||||
// - Default (backward compatible): "email"
|
||||
// - Azure AD without email: "sub", "oid", "upn", or "preferred_username"
|
||||
// - Generic OIDC: "sub" (always present per OIDC spec)
|
||||
//
|
||||
// When set to a non-email claim:
|
||||
// - AllowedUsers will match against this claim value instead of email
|
||||
// - AllowedUserDomains validation is skipped (domains only apply to email)
|
||||
// - The session will store this identifier as the user's identity
|
||||
//
|
||||
// Default: "email"
|
||||
UserIdentifierClaim string `json:"userIdentifierClaim,omitempty"`
|
||||
|
||||
// DynamicClientRegistration enables OIDC Dynamic Client Registration (RFC 7591)
|
||||
// When enabled, the middleware will automatically register as a client with
|
||||
// the OIDC provider if ClientID/ClientSecret are not provided.
|
||||
DynamicClientRegistration *DynamicClientRegistrationConfig `json:"dynamicClientRegistration,omitempty"`
|
||||
|
||||
// AllowPrivateIPAddresses disables the security check that blocks private/internal IP addresses.
|
||||
// By default, the plugin rejects URLs containing private IP ranges (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
|
||||
// to prevent SSRF attacks and ensure OIDC providers are publicly accessible.
|
||||
//
|
||||
// Enable this option ONLY when:
|
||||
// - Your OIDC provider (e.g., Keycloak) runs on an internal network with private IPs
|
||||
// - You have no DNS resolution available for internal services
|
||||
// - Your entire stack runs in a Docker network or Kubernetes cluster with private addressing
|
||||
//
|
||||
// Security Warning: Enabling this option reduces SSRF protection. Only use in trusted
|
||||
// network environments where the OIDC provider is known and controlled.
|
||||
//
|
||||
// Default: false (private IPs are blocked for security)
|
||||
AllowPrivateIPAddresses bool `json:"allowPrivateIPAddresses,omitempty"`
|
||||
|
||||
// MinimalHeaders reduces the number of headers forwarded to downstream services.
|
||||
// This helps prevent "431 Request Header Fields Too Large" errors when downstream
|
||||
// services have limited header buffer sizes.
|
||||
//
|
||||
// When enabled (true):
|
||||
// - Only forwards: X-Forwarded-User
|
||||
// - Skips: X-Auth-Request-Token (full ID token), X-Auth-Request-Redirect
|
||||
// - Groups/roles headers (X-User-Groups, X-User-Roles) are still forwarded if configured
|
||||
// - Custom templated headers are still processed
|
||||
//
|
||||
// When disabled (false, default):
|
||||
// - Forwards all headers: X-Forwarded-User, X-Auth-Request-User, X-Auth-Request-Redirect,
|
||||
// X-Auth-Request-Token (full ID token)
|
||||
//
|
||||
// Use this option when:
|
||||
// - Downstream services return "431 Request Header Fields Too Large" errors
|
||||
// - You don't need the full ID token forwarded to backend services
|
||||
// - You want to reduce request overhead
|
||||
//
|
||||
// Default: false (all headers forwarded for backward compatibility)
|
||||
MinimalHeaders bool `json:"minimalHeaders,omitempty"`
|
||||
}
|
||||
|
||||
// RedisConfig configures Redis cache backend settings for distributed caching.
|
||||
|
||||
Reference in New Issue
Block a user