O blog da AWS
Acelere sua jornada em nuvem AWS através do uso da estrutura de múltiplas contas e Account Factory for Terraform (AFT) – Parte 2
Por Lucas Leme Lopes, Arquiteto de Infraestrutura Cloud, AWS;
Rubens Macegossa Dias, Arquiteto de Infraestrutura Cloud, AWS;
e Victor Okuhama, Arquiteto de Aplicação Cloud, AWS.
Configurando e Implementando AFT
Requisitos
Aqui estão os requisitos para você instalar o AFT:
- Você deve ter um ambiente AWS Control Tower implantado. Siga esta documentação caso precise criar um AWS Control Tower.
- Você deve ter o Terraform, Git e AWS CLI instalados.
- Você precisa criar uma conta AWS específica para gerenciar o AFT.
Para este blogpost, a conta que contém o AWS Control Tower implantada é chamada de conta de gerenciamento do Control Tower e a conta AWS específica para o AFT é chamado de conta de gerenciamento do AFT.
Implementando o AFT
Configurando o módulo de criação do AFT
Crie um arquivo main.tf e adicione o código abaixo
module "aft_pipeline" {
source = "github.com/aws-ia/terraform-aws-control_tower_account_factory"
# Required Variables
ct_management_account_id = "<Conta-CT>"
log_archive_account_id = "<Conta-Log>"
audit_account_id = "<Conta-Audit>"
aft_management_account_id = "<Conta-AFT>"
ct_home_region = "<Regiao-CT>"
tf_backend_secondary_region = "<Regiao-Alternativa">
# Terraform variables
terraform_version = "0.15.5"
terraform_distribution = "oss"
# VCS variables
vcs_provider = "codecommit"
# AFT Feature flags
aft_feature_cloudtrail_data_events = false
aft_feature_enterprise_support = false
aft_feature_delete_default_vpcs_enabled = true
}
Edite os <PLACEHOLDERS> com as configurações do seu ambiente, sendo:
**⚠️ O campo <ct_home_region> deve ser a mesma região em que Amazon Control Tower foi implementado. **
- ct_management_account_id – ID da conta de gerenciamento do Control Tower
- log_archive_account_id – ID da conta de log do Control Tower
- audit_account_id – ID da conta de audit do Control Tower
- aft_management_account_id – ID da conta de gerenciamento do AFT
- ct_home_region – Região AWS na qual o Control Tower foi implantado
- tf_backend_secondary_region – Região AWS para backup dos estados do terraform.
Por padrão, as feature flags vem desabilitadas e tem as seguintes funcionalidades:
- aft_feature_cloudtrail_data_events – Habilita eventos de dados do AWS CloudTrail em novas contas.
- aft_feature_enterprise_support – Habilita suporte empresarial em novas contas, caso você tenha o plano.
- aft_feature_delete_default_vpcs_enabled – Deleta a VPC padrão em novas contas.
Para este blogpost foi utilizado o versionamento de código com o AWS CodeCommit. Entretanto, para utilizar o VCS terceiros, veja aqui como fazer passo a passo.
Executando o código terraform na conta de gerenciamento do Control Tower
Autentique-se na conta de gerenciamento do Control Tower via terminal e execute os comandos abaixo:
terraform init
terraform plan
terraform apply
A implementação levará aproximadamente 30 minutos para ser efetuada, criando as configurações iniciais da arquitetura descrita. Após a implementação ser realizada, o próximo passo é garantir que a IAM Role AWSAFTExecution tenha acesso ao AWS Service Catalog.
Garantindo acesso via AWS Service Catalog
Para permitir que a conta de gerenciamento do AFT consiga criar novas contas é necessário que a IAM Role AWSAFTExecution tenha acesso para executar o Service Catalog dentro da conta de gerenciamento do AFT.
Siga as etapas abaixo para conceder acesso ao AWS Service Catalog:
Via AWS Console
-
- Acesse o Console da AWS da conta de gerenciamento do CT e vá para o AWS Service Catalog.
- Clique na guia “Portfolio” e selecione o portfolio “AWS Control Tower Account Factory Portfolio”.
Figura 1: Exemplo de Portfolio
- Na guia “Access”, clique no botão “Grant Access”.
- Digite “AWSAFTExecution” na caixa de pesquisa e selecione a função IAM correspondente.
- Clique em “Grant Access” para conceder acesso à função IAM.
- Você vera o AWSAFTExecution como na imagem abaixo
Figura 2: Exemplo de AWSAFTExecution
Via AWS CLI
- Assuma a conta de gerenciamento do CT e rode o comando abaixo.
sudo yum install jq -y
export ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
export AWS_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
export ACCOUNT_FACTORY_PORTFOLIO=`aws servicecatalog list-portfolios --region $AWS_REGION | jq -r '.PortfolioDetails[] | select (.DisplayName | contains("AWS Control Tower Account Factory Portfolio")) | .Id'`
AWSAFTEXECUTION_ROLE="arn:aws:iam::${ACCOUNT_ID}:role/AWSAFTExecution"
aws servicecatalog associate-principal-with-portfolio --portfolio-id $ACCOUNT_FACTORY_PORTFOLIO --principal-arn $AWSAFTEXECUTION_ROLE --principal-type IAM --region $AWS_REGION
- Valide com o seguinte comando
aws servicecatalog list-principals-for-portfolio --portfolio-id $ACCOUNT_FACTORY_PORTFOLIO --region $AWS_REGION | jq -r
'.Principals[] | .PrincipalARN' | grep AWSAFTExecution -q && echo "Portfolio shared to AWSAFTExecution" || echo "Portfolio not shared
properly"
Com isso, você garante que a IAM Role AWSAFTExecution tenha permissão para executar o Service Catalog na conta de gerenciamento do AFT. Agora você pode usar o Terraform para criar novas contas AWS, assim como faz para criar recursos de infraestrutura AWS.
Repositórios AFT
Na conta de gerenciamento do AFT, existem 4 repositórios no AWS CodeCommit que são utilizados pelas pipelines do AWS CodePipeline para automatizar a criação de contas. Cada repositório contém uma finalidade específica:
Figura 3: Exemplo da conta de gerenciamento com os repositórios criados
aft-account-customizations
Repositório responsável por criar recursos customizados por definições de ambiente (Desenvolvimento, Homologação e Produção) ou qualquer tipo de organização lógica, tendo como única regra de ser o mesmo valor do parâmetro account_customizations_name do repositório aft-account-request.
Você pode criar pastas personalizadas dentro deste repositório para diferentes configurações.
Aqui temos um exemplo de estrutura de pastas dentro deste repositório, temos duas pastas customizadas que correspondem à PRODUCTION e SANDBOX.
aft-account-customizations/
── PRODUCTION
│ ├── api_helpers
│ │ ├── post-api-helpers.sh
│ │ ├── pre-api-helpers.sh
│ │ └── python
│ │ └── requirements.txt
│ └── terraform
│ ├── aft-providers.jinja
│ ├── backend.jinja
│ └── main.tf
└── SANDBOX
├── api_helpers
│ ├── post-api-helpers.sh
│ ├── pre-api-helpers.sh
│ └── python
│ └── requirements.txt
└── terraform
├── aft-providers.jinja
├── backend.jinja
└── main.tf
A finalidade dos auxiliares de API (pasta api_helpers) é executar ações que não podem ser executadas no Terraform e que podem ser atendidas com Python e Bash.
Instalando bibliotecas Python
A pasta api_helpers/python contém um requirements.txt, onde você pode especificar as bibliotecas/pacotes a serem instalados via PIP.
Scripts Bash – pre-api-helper.sh e post-api-helpers.sh
É aqui que você define o que é executado antes/depois do Terraform, bem como a ordem de execução dos scripts Python, juntamente com quaisquer parâmetros de linha de comando. Esses scripts bash podem ser estendidos para executar outras ações, como aproveitar a AWS CLI ou executar scripts Bash adicionais/personalizados.
- pre-api-helpers.sh – Ações a serem executadas antes de executar o Terraform.
- post-api-helpers.sh – Ações a serem executadas após a execução do Terraform.
aft-global-customizations
Repositório responsável por criar customizações globais em todas as contas. Exemplo: Bloquear acesso S3 público.
Aqui temos um exemplo de estrutura de pastas dentro deste repositório.
aft-global-customizations/
── api_helpers
│ ├── post-api-helpers.sh
│ ├── pre-api-helpers.sh
│ └── python
│ └── requirements.txt
└── terraform
├── aft-providers.jinja
├── backend.jinja
└── main.tf
Por funcionar a nível global, não é preciso especificar a pasta customizada como no repositório aft-account-customizations.
Contém a pasta api_helpers que auxiliam da mesma forma que no repositório aft-account-customizations.
aft-account-provisioning-customizations
Repositório responsável por usar AWS Step Functions para customizar e provisionar recursos que requerem mais customizações.
Por exemplo, você pode precisar de integração com sistema externo. A personalização de provisionamento é implementada antes da customização da conta e do estágio de personalização global.
Aqui temos um exemplo de estrutura de pastas dentro deste repositório.
aft-account-provisioning-customizations/
└── terraform
├── aft-providers.jinja
├── backend.jinja
├── iam
│ ├── role-policies
│ │ └── iam-aft-states.tpl
│ └── trust-policies
│ └── states.tpl
├── iam.tf
├── states
│ └── customizations.asl.json
├── states.tf
└── versions.tf
aft-account request
Repositório responsável pela criação de novas contas. Você precisa fornecer informações obrigatórias, como o endereço de e-mail e a unidade organizacional (OU). Cada vez que você adiciona ou modifica este repositório no AWS CodeCommit, o arquivo Terraform é confirmado no repositório e então aciona a pipeline do AFT.
Aqui temos um exemplo de estrutura de pastas dentro deste repositório.
aft-account-request/
├── terraform
│ ├── modules
│ │ └── aft-account-request
│ │ ├── ddb.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── account-imports.tf
│ ├── account-requests.tf
│ ├── aft-providers.jinja
│ ├── backend.jinja
Exemplo de arquivo terraform para criação de conta:
module "sandbox_account_01" {
source = "./modules/aft-account-request"
control_tower_parameters = {
AccountEmail = "john.doe@amazon.com"
AccountName = "sandbox-account-01"
# Syntax for top-level OU
ManagedOrganizationalUnit = "Sandbox"
# Syntax for nested OU
# ManagedOrganizationalUnit = "Sandbox (ou-xxxx-xxxxxxxx)"
SSOUserEmail = "john.doe@amazon.com"
SSOUserFirstName = "John"
SSOUserLastName = "Doe"
}
account_tags = {
"ABC:Owner" = "john.doe@amazon.com"
"ABC:Division" = "ENT"
"ABC:Environment" = "Dev"
"ABC:CostCenter" = "123456"
"ABC:Vended" = "true"
"ABC:DivCode" = "102"
"ABC:BUCode" = "ABC003"
"ABC:Project" = "123456"
}
change_management_parameters = {
change_requested_by = "John Doe"
change_reason = "testing the account vending process"
}
custom_fields = {
custom1 = "a"
custom2 = "b"
}
account_customizations_name = "SANDBOX"
}
O campo AccountName não pode conter caracteres especiais (exceto `-`) ou espaço.
Os campos acima tem a função de:
- control_tower_parameterers – Capturar as entradas obrigatórias para criar uma conta gerenciada do AWS Control Tower.
- account_tags – Capturar chaves e valores definidos pelo usuário para taggear contas da AWS.
- change_management_parameters – Capturar o motivo da criação da conta.
- custom_fields – Capturar chaves e valores customizados que são gerados automaticamente no SSM Parameter Store.
- account_customizations_name (Opcional) Nome de uma personalização de conta fornecida pelo cliente a ser aplicada quando a conta for provisionada.
Importante lembrar da relação do campo account_customization_name com o repositório aft-account-customizations, temos neste exemplo, o campo account_customization_name como SANDBOX e temos a pasta SANDBOX dentro de aft-account-customizations.
Utilizando o AFT
Para utilizar o AFT é necessário usar apenas a conta de gerenciamento do AFT e ter o código terraform armazenado dentro dos repositórios do AWS CodeCommit.
Para isso é necessário, implementar os códigos de infraestrutura (IaC) dentro dos repositórios dentro do AWS CodeCommit.
Primeiro, vamos implementar o código dentro do repositório
aft-account-customizations
- Responsável por gerar toda a customização de acordo com o flavor.
Assuma a conta de gerenciamento do AFT e rode o comando abaixo
AWS_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
AFT_ACCOUNT_CUSTOMIZATIONS_BRANCH=`aws ssm get-parameter --name /aft/config/account-customizations/repo-branch --region $AWS_REGION | jq -r ".Parameter.Value"`
AFT_ACCOUNT_CUSTOMIZATIONS_HTTP=`aws codecommit get-repository --repository-name $AFT_ACCOUNT_CUSTOMIZATIONS_REPO --region $AWS_REGION | jq -r ".repositoryMetadata.cloneUrlHttp"`
git clone --branch $AFT_ACCOUNT_CUSTOMIZATIONS_REPO https://github.com/aws-samples/aft-account-customizations-examples
cd aft-account-customizations-examples
rm -rf .git
git init
git remote add origin $AFT_ACCOUNT_CUSTOMIZATIONS_HTTP
git add .
git commit -m 'first commit'
git branch -m $AFT_ACCOUNT_CUSTOMIZATIONS_BRANCH
git push --set-upstream origin $AFT_ACCOUNT_CUSTOMIZATIONS_BRANCH
aft-global-customization
- Irá conter uma regra global para não permitir acesso público ao S3.
Assuma a conta de gerenciamento do AFT e rode o comando abaixo
AWS_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
AFT_GLOBAL_CUSTOMIZATIONS_REPO=`aws ssm get-parameter --name /aft/config/global-customizations/repo-name --region $AWS_REGION | jq -r ".Parameter.Value"`
AFT_GLOBAL_CUSTOMIZATIONS_BRANCH=`aws ssm get-parameter --name /aft/config/global-customizations/repo-branch --region $AWS_REGION | jq -r ".Parameter.Value"`
AFT_GLOBAL_CUSTOMIZATIONS_HTTP=`aws codecommit get-repository --repository-name $AFT_GLOBAL_CUSTOMIZATIONS_REPO --region $AWS_REGION | jq -r ".repositoryMetadata.cloneUrlHttp"`
git clone --branch $AFT_GLOBAL_CUSTOMIZATIONS_REPO https://github.com/aws-samples/aft-workshop-sample $AFT_GLOBAL_CUSTOMIZATIONS_REPO
cd $AFT_GLOBAL_CUSTOMIZATIONS_REPO
rm -rf .git
git init
git remote add origin $AFT_GLOBAL_CUSTOMIZATIONS_HTTP
git add .
git commit -m 'first commit'
git branch -m $AFT_GLOBAL_CUSTOMIZATIONS_BRANCH
git push --set-upstream origin $AFT_GLOBAL_CUSTOMIZATIONS_BRANCH
aft-account-request
- Responsável por criar contas AWS de acordo os parâmetros setados.
Assuma a conta de gerenciamento do AFT e rode o comando abaixo
AWS_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
AFT_ACCOUNT_REQUEST_REPO=`aws ssm get-parameter --name /aft/config/account-request/repo-name --region $AWS_REGION | jq -r ".Parameter.Value"`
AFT_ACCOUNT_REQUEST_BRANCH=`aws ssm get-parameter --name /aft/config/account-request/repo-branch --region $AWS_REGION | jq -r ".Parameter.Value"`
AFT_ACCOUNT_REQUEST_HTTP=`aws codecommit get-repository --repository-name $AFT_ACCOUNT_REQUEST_REPO --region $AWS_REGION | jq -r ".repositoryMetadata.cloneUrlHttp"`
git clone --branch $AFT_ACCOUNT_REQUEST_REPO https://github.com/aws-samples/aft-workshop-sample $AFT_ACCOUNT_REQUEST_REPO
cd $AFT_ACCOUNT_REQUEST_REPO
rm -rf .git
git init
git remote add origin $AFT_ACCOUNT_REQUEST_HTTP
git add .
git commit -m 'first commit'
git branch -m $AFT_ACCOUNT_REQUEST_BRANCH
git push --set-upstream origin $AFT_ACCOUNT_REQUEST_BRANCH
Com todos os repositórios com os seus respectivos códigos, estamos com o setup pronto para criação de contas de modo dinâmico, clique aqui para acessar a parte III deste blogpost, vamos criar contas usando o AFT e com os seguintes exemplos de customização:
- Criação da conta;
- 4 tipos de contas: DEV / HML / PRD / PIPE
- Criação de VPC + Alocação de IP em uma planilha;
- Cada conta terá sua VPC sem overlapping.
- Criação de Roles cross-account para esteiras CI/CD;
- Necessário para rodar as pipelines de forma transparente.
- Criação da estrutura de deploy + esteiras CI/CD
- Necessário para rodar as pipelines de forma transparente.
Referências
https://controltower.aws-management.tools/automation/aft_repo/
https://docs.aws.amazon.com/controltower/latest/userguide/aft-getting-started.html
Relacionados:
Sobre os autores
Lucas Leme Lopes é Arquiteto de Infraestrutura Cloud e atua no atendimento de clientes do setor público. Trabalha com soluções de Cloud há mais de 7 anos com o propósito de ajudar clientes a resolverem demandas através de tecnologia.
Rubens Macegossa Dias é Arquiteto de Infraestrutura Cloud na AWS e atua no time de Public Sector apoiando clientes em sua jornada para a nuvem. Possui mais de 17 anos de experiencia na área de T.I. onde atuou em multinacionais nos setores Alimentício, Industrial e de Tecnologia.
Victor Okuhama é Arquiteto de Aplicação Cloud e atua na área de Serviços Profissionais para o setor público. Seu conhecimento é em desenvolvimento de software e infraestrutura, antes de se juntar AWS, atuou como desenvolvedor backend na área de finanças.