mirror of
https://github.com/storytold/irsa-manager.git
synced 2026-10-09 00:09:43 +00:00
extract stale policy and new policy
This commit is contained in:
@@ -27,6 +27,7 @@ type AwsIamAPI interface {
|
||||
DeleteOpenIDConnectProvider(ctx context.Context, params *iam.DeleteOpenIDConnectProviderInput, optFns ...func(*iam.Options)) (*iam.DeleteOpenIDConnectProviderOutput, error)
|
||||
CreateRole(ctx context.Context, params *iam.CreateRoleInput, optFns ...func(*iam.Options)) (*iam.CreateRoleOutput, error)
|
||||
UpdateAssumeRolePolicy(ctx context.Context, params *iam.UpdateAssumeRolePolicyInput, optFns ...func(*iam.Options)) (*iam.UpdateAssumeRolePolicyOutput, error)
|
||||
ListAttachedRolePolicies(ctx context.Context, params *iam.ListAttachedRolePoliciesInput, optFns ...func(*iam.Options)) (*iam.ListAttachedRolePoliciesOutput, error)
|
||||
AttachRolePolicy(ctx context.Context, params *iam.AttachRolePolicyInput, optFns ...func(*iam.Options)) (*iam.AttachRolePolicyOutput, error)
|
||||
DeleteRole(ctx context.Context, params *iam.DeleteRoleInput, optFns ...func(*iam.Options)) (*iam.DeleteRoleOutput, error)
|
||||
DetachRolePolicy(ctx context.Context, params *iam.DetachRolePolicyInput, optFns ...func(*iam.Options)) (*iam.DetachRolePolicyOutput, error)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/iam"
|
||||
"github.com/aws/aws-sdk-go-v2/service/iam/types"
|
||||
"github.com/aws/smithy-go"
|
||||
irsav1alpha1 "github.com/kkb0318/irsa-manager/api/v1alpha1"
|
||||
"github.com/kkb0318/irsa-manager/internal/issuer"
|
||||
@@ -29,6 +30,7 @@ type RoleManager struct {
|
||||
AccountId string
|
||||
}
|
||||
|
||||
// PolicyArn returns the full ARN of a given policy name. If the policy name already has the full ARN, it returns it as is.
|
||||
func (r *RoleManager) PolicyArn(policy string) *string {
|
||||
prefix := "arn:aws:iam::"
|
||||
if strings.HasPrefix(policy, prefix) {
|
||||
@@ -37,6 +39,33 @@ func (r *RoleManager) PolicyArn(policy string) *string {
|
||||
return aws.String(fmt.Sprintf("%saws:policy/%s", prefix, policy))
|
||||
}
|
||||
|
||||
// ExtractNewPolicies returns the names of the policies that are in the current settings (r.Policies) but are not yet attached to the role.
|
||||
|
||||
func (r *RoleManager) ExtractNewPolicies(l *iam.ListAttachedRolePoliciesOutput) []string {
|
||||
result := []string{}
|
||||
for _, p := range r.Policies {
|
||||
if slices.ContainsFunc(l.AttachedPolicies, func(a types.AttachedPolicy) bool {
|
||||
return *r.PolicyArn(p) != *a.PolicyArn
|
||||
}) {
|
||||
result = append(result, p)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ExtractStalePolicies returns the ARNs of the policies that are attached to the role but are not in the current settings (r.Policies).
|
||||
func (r *RoleManager) ExtractStalePolicies(l *iam.ListAttachedRolePoliciesOutput) []string {
|
||||
result := []string{}
|
||||
for _, ap := range l.AttachedPolicies {
|
||||
if slices.ContainsFunc(r.Policies, func(p string) bool {
|
||||
return *r.PolicyArn(p) != *ap.PolicyArn
|
||||
}) {
|
||||
result = append(result, *ap.PolicyArn)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DeleteIRSARole detaches specified policies from the IAM role and deletes the IAM role
|
||||
func (a *AwsIamClient) DeleteIRSARole(ctx context.Context, r RoleManager) error {
|
||||
for _, policy := range r.Policies {
|
||||
@@ -93,7 +122,7 @@ func (a *AwsIamClient) CreateIRSARole(ctx context.Context, issuerMeta issuer.OID
|
||||
AssumeRolePolicyDocument: aws.String(string(trustPolicyJSON)),
|
||||
}
|
||||
|
||||
_, err = a.Client.CreateRole(context.TODO(), createRoleInput)
|
||||
_, err = a.Client.CreateRole(ctx, createRoleInput)
|
||||
if errorHandler(err, []string{"EntityAlreadyExists"}) != nil {
|
||||
return err
|
||||
}
|
||||
@@ -104,11 +133,16 @@ func (a *AwsIamClient) CreateIRSARole(ctx context.Context, issuerMeta issuer.OID
|
||||
PolicyDocument: aws.String(string(trustPolicyJSON)),
|
||||
}
|
||||
|
||||
_, err = a.Client.UpdateAssumeRolePolicy(context.TODO(), updateRoleInput)
|
||||
_, err = a.Client.UpdateAssumeRolePolicy(ctx, updateRoleInput)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update assume role policy for role %s: %w", r.RoleName, err)
|
||||
}
|
||||
log.Printf("Assume role policy for %s updated successfully", r.RoleName)
|
||||
// TODO:
|
||||
// listPoliciesOutput, err := a.Client.ListAttachedRolePolicies(ctx, &iam.ListAttachedRolePoliciesInput{RoleName: aws.String(r.RoleName)})
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("failed to list attached role policies with %s: %w", r.RoleName, err)
|
||||
// }
|
||||
|
||||
for _, policy := range r.Policies {
|
||||
attachRolePolicyInput := &iam.AttachRolePolicyInput{
|
||||
@@ -116,7 +150,7 @@ func (a *AwsIamClient) CreateIRSARole(ctx context.Context, issuerMeta issuer.OID
|
||||
PolicyArn: r.PolicyArn(policy),
|
||||
}
|
||||
|
||||
_, err = a.Client.AttachRolePolicy(context.TODO(), attachRolePolicyInput)
|
||||
_, err = a.Client.AttachRolePolicy(ctx, attachRolePolicyInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/iam"
|
||||
"github.com/aws/aws-sdk-go-v2/service/iam/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestExtractNewPolicies(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
policies []string
|
||||
attachedPolicies *iam.ListAttachedRolePoliciesOutput
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
"PolicyAlreadyAttached",
|
||||
[]string{"ReadOnlyAccess", "AdministratorAccess"},
|
||||
&iam.ListAttachedRolePoliciesOutput{
|
||||
AttachedPolicies: []types.AttachedPolicy{
|
||||
{PolicyArn: aws.String("arn:aws:iam::aws:policy/ReadOnlyAccess")},
|
||||
},
|
||||
},
|
||||
[]string{"AdministratorAccess"},
|
||||
},
|
||||
{
|
||||
"NoPolicyAttached",
|
||||
[]string{"PowerUserAccess", "SecurityAudit"},
|
||||
&iam.ListAttachedRolePoliciesOutput{
|
||||
AttachedPolicies: []types.AttachedPolicy{
|
||||
{PolicyArn: aws.String("arn:aws:iam::aws:policy/ReadOnlyAccess")},
|
||||
},
|
||||
},
|
||||
[]string{"PowerUserAccess", "SecurityAudit"},
|
||||
},
|
||||
{
|
||||
"AllPoliciesAlreadyAttached",
|
||||
[]string{"ReadOnlyAccess"},
|
||||
&iam.ListAttachedRolePoliciesOutput{
|
||||
AttachedPolicies: []types.AttachedPolicy{
|
||||
{PolicyArn: aws.String("arn:aws:iam::aws:policy/ReadOnlyAccess")},
|
||||
},
|
||||
},
|
||||
[]string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &RoleManager{Policies: tt.policies}
|
||||
result := r.ExtractNewPolicies(tt.attachedPolicies)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractStalePolicies(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
policies []string
|
||||
attachedPolicies *iam.ListAttachedRolePoliciesOutput
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
"StalePolicyExists",
|
||||
[]string{"ReadOnlyAccess"},
|
||||
&iam.ListAttachedRolePoliciesOutput{
|
||||
AttachedPolicies: []types.AttachedPolicy{
|
||||
{PolicyArn: aws.String("arn:aws:iam::aws:policy/ReadOnlyAccess")},
|
||||
{PolicyArn: aws.String("arn:aws:iam::aws:policy/AdministratorAccess")},
|
||||
},
|
||||
},
|
||||
[]string{"arn:aws:iam::aws:policy/AdministratorAccess"},
|
||||
},
|
||||
{
|
||||
"MultipleStalePoliciesExist",
|
||||
[]string{"ReadOnlyAccess", "SecurityAudit"},
|
||||
&iam.ListAttachedRolePoliciesOutput{
|
||||
AttachedPolicies: []types.AttachedPolicy{
|
||||
{PolicyArn: aws.String("arn:aws:iam::aws:policy/PowerUserAccess")},
|
||||
{PolicyArn: aws.String("arn:aws:iam::aws:policy/AdministratorAccess")},
|
||||
},
|
||||
},
|
||||
[]string{"arn:aws:iam::aws:policy/PowerUserAccess", "arn:aws:iam::aws:policy/AdministratorAccess"},
|
||||
},
|
||||
{
|
||||
"NoStalePolicies",
|
||||
[]string{"ReadOnlyAccess"},
|
||||
&iam.ListAttachedRolePoliciesOutput{
|
||||
AttachedPolicies: []types.AttachedPolicy{
|
||||
{PolicyArn: aws.String("arn:aws:iam::aws:policy/ReadOnlyAccess")},
|
||||
},
|
||||
},
|
||||
[]string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &RoleManager{Policies: tt.policies}
|
||||
result := r.ExtractStalePolicies(tt.attachedPolicies)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user