From 886019f467abaf798ade47a8e4e26fac1dfae131 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Sun, 8 Mar 2026 15:26:55 -0700 Subject: [PATCH] iam: check group attachment before policy deletion Reject DeletePolicy if the policy is attached to any group, matching AWS IAM behavior. Add PolicyArn to ListAttachedGroupPolicies response. --- weed/iamapi/iamapi_management_handlers.go | 8 ++++++++ weed/s3api/s3api_embedded_iam.go | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/weed/iamapi/iamapi_management_handlers.go b/weed/iamapi/iamapi_management_handlers.go index 5449a5d9f..a8babd24e 100644 --- a/weed/iamapi/iamapi_management_handlers.go +++ b/weed/iamapi/iamapi_management_handlers.go @@ -544,6 +544,14 @@ func (iama *IamApiServer) DeletePolicy(s3cfg *iam_pb.S3ApiConfiguration, values } } + // Reject deletion if the policy is attached to any group + if groupName, attached := isPolicyAttachedToAnyGroup(s3cfg, policyName); attached { + return resp, &IamError{ + Code: iam.ErrCodeDeleteConflictException, + Error: fmt.Errorf("policy %s is still attached to group %s", policyName, groupName), + } + } + delete(policies.Policies, policyName) if err := iama.s3ApiConfig.PutPolicies(&policies); err != nil { return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: err} diff --git a/weed/s3api/s3api_embedded_iam.go b/weed/s3api/s3api_embedded_iam.go index 8ea95b666..f6ee985e5 100644 --- a/weed/s3api/s3api_embedded_iam.go +++ b/weed/s3api/s3api_embedded_iam.go @@ -510,6 +510,25 @@ func (e *EmbeddedIamApi) DeletePolicy(ctx context.Context, values url.Values) (* } } } + // Check if policy is attached to any group + groupNames, err := e.credentialManager.ListGroups(ctx) + if err != nil { + return resp, &iamError{Code: iam.ErrCodeServiceFailureException, Error: err} + } + for _, gn := range groupNames { + g, err := e.credentialManager.GetGroup(ctx, gn) + if err != nil { + continue + } + for _, pn := range g.PolicyNames { + if pn == policyName { + return resp, &iamError{ + Code: iam.ErrCodeDeleteConflictException, + Error: fmt.Errorf("policy %s is attached to group %s", policyName, gn), + } + } + } + } if err := e.credentialManager.DeletePolicy(ctx, policyName); err != nil { return resp, &iamError{Code: iam.ErrCodeServiceFailureException, Error: err} } @@ -1630,8 +1649,10 @@ func (e *EmbeddedIamApi) ListAttachedGroupPolicies(s3cfg *iam_pb.S3ApiConfigurat if g.Name == groupName { for _, policyName := range g.PolicyNames { pn := policyName + policyArn := fmt.Sprintf("arn:aws:iam:::policy/%s", policyName) resp.ListAttachedGroupPoliciesResult.AttachedPolicies = append(resp.ListAttachedGroupPoliciesResult.AttachedPolicies, &iam.AttachedPolicy{ PolicyName: &pn, + PolicyArn: &policyArn, }) } return resp, nil