From 0cbb29161df7a647c2cfacc57c3c47676c628163 Mon Sep 17 00:00:00 2001 From: chrislu Date: Sun, 24 Aug 2025 21:14:31 -0700 Subject: [PATCH] fix: improve S3 IAM integration test JWT token generation and configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhanced the S3 IAM integration test framework to generate proper JWT tokens with all required claims and added missing identity provider configuration. ### Problem: - TestS3IAMPolicyEnforcement and TestS3IAMBucketPolicyIntegration failing - GitHub Actions: 501 NotImplemented error - Local environment: 403 AccessDenied error - JWT tokens missing required claims (role, snam, principal, etc.) - IAM config missing identity provider for 'test-oidc' ### Solution: - Enhanced generateSTSSessionToken() to include all required JWT claims: - role: Role ARN (arn:seaweed:iam::role/TestAdminRole) - snam: Session name (test-session-admin-user) - principal: Principal ARN (arn:seaweed:sts::assumed-role/...) - assumed, assumed_at, ext_uid, idp, max_dur, sid - Added test-oidc identity provider to iam_config.json - Added sts:ValidateSession action to S3AdminPolicy and S3ReadOnlyPolicy ### Technical Details: - JWT tokens now match the format expected by S3IAMIntegration middleware - Identity provider 'test-oidc' configured as mock type - Policies include both S3 actions and STS session validation - Signing key matches between test framework and S3 server config ### Current Status: - ✅ JWT token generation: Complete with all required claims - ✅ IAM configuration: Identity provider and policies configured - ⚠️ Authentication: Still investigating 403 AccessDenied locally - 🔄 Need to verify if this resolves 501 NotImplemented in GitHub Actions This addresses the core JWT token format and configuration issues. Further debugging may be needed for the authentication flow. --- test/s3/iam/iam_config.json | 19 +++++++++++++++ test/s3/iam/s3_iam_framework.go | 16 ++++++++++++- test/s3/iam/test_jwt.go | 41 +++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 test/s3/iam/test_jwt.go diff --git a/test/s3/iam/iam_config.json b/test/s3/iam/iam_config.json index ad2920fb5..35e9d28e3 100644 --- a/test/s3/iam/iam_config.json +++ b/test/s3/iam/iam_config.json @@ -5,6 +5,15 @@ "issuer": "seaweedfs-sts", "signingKey": "dGVzdC1zaWduaW5nLWtleS0zMi1jaGFyYWN0ZXJzLWxvbmc=" }, + "identityProviders": [ + { + "name": "test-oidc", + "type": "mock", + "config": { + "issuer": "test-oidc-issuer" + } + } + ], "policy": { "defaultEffect": "Deny", "storeType": "memory" @@ -57,6 +66,11 @@ "Effect": "Allow", "Action": "s3:*", "Resource": "*" + }, + { + "Effect": "Allow", + "Action": "sts:ValidateSession", + "Resource": "*" } ] } @@ -76,6 +90,11 @@ "arn:seaweed:s3:::*", "arn:seaweed:s3:::*/*" ] + }, + { + "Effect": "Allow", + "Action": "sts:ValidateSession", + "Resource": "*" } ] } diff --git a/test/s3/iam/s3_iam_framework.go b/test/s3/iam/s3_iam_framework.go index 1cd1c921e..0e4e5d7b8 100644 --- a/test/s3/iam/s3_iam_framework.go +++ b/test/s3/iam/s3_iam_framework.go @@ -305,12 +305,26 @@ func (f *S3IAMTestFramework) generateSTSSessionToken(username, roleName string, sessionId := fmt.Sprintf("test-session-%s-%s-%d", username, roleName, now.Unix()) // Create session token claims exactly as TokenGenerator does + roleArn := fmt.Sprintf("arn:seaweed:iam::role/%s", roleName) + sessionName := fmt.Sprintf("test-session-%s", username) + principalArn := fmt.Sprintf("arn:seaweed:sts::assumed-role/%s/%s", roleName, sessionName) + sessionClaims := jwt.MapClaims{ "iss": "seaweedfs-sts", "sub": sessionId, "iat": now.Unix(), "exp": now.Add(validDuration).Unix(), - "token_type": "session", + "nbf": now.Unix(), + "typ": "session", + "role": roleArn, + "snam": sessionName, + "principal": principalArn, + "assumed": principalArn, + "assumed_at": now.Format(time.RFC3339Nano), + "ext_uid": username, + "idp": "test-oidc", + "max_dur": int64(validDuration.Seconds()), + "sid": sessionId, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, sessionClaims) diff --git a/test/s3/iam/test_jwt.go b/test/s3/iam/test_jwt.go new file mode 100644 index 000000000..7e796eb27 --- /dev/null +++ b/test/s3/iam/test_jwt.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" + "time" + "encoding/base64" + "github.com/golang-jwt/jwt/v5" +) + +func main() { + now := time.Now() + signingKeyB64 := "dGVzdC1zaWduaW5nLWtleS0zMi1jaGFyYWN0ZXJzLWxvbmc=" + signingKey, _ := base64.StdEncoding.DecodeString(signingKeyB64) + + sessionId := fmt.Sprintf("test-session-admin-user-TestAdminRole-%d", now.Unix()) + roleArn := "arn:seaweed:iam::role/TestAdminRole" + sessionName := "test-session-admin-user" + principalArn := fmt.Sprintf("arn:seaweed:sts::assumed-role/TestAdminRole/%s", sessionName) + + sessionClaims := jwt.MapClaims{ + "iss": "seaweedfs-sts", + "sub": sessionId, + "iat": now.Unix(), + "exp": now.Add(time.Hour).Unix(), + "nbf": now.Unix(), + "typ": "session", + "role": roleArn, + "snam": sessionName, + "principal": principalArn, + "assumed": principalArn, + "assumed_at": now.Format(time.RFC3339Nano), + "ext_uid": "admin-user", + "idp": "test-oidc", + "max_dur": int64(time.Hour.Seconds()), + "sid": sessionId, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, sessionClaims) + tokenString, _ := token.SignedString(signingKey) + fmt.Println(tokenString) +}