AWS Certified CloudOps Engineer - Associate

CloudFormation StackSets

Implantar um template em muitas contas e Regiões com uma operação só: stack sets e stack instances, permissões self-managed contra service-managed, targets de implantação e filtros de conta, concorrência e tolerância a falhas, drift, e as falhas que se escondem atrás de um status SUCCEEDED.

Intermediário 30 minutos 7 Objetivos de aprendizado
  1. Distinguir stack set, stack instance e stack, e explicar por que uma stack instance pode existir sem stack
  2. Escolher entre permissões self-managed e service-managed, e nomear as roles que cada modelo exige
  3. Apontar para uma organização, para OUs específicas ou para contas filtradas, e prever quais contas recebem uma stack
  4. Ajustar tolerância a falhas, máximo de contas concorrentes e concorrência de Regiões conforme o risco da implantação
  5. Interpretar os códigos de status de stack set e de stack instance, incluindo OUTDATED e INOPERABLE
  6. Explicar como a detecção de drift em um stack set difere da detecção em uma stack individual
  7. Diagnosticar as falhas comuns de StackSets, incluindo uma operação que reporta SUCCEEDED com stacks falhadas

Um time de segurança precisa de uma role IAM só de leitura, um recorder do Config e uma regra de envio de logs em 40 contas e 4 Regiões. São 160 stacks. A versão em script é um loop que assume uma role em cada conta e chama create-stack, e funciona até a conta 23 bater em um service quota, o loop seguir em frente e ninguém perceber por três semanas que quatro contas estão sem recorder do Config.

O problema não é o loop. É que o loop não tem memória. Nada registra que aquelas 160 stacks deveriam ser a mesma coisa, então nada consegue te dizer quais estão atualizadas, quais falharam e quais alguém editou na mão.

StackSets é essa memória. Você define o template uma vez, nomeia as contas e as Regiões, e o CloudFormation rastreia cada stack resultante como parte de um conjunto gerenciado.

Stack set, stack instance, stack

Três palavras que parecem intercambiáveis e não são.

Um stack set é o contêiner: um template, um conjunto de parameters e a configuração de implantação. Ele vive na conta administradora e é um recurso regional. Crie um stack set em eu-west-1 e você não vai vê-lo com o console em us-east-1, o que surpreende quem assume que um recurso multi-Região precisa ser global.

Uma stack instance é uma referência a uma stack em uma conta alvo dentro de uma Região. Três contas em duas Regiões dão 6 stack instances, e cada uma carrega o próprio status.

Uma stack é a stack comum do CloudFormation que de fato guarda recursos, na conta alvo.

A separação entre instance e stack parece preciosismo de nomenclatura até a primeira falha. Uma stack instance pode existir sem stack: se a criação falhou, não existe stack, mas a instance sobrevive e guarda o motivo. É isso que torna um rollout falhado diagnosticável em vez de invisível.

aws cloudformation list-stack-instances --stack-set-name org-baseline \
  --filters Name=DETAILED_STATUS,Values=FAILED

Dois modelos de permissão, uma escolha real

Implantar em outra conta significa assumir uma role lá. O StackSets te dá dois jeitos de organizar isso, e a prova testa qual deles um cenário obriga.

Permissões self-managed significam que você monta o elo de confiança na mão, com duas roles cujos nomes importam:

  • AWSCloudFormationStackSetAdministrationRole na conta administradora. A trust policy dela permite que cloudformation.amazonaws.com a assuma, e a permissions policy permite sts:AssumeRole na execution role dos alvos.
  • AWSCloudFormationStackSetExecutionRole em cada conta alvo, confiando na conta administradora. Essa role precisa de permissão total no CloudFormation mais permissão para tudo que o template cria.

Use exatamente esses nomes e o StackSets os encontra sozinho. Use nomes customizados e toda operação precisa nomear as roles explicitamente. Os templates de exemplo que a AWS publica para essas roles dão "Action": "*" na execution role, o que serve para um primeiro teste e está errado para qualquer coisa permanente. Reduza a execution role para os tipos de recurso que o seu template realmente cria, porque aquela role é o teto do que qualquer operação de stack set consegue fazer naquela conta.

Permissões service-managed entregam o problema das roles para o CloudFormation. Você ativa o trusted access entre o CloudFormation e o AWS Organizations e, dali em diante, o CloudFormation cria e mantém as roles nas contas membro para você. Você aponta para OUs em vez de listar account IDs, e ganha implantação automática.

Self-managedService-managed
Contas alvoQualquer conta onde você consiga criar uma roleSó contas da sua organização
Configuração das rolesVocê cria as duasO CloudFormation cria
Alvos informados comoAccount IDsRaiz da organização ou IDs de OU
Conta nova entra na OUNada aconteceA implantação automática adiciona uma stack
Roda de ondeQualquer contaConta de gerenciamento ou um delegated administrator
Nested stacks, macros, transformsAceitosNão aceitos

Duas restrições do modelo service-managed valem decorar, porque contradizem o que as pessoas supõem.

A conta de gerenciamento nunca recebe uma stack. Aponte para a organização inteira e o CloudFormation ainda pula ela. Se a conta de gerenciamento precisa do mesmo baseline, ela ganha a própria stack ou o próprio stack set self-managed.

Delegated administrators não podem ser limitados. A conta de gerenciamento pode registrar até 5 contas membro como delegated administrators, então um time central de plataforma roda stack sets em toda a organização sem ter credenciais da conta de gerenciamento. Mas um delegated administrator alcança todas as contas da organização. Não existe uma configuração do tipo "este time só pode implantar na OU Sandbox".

aws organizations register-delegated-administrator \
  --service-principal member.org.stacksets.cloudformation.amazonaws.com \
  --account-id 444455556666

Da conta delegated administrator, todo comando carrega --call-as DELEGATED_ADMIN. Deixe isso de fora e a CLI procura stack sets self-managed na própria conta membro, não acha nada e devolve uma lista vazia que parece problema de permissão.

Escolher quem recebe uma stack

Com permissões service-managed, os targets de implantação são a raiz da organização ou uma lista de IDs de OU. Apontar para uma OU pai inclui as filhas automaticamente, que é o comportamento desejado para um baseline de segurança e o comportamento que te pega quando uma OU de sandbox aninhada herda uma policy de produção.

Por padrão, toda conta de uma OU alvo recebe uma stack. Os filtros de conta estreitam isso:

Tipo de filtroSignificado
NONE (padrão)Todas as contas das OUs listadas
INTERSECTIONSó as contas listadas, e só se estiverem nas OUs listadas
DIFFERENCETodas as contas das OUs listadas, exceto as contas listadas
UNIONTodas as contas das OUs listadas, mais as contas listadas
aws cloudformation create-stack-instances --stack-set-name org-baseline \
  --deployment-targets OrganizationalUnitIds=ou-rcuk-1x5j1lwo,Accounts=111122223333,AccountFilterType=DIFFERENCE \
  --regions eu-west-1 us-east-1

DIFFERENCE é o que se paga na prática. Um baseline vale para a OU Workloads inteira, menos a única conta legada que quebraria, e você expressa essa exceção na implantação em vez de tirar a conta da OU dela.

Concorrência e tolerância a falhas

Empurrar um template para 160 lugares de uma vez é um jeito eficiente de quebrar 160 lugares de uma vez. Quatro configurações controlam o raio de impacto, e elas interagem.

Máximo de contas concorrentes limita quantas contas alvo uma operação toca ao mesmo tempo, em número ou percentual. Percentuais arredondam para baixo: 25 por cento de 10 contas é 2, não 3.

Tolerância a falhas é o número ou percentual de falhas permitidas por Região antes de o CloudFormation parar. Também arredonda para baixo.

Concorrência de Regiões é SEQUENTIAL (o padrão, uma Região por vez na ordem de implantação que você definiu) ou PARALLEL (todas as Regiões de uma vez).

Concurrency mode decide o que acontece com a concorrência quando as falhas começam. STRICT_FAILURE_TOLERANCE mantém o máximo de contas concorrentes em no máximo tolerância a falhas mais 1, e desacelera conforme as falhas acumulam. SOFT_FAILURE_TOLERANCE mantém o seu nível de concorrência de qualquer forma.

Vamos andar por uma operação. Você implanta em 10 contas em eu-west-1, us-east-1 e ap-southeast-2, nessa ordem de implantação, com tolerância a falhas de 20 por cento, máximo de contas concorrentes de 50 por cento e Regiões sequenciais.

  1. 20 por cento de 10 arredonda para baixo e dá 2 falhas permitidas por Região. 50 por cento de 10 dá 5 contas por vez.
  2. eu-west-1 roda 5 contas, depois as outras 5. Duas falham. É exatamente a tolerância, então a Região termina e a operação segue.
  3. us-east-1 roda e uma terceira conta falha naquela Região. A tolerância foi excedida ali, então o status da operação vira FAILED e ap-southeast-2 é cancelada inteira.

A tolerância a falhas reinicia por Região. É isso que faz da implantação sequencial um mecanismo de segurança útil: um template quebrado em todo lugar falha na primeira Região e nunca chega nas outras.

Os padrões são deliberadamente tímidos, MaxConcurrentCount=1 e FailureToleranceCount=0 nos exemplos da CLI, o que significa uma conta por vez e parada na primeira falha. Para o primeiro rollout de um template novo, é a escolha certa. Aumente depois que o template provar que funciona.

Status, e o que engana

As operações de stack set reportam RUNNING, SUCCEEDED, FAILED, QUEUED, STOPPING ou STOPPED. QUEUED aparece com implantação automática: mova uma conta entre OUs e o StackSets roda um delete da stack da OU antiga e enfileira um create para a nova.

As stack instances têm os próprios status, e dois deles significam trabalho esperando por você:

  • OUTDATED significa que a stack não está atualizada em relação ao stack set, quase sempre porque um create ou update falhou ali, ou porque a operação parou antes de alcançá-la.
  • INOPERABLE significa que uma operação de delete de instances falhou e deixou a stack em estado instável. Instances nesse estado são excluídas de futuros updates do stack set, então elas silenciosamente param de receber suas mudanças. Recuperar significa apagar a instance com RetainStacks em true e depois limpar a stack na mão.

Agora o erro de leitura que custa cobertura de verdade. Uma operação SUCCEEDED não significa que toda stack deu certo. Significa que a tolerância a falhas nunca foi excedida. Coloque tolerância a falhas em 10 para 10 contas e uma operação em que absolutamente toda stack falha ainda devolve SUCCEEDED, porque você disse ao CloudFormation que aquele número de falhas era aceitável.

O número que você quer de verdade está nos detalhes de status:

aws cloudformation describe-stack-set-operation \
  --stack-set-name org-baseline --operation-id 5550e62f-c822-4331-88fa-21c1d7bafc60
{
  "StackSetOperation": {
    "Status": "SUCCEEDED",
    "StatusDetails": { "FailedStackInstancesCount": 3 }
  }
}

SUCCEEDED com FailedStackInstancesCount diferente de zero é a assinatura de um baseline implantado pela metade. Trate esse campo, e não o status da operação, como a definição de pronto.

Drift em um stack set

A detecção de drift no nível do stack set roda a detecção de drift de stack em cada stack instance e agrega as respostas. Um recurso em drift deixa a stack dele em drift, uma stack em drift deixa a instance em drift, e uma instance em drift deixa o stack set inteiro DRIFTED.

aws cloudformation detect-stack-set-drift --stack-set-name org-baseline

A operação devolve um ID porque é longa, e describe-stack-set-operation reporta as contagens conforme ela avança: DriftedStackInstancesCount, InSyncStackInstancesCount, InProgressStackInstancesCount, FailedStackInstancesCount, sobre TotalStackInstancesCount. Só uma operação de detecção de drift roda por vez em um stack set, e você para ela com stop-stack-set-operation.

Dois limites decidem quanto vale um resultado limpo:

  • Mudanças feitas pelo CloudFormation nunca são drift. Atualize a stack de uma conta alvo direto para um template diferente e a detecção de drift ainda reporta IN_SYNC, porque a stack bate com a própria configuração esperada. Aquela stack agora está inconsistente com as irmãs, o que é um problema legítimo, e a detecção de drift não é a ferramenta que encontra isso.
  • A detecção no nível da stack não sobe. Rode a detecção em uma stack individual da conta alvo e o resultado nunca aparece na página de StackSets do console. Comece a detecção no nível do stack set ou o status de drift do stack set fica velho.

Overrides de parameter são tratados corretamente: como a detecção roda por stack, uma instance com valores de parameter sobrescritos é comparada com as próprias expectativas sobrescritas, não com o padrão do stack set.

Quando as operações falham

As falhas se concentram em uma lista curta, e o status reason normalmente nomeia a causa direto.

SintomaCausa
should have 'AWSCloudFormationStackSetExecutionRole' role with trust relationship...Elo de confiança self-managed ausente ou com nome errado no alvo
Falha em uma conta só, template ok nas outrasPermissão insuficiente na execution role para um tipo de recurso naquela conta
Falhas em muitas contas em um nome globalO template cria um recurso globalmente único, como um bucket S3 com nome fixo
Erro de quota só em algumas contasA conta alvo já tem o máximo de um recurso que o template cria, como roles IAM
Delete falha em uma stackProteção contra exclusão está ligada naquela stack
Instance travada em INOPERABLE depois de um importO import falhou; apague a instance com RetainStacks, corrija e tente de novo

Tentar de novo não é uma API especial. Você corrige a causa e roda um update no stack set com o mesmo template ou um corrigido, e as instances OUTDATED se atualizam.

As quotas que importam em escala: 1.000 stack sets por conta administradora, 100.000 stack instances por stack set e 10.000 operações de stack instance rodando ao mesmo tempo por Região por conta administradora, somando todos os stack sets. Bater na última é o que deixa um rollout grande misteriosamente lento em vez de falhado.

Dicas para a prova

  • "Implantar o mesmo template em muitas contas e Regiões de um lugar só" é StackSets. Uma resposta que descreve um script em loop pelas contas está errada mesmo que funcionasse.
  • "Contas gerenciadas pelo AWS Organizations" mais "contas novas devem receber automaticamente" é service-managed com implantação automática. "Contas fora da organização" ou "sem organização" força self-managed.
  • AWSCloudFormationStackSetAdministrationRole fica na conta administradora, AWSCloudFormationStackSetExecutionRole em cada alvo. Um status reason que nomeia a execution role é problema de confiança self-managed, nunca de trusted access.
  • A conta de gerenciamento nunca recebe uma stack instance service-managed. Fique atento a cenários em que a conta faltante é a de gerenciamento.
  • A tolerância a falhas é por Região e arredonda para baixo. Excedê-la em uma Região cancela as Regiões restantes.
  • Status SUCCEEDED com recursos faltando significa que a tolerância a falhas absorveu as falhas. Olhe FailedStackInstancesCount.
  • Retain stacks mantém os recursos e derruba a associação com o stack set. Não apaga nada.
  • OUTDATED significa operação falhada ou pulada. INOPERABLE significa que a instance está fora dos updates futuros até você apagá-la.
  • Stack sets service-managed não aceitam nested stacks, macros nem transforms, incluindo AWS::Serverless.
  • A detecção de drift em um stack set nunca trata uma mudança feita pelo CloudFormation como drift.

Leve uma regra desta lição: com StackSets, "implantado" é um fato por instance, não por operação. Antes de considerar um rollout completo, olhe os status das instances e a contagem de instances falhadas, porque o status da operação foi feito para te dizer algo mais estreito do que você quer saber.

O StackSets empurra recursos idênticos para dentro das contas. A próxima lição cobre o movimento oposto: manter um recurso em uma conta e deixar outras contas usarem ele, com o AWS RAM.