From 0653cf133fc41e089043855311151b28997cdc98 Mon Sep 17 00:00:00 2001 From: Marwin Baumann Date: Thu, 1 Aug 2024 15:19:06 +0200 Subject: [PATCH 1/2] breaking: set default auth mode from 'iam_user' to 'iam_role_oidc' and modify outputs --- README.md | 33 ++++++++++++++++++--------------- UPGRADING.md | 33 ++++++++++++++++++++++++--------- outputs.tf | 2 +- variables.tf | 2 +- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index ebabc5a..402860b 100644 --- a/README.md +++ b/README.md @@ -5,22 +5,18 @@ Terraform module providing an AWS Account Vending Machine (AVM). This module pro ## Workspace authentication This module provides three modes of workspace authentication: +* (default) An IAM role using OpenID Connect integration with the AWS account. This works for remote runners or with using self-hosted Terraform Cloud agents (agent version v1.7.0+). +* An IAM role using an external ID to authenticate with the AWS account in combination with using self-hosted Terraform Cloud agents. +* An IAM user per workspace in the provisioned AWS account. -* Using the default values, this module will create an IAM user per workspace in the provisioned AWS account. -* An IAM role using OpenID Connect integration with the AWS account can be used. This works for remote runners or with using self-hosted Terraform Cloud agents (agent version v1.7.0+). -* An IAM role using an external ID to authenticate with the AWS account can be used in combination with using self-hosted Terraform Cloud agents. +Using one of the first 2 authentication methods is in line with authentication best practices to use IAM roles over IAM users with long-lived tokens. -Using one of the last 2 authentication methods is in line with authentication best practices to use IAM roles over IAM users with long-lived tokens. +### IAM Roles with OIDC (default) -### IAM Roles with OIDC +The [IAM roles with OIDC](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials) feature creates an IAM role with a trust policy allowing the OIDC provider created as part of this module. The workspace will be configured to use OIDC by feeding the AWS provider with the right environment variables. -To use [IAM roles with OIDC](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials) for authentication: - -* Set `var.tfe_workspace.auth_method` or (`auth_method` if specifying additional workspaces) to `iam_role_oidc` - -This will create an IAM role with a trust policy allowing the OIDC provider created as part of this module. The workspace will be configured to use OIDC by feeding the AWS provider with the right environment variables. - -> Using [multiple configurations](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/aws-configuration#specifying-multiple-configurations) (e.g. provider aliases), is currently not supported. Use one of the other two authentication modes if this is a requirement. +> [!WARNING] +> When using using self-hosted Terraform Cloud agents, ensure that your agents use v1.12.0+ when using [multiple configurations](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/specifying-multiple-configurations) (e.g. provider aliases). ### IAM Roles @@ -44,6 +40,12 @@ provider "aws" { } ``` +### IAM Users +* Set `var.tfe_workspace.auth_method` or (`auth_method` if specifying additional workspaces) to `iam_user`. + +This will create an IAM user in the provisioned AWS account with the access key and secret access key added as environmental variables to the workspace. + + ## Workspace team access Team access can be configured per workspace using the `team_access` variable. @@ -67,7 +69,8 @@ team_access = { More complete usage information can be found in the underlying [terraform-aws-mcaf-workspace module README](https://github.com/schubergphilis/terraform-aws-mcaf-workspace#team-access). -Note: the team should already exist, this module will not create it for you. +> [!WARNING] +> The team should already exist, this module will not create it for you. ## AWS SSO Configuration @@ -188,8 +191,8 @@ module "aws_account" { ... } ``` - -Note: the `workspace_boundary` and `workload_boundary` can be templated files, `account_id` will be replaced by AVM by the account ID of the AWS account created. +> [!TIP] +> The `workspace_boundary` and `workload_boundary` can be templated files, `account_id` will be replaced by AVM by the account ID of the AWS account created. ## Requirements diff --git a/UPGRADING.md b/UPGRADING.md index d1463b7..39bc678 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,28 +1,37 @@ # UPGRADING -## Upgrading to 3.0.0 +## Upgrading to v4.0.0 + +### Variables (v4.0.0) +- The variable `assessments_enabled` has been introduced with default set to `true`. +- The default `auth_method` has been modified from `iam_user` to `iam_role_oidc`. + +### Outputs (v4.0.0) +- `additional_tfe_workspace` has been renamed to `additional_tfe_workspaces`. + +## Upgrading to v3.0.0 3.0.0 introduces new optional variables and removes existing optional variables. Upgrading requires changes if you currently use the `slack_notification_triggers` or `slack_notification_url` variables. -Variable changes: +### Variables (v3.0.0) In both `var.additional_tfe_workspaces` and `var.tfe_workspaces`: - Added `workspace_tags` - The `slack_notification_triggers` & `slack_notification_url` variables have been merged into `notification_configuration`. This allows to easily configure notifications for both slack and teams. -## Upgrading to 2.0.0 +## Upgrading to v2.0.0 2.0.0 is a major refactor to make use of `optional`. This commit also introduces breaking changes while we consolidate variables that previously were optional but could not be part of an object (because we had no way to make specific object keys optional). -Variable changes: +### Variables (v2.0.0) - Renamed `var.account_settings` to `var.account` - Renamed `var.tfe_workspace_settings` to `var.tfe_workspace` - Renamed `var.tfe_workspace_settings.terraform_organization` to `var.tfe_workspace.organization` - Moved variables with a `tfe_workspace_` prefix into `var.tfe_workspace` (and removed the prefix) -Behaviour changes to be aware of: +### Behaviour (v2.0.0) - `var.account.environment` (was `var.account_settings.environment`) is now an optional value - The region configured in the workspace is now set using `var.tfe_workspace.default_region` (was `var.region`) and has been made mandatory @@ -49,15 +58,21 @@ Updated requirements: - Minimum terraform version has been set to v1.3.0 - Minimum MCAF provider version has been set to v0.4.2 to be compatible with the latest version of service catalogue -## Upgrading to 1.1.0 +## Upgrading to v1.1.0 -`v1.1.0` is not backwards compatible with `v1.0.0`. First follow the steps to upgrade to `v1.0.0`. The option to automatically create email address with Office 365 has been removed. This upgrade requires the following changes: +`v1.1.0` is not backwards compatible with `v1.0.0`. First follow the steps to upgrade to `v1.0.0`. The option to automatically create email address with Office 365 has been removed. + +### Variables (v1.1.0) +This upgrade requires the following changes: - variable `account_settings` no longer supports a field called `create_email_address`. -## Upgrading to 1.0.0 +## Upgrading to v1.0.0 + +`v1.0.0` is not backward compatible with `v0.4.1` because terraform-aws-mcaf-workspace changed the variables it uses to connect Terraform workspaces to a VCS. -`v1.0.0` is not backward compatible with `v0.4.1` because terraform-aws-mcaf-workspace changed the variables it uses to connect Terraform workspaces to a VCS. This upgrade requires the following changes: +### Variables (v1.0.0) +This upgrade requires the following changes: - Variable `tfe_workspace_settings` requires an additional field called `global_remote_state`, either enabling or disabling global remote state on the workspace. - Variable `tfe_workspace_settings` requires an additional field called `remote_state_consumer_ids`, containing a set of workspace ID's that are allowed access to the global remote state. Set to `null` to share with everyone. diff --git a/outputs.tf b/outputs.tf index c85e527..a4a6f52 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,4 +1,4 @@ -output "additional_tfe_workspace" { +output "additional_tfe_workspaces" { value = { for name, workspace in var.additional_tfe_workspaces : name => module.additional_tfe_workspaces[name].workspace_id } description = "Map of any additional Terraform Cloud workspace names and IDs" } diff --git a/variables.tf b/variables.tf index d5d7e8b..5181fbd 100644 --- a/variables.tf +++ b/variables.tf @@ -140,7 +140,7 @@ variable "tfe_workspace" { agent_role_arns = optional(list(string)) allow_destroy_plan = optional(bool, true) assessments_enabled = optional(bool, true) - auth_method = optional(string, "iam_user") + auth_method = optional(string, "iam_role_oidc") auto_apply = optional(bool, false) auto_apply_run_trigger = optional(bool, false) branch = optional(string, "main") From 68000bdb2d6bb5a7b4aca31c87437b573ca49685 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 1 Aug 2024 13:22:01 +0000 Subject: [PATCH 2/2] docs(readme): update module usage --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 402860b..8aba9f3 100644 --- a/README.md +++ b/README.md @@ -239,7 +239,7 @@ module "aws_account" { |------|-------------|------|---------|:--------:| | [account](#input\_account) | AWS account settings |
object({
alias_prefix = optional(string)
contact_billing = optional(object({
email_address = string
name = string
phone_number = string
title = string
}), null)
contact_operations = optional(object({
email_address = string
name = string
phone_number = string
title = string
}), null)
contact_security = optional(object({
email_address = string
name = string
phone_number = string
title = string
}), null)
email = string
environment = optional(string)
organizational_unit = string
provisioned_product_name = optional(string)
sso_email = string
sso_firstname = optional(string, "AWS Control Tower")
sso_lastname = optional(string, "Admin")
})
| n/a | yes | | [name](#input\_name) | Name of the account and default TFE workspace | `string` | n/a | yes | -| [tfe\_workspace](#input\_tfe\_workspace) | TFE workspace settings |
object({
add_permissions_boundary = optional(bool, false)
agent_pool_id = optional(string)
agent_role_arns = optional(list(string))
allow_destroy_plan = optional(bool, true)
assessments_enabled = optional(bool, true)
auth_method = optional(string, "iam_user")
auto_apply = optional(bool, false)
auto_apply_run_trigger = optional(bool, false)
branch = optional(string, "main")
clear_text_env_variables = optional(map(string), {})
clear_text_hcl_variables = optional(map(string), {})
clear_text_terraform_variables = optional(map(string), {})
connect_vcs_repo = optional(bool, true)
default_region = string
description = optional(string)
execution_mode = optional(string, "remote")
file_triggers_enabled = optional(bool, true)
global_remote_state = optional(bool, false)
name = optional(string)
organization = string
policy = optional(string)
policy_arns = optional(list(string), ["arn:aws:iam::aws:policy/AdministratorAccess"])
project_id = optional(string)
queue_all_runs = optional(bool)
remote_state_consumer_ids = optional(set(string))
repository_identifier = optional(string)
role_name = optional(string, "TFEPipeline")
sensitive_env_variables = optional(map(string), {})
sensitive_hcl_variables = optional(map(object({ sensitive = string })), {})
sensitive_terraform_variables = optional(map(string), {})
ssh_key_id = optional(string)
terraform_version = optional(string)
trigger_patterns = optional(list(string))
trigger_prefixes = optional(list(string), ["modules"])
username = optional(string, "TFEPipeline")
vcs_oauth_token_id = string
working_directory = optional(string)
workspace_tags = optional(list(string))

notification_configuration = optional(list(object({
destination_type = string
enabled = optional(bool, true)
url = string
triggers = optional(list(string), [
"run:created",
"run:planning",
"run:needs_attention",
"run:applying",
"run:completed",
"run:errored",
])
})), [])

team_access = optional(map(object({
access = optional(string, null),
permissions = optional(object({
run_tasks = bool
runs = string
sentinel_mocks = string
state_versions = string
variables = string
workspace_locking = bool
}), null)
})), {})
})
| n/a | yes | +| [tfe\_workspace](#input\_tfe\_workspace) | TFE workspace settings |
object({
add_permissions_boundary = optional(bool, false)
agent_pool_id = optional(string)
agent_role_arns = optional(list(string))
allow_destroy_plan = optional(bool, true)
assessments_enabled = optional(bool, true)
auth_method = optional(string, "iam_role_oidc")
auto_apply = optional(bool, false)
auto_apply_run_trigger = optional(bool, false)
branch = optional(string, "main")
clear_text_env_variables = optional(map(string), {})
clear_text_hcl_variables = optional(map(string), {})
clear_text_terraform_variables = optional(map(string), {})
connect_vcs_repo = optional(bool, true)
default_region = string
description = optional(string)
execution_mode = optional(string, "remote")
file_triggers_enabled = optional(bool, true)
global_remote_state = optional(bool, false)
name = optional(string)
organization = string
policy = optional(string)
policy_arns = optional(list(string), ["arn:aws:iam::aws:policy/AdministratorAccess"])
project_id = optional(string)
queue_all_runs = optional(bool)
remote_state_consumer_ids = optional(set(string))
repository_identifier = optional(string)
role_name = optional(string, "TFEPipeline")
sensitive_env_variables = optional(map(string), {})
sensitive_hcl_variables = optional(map(object({ sensitive = string })), {})
sensitive_terraform_variables = optional(map(string), {})
ssh_key_id = optional(string)
terraform_version = optional(string)
trigger_patterns = optional(list(string))
trigger_prefixes = optional(list(string), ["modules"])
username = optional(string, "TFEPipeline")
vcs_oauth_token_id = string
working_directory = optional(string)
workspace_tags = optional(list(string))

notification_configuration = optional(list(object({
destination_type = string
enabled = optional(bool, true)
url = string
triggers = optional(list(string), [
"run:created",
"run:planning",
"run:needs_attention",
"run:applying",
"run:completed",
"run:errored",
])
})), [])

team_access = optional(map(object({
access = optional(string, null),
permissions = optional(object({
run_tasks = bool
runs = string
sentinel_mocks = string
state_versions = string
variables = string
workspace_locking = bool
}), null)
})), {})
})
| n/a | yes | | [additional\_tfe\_workspaces](#input\_additional\_tfe\_workspaces) | Additional TFE workspaces |
map(object({
add_permissions_boundary = optional(bool, false)
agent_pool_id = optional(string)
agent_role_arns = optional(list(string))
allow_destroy_plan = optional(bool)
assessments_enabled = optional(bool)
auth_method = optional(string)
auto_apply = optional(bool, false)
auto_apply_run_trigger = optional(bool, false)
branch = optional(string)
clear_text_env_variables = optional(map(string), {})
clear_text_hcl_variables = optional(map(string), {})
clear_text_terraform_variables = optional(map(string), {})
connect_vcs_repo = optional(bool, true)
default_region = optional(string)
description = optional(string)
execution_mode = optional(string)
file_triggers_enabled = optional(bool, true)
global_remote_state = optional(bool, false)
name = optional(string)
policy = optional(string)
policy_arns = optional(list(string), ["arn:aws:iam::aws:policy/AdministratorAccess"])
project_id = optional(string)
queue_all_runs = optional(bool)
remote_state_consumer_ids = optional(set(string))
repository_identifier = optional(string)
role_name = optional(string)
sensitive_env_variables = optional(map(string), {})
sensitive_hcl_variables = optional(map(object({ sensitive = string })), {})
sensitive_terraform_variables = optional(map(string), {})
ssh_key_id = optional(string)
terraform_version = optional(string)
trigger_patterns = optional(list(string))
trigger_prefixes = optional(list(string))
username = optional(string)
vcs_oauth_token_id = optional(string)
working_directory = optional(string)
workspace_tags = optional(list(string))

notification_configuration = optional(list(object({
destination_type = string
enabled = optional(bool, true)
url = string
triggers = optional(list(string), [
"run:created",
"run:planning",
"run:needs_attention",
"run:applying",
"run:completed",
"run:errored",
])
})), [])

team_access = optional(map(object({
access = optional(string, null),
permissions = optional(object({
run_tasks = bool
runs = string
sentinel_mocks = string
state_versions = string
variables = string
workspace_locking = bool
}), null)
})), {})
}))
| `{}` | no | | [create\_default\_workspace](#input\_create\_default\_workspace) | Set to false to skip creating default workspace | `bool` | `true` | no | | [path](#input\_path) | Optional path for all IAM users, user groups, roles, and customer managed policies created by this module | `string` | `"/"` | no | @@ -250,7 +250,7 @@ module "aws_account" { | Name | Description | |------|-------------| -| [additional\_tfe\_workspace](#output\_additional\_tfe\_workspace) | Map of any additional Terraform Cloud workspace names and IDs | +| [additional\_tfe\_workspaces](#output\_additional\_tfe\_workspaces) | Map of any additional Terraform Cloud workspace names and IDs | | [environment](#output\_environment) | The environment name | | [id](#output\_id) | The AWS account ID | | [name](#output\_name) | The AWS account name |