Sessão 001 — AWS CLI avançado: SSO, perfis, assume-role e paginação
Duração estimada: 60 minutos
Pré-requisitos: nenhum
Objetivo
Ao final, você conseguirá configurar perfis nomeados com SSO via aws configure sso, realizar aws sts assume-role para troca de contexto entre contas, paginar resultados com --page-size e --max-items sem perder registros, e usar --query com JMESPath para filtrar saídas.
Contexto
[FATO] O AWS CLI v2 introduziu suporte nativo ao IAM Identity Center (antigo AWS SSO) com gerenciamento automático de tokens, eliminando a necessidade de ferramentas externas como aws-vault para o fluxo básico de autenticação. Antes disso, a única forma de usar credenciais temporárias com o CLI era exportar manualmente as variáveis de ambiente retornadas por aws sts assume-role.
[CONSENSO] Para ambientes multi-conta — que é o padrão em organizações com uso maduro de AWS — o fluxo de autenticação recomendado hoje é SSO via IAM Identity Center, com perfis nomeados no ~/.aws/config para cada combinação de conta+role. O aws sts assume-role manual ainda tem uso legítimo em automações e pipelines, mas perdeu espaço como fluxo primário de engenheiros.
Este guia cobre os três pilares que todo engenheiro AWS usa no dia a dia: autenticar via SSO, trocar de contexto entre contas, e extrair dados de APIs sem perder registros ou sobrecarregar a API.
Conceitos principais
1. Arquitetura de credenciais do AWS CLI
O CLI resolve credenciais numa cadeia de prioridade bem definida ([FATO], conforme documentação oficial):
1. Variáveis de ambiente AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
2. Perfil padrão no ~/.aws [default] em ~/.aws/credentials ou ~/.aws/config
3. Container credentials (ECS task role via ECS_CONTAINER_METADATA_URI)
4. Instance profile (EC2 instance role via IMDS)
O arquivo ~/.aws/config é o lugar correto para perfis nomeados — inclusive SSO. O ~/.aws/credentials é legado e carrega apenas aws_access_key_id e aws_secret_access_key. [CONSENSO] Em ambientes modernos, o ideal é que ~/.aws/credentials esteja vazio ou inexistente.
~/.aws/
├── config # perfis, SSO, roles — tudo aqui
└── credentials # legado; evite usar para novos perfis
A distinção entre os dois arquivos importa porque o --profile flag do CLI lê ambos, mas o config tem suporte a funcionalidades mais ricas (SSO, source_profile, role chaining, MFA serial).
2. SSO com IAM Identity Center — o modelo sso-session
[FATO] O AWS CLI v2.x introduziu o conceito de sso-session, que é uma seção separada no ~/.aws/config responsável por gerenciar o token de acesso SSO de forma centralizada. Antes disso, cada perfil precisava ter as configurações SSO repetidas — e o token não era compartilhado.
Estrutura atual (v2, recomendada):
# ~/.aws/config
[sso-session minha-org]
sso_start_url = https://minha-org.awsapps.com/start
sso_region = us-east-1
sso_registration_scopes = sso:account:access
[profile dev]
sso_session = minha-org
sso_account_id = 111122223333
sso_role_name = DeveloperAccess
region = us-east-1
output = json
[profile prod-readonly]
sso_session = minha-org
sso_account_id = 444455556666
sso_role_name = ReadOnlyAccess
region = us-east-1
output = json
O bloco [sso-session] é compartilhado entre todos os perfis da mesma org. Um único aws sso login --sso-session minha-org autentica todos os perfis simultaneamente.
Fluxo de autenticação:
aws configure sso
└── cria a sso-session e o perfil no ~/.aws/config
aws sso login --profile dev
└── abre o browser → autoriza no Identity Center
└── salva o token em ~/.aws/sso/cache/<hash>.json
aws s3 ls --profile dev
└── CLI lê o token do cache
└── troca por credenciais temporárias via STS
└── credenciais ficam em ~/.aws/cli/cache/<hash>.json (TTL = duração da role)
Cache de tokens e refresh automático:
[FATO] O token SSO fica em ~/.aws/sso/cache/. O CLI v2 verifica o token a cada hora e usa o refresh token para renová-lo automaticamente dentro do período de sessão estendida configurado no Identity Center (padrão: 8h, máximo configurável: 90 dias). Quando o token expira completamente, o comando falha com Token has expired and refresh failed — nesse caso, aws sso login resolve.
# Ver o token em cache (útil para debug)
cat ~/.aws/sso/cache/*.json | jq .
# Revogar e reautenticar
aws sso logout
aws sso login --profile dev
Diagrama do fluxo SSO completo:
[Você]
│
├─ aws sso login ──► [Browser: Identity Center]
│ │
│ Autoriza acesso
│ │
│◄──────── access_token + refresh_token ──────────
│ (em ~/.aws/sso/cache/)
│
├─ aws ec2 describe-instances --profile dev
│ │
│ CLI lê access_token do cache SSO
│ │
│ ┌────▼────────────────────┐
│ │ STS: AssumeRoleWithWebIdentity │
│ └────┬────────────────────┘
│ │
│ credenciais temporárias (15min–12h)
│ (em ~/.aws/cli/cache/)
│ │
│ ┌────▼────────────────┐
│ │ EC2 API call │
│ └─────────────────────┘
3. aws sts assume-role — troca de contexto entre contas
assume-role é a operação STS que troca credenciais atuais por credenciais temporárias de outra role. É o mecanismo por trás de todo acesso cross-account.
Uso direto (imperativo — bom para scripts):
# Assume a role e extrai as credenciais
CREDS=$(aws sts assume-role \
--role-arn arn:aws:iam::999988887777:role/DeployRole \
--role-session-name minha-sessao \
--duration-seconds 3600 \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
--output text)
export AWS_ACCESS_KEY_ID=$(echo $CREDS | awk '{print $1}')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | awk '{print $2}')
export AWS_SESSION_TOKEN=$(echo $CREDS | awk '{print $3}')
# Verificar que está operando como a role assumida
aws sts get-caller-identity
Uso declarativo via perfil (recomendado para uso interativo):
# ~/.aws/config
[profile deploy-prod]
role_arn = arn:aws:iam::999988887777:role/DeployRole
source_profile = dev # usa as credenciais do perfil 'dev' para assumir
role_session_name = luiz-cli
duration_seconds = 3600
region = us-east-1
aws sts get-caller-identity --profile deploy-prod
# O CLI faz o AssumeRole automaticamente, sem nenhum script
Role chaining — e seu limite crítico:
[FATO] Role chaining é quando você usa as credenciais de uma role assumida para assumir outra role. O limite de duração é fixo em 1 hora, independentemente do valor passado em --duration-seconds. Isso é uma restrição do STS, não do CLI.
Usuário IAM → Assume RoleA (duração: até 12h) ✅ OK
RoleA → Assume RoleB (duração: máx 1h) ⚠️ Sempre 1h
RoleB → Assume RoleC (duração: máx 1h) ⚠️ Sempre 1h
Se você tentar --duration-seconds 7200 num chain, o STS retorna erro. O design é intencional — a AWS limita a "profundidade" de delegação para reduzir superfície de ataque.
# Exemplo de chain: dev → staging → prod
[profile staging]
role_arn = arn:aws:iam::222233334444:role/StagingAccess
source_profile = dev
[profile prod]
role_arn = arn:aws:iam::555566667777:role/ProdAccess
source_profile = staging # chain: usa staging para chegar em prod
MFA num assume-role:
aws sts assume-role \
--role-arn arn:aws:iam::999988887777:role/PrivilegedRole \
--role-session-name mfa-session \
--serial-number arn:aws:iam::111122223333:mfa/luiz \
--token-code 123456
# Ou declarativo no config:
[profile privileged]
role_arn = arn:aws:iam::999988887777:role/PrivilegedRole
source_profile = default
mfa_serial = arn:aws:iam::111122223333:mfa/luiz
4. Paginação — --page-size vs --max-items
Esta é uma das confusões mais comuns no CLI. Os dois parâmetros controlam coisas diferentes.
--page-size = tamanho de cada request para a API AWS
--max-items = quantidade total de itens no output do CLI
Diagrama do fluxo:
API AWS tem 500 objetos S3
Sem paginação:
CLI faz 1 request → retorna 500 itens (pode dar timeout)
Com --page-size 50:
CLI faz 10 requests de 50 itens cada → output: 500 itens
(protege contra timeout, transparente pro usuário)
Com --max-items 100:
CLI faz requests até ter 100 itens → para
output: 100 itens + NextToken para continuar
Com --page-size 50 --max-items 100:
CLI faz 2 requests de 50 itens → para
output: 100 itens + NextToken
O bug silencioso:
[FATO] Se --max-items não for múltiplo de --page-size, você pode receber itens duplicados ou perder itens. Exemplo clássico: --page-size 30 --max-items 50 — o CLI pega 2 páginas de 30 (60 itens), retorna os primeiros 50, mas o NextToken aponta para o item 31 da segunda página, não para o item 51 do total. Ao usar --starting-token, você recomeça do item 31, perdendo o 51–60.
Recomendação segura:
# 1. Para listar tudo sem risco: use apenas --page-size para controlar throughput
aws s3api list-objects-v2 \
--bucket meu-bucket \
--page-size 100
# 2. Para paginar manualmente com cursor explícito
aws s3api list-objects-v2 \
--bucket meu-bucket \
--page-size 50 \
--max-items 50
# Pegar o NextToken do output anterior e continuar:
aws s3api list-objects-v2 \
--bucket meu-bucket \
--page-size 50 \
--max-items 50 \
--starting-token "eyJ..."
# 3. Para evitar timeout em buckets enormes (page menor = requests menores)
aws s3api list-objects-v2 \
--bucket bucket-com-milhoes-de-objetos \
--page-size 20
5. --query com JMESPath
--query aplica uma expressão JMESPath à resposta JSON antes do output. É processado localmente (sem custo adicional de API).
Sintaxe essencial:
# Acesso a campo simples
aws ec2 describe-instances \
--query 'Reservations[0].Instances[0].InstanceId'
# Projeção: pegar campos específicos de uma lista
aws ec2 describe-instances \
--query 'Reservations[].Instances[].[InstanceId,State.Name,Tags[?Key==`Name`].Value|[0]]' \
--output table
# Filtro: apenas instâncias rodando
aws ec2 describe-instances \
--query 'Reservations[].Instances[?State.Name==`running`].[InstanceId,PrivateIpAddress]' \
--output text
# Pipe: pegar só o primeiro resultado de uma lista filtrada
aws ec2 describe-instances \
--query 'Reservations[].Instances[?State.Name==`running`].InstanceId | [0]'
# Aplanar listas aninhadas com []
aws ec2 describe-instances \
--query 'Reservations[].Instances[].InstanceId'
# Sem o [] interno você teria [[id1, id2], [id3]] em vez de [id1, id2, id3]
Combinando paginação com query:
# Listar todas as funções Lambda com runtime Python
aws lambda list-functions \
--page-size 50 \
--query 'Functions[?Runtime==`python3.12`].[FunctionName,CodeSize]' \
--output table
Exemplo prático
Cenário: você tem acesso SSO à conta de desenvolvimento e precisa listar todas as instâncias EC2 em produção (outra conta), filtrando só as que estão running, sem baixar a lista inteira de uma vez.
# 1. Autenticar via SSO (uma vez por sessão)
aws sso login --profile dev
# 2. Verificar identidade atual
aws sts get-caller-identity --profile dev
# 3. Assumir a role de prod via perfil encadeado
# (já configurado no ~/.aws/config com source_profile = dev)
aws sts get-caller-identity --profile prod-readonly
# 4. Listar instâncias running em prod, paginando de 20 em 20
aws ec2 describe-instances \
--profile prod-readonly \
--region us-east-1 \
--page-size 20 \
--query 'Reservations[].Instances[?State.Name==`running`].[InstanceId,InstanceType,Tags[?Key==`Name`].Value|[0]]' \
--output table
# 5. Se o ambiente tem muitas instâncias e você quer paginar manualmente
RESULT=$(aws ec2 describe-instances \
--profile prod-readonly \
--page-size 20 \
--max-items 20 \
--output json)
echo $RESULT | jq '.NextToken' # token para a próxima página
aws ec2 describe-instances \
--profile prod-readonly \
--page-size 20 \
--max-items 20 \
--starting-token "$(echo $RESULT | jq -r '.NextToken')" \
--output json
Armadilhas comuns
1. --max-items sem --page-size alinhado — dados faltando silenciosamente
O erro é usar --max-items 100 com --page-size 30 e depois tentar continuar com --starting-token. O cursor fica dessincronizado com os limites de página e você perde itens entre as páginas. Solução: use o mesmo valor para ambos, ou use só --page-size para listar tudo.
2. Confundir ~/.aws/credentials com ~/.aws/config para perfis SSO
Perfis SSO não funcionam no ~/.aws/credentials. O credentials só entende aws_access_key_id e aws_secret_access_key. Se você colocar sso_session lá, o CLI ignora silenciosamente e cai para o próximo provider na cadeia.
3. Role chaining com duration_seconds > 3600
Se um perfil usa source_profile que aponta para outro perfil (não para credenciais de usuário IAM direto), você está fazendo role chaining. Qualquer duration_seconds acima de 3600 vai falhar com DurationSeconds exceeds the 1 hour session duration limit for roles assumed by role chaining. O erro não é óbvio se você não sabe que está em chain.
Exercício de reflexão
Você tem três contas AWS: tools (onde o IAM Identity Center está), staging e prod. Um engenheiro configura o seguinte ~/.aws/config:
[sso-session empresa]
sso_start_url = https://empresa.awsapps.com/start
sso_region = us-east-1
[profile staging]
sso_session = empresa
sso_account_id = 111122223333
sso_role_name = DevAccess
region = us-east-1
[profile prod]
role_arn = arn:aws:iam::444455556666:role/ProdDeploy
source_profile = staging
duration_seconds = 7200
region = us-east-1
Quando ele executa aws sts get-caller-identity --profile prod, o comando falha. Por que? Quais são os dois problemas distintos nessa configuração — um de arquitetura, um de limite de serviço — e como você corrigiria cada um? Considere também o impacto na duração da sessão em prod caso a configuração seja corrigida.
Recursos para aprofundar
Configuração e perfis:
- Configuring IAM Identity Center authentication with the AWS CLI — referência primária para o modelo sso-session, inclui todos os campos aceitos e exemplos de aws configure sso interativo.
Assume-role e role chaining:
- Using an IAM role in the AWS CLI — cobre source_profile, credential_source, MFA e os limites de role chaining com exemplos de config.
Paginação:
- Using the pagination options in the AWS CLI — documento curto e direto com a distinção entre --page-size e --max-items e como usar --starting-token.