Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(iam): IAM Policies are too large to deploy #19114

Merged
merged 37 commits into from Mar 18, 2022
Merged

Conversation

rix0rrr
Copy link
Contributor

@rix0rrr rix0rrr commented Feb 23, 2022

The policies we generate sometimes have a lot of duplication between
statements. This duplication can lead to the policy going over the size
limit an IAM policy (either 2k, 6k or 10k bytes, depending on the resource
type).

This change combines multiple statements together, as long as it
doesn't change the meaning of the final policy.

Because doing so for all existing stacks will probably provoke minor
heart attacks in operators everywhere, the new behavior is gated
behind a feature flag. It can be retroactively switched on by
people currently being bit by the size issues:

@aws-cdk/aws-iam:minimizePolicies

We will merge 2 statements if their effects are the same, and they are otherwise exactly the same apart from their Action, Resource or Principal declarations. We will not merge NotXxx statements, because doing so will change the meaning of the statement (not A or not B ≠ not (A or B)). There may be multiple possible merges that apply and we are not guaranteed to find the smallest merging, nor do we take effort to find all possible merges and do simplifications like *-subsumption. This is a starting point that should help out in the common case.

Fixes #18774, fixes #16350, fixes #18457, fixes #18564, fixes #19276.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

The policies we generate sometimes have a lot of duplication between
statements. This duplication can lead to the policy going over the size
limit an IAM policy (either 2k, 6k or 10k bytes, depending on the resource
type).

This change combines multiple statements together, as long as it
doesn't change the meaning of the final policy.

Because doing so for all existing stacks will probably provoke minor
heart attacks in operators everywhere, the new behavior is gated
behind a feature flag. It can be retroactively switched on by
people currently being bit by the size issues:

```
@aws-cdk/aws-iam:minimizePolicies
```

Fixes #18774, fixes #16350, fixes #18457.
@rix0rrr rix0rrr requested a review from a team February 23, 2022 16:26
@rix0rrr rix0rrr self-assigned this Feb 23, 2022
@gitpod-io
Copy link

gitpod-io bot commented Feb 23, 2022

@github-actions github-actions bot added the @aws-cdk/aws-iam Related to AWS Identity and Access Management label Feb 23, 2022
@rix0rrr
Copy link
Contributor Author

rix0rrr commented Feb 23, 2022

Still a draft as this will need a lot of snapshot updates and still needs unit tests for the new functionality.

@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Feb 23, 2022
@rix0rrr rix0rrr added the pr/requires-two-approvers This PR is critical (e.g., security, broadly-impacting) and requires 2 approvers to be merged. label Feb 23, 2022
@rix0rrr rix0rrr marked this pull request as ready for review February 25, 2022 23:38
Copy link
Contributor

@skinny85 skinny85 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did my best, but the actual merging algorithm is so complex that I can't really give a lot of feedback there, other than, "maybe more comments"? 😛

@@ -92,6 +92,7 @@
},
"dependencies": {
"@aws-cdk/core": "0.0.0",
"@aws-cdk/cx-api": "0.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also be added to peerDependencies?

Copy link
Contributor Author

@rix0rrr rix0rrr Feb 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it doesn't mean anything to do that.

*
* @default false, unless the feature flag `@aws-cdk/aws-iam:minimizePolicies` is set
*/
readonly minimize?: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this property? Is the feature flag not enough?

I would get rid of it for now. We can always come back later, and add it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this better on principle. The boolean toggles the feature, and the default value for the boolean is taken from the flag for cases where you don't control the Policy initialization.

packages/@aws-cdk/aws-iam/lib/policy-document.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-iam/lib/policy-document.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-iam/lib/policy-document.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-iam/test/merge-statements.test.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-iam/test/merge-statements.test.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-iam/test/merge-statements.test.ts Outdated Show resolved Hide resolved
@rix0rrr rix0rrr requested review from skinny85, Chriscbr and a team February 26, 2022 16:54
@rix0rrr
Copy link
Contributor Author

rix0rrr commented Feb 26, 2022

In fact I can prove using the Alloy model that there is even more optimization to be had:

It is safe to merge Statements on Action, also merging Resource and Principal, if:

  • a.NotAction = b.NotAction = ∅
  • AND either a.Resources ⊆ b.Resources OR b.Resources ⊆ a.Resources
  • AND a.NotResources = b.NotResources
  • AND either a.Principal ⊆ b.Principal OR b.Principal ⊆ a.Principal
  • AND a.NotPrincipal = b.NotPrincipal

/**
* Merge as many statements as possible to shrink the total policy doc, modifying the input array in place
*
* If there are multiple merges to be made (which may involve the same
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the description in PolicyDocumentProps, it sounds like the merge is associative, commutative and idempotent (but I may be missing something). If that's the case, the order shouldn't matter. And if it's not the case, can we make it so?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question. I can ask the Alloy model whether that is true as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is! Obvious in hindsight, as always 😆. Thanks for pointing this out. Combined with doing subset analysis (instead of == analysis), I think this is now much simpler and more optimal.

Had to move some code around for statement normalization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well nevermind. That subset-based merging I said we could do is in fact NOT safe, and leads to the exact same error as the one we had last time around.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But merging is still associative.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the counterexample for commutativity? My intuition is that we can define a merge operation that forms a semilattice, which induces a partial order (if not the subset relation you tried, maybe some variation of it). Then, navigate the DAG and keep only the statements that are "leaves" in the graph (i.e., not a predecessor of any other statement).

Copy link
Contributor

@Chriscbr Chriscbr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I could see some value in adding unit tests for the makeComparable and renderComparable functions since they have a lot of logic stuffed in them now, but I get that it's just an implementation detail, so I'll leave the call up to you. 🙂

Disclaimer: I did not check the integration test snapshots. There are so many of them... 😱

packages/@aws-cdk/aws-iam/lib/private/merge-statements.ts Outdated Show resolved Hide resolved
Comment on lines 120 to 122
if (Array.isArray(x) || typeof x === 'string') {
x = { AWS: x };
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we performing normalization here / can we normalize the statements in this way before they are passed to mergeStatements? I feel like normalization and statement merging should be logically separate steps, to the extent that it's possible anyways.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not where we merge. This is where we "lift" the IAM statement into a representation that is amenable to merging. Is this not enough separation?

@rix0rrr rix0rrr removed the pr/requires-two-approvers This PR is critical (e.g., security, broadly-impacting) and requires 2 approvers to be merged. label Mar 18, 2022
@mergify
Copy link
Contributor

mergify bot commented Mar 18, 2022

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject89A8053A-LhjRyN9kxr8o
  • Commit ID: 37eaa56
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@mergify mergify bot merged commit 3a4fe33 into master Mar 18, 2022
@mergify mergify bot deleted the huijbers/minimize-policies branch March 18, 2022 17:47
@mergify
Copy link
Contributor

mergify bot commented Mar 18, 2022

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

iliapolo pushed a commit that referenced this pull request Mar 20, 2022
The policies we generate sometimes have a lot of duplication between
statements. This duplication can lead to the policy going over the size
limit an IAM policy (either 2k, 6k or 10k bytes, depending on the resource
type).

This change combines multiple statements together, as long as it
doesn't change the meaning of the final policy.

Because doing so for all existing stacks will probably provoke minor
heart attacks in operators everywhere, the new behavior is gated
behind a feature flag. It can be retroactively switched on by
people currently being bit by the size issues:

```
@aws-cdk/aws-iam:minimizePolicies
```

We will merge 2 statements if their effects are the same, and they are otherwise exactly the same apart from their `Action`, `Resource` or `Principal` declarations. We will not merge `NotXxx` statements, because doing so will change the meaning of the statement (`not A or not B ≠ not (A or B)`). There may be multiple possible merges that apply and we are not guaranteed to find the smallest merging, nor do we take effort to find all possible merges and do simplifications like `*`-subsumption. This is a starting point that should help out in the common case.

Fixes #18774, fixes #16350, fixes #18457, fixes #18564, fixes #19276.


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug. contribution/core This is a PR that came from AWS. p1
Projects
None yet
7 participants