mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 09:01:31 +00:00
fix: apply PathPrefix, Scope and OnlyAttached in IAM ListPolicies
This commit is contained in:
@@ -1303,7 +1303,10 @@ func (s *IAMServiceImpl) ListPolicies(accountID string, input *iam.ListPoliciesI
|
||||
}
|
||||
|
||||
keyPrefix := accountID + "."
|
||||
var policies []*iam.Policy
|
||||
pathPrefix := aws.StringValue(input.PathPrefix)
|
||||
scope := aws.StringValue(input.Scope)
|
||||
onlyAttached := aws.BoolValue(input.OnlyAttached)
|
||||
policies := []*iam.Policy{}
|
||||
for _, key := range keys {
|
||||
if key == utils.VersionKey {
|
||||
continue
|
||||
@@ -1328,6 +1331,13 @@ func (s *IAMServiceImpl) ListPolicies(accountID string, input *iam.ListPoliciesI
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(policy.Path, pathPrefix) || !policyInScope(policy.ARN, scope) {
|
||||
continue
|
||||
}
|
||||
if onlyAttached && attachCounts[policy.ARN] == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
createdAt := parseCreatedAt(policy.CreatedAt)
|
||||
policies = append(policies, &iam.Policy{
|
||||
PolicyName: aws.String(policy.PolicyName),
|
||||
@@ -1348,6 +1358,20 @@ func (s *IAMServiceImpl) ListPolicies(accountID string, input *iam.ListPoliciesI
|
||||
}, nil
|
||||
}
|
||||
|
||||
// policyInScope applies ListPolicies' Scope: Local is customer-managed, AWS is
|
||||
// arn:aws:iam::aws:policy/..., and All (or unset) keeps both.
|
||||
func policyInScope(policyARN, scope string) bool {
|
||||
awsManaged := isAWSManagedPolicyARN(policyARN)
|
||||
switch scope {
|
||||
case iam.PolicyScopeTypeLocal:
|
||||
return !awsManaged
|
||||
case iam.PolicyScopeTypeAws:
|
||||
return awsManaged
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *IAMServiceImpl) DeletePolicy(accountID string, input *iam.DeletePolicyInput) (*iam.DeletePolicyOutput, error) {
|
||||
ctx := context.Background()
|
||||
policyARN := *input.PolicyArn
|
||||
|
||||
@@ -1479,6 +1479,73 @@ func TestListPolicies_Empty(t *testing.T) {
|
||||
assert.Empty(t, out.Policies)
|
||||
}
|
||||
|
||||
func TestListPolicies_Filters(t *testing.T) {
|
||||
t.Parallel()
|
||||
svc := setupTestIAMService(t)
|
||||
|
||||
createTestPolicy(t, svc, "RootPolicy")
|
||||
_, err := svc.CreatePolicy(testAccountID, &iam.CreatePolicyInput{
|
||||
PolicyName: aws.String("TeamPolicy"),
|
||||
Path: aws.String("/team/"),
|
||||
PolicyDocument: aws.String(validPolicyDocument()),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
attached := createTestPolicy(t, svc, "AttachedPolicy")
|
||||
createTestUser(t, svc, "filterlistuser")
|
||||
_, err = svc.AttachUserPolicy(testAccountID, &iam.AttachUserPolicyInput{
|
||||
UserName: aws.String("filterlistuser"),
|
||||
PolicyArn: attached.Arn,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input *iam.ListPoliciesInput
|
||||
want []string
|
||||
}{
|
||||
{"no filters", &iam.ListPoliciesInput{}, []string{"AttachedPolicy", "RootPolicy", "TeamPolicy"}},
|
||||
{"path prefix", &iam.ListPoliciesInput{PathPrefix: aws.String("/team/")}, []string{"TeamPolicy"}},
|
||||
{"partial path prefix", &iam.ListPoliciesInput{PathPrefix: aws.String("/te")}, []string{"TeamPolicy"}},
|
||||
{"root path prefix", &iam.ListPoliciesInput{PathPrefix: aws.String("/")}, []string{"AttachedPolicy", "RootPolicy", "TeamPolicy"}},
|
||||
{"scope local", &iam.ListPoliciesInput{Scope: aws.String("Local")}, []string{"AttachedPolicy", "RootPolicy", "TeamPolicy"}},
|
||||
{"scope all", &iam.ListPoliciesInput{Scope: aws.String("All")}, []string{"AttachedPolicy", "RootPolicy", "TeamPolicy"}},
|
||||
{"scope aws", &iam.ListPoliciesInput{Scope: aws.String("AWS")}, []string{}},
|
||||
{"only attached", &iam.ListPoliciesInput{OnlyAttached: aws.Bool(true)}, []string{"AttachedPolicy"}},
|
||||
{"only attached false", &iam.ListPoliciesInput{OnlyAttached: aws.Bool(false)}, []string{"AttachedPolicy", "RootPolicy", "TeamPolicy"}},
|
||||
{"only attached under path", &iam.ListPoliciesInput{PathPrefix: aws.String("/team/"), OnlyAttached: aws.Bool(true)}, []string{}},
|
||||
{"local under path", &iam.ListPoliciesInput{Scope: aws.String("Local"), PathPrefix: aws.String("/team/")}, []string{"TeamPolicy"}},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
out, err := svc.ListPolicies(testAccountID, tc.input)
|
||||
require.NoError(t, err)
|
||||
// A nil slice would drop the Policies element from the XML response.
|
||||
require.NotNil(t, out.Policies)
|
||||
names := []string{}
|
||||
for _, p := range out.Policies {
|
||||
names = append(names, *p.PolicyName)
|
||||
}
|
||||
assert.ElementsMatch(t, tc.want, names)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPolicyInScope(t *testing.T) {
|
||||
t.Parallel()
|
||||
local := "arn:aws:iam::000000000000:policy/AdministratorAccess"
|
||||
awsManaged := "arn:aws:iam::aws:policy/AdministratorAccess"
|
||||
|
||||
assert.True(t, policyInScope(local, ""))
|
||||
assert.True(t, policyInScope(awsManaged, ""))
|
||||
assert.True(t, policyInScope(local, "All"))
|
||||
assert.True(t, policyInScope(awsManaged, "All"))
|
||||
assert.True(t, policyInScope(local, "Local"))
|
||||
assert.False(t, policyInScope(awsManaged, "Local"))
|
||||
assert.False(t, policyInScope(local, "AWS"))
|
||||
assert.True(t, policyInScope(awsManaged, "AWS"))
|
||||
}
|
||||
|
||||
func TestDeletePolicy(t *testing.T) {
|
||||
t.Parallel()
|
||||
svc := setupTestIAMService(t)
|
||||
|
||||
@@ -370,6 +370,25 @@ func TestIAMPolicyCRUD(t *testing.T) {
|
||||
all, err := iamCli.ListPolicies(&iam.ListPoliciesInput{})
|
||||
require.NoError(t, err, "list-policies")
|
||||
require.GreaterOrEqual(t, len(all.Policies), 5, "expected >=5 policies, got %d", len(all.Policies))
|
||||
|
||||
pathed, err := iamCli.ListPolicies(&iam.ListPoliciesInput{
|
||||
Scope: aws.String("Local"),
|
||||
PathPrefix: aws.String(iamPolicyFullAdminPath),
|
||||
})
|
||||
require.NoError(t, err, "list-policies scope Local path %s", iamPolicyFullAdminPath)
|
||||
require.Len(t, pathed.Policies, 1)
|
||||
require.Equal(t, iamPolicyFullAdmin, aws.StringValue(pathed.Policies[0].PolicyName))
|
||||
|
||||
attached, err := iamCli.ListPolicies(&iam.ListPoliciesInput{
|
||||
PathPrefix: aws.String(iamPolicyFullAdminPath),
|
||||
OnlyAttached: aws.Bool(true),
|
||||
})
|
||||
require.NoError(t, err, "list-policies only attached")
|
||||
require.Empty(t, attached.Policies)
|
||||
|
||||
awsScope, err := iamCli.ListPolicies(&iam.ListPoliciesInput{Scope: aws.String("AWS")})
|
||||
require.NoError(t, err, "list-policies scope AWS")
|
||||
require.Empty(t, awsScope.Policies)
|
||||
}
|
||||
|
||||
// TestIAMPolicyAttachmentEnforcement proves AttachUserPolicy idempotency,
|
||||
|
||||
Reference in New Issue
Block a user