terraform-aws-control_tower_account_factory
terraform-aws-control_tower_account_factory copied to clipboard
Documentation on how to terraform plan on your local
Hi
Good day.
Describe the outcome you'd like Documentation on how to "terraform plan" on your local. At the moment you are forced to push changes to the pipeline.
A clear and concise description of what you want to happen. A way to setup terraform locally to run "terraform plan" against a provisioned account to view changes before pushing.
Is your feature request related to a problem you are currently experiencing? If so, please describe. The problem is coding in the dark basically. The lifecycle is made harder by not being able to plan locally.
A clear and concise description of what the problem is.
Additional context
Add any other context or screenshots about the feature request here. We've managed to reference the provisioned account state file on the management account. But the "terraform plan" still shows all to update. It's better than nothing for now. But as the infrastructure increases it will become harder to read.
Regards. Jarrett
@jarrettj I would say this feature might be covered by https://github.com/aws-ia/terraform-aws-control_tower_account_factory/issues/153
Hey @v-rosa , good day. Would this cover working locally though? Looks more like approval gates added to the pipeline.
What I'm asking is simply being able to init and plan locally. Would be way faster, 5-8 mins than pushing to the pipeline.
Ohh by locally you mean from your laptop? It would be a different request then.
Yup, that's correct. Thought I'd add it here in the event that it's been done already, and I missed it in the docs. I'll probably figure it out as I go along working through more terraform examples etc :)
Hey @jarrettj AFT is not intended as a development tool, but rather as a deployment tool. One potential route for leveraging terraform plan locally would be to execute terraform plan against a development/testing account directly before pushing to AFT's customizations
That being said, I've made a backlog with the team to consider this request, thanks!
Thank you @balltrev.
I think the underlying question really is how to get the plan output. In that respect, it doesn't really matter whether the terraform plan command is executed locally or via CI/CD or anywhere else.
(Housekeeping: perhaps we should rename this issue to remove the "on your local" part? Or should this be raised as a separate issue?)
Example
Assume I already have an AFT account provisioned (in production, to make it extra spicy). The existing Terraform source might look like:
module "foo_prod" {
source = "./modules/aft-account-request"
control_tower_parameters = {
AccountName = "bar-prod"
...
}
...
}
But wait, I've just spotted an inconsistency in the resource name, and coincidentally somebody is now requesting for an actual foo-prod account, so I proceed to make a harmless change request to fix the existing resource name:
- module "foo_prod" {
+ module "bar_prod" {
...
+
+ moved {
+ from = module.fooo_prod
+ to = module.bar_prod
+ }
Guess what? I've now actually made another typo, but there's no easy way to detect this (e.g. no Terraform plan).
So, when my CI/CD pipeline (or whatever) deploys this change, it will actually close my existing production account bar-prod.
The potential impact/disruption of this could be huge! It's not just a simple case of "oops, I misspelled one of my tag values, let me make a follow-up change request to fix forward".
@theipster in that case the request here https://github.com/aws-ia/terraform-aws-control_tower_account_factory/issues/153 would prevent it. Still not able to test it from non main branches, but for sure it's much safer.
a bit related to https://github.com/aws-ia/terraform-aws-control_tower_account_factory/issues/249#issuecomment-1451908276, I want to move the account creation process a bit to use for_each. is there a safe way to migrate the state properly? I'm looking to move multiple "module" blocks into one block with for_each specified.
any update on this?
Hey, I do plan partly from my local. It however fails on an ACM I created in the US East region, which is different from my default region. To setup do the following:
New account requirements
Go to the IAM Identity Center(Billing account) and assign the newly created account and add the Control Tower User with AWSAdministratorAccess permission set. (https://us-east-1.console.aws.amazon.com/iamv2/home?region=eu-west-1#/organization/accounts)
This should allow you to see the account in your AWS access portal. The URL is on the IAM Identity Center landing page to the right. Once in, you should assume the administrator user to get the info of the below.
You will need an IAM admin user in your newly created account, something similar to the below, iam.tf:
# Groups
resource "aws_iam_group" "administrators" {
name = "administrators"
lifecycle {
prevent_destroy = true
}
}
# Group Policies
resource "aws_iam_group_policy_attachment" "administrators" {
group = aws_iam_group.administrators.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
resource "aws_iam_group_policy_attachment" "IAMUserChangePassword" {
group = aws_iam_group.administrators.name
policy_arn = "arn:aws:iam::aws:policy/IAMUserChangePassword"
}
# Create iam user
module "iam_iam-user-administrator" {
source = "terraform-aws-modules/iam/aws//modules/iam-user"
version = "5.3.3"
name = var.name
}
resource "aws_iam_user_group_membership" "administrators" {
user = var.name
groups = [aws_iam_group.administrators.name]
depends_on = [
module.iam_iam-user-administrator
]
}
resource "aws_ssm_parameter" "iam_user_login_profile_password" {
name = "/iam/user/${var.name}/iam_user_login_profile_password"
type = "SecureString"
value = module.iam_iam-user-administrator.iam_user_login_profile_password
depends_on = [
module.iam_iam-user-administrator
]
}
resource "aws_ssm_parameter" "iam_access_key_secret" {
name = "/iam/user/${var.name}/iam_access_key_secret"
type = "SecureString"
value = module.iam_iam-user-administrator.iam_access_key_secret
depends_on = [
module.iam_iam-user-administrator
]
}
Add the above to your new account aft-account-customizations repo and commit/push and run codepipeline. Once complete you should have an account to use locally. And well, to login to your new account as admin as well.
You can log into your new account via your AFT Control account(Billing account). Once in, the saved credentials are in the ssm parameters section. You will need your AWS Key, which is on the user created above and the AWS Secret which is in the ssm parameters to create your AWS profile locally:
vim ~/.aws/credentials
[your_new_account]
aws_access_key_id=aws_access_key_id
aws_secret_access_key=aws_secret_access_key
region=eu-region
Create an alias to your new account using your bash rc file. I use zsh, so inmy ~/.zshrc, added: vim ~/.zshrc
alias terraform_your_new_account = 'AWS_PROFILE=your_new_account terraform'
Save your new account account id as you will need that later below.
Create a backend override config in the customization terraform root
aft-account-customizations/your_new_account/backend_override.tf
terraform {
required_version = ">= 0.15.0"
backend "s3" {
region = "{aft-management-region}"
bucket = "aft-backend-{aft-management-account-id}-primary-region"
key = "{account-id}-aft-account-customizations/terraform.tfstate"
encrypt = "true"
kms_key_id = "{aft-management-kms-key}"
}
}
Please use your own values for the below variables: aft-management-region aft-management-account-id account-id aft-management-kms-key
Made it an override so as not to commit it to CVS.
Create a local provider in customization terraform root
aft-account-customizations/your_new_account/provider.tf
# Used for local terraform init and validate to work.
provider "aws" {
alias = "main"
region = "{account-region}"
assume_role {
role_arn = "arn:aws:iam::{aft-management-account-id}:role/AWSAFTAdmin"
}
default_tags {
tags = {
managed_by = "AFT"
}
}
}
Please use your own values for the below variables: account-region aft-management-account-id
Remember to add provider.tf to .gitignore. You don't want that in CVS.
Update trust entity for AWSAFTAdmin role:
https://us-east-1.console.aws.amazon.com/iamv2/home?region=eu-west-1#/roles/details/AWSAFTAdmin?section=trust_relationships
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{account_id}:user/{iam_user}"
},
"Action": "sts:AssumeRole"
},
Please use your own values for the below variables: account_id iam_user
This role can be found in the AWS AFT Management account. Hint: Use your browser profiles to switch between AWS accounts. Instead of the role switching AWS provides as it is very iffy!
Include the user you will use to access terraform as.
Update state file S3 bucket permissions: https://s3.console.aws.amazon.com/s3/buckets/aft-backend-035819274757-primary-region?region=eu-west-1&tab=permissions
{
"Sid": "account_id",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{account_id}:user/{iam_user}"
},
"Action": [
"s3:GetObject"
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::aft-backend-{aft-management-account-id}-primary-region"
"arn:aws:s3:::aft-backend-{aft-management-account-id}-primary-region/{account_id}-aft-account-customizations/*"
]
}
Please use your own values for the below variables: account_id iam_user aft-management-account-id
This bucket can be found in the AWS AFT Management account.
Grant KMS access
Add the following terraform to the aft-account-provisioning-customizations repo.
resource "aws_kms_grant" "cross-account-grants-{account_id}-{iam_user}" {
grantee_principal = "arn:aws:iam::{account_id}:user/{iam_user}"
key_id = data.aws_kms_key.aft-backend.id
operations = ["Encrypt", "Decrypt", "DescribeKey", "ReEncryptFrom", "ReEncryptTo", "GenerateDataKey"]
}
Please use your own values for the below variables: account_id iam_user
Push those changes to allow the grants to be added. Once the pipeline has completed running, execute the following to see grants:
aws kms list-grants --key-id {kms_key_arn} --profile aft-management
Running locally
You should now be able to run the following on your local machine:
terraform_your_new_account -chdir=your_repo/new_account/terraform init -reconfigure
This should reconfigure your state file to be the one on S3 in the AFT Management account. Next you can do a validate and see if all is well:
terraform_your_new_account -chdir=your_repo/new_account/terraform validate
And then, after all that:
terraform_your_new_account -chdir=your_repo/new_account/terraform plan
Hope that helps.
Regards, Jarrett
https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/validate-account-factory-for-terraform-aft-code-locally.html. I hope this helps to run locally , thanks !