* Add tests for AWS user principal in AssumeRole trust policies Add test cases that verify trust policy validation when using specific AWS user principals (e.g., "arn:aws:iam::000000000000:user/backend") in the Principal field of trust policies for AssumeRole. Covers single user, multiple users (array), wildcard, and plain string principal formats. These tests demonstrate the bug reported in #8588 where specific user principals always fail validation. * Populate RequestContext in ValidateTrustPolicyForPrincipal ValidateTrustPolicyForPrincipal was creating an EvaluationContext with a nil RequestContext. The policy engine's principal matching logic looks up "aws:PrincipalArn" in RequestContext for non-wildcard principals, so specific user ARNs like "arn:aws:iam::000000000000:user/backend" always failed to match, while wildcard "*" worked because it short-circuits before the lookup. Populate RequestContext with both "principal" and "aws:PrincipalArn" keys, consistent with how IsActionAllowed already does it. Fixes #8588 * Remove GitHub discussion URL from source code comments * Add specific error message assertions in trust policy tests
249 lines
7.0 KiB
Go
249 lines
7.0 KiB
Go
package integration
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/iam/policy"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestTrustPolicyAWSUserPrincipal tests that trust policies with specific AWS user
|
|
// principals work correctly with ValidateTrustPolicyForPrincipal.
|
|
// This is a regression test for the case where setting a specific user principal like:
|
|
//
|
|
// "Principal": {"AWS": "arn:aws:iam::000000000000:user/backend"}
|
|
//
|
|
// would fail with "trust policy denies access to principal" even though the
|
|
// caller's principal ARN matched.
|
|
func TestTrustPolicyAWSUserPrincipal(t *testing.T) {
|
|
iamManager := setupIntegratedIAMSystem(t)
|
|
ctx := context.Background()
|
|
|
|
const (
|
|
accountID = "000000000000"
|
|
backendUser = "backend"
|
|
backendArn = "arn:aws:iam::" + accountID + ":user/" + backendUser
|
|
otherUser = "other"
|
|
otherArn = "arn:aws:iam::" + accountID + ":user/" + otherUser
|
|
clientRoleN = "ClientRole"
|
|
clientRoleA = "arn:aws:iam::role/" + clientRoleN
|
|
)
|
|
|
|
// Create role with trust policy restricted to a specific AWS user principal
|
|
// (the exact scenario from discussion #8588)
|
|
err := iamManager.CreateRole(ctx, "", clientRoleN, &RoleDefinition{
|
|
RoleName: clientRoleN,
|
|
TrustPolicy: &policy.PolicyDocument{
|
|
Version: "2012-10-17",
|
|
Statement: []policy.Statement{
|
|
{
|
|
Effect: "Allow",
|
|
Principal: map[string]interface{}{
|
|
"AWS": backendArn,
|
|
},
|
|
Action: []string{"sts:AssumeRole"},
|
|
},
|
|
},
|
|
},
|
|
AttachedPolicies: []string{"S3ReadOnlyPolicy"},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
tests := []struct {
|
|
name string
|
|
principalArn string
|
|
expectErr bool
|
|
description string
|
|
}{
|
|
{
|
|
name: "matching user principal should be allowed",
|
|
principalArn: backendArn,
|
|
expectErr: false,
|
|
description: "Backend user ARN matches the trust policy principal exactly",
|
|
},
|
|
{
|
|
name: "non-matching user principal should be denied",
|
|
principalArn: otherArn,
|
|
expectErr: true,
|
|
description: "Other user ARN does not match the trust policy principal",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := iamManager.ValidateTrustPolicyForPrincipal(ctx, clientRoleA, tt.principalArn)
|
|
if tt.expectErr {
|
|
assert.Error(t, err, tt.description)
|
|
assert.Contains(t, err.Error(), "trust policy denies access")
|
|
} else {
|
|
assert.NoError(t, err, tt.description)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestTrustPolicyAWSWildcardPrincipal tests that wildcard AWS principals
|
|
// continue to work correctly (this already works, serves as a regression guard).
|
|
func TestTrustPolicyAWSWildcardPrincipal(t *testing.T) {
|
|
iamManager := setupIntegratedIAMSystem(t)
|
|
ctx := context.Background()
|
|
|
|
const roleName = "WildcardAWSRole"
|
|
const roleArn = "arn:aws:iam::role/" + roleName
|
|
|
|
err := iamManager.CreateRole(ctx, "", roleName, &RoleDefinition{
|
|
RoleName: roleName,
|
|
TrustPolicy: &policy.PolicyDocument{
|
|
Version: "2012-10-17",
|
|
Statement: []policy.Statement{
|
|
{
|
|
Effect: "Allow",
|
|
Principal: map[string]interface{}{
|
|
"AWS": "*",
|
|
},
|
|
Action: []string{"sts:AssumeRole"},
|
|
},
|
|
},
|
|
},
|
|
AttachedPolicies: []string{"S3ReadOnlyPolicy"},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Any user should be able to assume a role with wildcard AWS principal
|
|
err = iamManager.ValidateTrustPolicyForPrincipal(ctx, roleArn, "arn:aws:iam::000000000000:user/anyuser")
|
|
assert.NoError(t, err, "Wildcard AWS principal should allow any user")
|
|
}
|
|
|
|
// TestTrustPolicyAWSUserArrayPrincipal tests trust policies with an array of
|
|
// AWS user principals.
|
|
func TestTrustPolicyAWSUserArrayPrincipal(t *testing.T) {
|
|
iamManager := setupIntegratedIAMSystem(t)
|
|
ctx := context.Background()
|
|
|
|
const (
|
|
accountID = "000000000000"
|
|
roleName = "MultiUserRole"
|
|
roleArn = "arn:aws:iam::role/" + roleName
|
|
user1Arn = "arn:aws:iam::" + accountID + ":user/user1"
|
|
user2Arn = "arn:aws:iam::" + accountID + ":user/user2"
|
|
user3Arn = "arn:aws:iam::" + accountID + ":user/user3"
|
|
)
|
|
|
|
// Create role with multiple allowed user principals
|
|
err := iamManager.CreateRole(ctx, "", roleName, &RoleDefinition{
|
|
RoleName: roleName,
|
|
TrustPolicy: &policy.PolicyDocument{
|
|
Version: "2012-10-17",
|
|
Statement: []policy.Statement{
|
|
{
|
|
Effect: "Allow",
|
|
Principal: map[string]interface{}{
|
|
"AWS": []interface{}{user1Arn, user2Arn},
|
|
},
|
|
Action: []string{"sts:AssumeRole"},
|
|
},
|
|
},
|
|
},
|
|
AttachedPolicies: []string{"S3ReadOnlyPolicy"},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
tests := []struct {
|
|
name string
|
|
principalArn string
|
|
expectErr bool
|
|
}{
|
|
{
|
|
name: "first listed user is allowed",
|
|
principalArn: user1Arn,
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "second listed user is allowed",
|
|
principalArn: user2Arn,
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "unlisted user is denied",
|
|
principalArn: user3Arn,
|
|
expectErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := iamManager.ValidateTrustPolicyForPrincipal(ctx, roleArn, tt.principalArn)
|
|
if tt.expectErr {
|
|
if assert.Error(t, err) {
|
|
assert.Contains(t, err.Error(), "trust policy denies access")
|
|
}
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestTrustPolicyPlainStringPrincipal tests trust policies with a plain string
|
|
// principal (not wrapped in {"AWS": ...}).
|
|
func TestTrustPolicyPlainStringPrincipal(t *testing.T) {
|
|
iamManager := setupIntegratedIAMSystem(t)
|
|
ctx := context.Background()
|
|
|
|
const (
|
|
roleName = "PlainStringPrincipalRole"
|
|
roleArn = "arn:aws:iam::role/" + roleName
|
|
userArn = "arn:aws:iam::000000000000:user/backend"
|
|
)
|
|
|
|
// Plain string wildcard - should work
|
|
err := iamManager.CreateRole(ctx, "", roleName, &RoleDefinition{
|
|
RoleName: roleName,
|
|
TrustPolicy: &policy.PolicyDocument{
|
|
Version: "2012-10-17",
|
|
Statement: []policy.Statement{
|
|
{
|
|
Effect: "Allow",
|
|
Principal: "*",
|
|
Action: []string{"sts:AssumeRole"},
|
|
},
|
|
},
|
|
},
|
|
AttachedPolicies: []string{"S3ReadOnlyPolicy"},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = iamManager.ValidateTrustPolicyForPrincipal(ctx, roleArn, userArn)
|
|
assert.NoError(t, err, "Plain wildcard principal should allow any user")
|
|
|
|
// Plain string with specific ARN
|
|
const roleName2 = "PlainStringSpecificRole"
|
|
const roleArn2 = "arn:aws:iam::role/" + roleName2
|
|
|
|
err = iamManager.CreateRole(ctx, "", roleName2, &RoleDefinition{
|
|
RoleName: roleName2,
|
|
TrustPolicy: &policy.PolicyDocument{
|
|
Version: "2012-10-17",
|
|
Statement: []policy.Statement{
|
|
{
|
|
Effect: "Allow",
|
|
Principal: userArn,
|
|
Action: []string{"sts:AssumeRole"},
|
|
},
|
|
},
|
|
},
|
|
AttachedPolicies: []string{"S3ReadOnlyPolicy"},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = iamManager.ValidateTrustPolicyForPrincipal(ctx, roleArn2, userArn)
|
|
assert.NoError(t, err, "Matching plain string principal should allow user")
|
|
|
|
err = iamManager.ValidateTrustPolicyForPrincipal(ctx, roleArn2, "arn:aws:iam::000000000000:user/other")
|
|
if assert.Error(t, err, "Non-matching plain string principal should deny user") {
|
|
assert.Contains(t, err.Error(), "trust policy denies access")
|
|
}
|
|
}
|