{"record":{"id":"ea3660a1adee11bd","repo":"kubernetes/kops","slug":"error-attaching-iamrolepolicy-v","errorCode":null,"errorMessage":"error attaching IAMRolePolicy: %v","messagePattern":"error attaching IAMRolePolicy: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/awstasks/iamrolepolicy.go","lineNumber":196,"sourceCode":"\t// Handles the full lifecycle of Policy Overrides\n\tif e.Managed {\n\t\t// Attach policies that are not already attached\n\tAttachPolicies:\n\t\tfor _, policy := range *e.ExternalPolicies {\n\t\t\tfor _, cloudPolicy := range *a.ExternalPolicies {\n\t\t\t\tif cloudPolicy == policy {\n\t\t\t\t\tcontinue AttachPolicies\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trequest := &iam.AttachRolePolicyInput{\n\t\t\t\tRoleName:  e.Role.Name,\n\t\t\t\tPolicyArn: s(policy),\n\t\t\t}\n\n\t\t\t_, err = t.Cloud.IAM().AttachRolePolicy(ctx, request)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error attaching IAMRolePolicy: %v\", err)\n\t\t\t}\n\t\t}\n\n\t\t// Clean up unused cloud policies\n\tCheckPolicies:\n\t\tfor _, cloudPolicy := range *a.ExternalPolicies {\n\t\t\tfor _, policy := range *e.ExternalPolicies {\n\t\t\t\tif policy == cloudPolicy {\n\t\t\t\t\tcontinue CheckPolicies\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tklog.V(2).Infof(\"Detaching unused IAMRolePolicy %s/%s\", aws.ToString(e.Role.Name), cloudPolicy)\n\n\t\t\t// Detach policy\n\t\t\trequest := &iam.DetachRolePolicyInput{\n\t\t\t\tRoleName:  e.Role.Name,\n\t\t\t\tPolicyArn: s(cloudPolicy),","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/awstasks/iamrolepolicy.go#L178-L214","documentation":"When the task is Managed (ExternalPolicies lifecycle), RenderAWS attaches each desired policy ARN to the role with AttachRolePolicy. Any non-nil error from that API call is wrapped as 'error attaching IAMRolePolicy'. The desired state is not converged.","triggerScenarios":"AttachRolePolicy returns AccessDenied, NoSuchEntity (policy ARN doesn't exist or role missing), throttling, or LimitExceeded while attaching an ExternalPolicies ARN in RenderAWS.","commonSituations":"Typo'd or nonexistent policy ARN in the cluster spec (often after copying ARNs across accounts/regions); credentials lacking iam:AttachRolePolicy; policy deleted from the account; IAM throttling on large clusters.","solutions":["Verify each ARN in ExternalPolicies exists: `aws iam get-policy --policy-arn <arn>`","Grant iam:AttachRolePolicy (and GetPolicy) to the kops credentials","Fix typo'd/region/account-wrong ARNs in the cluster spec and re-run update","Retry if the wrapped error is throttling"],"exampleFix":"// before\nExternalPolicies: &[]string{\"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccessv2\"} // typo\n// after\nExternalPolicies: &[]string{\"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess\"}","handlingStrategy":"try-catch","validationCode":"// verify every ExternalPolicies ARN exists before kops update\nfor _, arn := range externalPolicies {\n  if _, err := iamClient.GetPolicy(ctx, &iam.GetPolicyInput{PolicyArn: aws.String(arn)}); err != nil {\n    log.Fatalf(\"policy ARN not found: %s (%v)\", arn, err)\n  }\n}","typeGuard":null,"tryCatchPattern":"var nfe *types.NoSuchEntityException\nif err := kopsUpdate(); err != nil {\n  switch {\n  case errors.As(err, &nfe): // fix wrong/missing policy ARN in spec\n  case isThrottling(err): // retry with backoff\n  default: log.Printf(\"attach failed: %v\", err)\n  }\n}","preventionTips":["Copy policy ARNs exactly from `aws iam list-policies`","Remember AWS-managed policies are global ARNs but customer policies are account-specific","Grant iam:AttachRolePolicy/GetPolicy to kops credentials","Avoid creating/deleting policies concurrently with kops runs"],"tags":["aws","iam","attach-policy"],"backgroundTag":"aws-iam-api-error","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}