Obtendo o Instance ID via Metadados do EC2: Por que IMDSv2 é Mais Seguro que V1
Você está escrevendo um script de inicialização ou uma rotina de automação que precisa saber em qual instância EC2 está rodando — e a pergunta natural é: como obter o Instance ID de dentro da própria máquina, sem depender de variáveis de ambiente ou arquivos de configuração externos? A resposta está no Instance Metadata Service (IMDS), mas a forma como você o acessa faz toda a diferença do ponto de vista de segurança.
TL;DR — Resumo Rápido
| Aspecto | IMDSv1 | IMDSv2 |
|---|---|---|
| Autenticação | Nenhuma — requisição direta | Token de sessão obrigatório |
| Vulnerabilidade SSRF | Exposta | Mitigada pelo token |
| Método HTTP | GET simples | PUT para obter token, depois GET |
| Recomendação AWS | Legado — evitar | Padrão recomendado |
| Configuração necessária | Nenhuma | Nenhuma (habilitado por padrão em novas instâncias) |
Como o Instance Metadata Service Funciona
O IMDS é um endpoint HTTP local disponível em http://169.254.169.254 — um endereço link-local que só é acessível de dentro da própria instância EC2. Ele expõe informações sobre a instância sem necessidade de credenciais IAM: Instance ID, tipo de instância, região, AMI ID, credenciais temporárias de roles IAM, e muito mais.
O endereço 169.254.169.254 não é roteável pela rede pública nem pela VPC — ele responde apenas localmente na instância. Qualquer processo rodando na máquina pode fazer uma requisição HTTP para esse IP e obter metadados. Esse é exatamente o ponto de atenção com o IMDSv1.
(X-aws-ec2-metadata-token-ttl-seconds: 21600) IMDS-->>Script: TOKEN (string opaca) Script->>IMDS: GET /latest/meta-data/instance-id
(X-aws-ec2-metadata-token: TOKEN) IMDS-->>Script: i-1234567890abcdef0
- IMDSv1 (fluxo superior): Um GET direto para o endpoint retorna os metadados imediatamente, sem qualquer verificação de origem ou autenticação.
- IMDSv2 (fluxo inferior): Primeiro, um PUT com um TTL gera um token de sessão. Esse token deve ser incluído em todas as requisições subsequentes via header
X-aws-ec2-metadata-token. - O token tem validade configurável em segundos — após expirar, um novo PUT é necessário.
- A exigência do método PUT para obter o token é a proteção central: navegadores e a maioria dos vetores SSRF não emitem PUT cross-origin com headers customizados sem CORS explícito.
Por que IMDSv1 é um Risco de Segurança
O problema do IMDSv1 não é teórico. Em ataques de Server-Side Request Forgery (SSRF), um agente malicioso induz a aplicação rodando na instância a fazer uma requisição HTTP para um endereço controlado pelo atacante — ou, no caso mais perigoso, para http://169.254.169.254. Se a aplicação for vulnerável a SSRF e a instância usar IMDSv1, o atacante pode extrair credenciais IAM temporárias da role associada à instância com um único GET.
Pense no IMDSv1 como uma sala de servidores com a porta destrancada: qualquer pessoa que consiga entrar no corredor — mesmo sem autorização explícita — pode acessar tudo dentro. O IMDSv2 adiciona uma fechadura que exige uma chave específica obtida apenas por quem já está fisicamente dentro da sala.
O IMDSv2 quebra esse vetor porque o token de sessão é obtido via método PUT com um header X-aws-ec2-metadata-token-ttl-seconds. Requisições SSRF típicas não conseguem forjar esse fluxo de dois passos — especialmente em cenários onde a vulnerabilidade está em uma aplicação web que processa URLs fornecidas pelo usuário.
Obtendo o Instance ID com IMDSv2 — Passo a Passo
O fluxo tem duas etapas: obter o token de sessão e usar esse token para consultar os metadados. Ambas as chamadas são feitas para o mesmo endpoint local.
Passo 1 — Obter o Token de Sessão
TOKEN=$(curl -s -X PUT \
'http://169.254.169.254/latest/api/token' \
-H 'X-aws-ec2-metadata-token-ttl-seconds: 21600')
O valor 21600 representa 6 horas em segundos. Ajuste conforme o tempo de vida esperado do seu script. O token retornado é uma string opaca que deve ser armazenada temporariamente.
Passo 2 — Consultar o Instance ID
INSTANCE_ID=$(curl -s \
'http://169.254.169.254/latest/meta-data/instance-id' \
-H "X-aws-ec2-metadata-token: $TOKEN")
echo "Instance ID: $INSTANCE_ID"
Script Completo e Reutilizável
🔽 Clique para expandir — script Bash completo com tratamento de erro
#!/bin/bash
set -euo pipefail
IMDS_ENDPOINT='http://169.254.169.254'
TOKEN_TTL=21600
# Obtém token IMDSv2
TOKEN=$(curl -s -f -X PUT \
"${IMDS_ENDPOINT}/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: ${TOKEN_TTL}")
if [ -z "$TOKEN" ]; then
echo 'ERRO: Falha ao obter token IMDSv2. Verifique se o IMDS está habilitado.' >&2
exit 1
fi
# Função auxiliar para consultar metadados
get_metadata() {
local path="$1"
curl -s -f \
"${IMDS_ENDPOINT}/latest/meta-data/${path}" \
-H "X-aws-ec2-metadata-token: ${TOKEN}"
}
INSTANCE_ID=$(get_metadata 'instance-id')
INSTANCE_TYPE=$(get_metadata 'instance-type')
AZ=$(get_metadata 'placement/availability-zone')
REGION=$(get_metadata 'placement/region')
echo "Instance ID: ${INSTANCE_ID}"
echo "Tipo: ${INSTANCE_TYPE}"
echo "AZ: ${AZ}"
echo "Região: ${REGION}"
Verificando e Forçando IMDSv2 na Instância
Mesmo que o IMDSv2 esteja disponível, por padrão instâncias mais antigas podem ainda aceitar requisições IMDSv1. Para garantir que apenas IMDSv2 seja aceito, você precisa modificar o atributo http-tokens para required.
Verificar a configuração atual do IMDS
aws ec2 describe-instances \
--instance-ids i-1234567890abcdef0 \
--query 'Reservations[0].Instances[0].MetadataOptions' \
--output json \
--region us-east-1
A saída esperada quando IMDSv2 é obrigatório:
{
"State": "applied",
"HttpTokens": "required",
"HttpPutResponseHopLimit": 1,
"HttpEndpoint": "enabled",
"HttpProtocolIpv6": "disabled",
"InstanceMetadataTags": "disabled"
}
Forçar IMDSv2 em uma instância existente
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required \
--http-endpoint enabled \
--region us-east-1
Essa mudança não requer reinicialização da instância e entra em vigor imediatamente.
Forçar IMDSv2 ao lançar novas instâncias via CLI
aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type t3.micro \
--metadata-options 'HttpTokens=required,HttpEndpoint=enabled' \
--region us-east-1 \
--count 1
Aplicando IMDSv2 em Escala com SCP ou IAM
Para garantir que nenhuma instância na conta seja lançada com IMDSv1, você pode usar uma Service Control Policy (SCP) no AWS Organizations ou uma política IAM com condição. A abordagem via SCP é mais abrangente porque se aplica a toda a unidade organizacional independentemente das permissões do usuário.
🔽 Clique para expandir — SCP que nega lançamento de instâncias sem IMDSv2 obrigatório
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyIMDSv1",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotEquals": {
"ec2:MetadataHttpTokens": "required"
}
}
}
]
}
Sinal de Experiência — O Diagnóstico que Enganou a Equipe
Um cenário que aparece com frequência: o script funciona perfeitamente em ambiente de desenvolvimento, mas falha silenciosamente em produção retornando uma string vazia para o Instance ID. O primeiro instinto é checar conectividade de rede ou variáveis de ambiente. Errado.
O que estava acontecendo: a instância de produção tinha HttpTokens=required configurado (correto), mas o script legado usava IMDSv1 — um GET direto sem token. Com IMDSv2 obrigatório, o endpoint retorna HTTP 401 e o curl sem a flag -f simplesmente retorna string vazia ao invés de falhar com código de erro não-zero. O script continuava executando com INSTANCE_ID vazio, causando falhas downstream difíceis de rastrear.
A correção foi dupla: migrar para o fluxo IMDSv2 e adicionar -f ao curl para que falhas HTTP se traduzam em exit codes não-zero. Usar set -euo pipefail no script garante que qualquer falha nesse ponto interrompa a execução imediatamente.
Detalhe não óbvio: o parâmetro HttpPutResponseHopLimit controla quantos saltos de rede o PUT para obter o token pode atravessar. O valor padrão é 1, o que significa que o token só pode ser obtido diretamente na instância — não através de um proxy ou container aninhado sem configuração adicional. Para containers rodando dentro da instância que precisam acessar o IMDS, pode ser necessário aumentar esse limite para 2. Isso é um detalhe que a documentação menciona, mas que frequentemente é esquecido em arquiteturas com ECS em instâncias EC2.
sem token IMDSv2] --> B{HttpTokens=required?} B -- Não --> C[Retorna Instance ID normalmente] B -- Sim --> D[IMDS retorna HTTP 401] D --> E{curl com flag -f?} E -- Não --> F[curl retorna string vazia
exit code 0] E -- Sim --> G[curl falha com exit code não-zero] F --> H[Script continua com
INSTANCE_ID vazio] G --> I[Script interrompido — falha visível] H --> J[Falha silenciosa downstream
difícil de diagnosticar] I --> K[Diagnóstico imediato:
migrar para IMDSv2]
- Script sem IMDSv2 + instância com HttpTokens=required: O GET direto recebe HTTP 401. Sem tratamento de erro adequado, o script continua com variável vazia.
- Diagnóstico correto: Verificar o status do IMDS com
describe-instancese testar manualmente o fluxo de dois passos. - Correção: Migrar para IMDSv2 no script e adicionar validação de token.
Permissões IAM Necessárias
O acesso ao IMDS em si não requer permissões IAM — é um serviço local da instância. Porém, os comandos AWS CLI usados para verificar e modificar as opções de metadados requerem as seguintes permissões:
🔽 Clique para expandir — política IAM mínima para gerenciar opções de metadados
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DescribeInstanceMetadataOptions",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances"
],
"Resource": "*"
},
{
"Sid": "ModifyInstanceMetadataOptions",
"Effect": "Allow",
"Action": [
"ec2:ModifyInstanceMetadataOptions"
],
"Resource": "arn:aws:ec2:us-east-1:123456789012:instance/*"
}
]
}
Nota: ec2:DescribeInstances não suporta restrição por ARN de recurso específico — o Resource: * é necessário para essa ação, conforme documentado no AWS Service Authorization Reference.
Próximos Passos e Conclusão — Obtendo Instance ID com Segurança
Usar IMDSv2 para obter o Instance ID e outros metadados do EC2 é a prática recomendada pela AWS e a única abordagem defensável em ambientes de produção. O fluxo de dois passos com token de sessão elimina o vetor de ataque SSRF que tornou IMDSv1 problemático, e a mudança no script é mínima.
Para consolidar essa prática no seu ambiente:
- Audite instâncias existentes com
describe-instancesfiltrando porMetadataOptions.HttpTokens != required - Adicione a SCP de bloqueio de IMDSv1 na sua organização AWS
- Revise scripts e SDKs legados — versões antigas do AWS SDK podem usar IMDSv1 internamente; verifique a documentação da versão utilizada
- Para containers ECS em EC2, avalie o
HttpPutResponseHopLimitconforme sua arquitetura
Referências oficiais: AWS EC2 — Configuring Instance Metadata Service e How IMDSv2 Works.
Glossário
| Termo | Definição |
|---|---|
| IMDS | Instance Metadata Service — endpoint HTTP local (169.254.169.254) que expõe metadados da instância EC2 sem autenticação IAM. |
| IMDSv2 | Versão 2 do IMDS, que exige um token de sessão obtido via PUT antes de qualquer consulta de metadados. |
| SSRF | Server-Side Request Forgery — ataque onde o servidor é induzido a fazer requisições HTTP para endereços internos, potencialmente expondo o IMDS. |
| HttpTokens | Atributo da instância EC2 que controla se IMDSv2 é opcional (optional) ou obrigatório (required). |
| Link-local | Faixa de endereços IP (169.254.0.0/16) não roteável além do segmento de rede local — garante que o IMDS só seja acessível de dentro da instância. |
Comentários
Postar um comentário