From 9d1d2c7b647dc4de337ceeb81dd6a095bd7df9e4 Mon Sep 17 00:00:00 2001 From: chrislu Date: Wed, 12 Nov 2025 20:31:42 -0800 Subject: [PATCH] arn:seaweed => arn:aws --- test/s3/iam/README-Docker.md | 2 +- test/s3/iam/README.md | 2 +- test/s3/iam/STS_DISTRIBUTED.md | 2 +- test/s3/iam/iam_config.github.json | 40 +++---- test/s3/iam/iam_config.json | 40 +++---- test/s3/iam/iam_config.local.json | 40 +++---- test/s3/iam/iam_config_distributed.json | 14 +-- test/s3/iam/iam_config_docker.json | 14 +-- test/s3/iam/s3_iam_framework.go | 4 +- test/s3/iam/s3_iam_integration_test.go | 4 +- test/s3/iam/test_config.json | 28 ++--- weed/iam/integration/iam_integration_test.go | 44 ++++---- weed/iam/integration/iam_manager.go | 2 +- weed/iam/integration/role_store_test.go | 6 +- weed/iam/oidc/oidc_provider_test.go | 6 +- weed/iam/policy/policy_engine.go | 2 +- .../policy/policy_engine_distributed_test.go | 30 ++--- weed/iam/policy/policy_engine_test.go | 48 ++++---- weed/iam/sts/cross_instance_token_test.go | 10 +- weed/iam/sts/session_policy_test.go | 18 +-- weed/iam/sts/sts_service.go | 4 +- weed/iam/sts/sts_service_test.go | 18 +-- weed/iam/sts/token_utils.go | 6 +- weed/iam/utils/arn_utils.go | 12 +- weed/s3api/auth_credentials.go | 8 +- weed/s3api/auth_credentials_test.go | 6 +- weed/s3api/s3_end_to_end_test.go | 26 ++--- weed/s3api/s3_iam_middleware.go | 8 +- weed/s3api/s3_iam_simple_test.go | 16 +-- weed/s3api/s3_jwt_auth_test.go | 20 ++-- weed/s3api/s3_multipart_iam_test.go | 14 +-- weed/s3api/s3_policy_templates.go | 56 +++++----- weed/s3api/s3_policy_templates_test.go | 32 +++--- weed/s3api/s3_presigned_url_iam.go | 4 +- weed/s3api/s3_presigned_url_iam_test.go | 12 +- weed/s3api/s3api_bucket_handlers.go | 20 ++-- weed/s3api/s3api_bucket_policy_arn_test.go | 104 ++++++++++++++++++ weed/s3api/s3api_bucket_policy_handlers.go | 4 +- 38 files changed, 415 insertions(+), 311 deletions(-) create mode 100644 weed/s3api/s3api_bucket_policy_arn_test.go diff --git a/test/s3/iam/README-Docker.md b/test/s3/iam/README-Docker.md index 3759d7fae..0f8d4108f 100644 --- a/test/s3/iam/README-Docker.md +++ b/test/s3/iam/README-Docker.md @@ -170,7 +170,7 @@ The `setup_keycloak_docker.sh` script automatically generates `iam_config.json` { "claim": "roles", "value": "s3-admin", - "role": "arn:seaweed:iam::role/KeycloakAdminRole" + "role": "arn:aws:iam::role/KeycloakAdminRole" } ``` diff --git a/test/s3/iam/README.md b/test/s3/iam/README.md index ba871600c..b28d0d262 100644 --- a/test/s3/iam/README.md +++ b/test/s3/iam/README.md @@ -257,7 +257,7 @@ Add policies to `test_config.json`: { "Effect": "Allow", "Action": ["s3:GetObject"], - "Resource": ["arn:seaweed:s3:::specific-bucket/*"], + "Resource": ["arn:aws:s3:::specific-bucket/*"], "Condition": { "StringEquals": { "s3:prefix": ["allowed-prefix/"] diff --git a/test/s3/iam/STS_DISTRIBUTED.md b/test/s3/iam/STS_DISTRIBUTED.md index b18ec4fdb..4d3edaf32 100644 --- a/test/s3/iam/STS_DISTRIBUTED.md +++ b/test/s3/iam/STS_DISTRIBUTED.md @@ -248,7 +248,7 @@ services: 3. User calls SeaweedFS STS AssumeRoleWithWebIdentity POST /sts/assume-role-with-web-identity { - "RoleArn": "arn:seaweed:iam::role/S3AdminRole", + "RoleArn": "arn:aws:iam::role/S3AdminRole", "WebIdentityToken": "eyJ0eXAiOiJKV1QiLCJhbGc...", "RoleSessionName": "user-session" } diff --git a/test/s3/iam/iam_config.github.json b/test/s3/iam/iam_config.github.json index b9a2fface..7a903b047 100644 --- a/test/s3/iam/iam_config.github.json +++ b/test/s3/iam/iam_config.github.json @@ -35,25 +35,25 @@ { "claim": "roles", "value": "s3-admin", - "role": "arn:seaweed:iam::role/KeycloakAdminRole" + "role": "arn:aws:iam::role/KeycloakAdminRole" }, { "claim": "roles", "value": "s3-read-only", - "role": "arn:seaweed:iam::role/KeycloakReadOnlyRole" + "role": "arn:aws:iam::role/KeycloakReadOnlyRole" }, { "claim": "roles", "value": "s3-write-only", - "role": "arn:seaweed:iam::role/KeycloakWriteOnlyRole" + "role": "arn:aws:iam::role/KeycloakWriteOnlyRole" }, { "claim": "roles", "value": "s3-read-write", - "role": "arn:seaweed:iam::role/KeycloakReadWriteRole" + "role": "arn:aws:iam::role/KeycloakReadWriteRole" } ], - "defaultRole": "arn:seaweed:iam::role/KeycloakReadOnlyRole" + "defaultRole": "arn:aws:iam::role/KeycloakReadOnlyRole" } } } @@ -64,7 +64,7 @@ "roles": [ { "roleName": "TestAdminRole", - "roleArn": "arn:seaweed:iam::role/TestAdminRole", + "roleArn": "arn:aws:iam::role/TestAdminRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -82,7 +82,7 @@ }, { "roleName": "TestReadOnlyRole", - "roleArn": "arn:seaweed:iam::role/TestReadOnlyRole", + "roleArn": "arn:aws:iam::role/TestReadOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -100,7 +100,7 @@ }, { "roleName": "TestWriteOnlyRole", - "roleArn": "arn:seaweed:iam::role/TestWriteOnlyRole", + "roleArn": "arn:aws:iam::role/TestWriteOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -118,7 +118,7 @@ }, { "roleName": "KeycloakAdminRole", - "roleArn": "arn:seaweed:iam::role/KeycloakAdminRole", + "roleArn": "arn:aws:iam::role/KeycloakAdminRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -136,7 +136,7 @@ }, { "roleName": "KeycloakReadOnlyRole", - "roleArn": "arn:seaweed:iam::role/KeycloakReadOnlyRole", + "roleArn": "arn:aws:iam::role/KeycloakReadOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -154,7 +154,7 @@ }, { "roleName": "KeycloakWriteOnlyRole", - "roleArn": "arn:seaweed:iam::role/KeycloakWriteOnlyRole", + "roleArn": "arn:aws:iam::role/KeycloakWriteOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -172,7 +172,7 @@ }, { "roleName": "KeycloakReadWriteRole", - "roleArn": "arn:seaweed:iam::role/KeycloakReadWriteRole", + "roleArn": "arn:aws:iam::role/KeycloakReadWriteRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -220,8 +220,8 @@ "s3:ListBucket" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { @@ -243,8 +243,8 @@ "s3:*" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { @@ -254,8 +254,8 @@ "s3:ListBucket" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { @@ -277,8 +277,8 @@ "s3:*" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { diff --git a/test/s3/iam/iam_config.json b/test/s3/iam/iam_config.json index b9a2fface..7a903b047 100644 --- a/test/s3/iam/iam_config.json +++ b/test/s3/iam/iam_config.json @@ -35,25 +35,25 @@ { "claim": "roles", "value": "s3-admin", - "role": "arn:seaweed:iam::role/KeycloakAdminRole" + "role": "arn:aws:iam::role/KeycloakAdminRole" }, { "claim": "roles", "value": "s3-read-only", - "role": "arn:seaweed:iam::role/KeycloakReadOnlyRole" + "role": "arn:aws:iam::role/KeycloakReadOnlyRole" }, { "claim": "roles", "value": "s3-write-only", - "role": "arn:seaweed:iam::role/KeycloakWriteOnlyRole" + "role": "arn:aws:iam::role/KeycloakWriteOnlyRole" }, { "claim": "roles", "value": "s3-read-write", - "role": "arn:seaweed:iam::role/KeycloakReadWriteRole" + "role": "arn:aws:iam::role/KeycloakReadWriteRole" } ], - "defaultRole": "arn:seaweed:iam::role/KeycloakReadOnlyRole" + "defaultRole": "arn:aws:iam::role/KeycloakReadOnlyRole" } } } @@ -64,7 +64,7 @@ "roles": [ { "roleName": "TestAdminRole", - "roleArn": "arn:seaweed:iam::role/TestAdminRole", + "roleArn": "arn:aws:iam::role/TestAdminRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -82,7 +82,7 @@ }, { "roleName": "TestReadOnlyRole", - "roleArn": "arn:seaweed:iam::role/TestReadOnlyRole", + "roleArn": "arn:aws:iam::role/TestReadOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -100,7 +100,7 @@ }, { "roleName": "TestWriteOnlyRole", - "roleArn": "arn:seaweed:iam::role/TestWriteOnlyRole", + "roleArn": "arn:aws:iam::role/TestWriteOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -118,7 +118,7 @@ }, { "roleName": "KeycloakAdminRole", - "roleArn": "arn:seaweed:iam::role/KeycloakAdminRole", + "roleArn": "arn:aws:iam::role/KeycloakAdminRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -136,7 +136,7 @@ }, { "roleName": "KeycloakReadOnlyRole", - "roleArn": "arn:seaweed:iam::role/KeycloakReadOnlyRole", + "roleArn": "arn:aws:iam::role/KeycloakReadOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -154,7 +154,7 @@ }, { "roleName": "KeycloakWriteOnlyRole", - "roleArn": "arn:seaweed:iam::role/KeycloakWriteOnlyRole", + "roleArn": "arn:aws:iam::role/KeycloakWriteOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -172,7 +172,7 @@ }, { "roleName": "KeycloakReadWriteRole", - "roleArn": "arn:seaweed:iam::role/KeycloakReadWriteRole", + "roleArn": "arn:aws:iam::role/KeycloakReadWriteRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -220,8 +220,8 @@ "s3:ListBucket" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { @@ -243,8 +243,8 @@ "s3:*" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { @@ -254,8 +254,8 @@ "s3:ListBucket" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { @@ -277,8 +277,8 @@ "s3:*" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { diff --git a/test/s3/iam/iam_config.local.json b/test/s3/iam/iam_config.local.json index b2b2ef4e5..30522771b 100644 --- a/test/s3/iam/iam_config.local.json +++ b/test/s3/iam/iam_config.local.json @@ -39,25 +39,25 @@ { "claim": "roles", "value": "s3-admin", - "role": "arn:seaweed:iam::role/KeycloakAdminRole" + "role": "arn:aws:iam::role/KeycloakAdminRole" }, { "claim": "roles", "value": "s3-read-only", - "role": "arn:seaweed:iam::role/KeycloakReadOnlyRole" + "role": "arn:aws:iam::role/KeycloakReadOnlyRole" }, { "claim": "roles", "value": "s3-write-only", - "role": "arn:seaweed:iam::role/KeycloakWriteOnlyRole" + "role": "arn:aws:iam::role/KeycloakWriteOnlyRole" }, { "claim": "roles", "value": "s3-read-write", - "role": "arn:seaweed:iam::role/KeycloakReadWriteRole" + "role": "arn:aws:iam::role/KeycloakReadWriteRole" } ], - "defaultRole": "arn:seaweed:iam::role/KeycloakReadOnlyRole" + "defaultRole": "arn:aws:iam::role/KeycloakReadOnlyRole" } } } @@ -68,7 +68,7 @@ "roles": [ { "roleName": "TestAdminRole", - "roleArn": "arn:seaweed:iam::role/TestAdminRole", + "roleArn": "arn:aws:iam::role/TestAdminRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -90,7 +90,7 @@ }, { "roleName": "TestReadOnlyRole", - "roleArn": "arn:seaweed:iam::role/TestReadOnlyRole", + "roleArn": "arn:aws:iam::role/TestReadOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -112,7 +112,7 @@ }, { "roleName": "TestWriteOnlyRole", - "roleArn": "arn:seaweed:iam::role/TestWriteOnlyRole", + "roleArn": "arn:aws:iam::role/TestWriteOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -134,7 +134,7 @@ }, { "roleName": "KeycloakAdminRole", - "roleArn": "arn:seaweed:iam::role/KeycloakAdminRole", + "roleArn": "arn:aws:iam::role/KeycloakAdminRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -156,7 +156,7 @@ }, { "roleName": "KeycloakReadOnlyRole", - "roleArn": "arn:seaweed:iam::role/KeycloakReadOnlyRole", + "roleArn": "arn:aws:iam::role/KeycloakReadOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -178,7 +178,7 @@ }, { "roleName": "KeycloakWriteOnlyRole", - "roleArn": "arn:seaweed:iam::role/KeycloakWriteOnlyRole", + "roleArn": "arn:aws:iam::role/KeycloakWriteOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -200,7 +200,7 @@ }, { "roleName": "KeycloakReadWriteRole", - "roleArn": "arn:seaweed:iam::role/KeycloakReadWriteRole", + "roleArn": "arn:aws:iam::role/KeycloakReadWriteRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -260,8 +260,8 @@ "s3:ListBucket" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { @@ -287,8 +287,8 @@ "s3:*" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { @@ -298,8 +298,8 @@ "s3:ListBucket" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { @@ -325,8 +325,8 @@ "s3:*" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] }, { diff --git a/test/s3/iam/iam_config_distributed.json b/test/s3/iam/iam_config_distributed.json index c9827c220..a6d2aa395 100644 --- a/test/s3/iam/iam_config_distributed.json +++ b/test/s3/iam/iam_config_distributed.json @@ -40,7 +40,7 @@ "roles": [ { "roleName": "S3AdminRole", - "roleArn": "arn:seaweed:iam::role/S3AdminRole", + "roleArn": "arn:aws:iam::role/S3AdminRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -63,7 +63,7 @@ }, { "roleName": "S3ReadOnlyRole", - "roleArn": "arn:seaweed:iam::role/S3ReadOnlyRole", + "roleArn": "arn:aws:iam::role/S3ReadOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -86,7 +86,7 @@ }, { "roleName": "S3ReadWriteRole", - "roleArn": "arn:seaweed:iam::role/S3ReadWriteRole", + "roleArn": "arn:aws:iam::role/S3ReadWriteRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -137,8 +137,8 @@ "s3:ListBucketVersions" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] } ] @@ -162,8 +162,8 @@ "s3:ListBucketVersions" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] } ] diff --git a/test/s3/iam/iam_config_docker.json b/test/s3/iam/iam_config_docker.json index c0fd5ab87..a533b16d7 100644 --- a/test/s3/iam/iam_config_docker.json +++ b/test/s3/iam/iam_config_docker.json @@ -25,7 +25,7 @@ "roles": [ { "roleName": "S3AdminRole", - "roleArn": "arn:seaweed:iam::role/S3AdminRole", + "roleArn": "arn:aws:iam::role/S3AdminRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -48,7 +48,7 @@ }, { "roleName": "S3ReadOnlyRole", - "roleArn": "arn:seaweed:iam::role/S3ReadOnlyRole", + "roleArn": "arn:aws:iam::role/S3ReadOnlyRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -71,7 +71,7 @@ }, { "roleName": "S3ReadWriteRole", - "roleArn": "arn:seaweed:iam::role/S3ReadWriteRole", + "roleArn": "arn:aws:iam::role/S3ReadWriteRole", "trustPolicy": { "Version": "2012-10-17", "Statement": [ @@ -122,8 +122,8 @@ "s3:ListBucketVersions" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] } ] @@ -147,8 +147,8 @@ "s3:ListBucketVersions" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] } ] diff --git a/test/s3/iam/s3_iam_framework.go b/test/s3/iam/s3_iam_framework.go index 92e880bdc..178ae0763 100644 --- a/test/s3/iam/s3_iam_framework.go +++ b/test/s3/iam/s3_iam_framework.go @@ -369,9 +369,9 @@ func (f *S3IAMTestFramework) generateSTSSessionToken(username, roleName string, sessionId := fmt.Sprintf("test-session-%s-%s-%d", username, roleName, now.Unix()) // Create session token claims exactly matching STSSessionClaims struct - roleArn := fmt.Sprintf("arn:seaweed:iam::role/%s", roleName) + roleArn := fmt.Sprintf("arn:aws:iam::role/%s", roleName) sessionName := fmt.Sprintf("test-session-%s", username) - principalArn := fmt.Sprintf("arn:seaweed:sts::assumed-role/%s/%s", roleName, sessionName) + principalArn := fmt.Sprintf("arn:aws:sts::assumed-role/%s/%s", roleName, sessionName) // Use jwt.MapClaims but with exact field names that STSSessionClaims expects sessionClaims := jwt.MapClaims{ diff --git a/test/s3/iam/s3_iam_integration_test.go b/test/s3/iam/s3_iam_integration_test.go index c7836c4bf..05675e630 100644 --- a/test/s3/iam/s3_iam_integration_test.go +++ b/test/s3/iam/s3_iam_integration_test.go @@ -410,7 +410,7 @@ func TestS3IAMBucketPolicyIntegration(t *testing.T) { "Effect": "Allow", "Principal": "*", "Action": ["s3:GetObject"], - "Resource": ["arn:seaweed:s3:::%s/*"] + "Resource": ["arn:aws:s3:::%s/*"] } ] }`, bucketName) @@ -455,7 +455,7 @@ func TestS3IAMBucketPolicyIntegration(t *testing.T) { "Effect": "Deny", "Principal": "*", "Action": ["s3:DeleteObject"], - "Resource": ["arn:seaweed:s3:::%s/*"] + "Resource": ["arn:aws:s3:::%s/*"] } ] }`, bucketName) diff --git a/test/s3/iam/test_config.json b/test/s3/iam/test_config.json index d2f1fb09e..2684c3cc3 100644 --- a/test/s3/iam/test_config.json +++ b/test/s3/iam/test_config.json @@ -164,8 +164,8 @@ "Effect": "Allow", "Action": ["s3:*"], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] } ] @@ -184,8 +184,8 @@ "s3:GetBucketVersioning" ], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ] } ] @@ -207,7 +207,7 @@ "s3:ListMultipartUploadParts" ], "Resource": [ - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*/*" ] } ] @@ -227,7 +227,7 @@ "s3:PutBucketVersioning" ], "Resource": [ - "arn:seaweed:s3:::*" + "arn:aws:s3:::*" ] } ] @@ -239,8 +239,8 @@ "Effect": "Allow", "Action": ["s3:*"], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ], "Condition": { "IpAddress": { @@ -257,8 +257,8 @@ "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": [ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*" + "arn:aws:s3:::*", + "arn:aws:s3:::*/*" ], "Condition": { "DateGreaterThan": { @@ -281,7 +281,7 @@ "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", - "Resource": "arn:seaweed:s3:::example-bucket/*" + "Resource": "arn:aws:s3:::example-bucket/*" } ] }, @@ -294,8 +294,8 @@ "Principal": "*", "Action": ["s3:DeleteObject", "s3:DeleteBucket"], "Resource": [ - "arn:seaweed:s3:::example-bucket", - "arn:seaweed:s3:::example-bucket/*" + "arn:aws:s3:::example-bucket", + "arn:aws:s3:::example-bucket/*" ] } ] @@ -308,7 +308,7 @@ "Effect": "Allow", "Principal": "*", "Action": ["s3:GetObject", "s3:PutObject"], - "Resource": "arn:seaweed:s3:::example-bucket/*", + "Resource": "arn:aws:s3:::example-bucket/*", "Condition": { "IpAddress": { "aws:SourceIp": ["203.0.113.0/24"] diff --git a/weed/iam/integration/iam_integration_test.go b/weed/iam/integration/iam_integration_test.go index 7684656ce..d413c3936 100644 --- a/weed/iam/integration/iam_integration_test.go +++ b/weed/iam/integration/iam_integration_test.go @@ -34,23 +34,23 @@ func TestFullOIDCWorkflow(t *testing.T) { }{ { name: "successful role assumption with policy validation", - roleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + roleArn: "arn:aws:iam::role/S3ReadOnlyRole", sessionName: "oidc-session", webToken: validJWTToken, expectedAllow: true, testAction: "s3:GetObject", - testResource: "arn:seaweed:s3:::test-bucket/file.txt", + testResource: "arn:aws:s3:::test-bucket/file.txt", }, { name: "role assumption denied by trust policy", - roleArn: "arn:seaweed:iam::role/RestrictedRole", + roleArn: "arn:aws:iam::role/RestrictedRole", sessionName: "oidc-session", webToken: validJWTToken, expectedAllow: false, }, { name: "invalid token rejected", - roleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + roleArn: "arn:aws:iam::role/S3ReadOnlyRole", sessionName: "oidc-session", webToken: invalidJWTToken, expectedAllow: false, @@ -113,17 +113,17 @@ func TestFullLDAPWorkflow(t *testing.T) { }{ { name: "successful LDAP role assumption", - roleArn: "arn:seaweed:iam::role/LDAPUserRole", + roleArn: "arn:aws:iam::role/LDAPUserRole", sessionName: "ldap-session", username: "testuser", password: "testpass", expectedAllow: true, testAction: "filer:CreateEntry", - testResource: "arn:seaweed:filer::path/user-docs/*", + testResource: "arn:aws:filer::path/user-docs/*", }, { name: "invalid LDAP credentials", - roleArn: "arn:seaweed:iam::role/LDAPUserRole", + roleArn: "arn:aws:iam::role/LDAPUserRole", sessionName: "ldap-session", username: "testuser", password: "wrongpass", @@ -181,7 +181,7 @@ func TestPolicyEnforcement(t *testing.T) { // Create a session for testing ctx := context.Background() assumeRequest := &sts.AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + RoleArn: "arn:aws:iam::role/S3ReadOnlyRole", WebIdentityToken: validJWTToken, RoleSessionName: "policy-test-session", } @@ -202,35 +202,35 @@ func TestPolicyEnforcement(t *testing.T) { { name: "allow read access", action: "s3:GetObject", - resource: "arn:seaweed:s3:::test-bucket/file.txt", + resource: "arn:aws:s3:::test-bucket/file.txt", shouldAllow: true, reason: "S3ReadOnlyRole should allow GetObject", }, { name: "allow list bucket", action: "s3:ListBucket", - resource: "arn:seaweed:s3:::test-bucket", + resource: "arn:aws:s3:::test-bucket", shouldAllow: true, reason: "S3ReadOnlyRole should allow ListBucket", }, { name: "deny write access", action: "s3:PutObject", - resource: "arn:seaweed:s3:::test-bucket/newfile.txt", + resource: "arn:aws:s3:::test-bucket/newfile.txt", shouldAllow: false, reason: "S3ReadOnlyRole should deny write operations", }, { name: "deny delete access", action: "s3:DeleteObject", - resource: "arn:seaweed:s3:::test-bucket/file.txt", + resource: "arn:aws:s3:::test-bucket/file.txt", shouldAllow: false, reason: "S3ReadOnlyRole should deny delete operations", }, { name: "deny filer access", action: "filer:CreateEntry", - resource: "arn:seaweed:filer::path/test", + resource: "arn:aws:filer::path/test", shouldAllow: false, reason: "S3ReadOnlyRole should not allow filer operations", }, @@ -261,7 +261,7 @@ func TestSessionExpiration(t *testing.T) { // Create a short-lived session assumeRequest := &sts.AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + RoleArn: "arn:aws:iam::role/S3ReadOnlyRole", WebIdentityToken: validJWTToken, RoleSessionName: "expiration-test", DurationSeconds: int64Ptr(900), // 15 minutes @@ -276,7 +276,7 @@ func TestSessionExpiration(t *testing.T) { allowed, err := iamManager.IsActionAllowed(ctx, &ActionRequest{ Principal: response.AssumedRoleUser.Arn, Action: "s3:GetObject", - Resource: "arn:seaweed:s3:::test-bucket/file.txt", + Resource: "arn:aws:s3:::test-bucket/file.txt", SessionToken: sessionToken, }) require.NoError(t, err) @@ -296,7 +296,7 @@ func TestSessionExpiration(t *testing.T) { allowed, err = iamManager.IsActionAllowed(ctx, &ActionRequest{ Principal: response.AssumedRoleUser.Arn, Action: "s3:GetObject", - Resource: "arn:seaweed:s3:::test-bucket/file.txt", + Resource: "arn:aws:s3:::test-bucket/file.txt", SessionToken: sessionToken, }) require.NoError(t, err, "Session should still be valid in stateless system") @@ -318,7 +318,7 @@ func TestTrustPolicyValidation(t *testing.T) { }{ { name: "OIDC user allowed by trust policy", - roleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + roleArn: "arn:aws:iam::role/S3ReadOnlyRole", provider: "oidc", userID: "test-user-id", shouldAllow: true, @@ -326,7 +326,7 @@ func TestTrustPolicyValidation(t *testing.T) { }, { name: "LDAP user allowed by different role", - roleArn: "arn:seaweed:iam::role/LDAPUserRole", + roleArn: "arn:aws:iam::role/LDAPUserRole", provider: "ldap", userID: "testuser", shouldAllow: true, @@ -334,7 +334,7 @@ func TestTrustPolicyValidation(t *testing.T) { }, { name: "Wrong provider for role", - roleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + roleArn: "arn:aws:iam::role/S3ReadOnlyRole", provider: "ldap", userID: "testuser", shouldAllow: false, @@ -442,8 +442,8 @@ func setupTestPoliciesAndRoles(t *testing.T, manager *IAMManager) { Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, }, @@ -461,7 +461,7 @@ func setupTestPoliciesAndRoles(t *testing.T, manager *IAMManager) { Effect: "Allow", Action: []string{"filer:*"}, Resource: []string{ - "arn:seaweed:filer::path/user-docs/*", + "arn:aws:filer::path/user-docs/*", }, }, }, diff --git a/weed/iam/integration/iam_manager.go b/weed/iam/integration/iam_manager.go index 51deb9fd6..fd99e9c3e 100644 --- a/weed/iam/integration/iam_manager.go +++ b/weed/iam/integration/iam_manager.go @@ -213,7 +213,7 @@ func (m *IAMManager) CreateRole(ctx context.Context, filerAddress string, roleNa // Set role ARN if not provided if roleDef.RoleArn == "" { - roleDef.RoleArn = fmt.Sprintf("arn:seaweed:iam::role/%s", roleName) + roleDef.RoleArn = fmt.Sprintf("arn:aws:iam::role/%s", roleName) } // Validate trust policy diff --git a/weed/iam/integration/role_store_test.go b/weed/iam/integration/role_store_test.go index 53ee339c3..716eef3c2 100644 --- a/weed/iam/integration/role_store_test.go +++ b/weed/iam/integration/role_store_test.go @@ -18,7 +18,7 @@ func TestMemoryRoleStore(t *testing.T) { // Test storing a role roleDef := &RoleDefinition{ RoleName: "TestRole", - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", Description: "Test role for unit testing", AttachedPolicies: []string{"TestPolicy"}, TrustPolicy: &policy.PolicyDocument{ @@ -42,7 +42,7 @@ func TestMemoryRoleStore(t *testing.T) { retrievedRole, err := store.GetRole(ctx, "", "TestRole") require.NoError(t, err) assert.Equal(t, "TestRole", retrievedRole.RoleName) - assert.Equal(t, "arn:seaweed:iam::role/TestRole", retrievedRole.RoleArn) + assert.Equal(t, "arn:aws:iam::role/TestRole", retrievedRole.RoleArn) assert.Equal(t, "Test role for unit testing", retrievedRole.Description) assert.Equal(t, []string{"TestPolicy"}, retrievedRole.AttachedPolicies) @@ -112,7 +112,7 @@ func TestDistributedIAMManagerWithRoleStore(t *testing.T) { // Test creating a role roleDef := &RoleDefinition{ RoleName: "DistributedTestRole", - RoleArn: "arn:seaweed:iam::role/DistributedTestRole", + RoleArn: "arn:aws:iam::role/DistributedTestRole", Description: "Test role for distributed IAM", AttachedPolicies: []string{"S3ReadOnlyPolicy"}, } diff --git a/weed/iam/oidc/oidc_provider_test.go b/weed/iam/oidc/oidc_provider_test.go index d37bee1f0..d8624ac30 100644 --- a/weed/iam/oidc/oidc_provider_test.go +++ b/weed/iam/oidc/oidc_provider_test.go @@ -210,15 +210,15 @@ func TestOIDCProviderAuthentication(t *testing.T) { { Claim: "email", Value: "*@example.com", - Role: "arn:seaweed:iam::role/UserRole", + Role: "arn:aws:iam::role/UserRole", }, { Claim: "groups", Value: "admins", - Role: "arn:seaweed:iam::role/AdminRole", + Role: "arn:aws:iam::role/AdminRole", }, }, - DefaultRole: "arn:seaweed:iam::role/GuestRole", + DefaultRole: "arn:aws:iam::role/GuestRole", }, } diff --git a/weed/iam/policy/policy_engine.go b/weed/iam/policy/policy_engine.go index 5af1d7e1a..41f7da086 100644 --- a/weed/iam/policy/policy_engine.go +++ b/weed/iam/policy/policy_engine.go @@ -95,7 +95,7 @@ type EvaluationContext struct { // Action being requested (e.g., "s3:GetObject") Action string `json:"action"` - // Resource being accessed (e.g., "arn:seaweed:s3:::bucket/key") + // Resource being accessed (e.g., "arn:aws:s3:::bucket/key") Resource string `json:"resource"` // RequestContext contains additional request information diff --git a/weed/iam/policy/policy_engine_distributed_test.go b/weed/iam/policy/policy_engine_distributed_test.go index f5b5d285b..046c4e179 100644 --- a/weed/iam/policy/policy_engine_distributed_test.go +++ b/weed/iam/policy/policy_engine_distributed_test.go @@ -47,13 +47,13 @@ func TestDistributedPolicyEngine(t *testing.T) { Sid: "AllowS3Read", Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket"}, - Resource: []string{"arn:seaweed:s3:::test-bucket/*", "arn:seaweed:s3:::test-bucket"}, + Resource: []string{"arn:aws:s3:::test-bucket/*", "arn:aws:s3:::test-bucket"}, }, { Sid: "DenyS3Write", Effect: "Deny", Action: []string{"s3:PutObject", "s3:DeleteObject"}, - Resource: []string{"arn:seaweed:s3:::test-bucket/*"}, + Resource: []string{"arn:aws:s3:::test-bucket/*"}, }, }, } @@ -83,9 +83,9 @@ func TestDistributedPolicyEngine(t *testing.T) { t.Run("evaluation_consistency", func(t *testing.T) { // Create evaluation context evalCtx := &EvaluationContext{ - Principal: "arn:seaweed:sts::assumed-role/TestRole/session", + Principal: "arn:aws:sts::assumed-role/TestRole/session", Action: "s3:GetObject", - Resource: "arn:seaweed:s3:::test-bucket/file.txt", + Resource: "arn:aws:s3:::test-bucket/file.txt", RequestContext: map[string]interface{}{ "sourceIp": "192.168.1.100", }, @@ -118,9 +118,9 @@ func TestDistributedPolicyEngine(t *testing.T) { // Test explicit deny precedence t.Run("deny_precedence_consistency", func(t *testing.T) { evalCtx := &EvaluationContext{ - Principal: "arn:seaweed:sts::assumed-role/TestRole/session", + Principal: "arn:aws:sts::assumed-role/TestRole/session", Action: "s3:PutObject", - Resource: "arn:seaweed:s3:::test-bucket/newfile.txt", + Resource: "arn:aws:s3:::test-bucket/newfile.txt", } // All instances should consistently apply deny precedence @@ -146,9 +146,9 @@ func TestDistributedPolicyEngine(t *testing.T) { // Test default effect consistency t.Run("default_effect_consistency", func(t *testing.T) { evalCtx := &EvaluationContext{ - Principal: "arn:seaweed:sts::assumed-role/TestRole/session", + Principal: "arn:aws:sts::assumed-role/TestRole/session", Action: "filer:CreateEntry", // Action not covered by any policy - Resource: "arn:seaweed:filer::path/test", + Resource: "arn:aws:filer::path/test", } result1, err1 := instance1.Evaluate(ctx, "", evalCtx, []string{"TestPolicy"}) @@ -196,9 +196,9 @@ func TestPolicyEngineConfigurationConsistency(t *testing.T) { // Test with an action not covered by any policy evalCtx := &EvaluationContext{ - Principal: "arn:seaweed:sts::assumed-role/TestRole/session", + Principal: "arn:aws:sts::assumed-role/TestRole/session", Action: "uncovered:action", - Resource: "arn:seaweed:test:::resource", + Resource: "arn:aws:test:::resource", } result1, _ := instance1.Evaluate(context.Background(), "", evalCtx, []string{}) @@ -277,9 +277,9 @@ func TestPolicyStoreDistributed(t *testing.T) { require.NoError(t, err) evalCtx := &EvaluationContext{ - Principal: "arn:seaweed:sts::assumed-role/TestRole/session", + Principal: "arn:aws:sts::assumed-role/TestRole/session", Action: "s3:GetObject", - Resource: "arn:seaweed:s3:::bucket/key", + Resource: "arn:aws:s3:::bucket/key", } // Evaluate with non-existent policies @@ -350,7 +350,7 @@ func TestPolicyEvaluationPerformance(t *testing.T) { Sid: fmt.Sprintf("Statement%d", i), Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket"}, - Resource: []string{fmt.Sprintf("arn:seaweed:s3:::bucket%d/*", i)}, + Resource: []string{fmt.Sprintf("arn:aws:s3:::bucket%d/*", i)}, }, }, } @@ -361,9 +361,9 @@ func TestPolicyEvaluationPerformance(t *testing.T) { // Test evaluation performance evalCtx := &EvaluationContext{ - Principal: "arn:seaweed:sts::assumed-role/TestRole/session", + Principal: "arn:aws:sts::assumed-role/TestRole/session", Action: "s3:GetObject", - Resource: "arn:seaweed:s3:::bucket5/file.txt", + Resource: "arn:aws:s3:::bucket5/file.txt", } policyNames := make([]string, 10) diff --git a/weed/iam/policy/policy_engine_test.go b/weed/iam/policy/policy_engine_test.go index 4e6cd3c3a..1f32b003b 100644 --- a/weed/iam/policy/policy_engine_test.go +++ b/weed/iam/policy/policy_engine_test.go @@ -71,7 +71,7 @@ func TestPolicyDocumentValidation(t *testing.T) { Sid: "AllowS3Read", Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket"}, - Resource: []string{"arn:seaweed:s3:::mybucket/*"}, + Resource: []string{"arn:aws:s3:::mybucket/*"}, }, }, }, @@ -84,7 +84,7 @@ func TestPolicyDocumentValidation(t *testing.T) { { Effect: "Allow", Action: []string{"s3:GetObject"}, - Resource: []string{"arn:seaweed:s3:::mybucket/*"}, + Resource: []string{"arn:aws:s3:::mybucket/*"}, }, }, }, @@ -108,7 +108,7 @@ func TestPolicyDocumentValidation(t *testing.T) { { Effect: "Maybe", Action: []string{"s3:GetObject"}, - Resource: []string{"arn:seaweed:s3:::mybucket/*"}, + Resource: []string{"arn:aws:s3:::mybucket/*"}, }, }, }, @@ -146,8 +146,8 @@ func TestPolicyEvaluation(t *testing.T) { Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket"}, Resource: []string{ - "arn:seaweed:s3:::public-bucket/*", // For object operations - "arn:seaweed:s3:::public-bucket", // For bucket operations + "arn:aws:s3:::public-bucket/*", // For object operations + "arn:aws:s3:::public-bucket", // For bucket operations }, }, }, @@ -163,7 +163,7 @@ func TestPolicyEvaluation(t *testing.T) { Sid: "DenyS3Delete", Effect: "Deny", Action: []string{"s3:DeleteObject"}, - Resource: []string{"arn:seaweed:s3:::*"}, + Resource: []string{"arn:aws:s3:::*"}, }, }, } @@ -182,7 +182,7 @@ func TestPolicyEvaluation(t *testing.T) { context: &EvaluationContext{ Principal: "user:alice", Action: "s3:GetObject", - Resource: "arn:seaweed:s3:::public-bucket/file.txt", + Resource: "arn:aws:s3:::public-bucket/file.txt", RequestContext: map[string]interface{}{ "sourceIP": "192.168.1.100", }, @@ -195,7 +195,7 @@ func TestPolicyEvaluation(t *testing.T) { context: &EvaluationContext{ Principal: "user:alice", Action: "s3:DeleteObject", - Resource: "arn:seaweed:s3:::public-bucket/file.txt", + Resource: "arn:aws:s3:::public-bucket/file.txt", }, policies: []string{"read-policy", "deny-policy"}, want: EffectDeny, @@ -205,7 +205,7 @@ func TestPolicyEvaluation(t *testing.T) { context: &EvaluationContext{ Principal: "user:alice", Action: "s3:PutObject", - Resource: "arn:seaweed:s3:::public-bucket/file.txt", + Resource: "arn:aws:s3:::public-bucket/file.txt", }, policies: []string{"read-policy"}, want: EffectDeny, @@ -215,7 +215,7 @@ func TestPolicyEvaluation(t *testing.T) { context: &EvaluationContext{ Principal: "user:admin", Action: "s3:ListBucket", - Resource: "arn:seaweed:s3:::public-bucket", + Resource: "arn:aws:s3:::public-bucket", }, policies: []string{"read-policy"}, want: EffectAllow, @@ -249,7 +249,7 @@ func TestConditionEvaluation(t *testing.T) { Sid: "AllowFromOfficeIP", Effect: "Allow", Action: []string{"s3:*"}, - Resource: []string{"arn:seaweed:s3:::*"}, + Resource: []string{"arn:aws:s3:::*"}, Condition: map[string]map[string]interface{}{ "IpAddress": { "seaweed:SourceIP": []string{"192.168.1.0/24", "10.0.0.0/8"}, @@ -272,7 +272,7 @@ func TestConditionEvaluation(t *testing.T) { context: &EvaluationContext{ Principal: "user:alice", Action: "s3:GetObject", - Resource: "arn:seaweed:s3:::mybucket/file.txt", + Resource: "arn:aws:s3:::mybucket/file.txt", RequestContext: map[string]interface{}{ "sourceIP": "192.168.1.100", }, @@ -284,7 +284,7 @@ func TestConditionEvaluation(t *testing.T) { context: &EvaluationContext{ Principal: "user:alice", Action: "s3:GetObject", - Resource: "arn:seaweed:s3:::mybucket/file.txt", + Resource: "arn:aws:s3:::mybucket/file.txt", RequestContext: map[string]interface{}{ "sourceIP": "8.8.8.8", }, @@ -296,7 +296,7 @@ func TestConditionEvaluation(t *testing.T) { context: &EvaluationContext{ Principal: "user:alice", Action: "s3:PutObject", - Resource: "arn:seaweed:s3:::mybucket/newfile.txt", + Resource: "arn:aws:s3:::mybucket/newfile.txt", RequestContext: map[string]interface{}{ "sourceIP": "10.1.2.3", }, @@ -325,32 +325,32 @@ func TestResourceMatching(t *testing.T) { }{ { name: "exact match", - policyResource: "arn:seaweed:s3:::mybucket/file.txt", - requestResource: "arn:seaweed:s3:::mybucket/file.txt", + policyResource: "arn:aws:s3:::mybucket/file.txt", + requestResource: "arn:aws:s3:::mybucket/file.txt", want: true, }, { name: "wildcard match", - policyResource: "arn:seaweed:s3:::mybucket/*", - requestResource: "arn:seaweed:s3:::mybucket/folder/file.txt", + policyResource: "arn:aws:s3:::mybucket/*", + requestResource: "arn:aws:s3:::mybucket/folder/file.txt", want: true, }, { name: "bucket wildcard", - policyResource: "arn:seaweed:s3:::*", - requestResource: "arn:seaweed:s3:::anybucket/file.txt", + policyResource: "arn:aws:s3:::*", + requestResource: "arn:aws:s3:::anybucket/file.txt", want: true, }, { name: "no match different bucket", - policyResource: "arn:seaweed:s3:::mybucket/*", - requestResource: "arn:seaweed:s3:::otherbucket/file.txt", + policyResource: "arn:aws:s3:::mybucket/*", + requestResource: "arn:aws:s3:::otherbucket/file.txt", want: false, }, { name: "prefix match", - policyResource: "arn:seaweed:s3:::mybucket/documents/*", - requestResource: "arn:seaweed:s3:::mybucket/documents/secret.txt", + policyResource: "arn:aws:s3:::mybucket/documents/*", + requestResource: "arn:aws:s3:::mybucket/documents/secret.txt", want: true, }, } diff --git a/weed/iam/sts/cross_instance_token_test.go b/weed/iam/sts/cross_instance_token_test.go index 243951d82..c628d5e0d 100644 --- a/weed/iam/sts/cross_instance_token_test.go +++ b/weed/iam/sts/cross_instance_token_test.go @@ -153,7 +153,7 @@ func TestCrossInstanceTokenUsage(t *testing.T) { mockToken := createMockJWT(t, "http://test-mock:9999", "test-user") assumeRequest := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/CrossInstanceTestRole", + RoleArn: "arn:aws:iam::role/CrossInstanceTestRole", WebIdentityToken: mockToken, // JWT token for mock provider RoleSessionName: "cross-instance-test-session", DurationSeconds: int64ToPtr(3600), @@ -198,7 +198,7 @@ func TestCrossInstanceTokenUsage(t *testing.T) { mockToken := createMockJWT(t, "http://test-mock:9999", "test-user") assumeRequest := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/RevocationTestRole", + RoleArn: "arn:aws:iam::role/RevocationTestRole", WebIdentityToken: mockToken, RoleSessionName: "revocation-test-session", } @@ -240,7 +240,7 @@ func TestCrossInstanceTokenUsage(t *testing.T) { // Try to assume role with same token on different instances assumeRequest := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/ProviderTestRole", + RoleArn: "arn:aws:iam::role/ProviderTestRole", WebIdentityToken: testToken, RoleSessionName: "provider-consistency-test", } @@ -452,7 +452,7 @@ func TestSTSRealWorldDistributedScenarios(t *testing.T) { mockToken := createMockJWT(t, "http://test-mock:9999", "production-user") assumeRequest := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/ProductionS3User", + RoleArn: "arn:aws:iam::role/ProductionS3User", WebIdentityToken: mockToken, // JWT token from mock provider RoleSessionName: "user-production-session", DurationSeconds: int64ToPtr(7200), // 2 hours @@ -470,7 +470,7 @@ func TestSTSRealWorldDistributedScenarios(t *testing.T) { sessionInfo2, err := gateway2.ValidateSessionToken(ctx, sessionToken) require.NoError(t, err, "Gateway 2 should validate session from Gateway 1") assert.Equal(t, "user-production-session", sessionInfo2.SessionName) - assert.Equal(t, "arn:seaweed:iam::role/ProductionS3User", sessionInfo2.RoleArn) + assert.Equal(t, "arn:aws:iam::role/ProductionS3User", sessionInfo2.RoleArn) // Simulate S3 request validation on Gateway 3 sessionInfo3, err := gateway3.ValidateSessionToken(ctx, sessionToken) diff --git a/weed/iam/sts/session_policy_test.go b/weed/iam/sts/session_policy_test.go index 6f94169ec..83267fd83 100644 --- a/weed/iam/sts/session_policy_test.go +++ b/weed/iam/sts/session_policy_test.go @@ -47,7 +47,7 @@ func TestAssumeRoleWithWebIdentity_SessionPolicy(t *testing.T) { testToken := createSessionPolicyTestJWT(t, "test-issuer", "test-user") request := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", WebIdentityToken: testToken, RoleSessionName: "test-session", DurationSeconds: nil, // Use default @@ -69,7 +69,7 @@ func TestAssumeRoleWithWebIdentity_SessionPolicy(t *testing.T) { testToken := createSessionPolicyTestJWT(t, "test-issuer", "test-user") request := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", WebIdentityToken: testToken, RoleSessionName: "test-session", DurationSeconds: nil, // Use default @@ -93,7 +93,7 @@ func TestAssumeRoleWithWebIdentity_SessionPolicy(t *testing.T) { testToken := createSessionPolicyTestJWT(t, "test-issuer", "test-user") request := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", WebIdentityToken: testToken, RoleSessionName: "test-session", Policy: nil, // ← Explicitly nil @@ -113,7 +113,7 @@ func TestAssumeRoleWithWebIdentity_SessionPolicy(t *testing.T) { emptyPolicy := "" // Empty string, but still a non-nil pointer request := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", WebIdentityToken: createSessionPolicyTestJWT(t, "test-issuer", "test-user"), RoleSessionName: "test-session", Policy: &emptyPolicy, // ← Non-nil pointer to empty string @@ -160,7 +160,7 @@ func TestAssumeRoleWithWebIdentity_SessionPolicy_ErrorMessage(t *testing.T) { testToken := createSessionPolicyTestJWT(t, "test-issuer", "test-user") request := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", WebIdentityToken: testToken, RoleSessionName: "test-session-with-complex-policy", Policy: &complexPolicy, @@ -196,7 +196,7 @@ func TestAssumeRoleWithWebIdentity_SessionPolicy_EdgeCases(t *testing.T) { malformedPolicy := `{"Version": "2012-10-17", "Statement": [` // Incomplete JSON request := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", WebIdentityToken: createSessionPolicyTestJWT(t, "test-issuer", "test-user"), RoleSessionName: "test-session", Policy: &malformedPolicy, @@ -215,7 +215,7 @@ func TestAssumeRoleWithWebIdentity_SessionPolicy_EdgeCases(t *testing.T) { whitespacePolicy := " \t\n " // Only whitespace request := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", WebIdentityToken: createSessionPolicyTestJWT(t, "test-issuer", "test-user"), RoleSessionName: "test-session", Policy: &whitespacePolicy, @@ -260,7 +260,7 @@ func TestAssumeRoleWithCredentials_NoSessionPolicySupport(t *testing.T) { // This is the expected behavior since session policies are typically only // supported with web identity (OIDC/SAML) flows in AWS STS request := &AssumeRoleWithCredentialsRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", Username: "testuser", Password: "testpass", RoleSessionName: "test-session", @@ -269,7 +269,7 @@ func TestAssumeRoleWithCredentials_NoSessionPolicySupport(t *testing.T) { // The struct should compile and work without a Policy field assert.NotNil(t, request) - assert.Equal(t, "arn:seaweed:iam::role/TestRole", request.RoleArn) + assert.Equal(t, "arn:aws:iam::role/TestRole", request.RoleArn) assert.Equal(t, "testuser", request.Username) // This documents that credential-based assume role does NOT support session policies diff --git a/weed/iam/sts/sts_service.go b/weed/iam/sts/sts_service.go index 7305adb4b..3d9f9af35 100644 --- a/weed/iam/sts/sts_service.go +++ b/weed/iam/sts/sts_service.go @@ -683,7 +683,7 @@ func (s *STSService) validateRoleAssumptionForWebIdentity(ctx context.Context, r } // Basic role ARN format validation - expectedPrefix := "arn:seaweed:iam::role/" + 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) } @@ -720,7 +720,7 @@ func (s *STSService) validateRoleAssumptionForCredentials(ctx context.Context, r } // Basic role ARN format validation - expectedPrefix := "arn:seaweed:iam::role/" + 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) } diff --git a/weed/iam/sts/sts_service_test.go b/weed/iam/sts/sts_service_test.go index 60d78118f..72d69c8c8 100644 --- a/weed/iam/sts/sts_service_test.go +++ b/weed/iam/sts/sts_service_test.go @@ -95,7 +95,7 @@ func TestAssumeRoleWithWebIdentity(t *testing.T) { }{ { name: "successful role assumption", - roleArn: "arn:seaweed:iam::role/TestRole", + roleArn: "arn:aws:iam::role/TestRole", webIdentityToken: createSTSTestJWT(t, "test-issuer", "test-user-id"), sessionName: "test-session", durationSeconds: nil, // Use default @@ -104,21 +104,21 @@ func TestAssumeRoleWithWebIdentity(t *testing.T) { }, { name: "invalid web identity token", - roleArn: "arn:seaweed:iam::role/TestRole", + roleArn: "arn:aws:iam::role/TestRole", webIdentityToken: "invalid-token", sessionName: "test-session", wantErr: true, }, { name: "non-existent role", - roleArn: "arn:seaweed:iam::role/NonExistentRole", + roleArn: "arn:aws:iam::role/NonExistentRole", webIdentityToken: createSTSTestJWT(t, "test-issuer", "test-user"), sessionName: "test-session", wantErr: true, }, { name: "custom session duration", - roleArn: "arn:seaweed:iam::role/TestRole", + roleArn: "arn:aws:iam::role/TestRole", webIdentityToken: createSTSTestJWT(t, "test-issuer", "test-user"), sessionName: "test-session", durationSeconds: int64Ptr(7200), // 2 hours @@ -182,7 +182,7 @@ func TestAssumeRoleWithLDAP(t *testing.T) { }{ { name: "successful LDAP role assumption", - roleArn: "arn:seaweed:iam::role/LDAPRole", + roleArn: "arn:aws:iam::role/LDAPRole", username: "testuser", password: "testpass", sessionName: "ldap-session", @@ -190,7 +190,7 @@ func TestAssumeRoleWithLDAP(t *testing.T) { }, { name: "invalid LDAP credentials", - roleArn: "arn:seaweed:iam::role/LDAPRole", + roleArn: "arn:aws:iam::role/LDAPRole", username: "testuser", password: "wrongpass", sessionName: "ldap-session", @@ -231,7 +231,7 @@ func TestSessionTokenValidation(t *testing.T) { // First, create a session request := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", WebIdentityToken: createSTSTestJWT(t, "test-issuer", "test-user"), RoleSessionName: "test-session", } @@ -275,7 +275,7 @@ func TestSessionTokenValidation(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, session) assert.Equal(t, "test-session", session.SessionName) - assert.Equal(t, "arn:seaweed:iam::role/TestRole", session.RoleArn) + assert.Equal(t, "arn:aws:iam::role/TestRole", session.RoleArn) } }) } @@ -289,7 +289,7 @@ func TestSessionTokenPersistence(t *testing.T) { // Create a session first request := &AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/TestRole", + RoleArn: "arn:aws:iam::role/TestRole", WebIdentityToken: createSTSTestJWT(t, "test-issuer", "test-user"), RoleSessionName: "test-session", } diff --git a/weed/iam/sts/token_utils.go b/weed/iam/sts/token_utils.go index 07c195326..3091ac519 100644 --- a/weed/iam/sts/token_utils.go +++ b/weed/iam/sts/token_utils.go @@ -207,11 +207,11 @@ func GenerateSessionId() (string, error) { // generateAssumedRoleArn generates the ARN for an assumed role user func GenerateAssumedRoleArn(roleArn, sessionName string) string { // Convert role ARN to assumed role user ARN - // arn:seaweed:iam::role/RoleName -> arn:seaweed:sts::assumed-role/RoleName/SessionName + // arn:aws:iam::role/RoleName -> arn:aws:sts::assumed-role/RoleName/SessionName roleName := utils.ExtractRoleNameFromArn(roleArn) if roleName == "" { // This should not happen if validation is done properly upstream - return fmt.Sprintf("arn:seaweed:sts::assumed-role/INVALID-ARN/%s", sessionName) + return fmt.Sprintf("arn:aws:sts::assumed-role/INVALID-ARN/%s", sessionName) } - return fmt.Sprintf("arn:seaweed:sts::assumed-role/%s/%s", roleName, sessionName) + return fmt.Sprintf("arn:aws:sts::assumed-role/%s/%s", roleName, sessionName) } diff --git a/weed/iam/utils/arn_utils.go b/weed/iam/utils/arn_utils.go index f4c05dab1..3f8cf0b8f 100644 --- a/weed/iam/utils/arn_utils.go +++ b/weed/iam/utils/arn_utils.go @@ -5,8 +5,8 @@ import "strings" // ExtractRoleNameFromPrincipal extracts role name from principal ARN // Handles both STS assumed role and IAM role formats func ExtractRoleNameFromPrincipal(principal string) string { - // Handle STS assumed role format: arn:seaweed:sts::assumed-role/RoleName/SessionName - stsPrefix := "arn:seaweed:sts::assumed-role/" + // 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 @@ -17,8 +17,8 @@ func ExtractRoleNameFromPrincipal(principal string) string { return remainder } - // Handle IAM role format: arn:seaweed:iam::role/RoleName - iamPrefix := "arn:seaweed:iam::role/" + // Handle IAM role format: arn:aws:iam::role/RoleName + iamPrefix := "arn:aws:iam::role/" if strings.HasPrefix(principal, iamPrefix) { return principal[len(iamPrefix):] } @@ -29,9 +29,9 @@ func ExtractRoleNameFromPrincipal(principal string) string { } // ExtractRoleNameFromArn extracts role name from an IAM role ARN -// Specifically handles: arn:seaweed:iam::role/RoleName +// Specifically handles: arn:aws:iam::role/RoleName func ExtractRoleNameFromArn(roleArn string) string { - prefix := "arn:seaweed:iam::role/" + prefix := "arn:aws:iam::role/" if strings.HasPrefix(roleArn, prefix) && len(roleArn) > len(prefix) { return roleArn[len(prefix):] } diff --git a/weed/s3api/auth_credentials.go b/weed/s3api/auth_credentials.go index 6a060bc9d..223882a92 100644 --- a/weed/s3api/auth_credentials.go +++ b/weed/s3api/auth_credentials.go @@ -63,7 +63,7 @@ type Identity struct { Account *Account Credentials []*Credential Actions []Action - PrincipalArn string // ARN for IAM authorization (e.g., "arn:seaweed:iam::user/username") + PrincipalArn string // ARN for IAM authorization (e.g., "arn:aws:iam::user/username") } // Account represents a system user, a system user can @@ -384,11 +384,11 @@ func generatePrincipalArn(identityName string) string { // Handle special cases switch identityName { case AccountAnonymous.Id: - return "arn:seaweed:iam::user/anonymous" + return "arn:aws:iam::user/anonymous" case AccountAdmin.Id: - return "arn:seaweed:iam::user/admin" + return "arn:aws:iam::user/admin" default: - return fmt.Sprintf("arn:seaweed:iam::user/%s", identityName) + return fmt.Sprintf("arn:aws:iam::user/%s", identityName) } } diff --git a/weed/s3api/auth_credentials_test.go b/weed/s3api/auth_credentials_test.go index 0753a833e..5bdf27256 100644 --- a/weed/s3api/auth_credentials_test.go +++ b/weed/s3api/auth_credentials_test.go @@ -194,7 +194,7 @@ func TestLoadS3ApiConfiguration(t *testing.T) { expectIdent: &Identity{ Name: "notSpecifyAccountId", Account: &AccountAdmin, - PrincipalArn: "arn:seaweed:iam::user/notSpecifyAccountId", + PrincipalArn: "arn:aws:iam::user/notSpecifyAccountId", Actions: []Action{ "Read", "Write", @@ -220,7 +220,7 @@ func TestLoadS3ApiConfiguration(t *testing.T) { expectIdent: &Identity{ Name: "specifiedAccountID", Account: &specifiedAccount, - PrincipalArn: "arn:seaweed:iam::user/specifiedAccountID", + PrincipalArn: "arn:aws:iam::user/specifiedAccountID", Actions: []Action{ "Read", "Write", @@ -238,7 +238,7 @@ func TestLoadS3ApiConfiguration(t *testing.T) { expectIdent: &Identity{ Name: "anonymous", Account: &AccountAnonymous, - PrincipalArn: "arn:seaweed:iam::user/anonymous", + PrincipalArn: "arn:aws:iam::user/anonymous", Actions: []Action{ "Read", "Write", diff --git a/weed/s3api/s3_end_to_end_test.go b/weed/s3api/s3_end_to_end_test.go index ba6d4e106..c840868fb 100644 --- a/weed/s3api/s3_end_to_end_test.go +++ b/weed/s3api/s3_end_to_end_test.go @@ -54,7 +54,7 @@ func TestS3EndToEndWithJWT(t *testing.T) { }{ { name: "S3 Read-Only Role Complete Workflow", - roleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + roleArn: "arn:aws:iam::role/S3ReadOnlyRole", sessionName: "readonly-test-session", setupRole: setupS3ReadOnlyRole, s3Operations: []S3Operation{ @@ -69,7 +69,7 @@ func TestS3EndToEndWithJWT(t *testing.T) { }, { name: "S3 Admin Role Complete Workflow", - roleArn: "arn:seaweed:iam::role/S3AdminRole", + roleArn: "arn:aws:iam::role/S3AdminRole", sessionName: "admin-test-session", setupRole: setupS3AdminRole, s3Operations: []S3Operation{ @@ -83,7 +83,7 @@ func TestS3EndToEndWithJWT(t *testing.T) { }, { name: "S3 IP-Restricted Role", - roleArn: "arn:seaweed:iam::role/S3IPRestrictedRole", + roleArn: "arn:aws:iam::role/S3IPRestrictedRole", sessionName: "ip-restricted-session", setupRole: setupS3IPRestrictedRole, s3Operations: []S3Operation{ @@ -145,7 +145,7 @@ func TestS3MultipartUploadWithJWT(t *testing.T) { // Assume role response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/S3WriteRole", + RoleArn: "arn:aws:iam::role/S3WriteRole", WebIdentityToken: validJWTToken, RoleSessionName: "multipart-test-session", }) @@ -255,7 +255,7 @@ func TestS3PerformanceWithIAM(t *testing.T) { // Assume role response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + RoleArn: "arn:aws:iam::role/S3ReadOnlyRole", WebIdentityToken: validJWTToken, RoleSessionName: "performance-test-session", }) @@ -452,8 +452,8 @@ func setupS3ReadOnlyRole(ctx context.Context, manager *integration.IAMManager) { Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket", "s3:HeadObject"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, { @@ -496,8 +496,8 @@ func setupS3AdminRole(ctx context.Context, manager *integration.IAMManager) { Effect: "Allow", Action: []string{"s3:*"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, { @@ -540,8 +540,8 @@ func setupS3WriteRole(ctx context.Context, manager *integration.IAMManager) { Effect: "Allow", Action: []string{"s3:PutObject", "s3:GetObject", "s3:ListBucket", "s3:DeleteObject"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, { @@ -584,8 +584,8 @@ func setupS3IPRestrictedRole(ctx context.Context, manager *integration.IAMManage Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, Condition: map[string]map[string]interface{}{ "IpAddress": { diff --git a/weed/s3api/s3_iam_middleware.go b/weed/s3api/s3_iam_middleware.go index 857123d7b..230b2d2cb 100644 --- a/weed/s3api/s3_iam_middleware.go +++ b/weed/s3api/s3_iam_middleware.go @@ -139,7 +139,7 @@ func (s3iam *S3IAMIntegration) AuthenticateJWT(ctx context.Context, r *http.Requ parts := strings.Split(roleName, "/") roleNameOnly = parts[len(parts)-1] } - principalArn = fmt.Sprintf("arn:seaweed:sts::assumed-role/%s/%s", roleNameOnly, sessionName) + principalArn = fmt.Sprintf("arn:aws:sts::assumed-role/%s/%s", roleNameOnly, sessionName) } // Validate the JWT token directly using STS service (avoid circular dependency) @@ -238,11 +238,11 @@ type MockAssumedRoleUser struct { // buildS3ResourceArn builds an S3 resource ARN from bucket and object func buildS3ResourceArn(bucket string, objectKey string) string { if bucket == "" { - return "arn:seaweed:s3:::*" + return "arn:aws:s3:::*" } if objectKey == "" || objectKey == "/" { - return "arn:seaweed:s3:::" + bucket + return "arn:aws:s3:::" + bucket } // Remove leading slash from object key if present @@ -250,7 +250,7 @@ func buildS3ResourceArn(bucket string, objectKey string) string { objectKey = objectKey[1:] } - return "arn:seaweed:s3:::" + bucket + "/" + objectKey + return "arn:aws:s3:::" + bucket + "/" + objectKey } // determineGranularS3Action determines the specific S3 IAM action based on HTTP request details diff --git a/weed/s3api/s3_iam_simple_test.go b/weed/s3api/s3_iam_simple_test.go index bdddeb24d..36691bb8f 100644 --- a/weed/s3api/s3_iam_simple_test.go +++ b/weed/s3api/s3_iam_simple_test.go @@ -84,31 +84,31 @@ func TestBuildS3ResourceArn(t *testing.T) { name: "empty bucket and object", bucket: "", object: "", - expected: "arn:seaweed:s3:::*", + expected: "arn:aws:s3:::*", }, { name: "bucket only", bucket: "test-bucket", object: "", - expected: "arn:seaweed:s3:::test-bucket", + expected: "arn:aws:s3:::test-bucket", }, { name: "bucket and object", bucket: "test-bucket", object: "test-object.txt", - expected: "arn:seaweed:s3:::test-bucket/test-object.txt", + expected: "arn:aws:s3:::test-bucket/test-object.txt", }, { name: "bucket and object with leading slash", bucket: "test-bucket", object: "/test-object.txt", - expected: "arn:seaweed:s3:::test-bucket/test-object.txt", + expected: "arn:aws:s3:::test-bucket/test-object.txt", }, { name: "bucket and nested object", bucket: "test-bucket", object: "folder/subfolder/test-object.txt", - expected: "arn:seaweed:s3:::test-bucket/folder/subfolder/test-object.txt", + expected: "arn:aws:s3:::test-bucket/folder/subfolder/test-object.txt", }, } @@ -447,7 +447,7 @@ func TestExtractRoleNameFromPrincipal(t *testing.T) { }{ { name: "valid assumed role ARN", - principal: "arn:seaweed:sts::assumed-role/S3ReadOnlyRole/session-123", + principal: "arn:aws:sts::assumed-role/S3ReadOnlyRole/session-123", expected: "S3ReadOnlyRole", }, { @@ -457,7 +457,7 @@ func TestExtractRoleNameFromPrincipal(t *testing.T) { }, { name: "missing session name", - principal: "arn:seaweed:sts::assumed-role/TestRole", + principal: "arn:aws:sts::assumed-role/TestRole", expected: "TestRole", // Extracts role name even without session name }, { @@ -479,7 +479,7 @@ func TestExtractRoleNameFromPrincipal(t *testing.T) { func TestIAMIdentityIsAdmin(t *testing.T) { identity := &IAMIdentity{ Name: "test-identity", - Principal: "arn:seaweed:sts::assumed-role/TestRole/session", + Principal: "arn:aws:sts::assumed-role/TestRole/session", SessionToken: "test-token", } diff --git a/weed/s3api/s3_jwt_auth_test.go b/weed/s3api/s3_jwt_auth_test.go index f6b2774d7..0e74aea01 100644 --- a/weed/s3api/s3_jwt_auth_test.go +++ b/weed/s3api/s3_jwt_auth_test.go @@ -56,7 +56,7 @@ func TestJWTAuthenticationFlow(t *testing.T) { }{ { name: "Read-Only JWT Authentication", - roleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + roleArn: "arn:aws:iam::role/S3ReadOnlyRole", setupRole: setupTestReadOnlyRole, testOperations: []JWTTestOperation{ {Action: s3_constants.ACTION_READ, Bucket: "test-bucket", Object: "test-file.txt", ExpectedAllow: true}, @@ -66,7 +66,7 @@ func TestJWTAuthenticationFlow(t *testing.T) { }, { name: "Admin JWT Authentication", - roleArn: "arn:seaweed:iam::role/S3AdminRole", + roleArn: "arn:aws:iam::role/S3AdminRole", setupRole: setupTestAdminRole, testOperations: []JWTTestOperation{ {Action: s3_constants.ACTION_READ, Bucket: "admin-bucket", Object: "admin-file.txt", ExpectedAllow: true}, @@ -221,7 +221,7 @@ func TestIPBasedPolicyEnforcement(t *testing.T) { // Assume role response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/S3IPRestrictedRole", + RoleArn: "arn:aws:iam::role/S3IPRestrictedRole", WebIdentityToken: validJWTToken, RoleSessionName: "ip-test-session", }) @@ -363,8 +363,8 @@ func setupTestReadOnlyRole(ctx context.Context, manager *integration.IAMManager) Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, { @@ -425,8 +425,8 @@ func setupTestAdminRole(ctx context.Context, manager *integration.IAMManager) { Effect: "Allow", Action: []string{"s3:*"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, { @@ -487,8 +487,8 @@ func setupTestIPRestrictedRole(ctx context.Context, manager *integration.IAMMana Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, Condition: map[string]map[string]interface{}{ "IpAddress": { @@ -544,7 +544,7 @@ func testJWTAuthorizationWithRole(t *testing.T, iam *IdentityAccessManagement, i req.Header.Set("X-SeaweedFS-Session-Token", token) // Use a proper principal ARN format that matches what STS would generate - principalArn := "arn:seaweed:sts::assumed-role/" + roleName + "/test-session" + principalArn := "arn:aws:sts::assumed-role/" + roleName + "/test-session" req.Header.Set("X-SeaweedFS-Principal", principalArn) // Test authorization diff --git a/weed/s3api/s3_multipart_iam_test.go b/weed/s3api/s3_multipart_iam_test.go index 2aa68fda0..608d30042 100644 --- a/weed/s3api/s3_multipart_iam_test.go +++ b/weed/s3api/s3_multipart_iam_test.go @@ -58,7 +58,7 @@ func TestMultipartIAMValidation(t *testing.T) { // Get session token response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/S3WriteRole", + RoleArn: "arn:aws:iam::role/S3WriteRole", WebIdentityToken: validJWTToken, RoleSessionName: "multipart-test-session", }) @@ -443,8 +443,8 @@ func TestMultipartUploadSession(t *testing.T) { UploadID: "test-upload-123", Bucket: "test-bucket", ObjectKey: "test-file.txt", - Initiator: "arn:seaweed:iam::user/testuser", - Owner: "arn:seaweed:iam::user/testuser", + Initiator: "arn:aws:iam::user/testuser", + Owner: "arn:aws:iam::user/testuser", CreatedAt: time.Now(), Parts: []MultipartUploadPart{ { @@ -550,8 +550,8 @@ func setupTestRolesForMultipart(ctx context.Context, manager *integration.IAMMan "s3:ListParts", }, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, }, @@ -603,8 +603,8 @@ func createMultipartRequest(t *testing.T, method, path, sessionToken string) *ht if sessionToken != "" { req.Header.Set("Authorization", "Bearer "+sessionToken) // Set the principal ARN header that matches the assumed role from the test setup - // This corresponds to the role "arn:seaweed:iam::role/S3WriteRole" with session name "multipart-test-session" - req.Header.Set("X-SeaweedFS-Principal", "arn:seaweed:sts::assumed-role/S3WriteRole/multipart-test-session") + // This corresponds to the role "arn:aws:iam::role/S3WriteRole" with session name "multipart-test-session" + req.Header.Set("X-SeaweedFS-Principal", "arn:aws:sts::assumed-role/S3WriteRole/multipart-test-session") } // Add common headers diff --git a/weed/s3api/s3_policy_templates.go b/weed/s3api/s3_policy_templates.go index 811872aee..1506c68ee 100644 --- a/weed/s3api/s3_policy_templates.go +++ b/weed/s3api/s3_policy_templates.go @@ -32,8 +32,8 @@ func (t *S3PolicyTemplates) GetS3ReadOnlyPolicy() *policy.PolicyDocument { "s3:ListAllMyBuckets", }, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, }, @@ -59,8 +59,8 @@ func (t *S3PolicyTemplates) GetS3WriteOnlyPolicy() *policy.PolicyDocument { "s3:ListParts", }, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, }, @@ -79,8 +79,8 @@ func (t *S3PolicyTemplates) GetS3AdminPolicy() *policy.PolicyDocument { "s3:*", }, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, }, @@ -103,8 +103,8 @@ func (t *S3PolicyTemplates) GetBucketSpecificReadPolicy(bucketName string) *poli "s3:GetBucketLocation", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName, - "arn:seaweed:s3:::" + bucketName + "/*", + "arn:aws:s3:::" + bucketName, + "arn:aws:s3:::" + bucketName + "/*", }, }, }, @@ -130,8 +130,8 @@ func (t *S3PolicyTemplates) GetBucketSpecificWritePolicy(bucketName string) *pol "s3:ListParts", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName, - "arn:seaweed:s3:::" + bucketName + "/*", + "arn:aws:s3:::" + bucketName, + "arn:aws:s3:::" + bucketName + "/*", }, }, }, @@ -150,7 +150,7 @@ func (t *S3PolicyTemplates) GetPathBasedAccessPolicy(bucketName, pathPrefix stri "s3:ListBucket", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName, + "arn:aws:s3:::" + bucketName, }, Condition: map[string]map[string]interface{}{ "StringLike": map[string]interface{}{ @@ -171,7 +171,7 @@ func (t *S3PolicyTemplates) GetPathBasedAccessPolicy(bucketName, pathPrefix stri "s3:AbortMultipartUpload", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName + "/" + pathPrefix + "/*", + "arn:aws:s3:::" + bucketName + "/" + pathPrefix + "/*", }, }, }, @@ -190,8 +190,8 @@ func (t *S3PolicyTemplates) GetIPRestrictedPolicy(allowedCIDRs []string) *policy "s3:*", }, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, Condition: map[string]map[string]interface{}{ "IpAddress": map[string]interface{}{ @@ -217,8 +217,8 @@ func (t *S3PolicyTemplates) GetTimeBasedAccessPolicy(startHour, endHour int) *po "s3:ListBucket", }, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, Condition: map[string]map[string]interface{}{ "DateGreaterThan": map[string]interface{}{ @@ -252,7 +252,7 @@ func (t *S3PolicyTemplates) GetMultipartUploadPolicy(bucketName string) *policy. "s3:ListParts", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName + "/*", + "arn:aws:s3:::" + bucketName + "/*", }, }, { @@ -262,7 +262,7 @@ func (t *S3PolicyTemplates) GetMultipartUploadPolicy(bucketName string) *policy. "s3:ListBucket", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName, + "arn:aws:s3:::" + bucketName, }, }, }, @@ -282,7 +282,7 @@ func (t *S3PolicyTemplates) GetPresignedURLPolicy(bucketName string) *policy.Pol "s3:PutObject", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName + "/*", + "arn:aws:s3:::" + bucketName + "/*", }, Condition: map[string]map[string]interface{}{ "StringEquals": map[string]interface{}{ @@ -310,8 +310,8 @@ func (t *S3PolicyTemplates) GetTemporaryAccessPolicy(bucketName string, expirati "s3:ListBucket", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName, - "arn:seaweed:s3:::" + bucketName + "/*", + "arn:aws:s3:::" + bucketName, + "arn:aws:s3:::" + bucketName + "/*", }, Condition: map[string]map[string]interface{}{ "DateLessThan": map[string]interface{}{ @@ -338,7 +338,7 @@ func (t *S3PolicyTemplates) GetContentTypeRestrictedPolicy(bucketName string, al "s3:CompleteMultipartUpload", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName + "/*", + "arn:aws:s3:::" + bucketName + "/*", }, Condition: map[string]map[string]interface{}{ "StringEquals": map[string]interface{}{ @@ -354,8 +354,8 @@ func (t *S3PolicyTemplates) GetContentTypeRestrictedPolicy(bucketName string, al "s3:ListBucket", }, Resource: []string{ - "arn:seaweed:s3:::" + bucketName, - "arn:seaweed:s3:::" + bucketName + "/*", + "arn:aws:s3:::" + bucketName, + "arn:aws:s3:::" + bucketName + "/*", }, }, }, @@ -385,8 +385,8 @@ func (t *S3PolicyTemplates) GetDenyDeletePolicy() *policy.PolicyDocument { "s3:ListParts", }, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, { @@ -398,8 +398,8 @@ func (t *S3PolicyTemplates) GetDenyDeletePolicy() *policy.PolicyDocument { "s3:DeleteBucket", }, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, }, diff --git a/weed/s3api/s3_policy_templates_test.go b/weed/s3api/s3_policy_templates_test.go index 9c1f6c7d3..03fa15890 100644 --- a/weed/s3api/s3_policy_templates_test.go +++ b/weed/s3api/s3_policy_templates_test.go @@ -26,8 +26,8 @@ func TestS3PolicyTemplates(t *testing.T) { assert.NotContains(t, stmt.Action, "s3:PutObject") assert.NotContains(t, stmt.Action, "s3:DeleteObject") - assert.Contains(t, stmt.Resource, "arn:seaweed:s3:::*") - assert.Contains(t, stmt.Resource, "arn:seaweed:s3:::*/*") + assert.Contains(t, stmt.Resource, "arn:aws:s3:::*") + assert.Contains(t, stmt.Resource, "arn:aws:s3:::*/*") }) t.Run("S3WriteOnlyPolicy", func(t *testing.T) { @@ -45,8 +45,8 @@ func TestS3PolicyTemplates(t *testing.T) { assert.NotContains(t, stmt.Action, "s3:GetObject") assert.NotContains(t, stmt.Action, "s3:DeleteObject") - assert.Contains(t, stmt.Resource, "arn:seaweed:s3:::*") - assert.Contains(t, stmt.Resource, "arn:seaweed:s3:::*/*") + assert.Contains(t, stmt.Resource, "arn:aws:s3:::*") + assert.Contains(t, stmt.Resource, "arn:aws:s3:::*/*") }) t.Run("S3AdminPolicy", func(t *testing.T) { @@ -61,8 +61,8 @@ func TestS3PolicyTemplates(t *testing.T) { assert.Equal(t, "S3FullAccess", stmt.Sid) assert.Contains(t, stmt.Action, "s3:*") - assert.Contains(t, stmt.Resource, "arn:seaweed:s3:::*") - assert.Contains(t, stmt.Resource, "arn:seaweed:s3:::*/*") + assert.Contains(t, stmt.Resource, "arn:aws:s3:::*") + assert.Contains(t, stmt.Resource, "arn:aws:s3:::*/*") }) } @@ -84,8 +84,8 @@ func TestBucketSpecificPolicies(t *testing.T) { assert.Contains(t, stmt.Action, "s3:ListBucket") assert.NotContains(t, stmt.Action, "s3:PutObject") - expectedBucketArn := "arn:seaweed:s3:::" + bucketName - expectedObjectArn := "arn:seaweed:s3:::" + bucketName + "/*" + expectedBucketArn := "arn:aws:s3:::" + bucketName + expectedObjectArn := "arn:aws:s3:::" + bucketName + "/*" assert.Contains(t, stmt.Resource, expectedBucketArn) assert.Contains(t, stmt.Resource, expectedObjectArn) }) @@ -104,8 +104,8 @@ func TestBucketSpecificPolicies(t *testing.T) { assert.Contains(t, stmt.Action, "s3:CreateMultipartUpload") assert.NotContains(t, stmt.Action, "s3:GetObject") - expectedBucketArn := "arn:seaweed:s3:::" + bucketName - expectedObjectArn := "arn:seaweed:s3:::" + bucketName + "/*" + expectedBucketArn := "arn:aws:s3:::" + bucketName + expectedObjectArn := "arn:aws:s3:::" + bucketName + "/*" assert.Contains(t, stmt.Resource, expectedBucketArn) assert.Contains(t, stmt.Resource, expectedObjectArn) }) @@ -127,7 +127,7 @@ func TestPathBasedAccessPolicy(t *testing.T) { assert.Equal(t, "Allow", listStmt.Effect) assert.Equal(t, "ListBucketPermission", listStmt.Sid) assert.Contains(t, listStmt.Action, "s3:ListBucket") - assert.Contains(t, listStmt.Resource, "arn:seaweed:s3:::"+bucketName) + assert.Contains(t, listStmt.Resource, "arn:aws:s3:::"+bucketName) assert.NotNil(t, listStmt.Condition) // Second statement: Object operations on path @@ -138,7 +138,7 @@ func TestPathBasedAccessPolicy(t *testing.T) { assert.Contains(t, objectStmt.Action, "s3:PutObject") assert.Contains(t, objectStmt.Action, "s3:DeleteObject") - expectedObjectArn := "arn:seaweed:s3:::" + bucketName + "/" + pathPrefix + "/*" + expectedObjectArn := "arn:aws:s3:::" + bucketName + "/" + pathPrefix + "/*" assert.Contains(t, objectStmt.Resource, expectedObjectArn) } @@ -216,7 +216,7 @@ func TestMultipartUploadPolicyTemplate(t *testing.T) { assert.Contains(t, multipartStmt.Action, "s3:ListMultipartUploads") assert.Contains(t, multipartStmt.Action, "s3:ListParts") - expectedObjectArn := "arn:seaweed:s3:::" + bucketName + "/*" + expectedObjectArn := "arn:aws:s3:::" + bucketName + "/*" assert.Contains(t, multipartStmt.Resource, expectedObjectArn) // Second statement: List bucket @@ -225,7 +225,7 @@ func TestMultipartUploadPolicyTemplate(t *testing.T) { assert.Equal(t, "ListBucketForMultipart", listStmt.Sid) assert.Contains(t, listStmt.Action, "s3:ListBucket") - expectedBucketArn := "arn:seaweed:s3:::" + bucketName + expectedBucketArn := "arn:aws:s3:::" + bucketName assert.Contains(t, listStmt.Resource, expectedBucketArn) } @@ -246,7 +246,7 @@ func TestPresignedURLPolicy(t *testing.T) { assert.Contains(t, stmt.Action, "s3:PutObject") assert.NotNil(t, stmt.Condition) - expectedObjectArn := "arn:seaweed:s3:::" + bucketName + "/*" + expectedObjectArn := "arn:aws:s3:::" + bucketName + "/*" assert.Contains(t, stmt.Resource, expectedObjectArn) // Check signature version condition @@ -495,7 +495,7 @@ func TestPolicyValidation(t *testing.T) { // Check resource format for _, resource := range stmt.Resource { if resource != "*" { - assert.Contains(t, resource, "arn:seaweed:s3:::", "Resource should be valid SeaweedFS S3 ARN: %s", resource) + assert.Contains(t, resource, "arn:aws:s3:::", "Resource should be valid SeaweedFS S3 ARN: %s", resource) } } } diff --git a/weed/s3api/s3_presigned_url_iam.go b/weed/s3api/s3_presigned_url_iam.go index 86b07668b..a9f49f02a 100644 --- a/weed/s3api/s3_presigned_url_iam.go +++ b/weed/s3api/s3_presigned_url_iam.go @@ -98,7 +98,7 @@ func (iam *IdentityAccessManagement) ValidatePresignedURLWithIAM(r *http.Request parts := strings.Split(roleName, "/") roleNameOnly = parts[len(parts)-1] } - principalArn = fmt.Sprintf("arn:seaweed:sts::assumed-role/%s/%s", roleNameOnly, sessionName) + principalArn = fmt.Sprintf("arn:aws:sts::assumed-role/%s/%s", roleNameOnly, sessionName) } // Create IAM identity for authorization using extracted information @@ -130,7 +130,7 @@ func (pm *S3PresignedURLManager) GeneratePresignedURLWithIAM(ctx context.Context // Validate session token and get identity // Use a proper ARN format for the principal - principalArn := fmt.Sprintf("arn:seaweed:sts::assumed-role/PresignedUser/presigned-session") + principalArn := fmt.Sprintf("arn:aws:sts::assumed-role/PresignedUser/presigned-session") iamIdentity := &IAMIdentity{ SessionToken: req.SessionToken, Principal: principalArn, diff --git a/weed/s3api/s3_presigned_url_iam_test.go b/weed/s3api/s3_presigned_url_iam_test.go index 890162121..b8da33053 100644 --- a/weed/s3api/s3_presigned_url_iam_test.go +++ b/weed/s3api/s3_presigned_url_iam_test.go @@ -57,7 +57,7 @@ func TestPresignedURLIAMValidation(t *testing.T) { // Get session token response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/S3ReadOnlyRole", + RoleArn: "arn:aws:iam::role/S3ReadOnlyRole", WebIdentityToken: validJWTToken, RoleSessionName: "presigned-test-session", }) @@ -136,7 +136,7 @@ func TestPresignedURLGeneration(t *testing.T) { // Get session token response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{ - RoleArn: "arn:seaweed:iam::role/S3AdminRole", + RoleArn: "arn:aws:iam::role/S3AdminRole", WebIdentityToken: validJWTToken, RoleSessionName: "presigned-gen-test-session", }) @@ -503,8 +503,8 @@ func setupTestRolesForPresigned(ctx context.Context, manager *integration.IAMMan Effect: "Allow", Action: []string{"s3:GetObject", "s3:ListBucket", "s3:HeadObject"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, }, @@ -539,8 +539,8 @@ func setupTestRolesForPresigned(ctx context.Context, manager *integration.IAMMan Effect: "Allow", Action: []string{"s3:*"}, Resource: []string{ - "arn:seaweed:s3:::*", - "arn:seaweed:s3:::*/*", + "arn:aws:s3:::*", + "arn:aws:s3:::*/*", }, }, }, diff --git a/weed/s3api/s3api_bucket_handlers.go b/weed/s3api/s3api_bucket_handlers.go index 78745dcca..cffcfe8cf 100644 --- a/weed/s3api/s3api_bucket_handlers.go +++ b/weed/s3api/s3api_bucket_handlers.go @@ -608,16 +608,16 @@ func (s3a *S3ApiServer) AuthWithPublicRead(handler http.HandlerFunc, action Acti return } - // Check bucket policy for anonymous access using the policy engine - principal := "*" // Anonymous principal - allowed, evaluated, err := s3a.policyEngine.EvaluatePolicy(bucket, object, string(action), principal) - if err != nil { - // SECURITY: Fail-close on policy evaluation errors - // If we can't evaluate the policy, deny access rather than falling through to IAM - glog.Errorf("AuthWithPublicRead: error evaluating bucket policy for %s/%s: %v - denying access", bucket, object, err) - s3err.WriteErrorResponse(w, r, s3err.ErrInternalError) - return - } else if evaluated && allowed { + // Check bucket policy for anonymous access using the policy engine + principal := "*" // Anonymous principal + allowed, evaluated, err := s3a.policyEngine.EvaluatePolicy(bucket, object, string(action), principal) + if err != nil { + // SECURITY: Fail-close on policy evaluation errors + // If we can't evaluate the policy, deny access rather than falling through to IAM + glog.Errorf("AuthWithPublicRead: error evaluating bucket policy for %s/%s: %v - denying access", bucket, object, err) + s3err.WriteErrorResponse(w, r, s3err.ErrInternalError) + return + } else if evaluated && allowed { glog.V(3).Infof("AuthWithPublicRead: allowing anonymous access to bucket %s (bucket policy)", bucket) handler(w, r) return diff --git a/weed/s3api/s3api_bucket_policy_arn_test.go b/weed/s3api/s3api_bucket_policy_arn_test.go new file mode 100644 index 000000000..b9daa9884 --- /dev/null +++ b/weed/s3api/s3api_bucket_policy_arn_test.go @@ -0,0 +1,104 @@ +package s3api + +import ( + "testing" +) + +// TestBuildResourceARN verifies that resource ARNs use the AWS-compatible format +func TestBuildResourceARN(t *testing.T) { + tests := []struct { + name string + bucket string + object string + expected string + }{ + { + name: "bucket only", + bucket: "my-bucket", + object: "", + expected: "arn:aws:s3:::my-bucket", + }, + { + name: "bucket with slash", + bucket: "my-bucket", + object: "/", + expected: "arn:aws:s3:::my-bucket", + }, + { + name: "bucket and object", + bucket: "my-bucket", + object: "path/to/object.txt", + expected: "arn:aws:s3:::my-bucket/path/to/object.txt", + }, + { + name: "bucket and object with leading slash", + bucket: "my-bucket", + object: "/path/to/object.txt", + expected: "arn:aws:s3:::my-bucket/path/to/object.txt", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := buildResourceARN(tt.bucket, tt.object) + if result != tt.expected { + t.Errorf("buildResourceARN(%q, %q) = %q, want %q", tt.bucket, tt.object, result, tt.expected) + } + }) + } +} + +// TestBuildPrincipalARN verifies that principal ARNs use the AWS-compatible format +func TestBuildPrincipalARN(t *testing.T) { + tests := []struct { + name string + identity *Identity + expected string + }{ + { + name: "nil identity (anonymous)", + identity: nil, + expected: "*", + }, + { + name: "identity with account and name", + identity: &Identity{ + Name: "test-user", + Account: &Account{ + Id: "123456789012", + }, + }, + expected: "arn:aws:iam::123456789012:user/test-user", + }, + { + name: "identity without account ID", + identity: &Identity{ + Name: "test-user", + Account: &Account{ + Id: "", + }, + }, + expected: "arn:aws:iam::000000000000:user/test-user", + }, + { + name: "identity without name", + identity: &Identity{ + Name: "", + Account: &Account{ + Id: "123456789012", + }, + }, + expected: "arn:aws:iam::123456789012:user/unknown", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := buildPrincipalARN(tt.identity) + if result != tt.expected { + t.Errorf("buildPrincipalARN() = %q, want %q", result, tt.expected) + } + }) + } +} + diff --git a/weed/s3api/s3api_bucket_policy_handlers.go b/weed/s3api/s3api_bucket_policy_handlers.go index 4a83f0da4..ca1acbbfd 100644 --- a/weed/s3api/s3api_bucket_policy_handlers.go +++ b/weed/s3api/s3api_bucket_policy_handlers.go @@ -275,11 +275,11 @@ func (s3a *S3ApiServer) validateBucketPolicy(policyDoc *policy.PolicyDocument, b // validateResourceForBucket checks if a resource ARN is valid for the given bucket func (s3a *S3ApiServer) validateResourceForBucket(resource, bucket string) bool { // Accepted formats for S3 bucket policies: - // AWS-style ARNs: + // AWS-style ARNs (recommended): // arn:aws:s3:::bucket-name // arn:aws:s3:::bucket-name/* // arn:aws:s3:::bucket-name/path/to/object - // SeaweedFS ARNs: + // Legacy SeaweedFS ARNs (supported for backward compatibility): // arn:seaweed:s3:::bucket-name // arn:seaweed:s3:::bucket-name/* // arn:seaweed:s3:::bucket-name/path/to/object