Skip to content

fix(cross-account-iam): allow instance-profile reads in cluster boundary - #36

Merged
Timothy Colbert (s3than) merged 1 commit into
mainfrom
s3than/20260904-boundary-instance-profile-reads
Sep 4, 2026
Merged

Timothy Colbert (s3than) merged 1 commit into
mainfrom
s3than/20260904-boundary-instance-profile-reads

Conversation

@s3than

Copy link
Copy Markdown
Member

Summary

Adds iam:GetInstanceProfile and iam:ListInstanceProfiles (resource arn:aws:iam::*:instance-profile/*) to the cluster-resources permissions boundary template, and updates the module README's service enumeration to match.

Why

Karpenter's EC2NodeClass termination finalizer calls iam:ListInstanceProfiles (PathPrefix-filtered) and iam:GetInstanceProfile when a node class is deleted. The boundary permitted iam:PassRole but neither read action, so any controller role wearing it had a one-way lifecycle: node classes could be created but never deleted — rendered classes wedge in Terminating while the controller loops AccessDenied, even when the role's identity policy already grants the actions. Identity policy and boundary must both allow the call.

Blast radius

This boundary renders once per deployment scope for every consumer of this module's cross_account_iam submodule — all customer BYOC deployments inherit the change on their next dittocloud upgrade. All consumers gain exactly two read-only IAM actions; the mutation surface is unchanged.

Size budget verification

IAM managed policies cap at 6,144 chars. Both real worst cases measured with the new statement included:

  • Scoped (≤6 LB subnets per variables.tf validation): dedicated run scoped_eks_boundary_stays_within_policy_size_limit passes.
  • Legacy/unscoped at the 9-subnet maximum: renders 5,780 chars (headroom 364).

terraform test -filter=tests/policy_conditions.tftest.hcl: 15/15 pass at planned HEAD.

Rollout

Consumers take the change on upgrade to the next tagged release. After it lands, any wedged EC2NodeClass deletion completes on the controller's next reconcile — no other changes required.

The Karpenter EC2NodeClass termination finalizer calls
iam:ListInstanceProfiles with a PathPrefix filter and iam:GetInstanceProfile
when deleting a node class. The cluster resources boundary policy granted
neither, so controller roles wearing it could delete EC2NodeClasses that
then wedged permanently in Terminating (observed on eks-ci-0-ditto with
ci-runner-kvm).

The boundary renders once per deployment scope (unscoped and
ditto-cluster-resources-boundary-<scope> variants) for every
cross_account_iam consumer; this widens the ceiling for all of them by two
read-only IAM actions. Measured worst case post-change: legacy/default at
the maximum 9 vpc_subnet_ids renders 5780 of 6144 chars; scoped mode is
capped at 6 subnets and its permanent size-limit test stays green.
@s3than
Timothy Colbert (s3than) requested a review from a team as a code owner September 4, 2026 04:35
@s3than
Timothy Colbert (s3than) merged commit dcb6723 into main Sep 4, 2026
7 checks passed
@s3than
Timothy Colbert (s3than) deleted the s3than/20260904-boundary-instance-profile-reads branch September 4, 2026 05:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants