{"record":{"id":"6519f5934dfb369d","repo":"kubernetes/kops","slug":"found-iam-instance-profile-assigned-to-multiple-in","errorCode":null,"errorMessage":"found IAM instance profile assigned to multiple Instance Group roles %v and %v: %v","messagePattern":"found IAM instance profile assigned to multiple Instance Group roles (.+?) and (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/awsmodel/iam.go","lineNumber":70,"sourceCode":"      \"Effect\": \"Allow\",\n      \"Principal\": { \"Service\": \"{{ IAMServiceEC2 }}\"},\n      \"Action\": \"sts:AssumeRole\"\n    }\n  ]\n}`\n\nfunc (b *IAMModelBuilder) Build(c *fi.CloudupModelBuilderContext) error {\n\t// Collect managed Instance Group roles\n\tmanagedRoles := make(map[kops.InstanceGroupRole]bool)\n\n\t// Collect Instance Profile ARNs and their associated Instance Group roles\n\tsharedProfileARNsToIGRole := make(map[string]kops.InstanceGroupRole)\n\tfor _, ig := range b.AllInstanceGroups {\n\t\tif ig.Spec.IAM != nil && ig.Spec.IAM.Profile != nil {\n\t\t\tspecProfile := fi.ValueOf(ig.Spec.IAM.Profile)\n\t\t\tif matchingRole, ok := sharedProfileARNsToIGRole[specProfile]; ok {\n\t\t\t\tif matchingRole != ig.Spec.Role {\n\t\t\t\t\treturn fmt.Errorf(\"found IAM instance profile assigned to multiple Instance Group roles %v and %v: %v\",\n\t\t\t\t\t\tig.Spec.Role, sharedProfileARNsToIGRole[specProfile], specProfile)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsharedProfileARNsToIGRole[specProfile] = ig.Spec.Role\n\t\t\t}\n\t\t} else {\n\t\t\tmanagedRoles[ig.Spec.Role] = true\n\t\t}\n\t}\n\n\t// Generate IAM tasks for each shared role\n\tfor profileARN, igRole := range sharedProfileARNsToIGRole {\n\t\tlchPermissions := false\n\t\tdefaultWarmPool := b.Cluster.Spec.CloudProvider.AWS.WarmPool\n\t\tfor _, ig := range b.InstanceGroups {\n\t\t\twarmPool := defaultWarmPool.ResolveDefaults(ig)\n\t\t\tif ig.Spec.Role == igRole && warmPool.IsEnabled() && warmPool.EnableLifecycleHook {\n\t\t\t\tlchPermissions = true","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/awsmodel/iam.go#L52-L88","documentation":"During cluster model building, kOps allows a single pre-existing IAM instance profile (specified via spec.iam.profile on an InstanceGroup) to be shared, but only by Instance Groups that have the SAME InstanceGroupRole (e.g. two Node groups). If the same profile ARN appears on Instance Groups with different roles, the generated IAM policy documents would conflict, so Build aborts with this error listing both roles and the offending ARN.","triggerScenarios":"Running `kops update cluster` / `kops edit cluster` when two or more InstanceGroups set spec.iam.profile to the same ARN while their spec.role values differ (e.g. one Node group and one ControlPlane group both point at the same instance profile ARN).","commonSituations":"Copy-pasting an existing profile ARN into a new instance group manifest and forgetting to change the role; consolidating groups to save IAM resources; migrating from managed to custom profiles on only part of the cluster.","solutions":["Give each role its own instance profile: set a distinct spec.iam.profile ARN per InstanceGroup role.","If the groups should truly share an identity, make their spec.role identical (e.g. both Node).","Remove spec.iam.profile from one group so it falls back to the kOps-managed profile for its role."],"exampleFix":"// before\napiVersion: kops.k8s.io/v1alpha2\nkind: InstanceGroup\nmetadata:\n  name: control-plane-1\nspec:\n  role: ControlPlane\n  iam:\n    profile: arn:aws:iam::123456789012:instance-profile/shared\n---\nkind: InstanceGroup\nmetadata:\n  name: nodes-1\nspec:\n  role: Node\n  iam:\n    profile: arn:aws:iam::123456789012:instance-profile/shared\n// after\nspec:\n  role: Node\n  iam:\n    profile: arn:aws:iam::123456789012:instance-profile/nodes-profile","handlingStrategy":"validation","validationCode":"profiles := map[string]string{}\nfor _, ig := range instanceGroups {\n\tif ig.Spec.IAM != nil && ig.Spec.IAM.Profile != nil {\n\t\tarn := fi.ValueOf(ig.Spec.IAM.Profile)\n\t\tif prev, ok := profiles[arn]; ok && prev != string(ig.Spec.Role) {\n\t\t\treturn fmt.Errorf(\"profile %s shared across roles %s and %s\", arn, prev, ig.Spec.Role)\n\t\t}\n\t\tprofiles[arn] = string(ig.Spec.Role)\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a one-to-one mapping between instance profile ARNs and InstanceGroup roles in your manifests.","Review `kops get ig -o yaml` before update and grep for duplicate iam.profile values.","Let kOps manage profiles unless a shared profile is a hard requirement, and then only within one role."],"tags":["aws","iam","instance-group","config-validation"],"backgroundTag":"iam-instance-profile-role-conflict","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"}