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

    1. Acesse o Console da AWS da conta de gerenciamento do CT e vá para o AWS Service Catalog.
    2. Clique na guia “Portfolio” e selecione o portfolio “AWS Control Tower Account Factory Portfolio”.

Figura 1: Exemplo de Portfolio

  1. Na guia “Access”, clique no botão “Grant Access”.
  1. Digite “AWSAFTExecution” na caixa de pesquisa e selecione a função IAM correspondente.
  2. Clique em “Grant Access” para conceder acesso à função IAM.
  3. Você vera o AWSAFTExecution como na imagem abaixo

Figura 2: Exemplo de AWSAFTExecution

Via AWS CLI

  1. 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
  1. 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://catalog.workshops.aws/control-tower/en-US/customization/aft/repositories/provisioning-customizations

https://controltower.aws-management.tools/automation/aft_repo/

https://docs.aws.amazon.com/controltower/latest/userguide/aft-getting-started.html

 

Relacionados:

Acelere sua jornada em nuvem AWS através do uso da estrutura de múltiplas contas e Account Factory for Terraform (AFT) – Parte 1

Acelere sua jornada em nuvem AWS através do uso da estrutura de múltiplas contas e Account Factory for Terraform (AFT) – Parte 3


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.