From 52b17bc6e6ebdb59c5dc52396eaf2238837a2207 Mon Sep 17 00:00:00 2001 From: milldr Date: Mon, 2 Feb 2026 15:12:18 -0500 Subject: [PATCH 01/11] docs: add S3 bucket policy size quota increase step for tfstate-backend --- docs/layers/accounts/initialize-tfstate.mdx | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index a59babbd5..1144e8313 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -49,6 +49,33 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These + + + ## Request S3 Bucket Policy Size Quota Increase + + The reference architecture follows the principle of least privilege by listing every specific ARN explicitly in the + `tfstate-backend` S3 bucket policy. This ensures only known, authorized roles and permission sets can access + Terraform state. Because explicit ARNs produce a larger policy, the default S3 bucket policy size limit of 20KB may + be exceeded. + + Before deploying the Terraform state backend, request a service quota increase for the S3 bucket policy size in the + **root** account: + + ```bash + aws service-quotas request-service-quota-increase \ + --service-code s3 \ + --quota-code L-DC2B2D3D \ + --desired-value 40 + ``` + + This requests a 40KB limit, which provides sufficient headroom for organizations with many accounts. + + :::note + Organizations preferring a smaller policy can substitute wildcard ARN patterns (e.g. + `arn:aws:iam::*:role/acme-*-gbl-*-terraform`) in the `tfstate-backend` catalog defaults instead. This trades + security for convenience and avoids the need for a quota increase. + ::: + ## Initialize the Terraform State Backend From 3f6e0ac5babad576b96aa2999811bc672361c322 Mon Sep 17 00:00:00 2001 From: milldr Date: Mon, 2 Feb 2026 15:19:01 -0500 Subject: [PATCH 02/11] docs: note accounts workflow includes s3 quota request, recommend quota increase --- docs/layers/accounts/initialize-tfstate.mdx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index 1144e8313..996aa469b 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -70,12 +70,17 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These This requests a 40KB limit, which provides sufficient headroom for organizations with many accounts. - :::note - Organizations preferring a smaller policy can substitute wildcard ARN patterns (e.g. - `arn:aws:iam::*:role/acme-*-gbl-*-terraform`) in the `tfstate-backend` catalog defaults instead. This trades - security for convenience and avoids the need for a quota increase. + :::tip + The `deploy/s3-quota` workflow step in the accounts layer workflow already includes this quota request. If you are + following the quickstart and running `atmos workflow all -f quickstart/foundation/accounts`, this step is handled + automatically and you do not need to run the command manually. ::: + Organizations preferring a smaller policy can substitute wildcard ARN patterns (e.g. + `arn:aws:iam::*:role/acme-*-gbl-*-terraform`) in the `tfstate-backend` catalog defaults, but additional changes + may also be needed to fit within the default 20KB limit. We recommend requesting the quota increase so the bucket + policy size is not a constraint. + ## Initialize the Terraform State Backend From b6b8bf0cbf529c7e726ac18501bdc6dc5f49878d Mon Sep 17 00:00:00 2001 From: milldr Date: Tue, 3 Feb 2026 09:49:54 -0500 Subject: [PATCH 03/11] docs: add Note component with atmos auth exec prefix and regex trade-offs --- docs/layers/accounts/initialize-tfstate.mdx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index 996aa469b..5274fecfe 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -62,10 +62,11 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These **root** account: ```bash - aws service-quotas request-service-quota-increase \ - --service-code s3 \ - --quota-code L-DC2B2D3D \ - --desired-value 40 + atmos auth exec --identity core-root/terraform -- \ + aws service-quotas request-service-quota-increase \ + --service-code s3 \ + --quota-code L-DC2B2D3D \ + --desired-value 40 ``` This requests a 40KB limit, which provides sufficient headroom for organizations with many accounts. @@ -76,11 +77,18 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These automatically and you do not need to run the command manually. ::: + Organizations preferring a smaller policy can substitute wildcard ARN patterns (e.g. `arn:aws:iam::*:role/acme-*-gbl-*-terraform`) in the `tfstate-backend` catalog defaults, but additional changes may also be needed to fit within the default 20KB limit. We recommend requesting the quota increase so the bucket policy size is not a constraint. + If you use wildcard ARN patterns, ensure the `tfstate-backend` component is configured with + `use_organization_id: true` to restrict access to principals within your AWS Organization. Without this restriction, + wildcard patterns like `arn:aws:iam::*:role/...` could potentially match roles in accounts outside your organization, + creating a security vulnerability. + + ## Initialize the Terraform State Backend From 9a95783d72254fb27210d518e54251329995ce5d Mon Sep 17 00:00:00 2001 From: milldr Date: Tue, 3 Feb 2026 14:35:05 -0500 Subject: [PATCH 04/11] docs: fix quota to IAM trust policy (L-C07B4B0D) instead of S3 bucket policy --- docs/layers/accounts/initialize-tfstate.mdx | 29 +++++++++++---------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index 5274fecfe..958bb4a37 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -51,37 +51,38 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These - ## Request S3 Bucket Policy Size Quota Increase + ## Request IAM Role Trust Policy Size Quota Increase The reference architecture follows the principle of least privilege by listing every specific ARN explicitly in the - `tfstate-backend` S3 bucket policy. This ensures only known, authorized roles and permission sets can access - Terraform state. Because explicit ARNs produce a larger policy, the default S3 bucket policy size limit of 20KB may - be exceeded. + `tfstate-backend` IAM role trust policies. This ensures only known, authorized roles and permission sets can access + Terraform state. Because explicit ARNs produce larger trust policies, the default IAM role trust policy size limit + of 2048 characters may be exceeded. - Before deploying the Terraform state backend, request a service quota increase for the S3 bucket policy size in the - **root** account: + Before deploying the Terraform state backend, request a service quota increase for the IAM role trust policy size in + the **root** account. Since IAM is a global service, this request must be made in `us-east-1`: ```bash atmos auth exec --identity core-root/terraform -- \ aws service-quotas request-service-quota-increase \ - --service-code s3 \ - --quota-code L-DC2B2D3D \ - --desired-value 40 + --service-code iam \ + --quota-code L-C07B4B0D \ + --desired-value 4096 \ + --region us-east-1 ``` - This requests a 40KB limit, which provides sufficient headroom for organizations with many accounts. + This requests the maximum allowed limit of 4096 characters. Requests up to this limit are automatically approved. :::tip - The `deploy/s3-quota` workflow step in the accounts layer workflow already includes this quota request. If you are + The `deploy/iam-quota` workflow step in the accounts layer workflow already includes this quota request. If you are following the quickstart and running `atmos workflow all -f quickstart/foundation/accounts`, this step is handled automatically and you do not need to run the command manually. ::: - Organizations preferring a smaller policy can substitute wildcard ARN patterns (e.g. + Organizations preferring smaller trust policies can substitute wildcard ARN patterns (e.g. `arn:aws:iam::*:role/acme-*-gbl-*-terraform`) in the `tfstate-backend` catalog defaults, but additional changes - may also be needed to fit within the default 20KB limit. We recommend requesting the quota increase so the bucket - policy size is not a constraint. + may also be needed to fit within the default 2048 character limit. We recommend requesting the quota increase so + the trust policy size is not a constraint. If you use wildcard ARN patterns, ensure the `tfstate-backend` component is configured with `use_organization_id: true` to restrict access to principals within your AWS Organization. Without this restriction, From 3cfb02d10a477b317ab6606462b4f9a769dac5d2 Mon Sep 17 00:00:00 2001 From: milldr Date: Thu, 5 Feb 2026 13:20:47 -0500 Subject: [PATCH 05/11] fix: update IAM quota documentation to 10240 --- docs/layers/accounts/initialize-tfstate.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index 958bb4a37..1f28e995e 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -66,11 +66,11 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These aws service-quotas request-service-quota-increase \ --service-code iam \ --quota-code L-C07B4B0D \ - --desired-value 4096 \ + --desired-value 10240 \ --region us-east-1 ``` - This requests the maximum allowed limit of 4096 characters. Requests up to this limit are automatically approved. + This requests an increase to 10KB, which provides ample room for organizations with many accounts. Requests are typically approved within minutes. :::tip The `deploy/iam-quota` workflow step in the accounts layer workflow already includes this quota request. If you are From 419db95e9600d8664ccf8baef4ea0dbbb2687f16 Mon Sep 17 00:00:00 2001 From: milldr Date: Thu, 5 Feb 2026 13:38:07 -0500 Subject: [PATCH 06/11] fix: correct IAM role trust policy quota limit from 10240 to 4096 --- docs/layers/accounts/initialize-tfstate.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index 1f28e995e..d69cf6522 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -66,11 +66,11 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These aws service-quotas request-service-quota-increase \ --service-code iam \ --quota-code L-C07B4B0D \ - --desired-value 10240 \ + --desired-value 4096 \ --region us-east-1 ``` - This requests an increase to 10KB, which provides ample room for organizations with many accounts. Requests are typically approved within minutes. + This requests an increase to the maximum allowed 4096 characters. Requests are typically approved within minutes. :::tip The `deploy/iam-quota` workflow step in the accounts layer workflow already includes this quota request. If you are From cbaa5bb05e13119459bf5c2c96e472795ea63ae1 Mon Sep 17 00:00:00 2001 From: milldr Date: Thu, 5 Feb 2026 13:51:53 -0500 Subject: [PATCH 07/11] docs: note that quota requests within max limit are auto-approved --- docs/layers/accounts/initialize-tfstate.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index d69cf6522..e9a9ff4b2 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -70,7 +70,7 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These --region us-east-1 ``` - This requests an increase to the maximum allowed 4096 characters. Requests are typically approved within minutes. + This requests an increase to the maximum allowed 4096 characters. Requests within this limit are auto-approved instantly—no AWS support ticket required. :::tip The `deploy/iam-quota` workflow step in the accounts layer workflow already includes this quota request. If you are From 91d73042d8c546e431506a68dd7814fb200c5f5c Mon Sep 17 00:00:00 2001 From: milldr Date: Thu, 5 Feb 2026 14:34:30 -0500 Subject: [PATCH 08/11] docs: explain trust policy security model and quota limits - Remove quota increase as a default/required step - Explain why wildcard patterns are used (IAM 4096 char hard limit) - Document the two-way security handshake model - Show how to request quota increase if customizations require it --- docs/layers/accounts/initialize-tfstate.mdx | 69 ++++++++++++--------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index e9a9ff4b2..10b4e79d5 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -51,45 +51,52 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These - ## Request IAM Role Trust Policy Size Quota Increase + ## Understanding Trust Policy Security - The reference architecture follows the principle of least privilege by listing every specific ARN explicitly in the - `tfstate-backend` IAM role trust policies. This ensures only known, authorized roles and permission sets can access - Terraform state. Because explicit ARNs produce larger trust policies, the default IAM role trust policy size limit - of 2048 characters may be exceeded. + The `tfstate-backend` component creates IAM roles with trust policies that control which principals can assume them. + Understanding how these policies work is important for security. - Before deploying the Terraform state backend, request a service quota increase for the IAM role trust policy size in - the **root** account. Since IAM is a global service, this request must be made in `us-east-1`: + ### Why We Use Wildcard Patterns + + IAM role trust policies have a **hard limit of 4096 characters** (after requesting a quota increase from the default + 2048). For organizations with multiple accounts, listing every role and permission set by explicit ARN would easily + exceed this limit—even with the maximum quota. + + Instead, the reference architecture uses wildcard ARN patterns like: + - `arn:aws:iam::*:role/acme-*-gbl-*-terraform` for Terraform execution roles + - `arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/*/AWSReservedSSO_Terraform*Access_*` for SSO permission sets + + ### The Two-Way Security Handshake + + Using wildcards in trust policies is secure because access requires a **two-way handshake**: + + 1. **Trust Policy (this side):** The tfstate role's trust policy allows principals matching the pattern to attempt + assumption, but only if they're within your AWS Organization (`aws:PrincipalOrgID` condition). + + 2. **Principal's Policy (other side):** The principal (e.g., a Terraform role or SSO permission set) must also have + an IAM policy granting `sts:AssumeRole` on the specific tfstate role ARN. + + A role matching the wildcard pattern cannot access Terraform state unless it also has explicit permission to assume + the tfstate role. This defense-in-depth approach maintains security while staying within IAM limits. + + ### Requesting a Quota Increase (If Needed) + + If you customize the trust policies and approach the 2048 character default limit, you can request an increase up to + the maximum of 4096 characters. Requests within this limit are auto-approved instantly: ```bash - atmos auth exec --identity core-root/terraform -- \ - aws service-quotas request-service-quota-increase \ - --service-code iam \ - --quota-code L-C07B4B0D \ - --desired-value 4096 \ - --region us-east-1 + aws service-quotas request-service-quota-increase \ + --service-code iam \ + --quota-code L-C07B4B0D \ + --desired-value 4096 \ + --region us-east-1 ``` - This requests an increase to the maximum allowed 4096 characters. Requests within this limit are auto-approved instantly—no AWS support ticket required. - - :::tip - The `deploy/iam-quota` workflow step in the accounts layer workflow already includes this quota request. If you are - following the quickstart and running `atmos workflow all -f quickstart/foundation/accounts`, this step is handled - automatically and you do not need to run the command manually. + :::note + This is only needed if you customize trust policies beyond the defaults. The reference architecture's wildcard + patterns fit comfortably within the default 2048 character limit. ::: - - Organizations preferring smaller trust policies can substitute wildcard ARN patterns (e.g. - `arn:aws:iam::*:role/acme-*-gbl-*-terraform`) in the `tfstate-backend` catalog defaults, but additional changes - may also be needed to fit within the default 2048 character limit. We recommend requesting the quota increase so - the trust policy size is not a constraint. - - If you use wildcard ARN patterns, ensure the `tfstate-backend` component is configured with - `use_organization_id: true` to restrict access to principals within your AWS Organization. Without this restriction, - wildcard patterns like `arn:aws:iam::*:role/...` could potentially match roles in accounts outside your organization, - creating a security vulnerability. - - ## Initialize the Terraform State Backend From ef0ae347fb4e1cd24611c7e7e6f4368e944e6cb9 Mon Sep 17 00:00:00 2001 From: milldr Date: Thu, 5 Feb 2026 14:38:50 -0500 Subject: [PATCH 09/11] docs: add atmos auth prefix to quota request example --- docs/layers/accounts/initialize-tfstate.mdx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index 10b4e79d5..b8478e222 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -85,11 +85,12 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These the maximum of 4096 characters. Requests within this limit are auto-approved instantly: ```bash - aws service-quotas request-service-quota-increase \ - --service-code iam \ - --quota-code L-C07B4B0D \ - --desired-value 4096 \ - --region us-east-1 + atmos auth exec --identity core-root/terraform -- \ + aws service-quotas request-service-quota-increase \ + --service-code iam \ + --quota-code L-C07B4B0D \ + --desired-value 4096 \ + --region us-east-1 ``` :::note From 4d4b20c8152c8980c606c6faf39f1d5aedf846bd Mon Sep 17 00:00:00 2001 From: sandbox Date: Fri, 6 Feb 2026 13:07:05 -0500 Subject: [PATCH 10/11] docs: use details component for trust policy explanation Applies Erik's feedback: - Move trust policy content out of Step into collapsible details - Rename to 'Why Do We Use Wildcard Patterns with IAM?' - Keep content between vendor and initialize steps --- docs/layers/accounts/initialize-tfstate.mdx | 51 +++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index b8478e222..ea6521876 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -50,6 +50,57 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These + +
+ Why Do We Use Wildcard Patterns with IAM? + + The `tfstate-backend` component creates IAM roles with trust policies that control which principals can assume them. + Understanding how these policies work is important for security. + + ### The Character Limit Problem + + IAM role trust policies have a **hard limit of 4096 characters** (after requesting a quota increase from the default + 2048). For organizations with multiple accounts, listing every role and permission set by explicit ARN would easily + exceed this limit—even with the maximum quota. + + Instead, the reference architecture uses wildcard ARN patterns like: + - `arn:aws:iam::*:role/acme-*-gbl-*-terraform` for Terraform execution roles + - `arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/*/AWSReservedSSO_Terraform*Access_*` for SSO permission sets + + ### The Two-Way Security Handshake + + Using wildcards in trust policies is secure because access requires a **two-way handshake**: + + 1. **Trust Policy (this side):** The tfstate role's trust policy allows principals matching the pattern to attempt + assumption, but only if they're within your AWS Organization (`aws:PrincipalOrgID` condition). + + 2. **Principal's Policy (other side):** The principal (e.g., a Terraform role or SSO permission set) must also have + an IAM policy granting `sts:AssumeRole` on the specific tfstate role ARN. + + A role matching the wildcard pattern cannot access Terraform state unless it also has explicit permission to assume + the tfstate role. This defense-in-depth approach maintains security while staying within IAM limits. + + ### Requesting a Quota Increase (If Needed) + + If you customize the trust policies and approach the 2048 character default limit, you can request an increase up to + the maximum of 4096 characters. Requests within this limit are auto-approved instantly: + + ```bash + atmos auth exec --identity core-root/terraform -- \ + aws service-quotas request-service-quota-increase \ + --service-code iam \ + --quota-code L-C07B4B0D \ + --desired-value 4096 \ + --region us-east-1 + ``` + + :::note + This is only needed if you customize trust policies beyond the defaults. The reference architecture's wildcard + patterns fit comfortably within the default 2048 character limit. + ::: + +
+ ## Understanding Trust Policy Security From 99e9196b3f41450a8e852df7e7a974dfffbd4e90 Mon Sep 17 00:00:00 2001 From: sandbox Date: Fri, 6 Feb 2026 13:07:05 -0500 Subject: [PATCH 11/11] docs: use details component for trust policy explanation Applies Erik's feedback: - Move trust policy content out of Step into collapsible details - Rename to 'Why Do We Use Wildcard Patterns with IAM?' - Remove duplicate Step block --- docs/layers/accounts/initialize-tfstate.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/layers/accounts/initialize-tfstate.mdx b/docs/layers/accounts/initialize-tfstate.mdx index b8478e222..65cb259f0 100644 --- a/docs/layers/accounts/initialize-tfstate.mdx +++ b/docs/layers/accounts/initialize-tfstate.mdx @@ -50,13 +50,14 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These - - ## Understanding Trust Policy Security + +
+ Why Do We Use Wildcard Patterns with IAM? The `tfstate-backend` component creates IAM roles with trust policies that control which principals can assume them. Understanding how these policies work is important for security. - ### Why We Use Wildcard Patterns + ### The Character Limit Problem IAM role trust policies have a **hard limit of 4096 characters** (after requesting a quota increase from the default 2048). For organizations with multiple accounts, listing every role and permission set by explicit ARN would easily @@ -98,7 +99,8 @@ If you look at `components/terraform/`, you'll see a bunch of directories. These patterns fit comfortably within the default 2048 character limit. ::: - +
+ ## Initialize the Terraform State Backend