Skip to content

feat: add TerraformAccess, RootAccess permission sets and account_map bypass#53

Merged
milldr merged 6 commits intomainfrom
feat/terraform-access-permission-sets
Dec 8, 2025
Merged

feat: add TerraformAccess, RootAccess permission sets and account_map bypass#53
milldr merged 6 commits intomainfrom
feat/terraform-access-permission-sets

Conversation

@milldr
Copy link
Contributor

@milldr milldr commented Dec 3, 2025

what

  • Add TerraformPlanAccess permission set for read-only Terraform state and account access
  • Add TerraformApplyAccess permission set for full Terraform state and admin account access
  • Add RootAccess permission set for centralized root credential management via sts:AssumeRoot
  • Add idp_groups variable to look up IdP-synced groups (Google Workspace, Okta, etc.)
  • Add group_ids output combining both manually created and IdP-synced groups
  • Add account_map_enabled variable to toggle between remote state lookup and static mapping
  • Add account_map variable for static account ID mapping
  • Add provider-root.tf for root account assignments using profile-based auth

why

  • Enables SSO users to run Terraform plan/apply without requiring IAM users or static credentials
  • Supports the account-map deprecation effort by allowing components to function with static account mappings
  • RootAccess permission set enables centralized root credential management for delegated accounts (AWS Organizations feature)
  • IdP group lookup enables referencing synced groups in other components without manual ID copying

references

  • Part of account-map deprecation initiative
  • Supports Atmos Auth profile-based authentication

Summary by CodeRabbit

  • New Features

    • Added support for IdP-managed groups synced to Identity Center.
    • Added Terraform state backend access controls with separate read-only plan and read-write apply permissions.
    • Added root account access permissions.
    • Added profile-based AWS authentication support.
  • Configuration

    • Added optional static account mapping as an alternative to dynamic lookup.
    • Added Terraform version (≥1.3.0) and AWS provider (≥4.0) requirements.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 3, 2025

Walkthrough

This PR extends the AWS Identity Center module to support IdP-managed groups lookup, adds three new permission sets for root access and Terraform state backend operations, introduces conditional account map handling, and provides mixin files for flexible provider and version configuration.

Changes

Cohort / File(s) Summary
Pre-commit and mixin configuration
.pre-commit-config.yaml
Adds exclude patterns to terraform_fmt and terraform_tflint hooks to skip mixins/ directory and context.tf files
Mixin setup files
mixins/.tflint.hcl, mixins/versions.tf, mixins/provider-root.tf
Adds new mixin files: tflint configuration (disabled by default), Terraform version constraints (≥1.3.0) and AWS provider pinning (≥4.0), and root provider block with profile-based authentication
IdP-managed groups integration
src/main.tf, src/outputs.tf, src/variables.tf
Adds data source for IdP group lookup via aws_identitystore_group, includes retrieved groups in group_ids output, and introduces idp_groups variable to specify group names
Permission set definitions
src/policy-RootAccess.tf, src/policy-TerraformAccess.tf
Defines three new permission sets: root_access (sts:AssumeRoot), terraform_plan_access (read-only S3 state), and terraform_apply_access (read-write S3 state with conditional DynamoDB access)
Account map abstraction
src/providers.tf, src/remote-state.tf
Adds account_map_enabled flag and static account_map variable; updates account_map module to conditionally use dynamic lookup or static mapping via new bypass and defaults inputs

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • src/policy-TerraformAccess.tf: Review complex IAM policy documents with dynamic DynamoDB conditionals and multiple statement blocks; verify correct action scopes and resource ARNs.
  • src/remote-state.tf: Verify conditional logic for account_map_enabled flag operates correctly and that bypass/defaults inputs integrate properly with the account_map module.
  • src/main.tf: Confirm IdP group data source iteration logic and permission set concatenation order are correct and maintainable.
  • New mixin files: Ensure mixin configurations are compatible with expected usage patterns and don't conflict with existing provider setup.

Possibly related PRs

Suggested labels

minor

Suggested reviewers

  • goruha
  • osterman
  • aknysh

Poem

🐰 Groups from IdP now dance in sync,
Root access granted with a strategic link,
Terraform's state locked down so tight,
Account maps flexible—static or dynamic flight!
We've woven identity's threads anew.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main changes: adding TerraformAccess, RootAccess permission sets and account_map bypass functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/terraform-access-permission-sets

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mergify mergify bot added the triage Needs triage label Dec 3, 2025
@milldr milldr changed the title feat: add GitHub OIDC provider support and policy_statements variable feat: add TerraformAccess, RootAccess permission sets and account_map bypass Dec 3, 2025
…support

New features:
- Add TerraformPlanAccess permission set (read-only state and account access)
- Add TerraformApplyAccess permission set (read/write state and admin access)
- Add RootAccess permission set (centralized root access via sts:AssumeRoot)
- Add provider-root.tf for root account assignments via profile
- Add idp_groups variable to look up IdP-synced groups
- Add group_ids output combining manual and IdP groups
- Add account_map_enabled variable to toggle between remote state and static mapping
- Add account_map variable for static account ID mapping

Changes:
- Update main.tf to conditionally use account_map module or static variable
- Update main.tf to include new permission sets and idp_groups data source
- Update remote-state.tf with conditional bypass for account_map
- Update variables.tf with new variables
- Update outputs.tf with group_ids output

These changes support the account-map deprecation effort by enabling
profile-based authentication and static account mappings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@milldr milldr force-pushed the feat/terraform-access-permission-sets branch from 757f7f6 to e8326b3 Compare December 3, 2025 21:58
@mergify mergify bot added the needs-test Needs testing label Dec 3, 2025
The root provider with alias "root" is now defined in provider-root.tf
as a simple profile-based provider. Remove the duplicate definition and
iam_roles_root module from providers.tf to avoid conflict.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
milldr and others added 4 commits December 4, 2025 09:36
Revert providers.tf to include the root provider using account-map and
move the profile-based providers to mixins/ for optional vendoring.

This allows the component to work with account-map out of the box while
still supporting profile-based authentication when using Atmos Auth by
vendoring the mixins.

Changes:
- Restore root provider and iam_roles_root module to src/providers.tf
- Delete src/provider-root.tf (profile-based version)
- Add mixins/providers.tf with profile-based default provider
- Add mixins/provider-root.tf with profile-based root provider
- Update .pre-commit-config.yaml to exclude mixins/ from tflint

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The main providers.tf is handled by the centralized mixin from
cloudposse-terraform-components/mixins. We only need component-specific
mixins for unique situations like aliased providers (provider-root.tf).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Since module.account_map.outputs provides values from either remote state
(when account_map_enabled is true) or from the static var.account_map
defaults (when bypassed), we can always reference module.account_map.outputs
directly without conditional logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@milldr milldr marked this pull request as ready for review December 4, 2025 14:51
@milldr milldr requested a review from a team as a code owner December 4, 2025 14:51
@milldr
Copy link
Contributor Author

milldr commented Dec 4, 2025

/terratest

@github-actions
Copy link

github-actions bot commented Dec 4, 2025

There are no real tests for this component. So we set terratest statuses to successful execution without running any tests

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/policy-TerraformAccess.tf (1)

24-45: Inline policy is partially redundant with AWS managed policy attachments.

The inline policies (lines 30 and 42) explicitly grant S3 and role assumption permissions, while policy attachments add ReadOnlyAccess or AdministratorAccess. The inline policies provide more granular control (e.g., specific S3 bucket scope), but this combination may be confusing. Consider documenting the intent or simplifying if the AWS managed policies are sufficient.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac149f5 and 3262177.

📒 Files selected for processing (11)
  • .pre-commit-config.yaml (1 hunks)
  • mixins/.tflint.hcl (1 hunks)
  • mixins/provider-root.tf (1 hunks)
  • mixins/versions.tf (1 hunks)
  • src/main.tf (3 hunks)
  • src/outputs.tf (1 hunks)
  • src/policy-RootAccess.tf (1 hunks)
  • src/policy-TerraformAccess.tf (1 hunks)
  • src/providers.tf (1 hunks)
  • src/remote-state.tf (1 hunks)
  • src/variables.tf (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/{main,variables,outputs,providers,versions,context}.tf

📄 CodeRabbit inference engine (AGENTS.md)

Keep the Terraform component source of truth in src with these files present: main.tf, variables.tf, outputs.tf, providers.tf, versions.tf, context.tf

Files:

  • src/variables.tf
  • src/providers.tf
  • src/outputs.tf
  • src/main.tf
src/**/*.tf

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.tf: Use 2-space indentation for all Terraform code
In Terraform, prefer lower_snake_case for variables and locals; keep resource/data source names descriptive and aligned with Cloud Posse null-label patterns
Run terraform fmt and adhere to formatting (do not commit formatting violations)
Adhere to TFLint rules defined for the project (do not commit lint violations)

Files:

  • src/variables.tf
  • src/providers.tf
  • src/policy-RootAccess.tf
  • src/outputs.tf
  • src/policy-TerraformAccess.tf
  • src/main.tf
  • src/remote-state.tf
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (12)
mixins/versions.tf (1)

1-13: LGTM!

The mixin file correctly enforces Terraform >= 1.3.0 and AWS provider >= 4.0. The comment about precedence is helpful for users deploying with vendored mixins.

.pre-commit-config.yaml (1)

28-35: LGTM!

The pre-commit hook exclusions for mixins/ are appropriate since mixins are partial Terraform files that shouldn't be independently formatted or linted.

mixins/.tflint.hcl (1)

1-5: LGTM!

Disabling linting by default for vendored mixin files is the correct approach since these are partial Terraform configurations meant to be merged into other components.

src/variables.tf (1)

80-88: LGTM!

The idp_groups variable is well-defined with a clear description. The default empty list is safe and allows gradual adoption of IdP group lookups.

mixins/provider-root.tf (1)

8-12: Reconcile with past reviewer feedback on default implementation.

A prior reviewer noted that "the default implementation should be without auth and with account-map". Since this mixin makes profile-based auth the default, verify that:

  1. Using this mixin is truly optional and doesn't break deployments when not used
  2. Documentation clearly explains when to use this mixin vs. the default account-map approach
  3. The default value "core-root/terraform" aligns with your organization's actual profile naming
src/main.tf (2)

78-90: Verify IdP group lookup error handling and existence guarantees.

The data source uses alternate_identifier with DisplayName to look up IdP groups. Terraform will error if a group in var.idp_groups doesn't exist in the Identity Store. Consider adding:

  1. Documentation warning users that IdP groups must be synced to AWS Identity Center before adding them to var.idp_groups
  2. Clear error messages if lookups fail during terraform plan/apply

105-107: Permission set definitions are correctly defined and properly named.

All three permission sets referenced at lines 105-107 in src/main.tf are correctly defined in src/policy-TerraformAccess.tf:

  • local.root_access_permission_set
  • local.terraform_plan_access_permission_set (defined at line 24) ✓
  • local.terraform_apply_access_permission_set (defined at line 36) ✓

Variable names match exactly and follow lower_snake_case conventions.

src/policy-RootAccess.tf (1)

1-31: Root-task policy ARNs are valid and current.

All five AWS managed root-task policies referenced in the condition are correct: IAMAuditRootUserCredentials, IAMCreateRootUserPassword, IAMDeleteRootUserCredentials, S3UnlockBucketPolicy, and SQSUnlockQueuePolicy. The implementation correctly restricts the permission set's sts:AssumeRoot action to these officially supported task policies.

src/providers.tf (1)

1-26: The account_map conditional mechanism is correctly implemented, but not via module count/for_each.

The variables are properly used in src/remote-state.tf: the module is always instantiated, but the remote-state module's bypass and defaults parameters handle the conditional behavior. When account_map_enabled = false, bypass = true and defaults = var.account_map work together to return the static account mappings instead of performing a remote state lookup. The var.account_map structure correctly matches the expected outputs (full_account_map, root_account_account_name), and downstream references in src/main.tf safely consume module.account_map.outputs without additional conditional logic since the module always provides the outputs.

src/policy-TerraformAccess.tf (1)

1-46: Permission sets are already integrated into the main module.

Both terraform_plan_access_permission_set and terraform_apply_access_permission_set are concatenated into the module.permission_sets input in src/main.tf (lines 106–107).

src/remote-state.tf (1)

16-18: Remove this review comment; module.iam_roles is properly defined and available.

The module is declared in src/providers.tf (not src/context.tf) at line 70 and sources from the external CloudPosse account-map/modules/iam-roles module. The outputs global_tenant_name, global_environment_name, and global_stage_name are correctly referenced in lines 16–18 and used consistently throughout the codebase (e.g., src/providers.tf, src/policy-TerraformUpdateAccess.tf). No action required.

src/outputs.tf (1)

11-17: Data source and variable definitions are correctly configured; merge behavior is intentional.

All components referenced in the output are properly defined: data.aws_identitystore_group.idp queries IdP-synced groups using var.idp_groups (a list of group names), and the merge operation correctly combines manual and IdP-synced groups. The second argument (IdP groups) takes precedence in a key collision, which is the intended design pattern—IdP-synced groups serve as the authoritative source. The code is correctly formatted with 2-space indentation and follows Terraform conventions.

@milldr milldr added minor New features that do not break anything and removed triage Needs triage labels Dec 4, 2025
@mergify mergify bot requested review from a team December 4, 2025 20:13
@mergify mergify bot requested a review from a team December 8, 2025 15:58
@milldr milldr added this pull request to the merge queue Dec 8, 2025
Merged via the queue into main with commit 26b7b65 Dec 8, 2025
20 checks passed
@milldr milldr deleted the feat/terraform-access-permission-sets branch December 8, 2025 16:10
@github-actions
Copy link

github-actions bot commented Dec 8, 2025

These changes were released in v1.540.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor New features that do not break anything needs-test Needs testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants