tfswitch 1.3.9
terraform init
awsume iam
It is possible to have a full workspace specific set of accounts if needed. Adjust variables.tf for this.
terraform workspace new training
terraform workspace new <customer>
Add to ~/.aws/config
[profile <customer>]
role_arn = arn:aws:iam::<accountid>:role/cloudpartners-iam
source_profile = iam
The settings in variables.tf
set up the providers needed in provider.tf
, but require a terraform
role on the target accounts.
The template is cross-account-access-terraform.yaml
and has to be added
awsume training
aws cloudformation create-stack --stack-name CrossAccountAccessTerraform --capabilities CAPABILITY_NAMED_IAM --template-body file://cross-account-access-terraform.yaml
awsume iam
awsume <customer>
aws cloudformation create-stack --stack-name CrossAccountAccessTerraform --capabilities CAPABILITY_NAMED_IAM --template-body file://cross-account-access-terraform.yaml
aws s3 mb s3://<accountid>-<customer>-terraform-state
awsume iam
awsume controltower
aws cloudformation create-stack --stack-name CrossAccountAccessTerraform --capabilities CAPABILITY_NAMED_IAM --template-body file://cross-account-access-terraform.yaml
awsume shared-services
aws cloudformation create-stack --stack-name CrossAccountAccessTerraform --capabilities CAPABILITY_NAMED_IAM --template-body file://cross-account-access-terraform.yaml
Note that we have prepared a bucket for the terraform state. This bucket is referred in backend.tf
too.
Some of the elements we are using in this project do no play nice with parallel execution currently:
│ Error: creating Service Catalog Portfolio Share: InvalidStateException: Cannot process more than one portfolio share action at the same time. Try again later.
│
│ with module.portfolio.aws_servicecatalog_portfolio_share.organizational_units[0],
│ on portfolio/main.tf line 40, in resource "aws_servicecatalog_portfolio_share" "organizational_units":
│ 40: resource "aws_servicecatalog_portfolio_share" "organizational_units" {
This can be fixed by explicitly setting parallelism to 1, as indicated below.
SharedService Service Catalog delegated master
awsume controltower
aws organizations enable-aws-service-access --service-principal servicecatalog.amazonaws.com
aws organizations enable-aws-service-access --service-principal member.org.stacksets.cloudformation.amazonaws.com
aws organizations list-aws-service-access-for-organization
awsume controltower
aws organizations list-delegated-administrators
# aws organizations list-accounts
delegated=$(aws organizations list-accounts | jq -r '.Accounts[] | select(.Name=="SharedServices") | .Id')
aws organizations register-delegated-administrator --account-id $delegated --service-principal servicecatalog.amazonaws.com
aws organizations list-delegated-administrators
aws organizations list-delegated-services-for-account --account-id 940740948575
https://docs.aws.amazon.com/cli/latest/reference/organizations/enable-aws-service-access.html
awsume controltower
aws organizations enable-aws-service-access --service-principal stacksets.cloudformation.amazonaws.com
aws organizations register-delegated-administrator --account-id $delegated --service-principal stacksets.cloudformation.amazonaws.com
aws organizations enable-aws-service-access --service-principal member.org.stacksets.cloudformation.amazonaws.com
aws organizations register-delegated-administrator --account-id $delegated --service-principal member.org.stacksets.cloudformation.amazonaws.com
aws organizations list-delegated-services-for-account --account-id 940740948575
/*
resource "aws_organizations_delegated_administrator" "on_master" {
provider = aws.master
account_id = local.account_id
service_principal = "servicecatalog.amazonaws.com"
}
*/
/*
terraform import aws_organizations_delegated_administrator.on_master 940740948575/servicecatalog.amazonaws.com
terraform state rm aws_organizations_delegated_administrator.on_master
*/
awsume shared-services
aws servicecatalog create-portfolio --display-name SharedServices --description 'Service Catalog shared portfolio' --provider-name "Base"
export portfolio=$(aws servicecatalog list-portfolios | jq -r '.PortfolioDetails[] | select(.DisplayName=="SharedServices") | .Id')
echo $portfolio
awsume controltower
aws ssm put-parameter --name '/org/sharedservices/servicecatalog/sharedportfolioid' --value $portfolio --description 'Service Catalog shared portfolio id' --type String --overwrite
export oid=$(aws organizations describe-organization --query Organization.Id --output text)
echo $oid
awsume shared-services
aws servicecatalog create-portfolio-share --portfolio-id $portfolio --organization-node Type=ORGANIZATION,Value=$oid
Make sure, that the SharedService account is registered as a delegated administrator
# products need to be created first and `depends_on` isn't enough to ensure that.
mv portfolio_* off
TF_CLI_ARGS_apply="-parallelism=1"
terraform apply
# (may have to be repeated a few times)
mv off/portfolio_* .
TF_CLI_ARGS_apply="-parallelism=1"
terraform apply
# (may have to be repeated a few times)
awsume iam
terraform destroy
# (may have to be repeated a few times)
Terraform can't really handle the deletion of stack-instances as they are not part of the initial deployment, so they have to be deleted manually.
awsume controltower
aws organizations list-organizational-units-for-parent --parent-id r-fmly
aws cloudformation list-stack-sets --status ACTIVE
# Custom
aws cloudformation delete-stack-instances --stack-set-name ServiceCatalogAccessStackSet-NiceHelpersTerraform --regions eu-west-1 --no-retain-stacks --deployment-targets OrganizationalUnitIds=ou-fmly-09e0b44o
# Juniors
aws cloudformation delete-stack-instances --stack-set-name ServiceCatalogAccessStackSet-NiceHelpersTerraform --regions eu-west-1 --no-retain-stacks --deployment-targets OrganizationalUnitIds=ou-fmly-t5qr49c2
awsume iam
terraform destroy