mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-12 01:07:35 +02:00
fix(iam): support both AWS standard and legacy IAM role ARN formats
Fix issue #7946 where SeaweedFS only recognized legacy IAM role ARN format (arn:aws:iam::role/RoleName) but not the standard AWS format with account ID (arn:aws:iam::ACCOUNT:role/RoleName). This was breaking EKS pod identity integration which expects the standard format. Changes: - Update ExtractRoleNameFromArn() to handle both formats by searching for 'role/' marker instead of matching a fixed prefix - Update ExtractRoleNameFromPrincipal() to clearly document both STS and IAM formats it supports - Simplify role ARN validation in validateRoleAssumptionForWebIdentity() and validateRoleAssumptionForCredentials() to use the extraction function The fix maintains backward compatibility with legacy format while adding support for standard AWS format with account ID. Fixes: https://github.com/seaweedfs/seaweedfs/issues/7946
This commit is contained in:
1 parent
fdb1d96a2c
commit
e2b58a0a5b
2 files changed
+29
-37
No files matched your search
@@ -699,13 +699,8 @@ func (s *STSService) validateRoleAssumptionForWebIdentity(ctx context.Context, r
|
||||
return fmt.Errorf("web identity token cannot be empty")
|
||||
}
|
||||
|
||||
// Basic role ARN format validation
|
||||
expectedPrefix := "arn:aws:iam::role/"
|
||||
if len(roleArn) < len(expectedPrefix) || roleArn[:len(expectedPrefix)] != expectedPrefix {
|
||||
return fmt.Errorf("invalid role ARN format: got %s, expected format: %s*", roleArn, expectedPrefix)
|
||||
}
|
||||
|
||||
// Extract role name and validate ARN format
|
||||
// Validate role ARN and extract role name
|
||||
// Accepts both arn:aws:iam::role/X and arn:aws:iam::ACCOUNT:role/X
|
||||
roleName := utils.ExtractRoleNameFromArn(roleArn)
|
||||
if roleName == "" {
|
||||
return fmt.Errorf("invalid role ARN format: %s", roleArn)
|
||||
@@ -736,13 +731,8 @@ func (s *STSService) validateRoleAssumptionForCredentials(ctx context.Context, r
|
||||
return fmt.Errorf("identity cannot be nil")
|
||||
}
|
||||
|
||||
// Basic role ARN format validation
|
||||
expectedPrefix := "arn:aws:iam::role/"
|
||||
if len(roleArn) < len(expectedPrefix) || roleArn[:len(expectedPrefix)] != expectedPrefix {
|
||||
return fmt.Errorf("invalid role ARN format: got %s, expected format: %s*", roleArn, expectedPrefix)
|
||||
}
|
||||
|
||||
// Extract role name and validate ARN format
|
||||
// Validate role ARN and extract role name
|
||||
// Accepts both arn:aws:iam::role/X and arn:aws:iam::ACCOUNT:role/X
|
||||
roleName := utils.ExtractRoleNameFromArn(roleArn)
|
||||
if roleName == "" {
|
||||
return fmt.Errorf("invalid role ARN format: %s", roleArn)
|
||||
|
||||
+25
-23
@@ -3,37 +3,39 @@ package utils
|
||||
import "strings"
|
||||
|
||||
// ExtractRoleNameFromPrincipal extracts role name from principal ARN
|
||||
// Handles both STS assumed role and IAM role formats
|
||||
// Handles both STS assumed role and IAM role formats with or without account ID:
|
||||
// - arn:aws:sts::assumed-role/Role/Session (legacy)
|
||||
// - arn:aws:sts::ACCOUNT:assumed-role/Role/Session (standard)
|
||||
// - arn:aws:iam::role/Role (legacy)
|
||||
// - arn:aws:iam::ACCOUNT:role/Role (standard)
|
||||
func ExtractRoleNameFromPrincipal(principal string) string {
|
||||
// Handle STS assumed role format: arn:aws:sts::assumed-role/RoleName/SessionName
|
||||
stsPrefix := "arn:aws:sts::assumed-role/"
|
||||
if strings.HasPrefix(principal, stsPrefix) {
|
||||
remainder := principal[len(stsPrefix):]
|
||||
// Split on first '/' to get role name
|
||||
if slashIndex := strings.Index(remainder, "/"); slashIndex != -1 {
|
||||
return remainder[:slashIndex]
|
||||
// Handle STS assumed role format
|
||||
if strings.HasPrefix(principal, "arn:aws:sts::") {
|
||||
remainder := principal[len("arn:aws:sts::"):]
|
||||
if idx := strings.Index(remainder, "assumed-role/"); idx != -1 {
|
||||
afterMarker := remainder[idx+len("assumed-role/"):]
|
||||
if slash := strings.Index(afterMarker, "/"); slash != -1 {
|
||||
return afterMarker[:slash]
|
||||
}
|
||||
return afterMarker
|
||||
}
|
||||
// If no slash found, return the remainder (edge case)
|
||||
return remainder
|
||||
}
|
||||
|
||||
// Handle IAM role format: arn:aws:iam::role/RoleName
|
||||
iamPrefix := "arn:aws:iam::role/"
|
||||
if strings.HasPrefix(principal, iamPrefix) {
|
||||
return principal[len(iamPrefix):]
|
||||
}
|
||||
|
||||
// Return empty string to signal invalid ARN format
|
||||
// This allows callers to handle the error explicitly instead of masking it
|
||||
return ""
|
||||
// Handle IAM role format
|
||||
return ExtractRoleNameFromArn(principal)
|
||||
}
|
||||
|
||||
// ExtractRoleNameFromArn extracts role name from an IAM role ARN
|
||||
// Specifically handles: arn:aws:iam::role/RoleName
|
||||
// Handles both formats:
|
||||
// - arn:aws:iam::role/RoleName (legacy, without account ID)
|
||||
// - arn:aws:iam::ACCOUNT:role/RoleName (standard AWS format)
|
||||
func ExtractRoleNameFromArn(roleArn string) string {
|
||||
prefix := "arn:aws:iam::role/"
|
||||
if strings.HasPrefix(roleArn, prefix) && len(roleArn) > len(prefix) {
|
||||
return roleArn[len(prefix):]
|
||||
if !strings.HasPrefix(roleArn, "arn:aws:iam::") {
|
||||
return ""
|
||||
}
|
||||
remainder := roleArn[len("arn:aws:iam::"):]
|
||||
if idx := strings.Index(remainder, "role/"); idx != -1 {
|
||||
return remainder[idx+len("role/"):]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in new issue
Block a user