From fa8830c71d642149fa53f8fe6717a7ea83923e53 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Fri, 2 Jan 2026 22:41:27 -0800 Subject: [PATCH] fix(auth): pass STS session token to IAM authorization for V4 signature auth CRITICAL FIX: Session tokens were not being passed to the authorization check when using AWS Signature V4 authentication with STS credentials. The bug: 1. AWS SDK sends request with X-Amz-Security-Token header (V4 signature) 2. validateSTSSessionToken validates the token, creates Identity with PrincipalArn 3. authorizeWithIAM only checked X-SeaweedFS-Session-Token (JWT auth header) 4. Since it was empty, fell into 'static V4' branch which set SessionToken = '' 5. AuthorizeAction returned ErrAccessDenied because SessionToken was empty The fix (in authorizeWithIAM): - Check X-SeaweedFS-Session-Token first (JWT auth) - If empty, fallback to X-Amz-Security-Token header (V4 STS auth) - If still empty, check X-Amz-Security-Token query param (presigned URLs) - When session token is found with PrincipalArn, use 'STS V4 signature' path - Only use 'static V4' path when there's no session token This ensures: - JWT Bearer auth with session tokens works (existing path) - STS V4 signature auth with session tokens works (new path) - Static V4 signature auth without session tokens works (existing path) Logging updated to distinguish: - 'JWT-based IAM authorization' - 'STS V4 signature IAM authorization' (new) - 'static V4 signature IAM authorization' (clarified) --- weed/s3api/auth_credentials.go | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/weed/s3api/auth_credentials.go b/weed/s3api/auth_credentials.go index 0cbed72a2..83dc6e91c 100644 --- a/weed/s3api/auth_credentials.go +++ b/weed/s3api/auth_credentials.go @@ -955,27 +955,44 @@ func (iam *IdentityAccessManagement) authenticateJWTWithIAM(r *http.Request) (*I func (iam *IdentityAccessManagement) authorizeWithIAM(r *http.Request, identity *Identity, action Action, bucket string, object string) s3err.ErrorCode { ctx := r.Context() - // Get session info from request headers (for JWT-based authentication) + // Get session info from request headers + // First check for JWT-based authentication headers (X-SeaweedFS-Session-Token) sessionToken := r.Header.Get("X-SeaweedFS-Session-Token") principal := r.Header.Get("X-SeaweedFS-Principal") + // Fallback to AWS Signature V4 STS token if JWT token not present + // This handles the case where STS AssumeRoleWithWebIdentity generates temporary credentials + // that include an X-Amz-Security-Token header (in addition to the access key and secret) + if sessionToken == "" { + sessionToken = r.Header.Get("X-Amz-Security-Token") + if sessionToken == "" { + // Also check query parameters for presigned URLs with STS tokens + sessionToken = r.URL.Query().Get("X-Amz-Security-Token") + } + } + // Create IAMIdentity for authorization iamIdentity := &IAMIdentity{ Name: identity.Name, Account: identity.Account, } - // Handle both session-based (JWT) and static-key-based (V4 signature) principals + // Handle both session-based (JWT and STS) and static-key-based (V4 signature) principals if sessionToken != "" && principal != "" { // JWT-based authentication - use session token and principal from headers iamIdentity.Principal = principal iamIdentity.SessionToken = sessionToken glog.V(3).Infof("Using JWT-based IAM authorization for principal: %s", principal) + } else if sessionToken != "" && identity.PrincipalArn != "" { + // STS V4 signature authentication - use session token (from X-Amz-Security-Token) with principal ARN + iamIdentity.Principal = identity.PrincipalArn + iamIdentity.SessionToken = sessionToken + glog.V(3).Infof("Using STS V4 signature IAM authorization for principal: %s with session token", identity.PrincipalArn) } else if identity.PrincipalArn != "" { - // V4 signature authentication - use principal ARN from identity + // Static V4 signature authentication - use principal ARN without session token iamIdentity.Principal = identity.PrincipalArn - iamIdentity.SessionToken = "" // No session token for static credentials - glog.V(3).Infof("Using V4 signature IAM authorization for principal: %s", identity.PrincipalArn) + iamIdentity.SessionToken = "" + glog.V(3).Infof("Using static V4 signature IAM authorization for principal: %s", identity.PrincipalArn) } else { glog.V(3).Info("No valid principal information for IAM authorization") return s3err.ErrAccessDenied