Entenda o risco das políticas. Faça perguntas sobre políticas em linguagem natural. Solicite uma demonstração →
Published:
Técnicas avançadas para defender o AWS ExternalID e o acesso AssumeRole entre contas
by FireMon
No mês passado, Kesten Broughton, da Praetorian Security, divulgou uma excelente pesquisa sobre produtos de segurança em nuvem de terceiros que utilizam a técnica de conexão entre contas preferida da Amazon – AWS IAM Assume Role Vulnerabilities Found in Many Top Vendors. O parágrafo de abertura oferece uma visão geral consistente da pesquisa:
Neste primeiro blog da nossa série sobre confiança entre contas, apresentaremos os resultados de 90 fornecedores, mostrando que 37% não implementaram o ExternalId corretamente para proteger contra ataques de confused deputy. Outros 15% dos fornecedores implementaram a integração da conta AWS na interface corretamente, mas o parâmetro ExternalId não era devidamente validado no backend, tornando esses sites igualmente vulneráveis. Concluiremos discutindo as novas superfícies de ataque expostas pela confiança de cross-account-assume-role da AWS. Nossa conclusão é que fornecedores e clientes devem examinar criticamente se a confiança baseada em função é o melhor mecanismo de confiança para sua solução SaaS multi-inquilino.
Minha primeira reação ao ler a pesquisa foi: “por que alguém tomaria uma decisão tão ruim?”. Mas a realidade é que todo o conceito de “especialista em segurança em nuvem” é relativamente novo e, embora a AWS trate razoavelmente bem do problema do confused deputy, ela não aborda algumas das implicações práticas em que você só pensa quando o produto chega ao cliente. As conexões entre contas que usam AssumeRole têm uma solução de engenharia direta, mas, sem uma modelagem de ameaças adequada, é extremamente fácil cometer os erros documentados na pesquisa de Kesten.
Aqui na DisruptOps, tomamos algumas decisões acertadas desde cedo, com base em nossa modelagem de ameaças inicial, o que nos manteve seguros. Ainda assim, aproveitamos alguns pontos da pesquisa e estamos acrescentando ainda mais hardening. Além disso, temos um projeto experimental que deve eliminar boa parte do problema e, mesmo assim, permitir automação em escala sem exigir acesso direto de escrita aos ambientes dos clientes.
Tenho, no entanto, um ponto importante de discordância com o texto. Eu prefiro credenciais rotacionadas automaticamente em vez da recomendação de usar credenciais estáticas e cofres de segredos. Ainda precisamos usá-las para outros provedores de nuvem e estamos sempre buscando maneiras de NÃO ter credenciais estáticas em NENHUM lugar do nosso ambiente.
O problema
Atualmente, uma variedade de tipos de aplicações precisa se conectar diretamente às APIs da nuvem. Isso pode ser tão simples quanto acessar um bucket S3 ou tão complexo quanto uma plataforma totalmente automatizada de Cloud Detection and Response (apenas como exemplo aleatório, claro). Essas requisições exigem algum tipo de credencial, que pode ser estática (como um nome de usuário e senha, ou uma chave de acesso e chave secreta do IAM) ou dinâmica. Credenciais dinâmicas incluem um token ou outro atributo efêmero com prazo limitado.
Credenciais estáticas de aplicação que permitem acesso direto ao seu plano de gerenciamento na nuvem são… ruins. Podemos resolver isso para usuários com MFA, mas isso não ajuda em aplicações automatizadas como nossa nada teórica plataforma de Cloud Detection and Response. Há algum tempo, a Amazon Web Services abordou esse problema com o conceito de IAM Role. Uma role na AWS é essencialmente um contêiner de permissões com duas políticas: o que o contêiner pode fazer e quem (ou o quê) pode assumir a role. As roles são baseadas em sessão, portanto, quando uma entidade autorizada assume a role, ela recebe um conjunto de credenciais (chave de acesso, chave secreta e token de sessão) que pode usar durante a sessão (de 1 a 24 horas).
As roles na AWS podem ser assumidas por meio de conexão SAML externa (para usuários), conexões internas “confiáveis” (de outras contas AWS) ou serviços da AWS (como uma instância EC2 ou função Lambda). Assim, é possível fazer coisas interessantes, como executar código em uma instância sem que ela jamais armazene credenciais estáticas. Isso elimina muitas dores de cabeça.
Permitir conexões a partir de uma conta que você não controla é um pouco diferente, especialmente se essa conta for uma plataforma que atende múltiplos clientes. Plataformas assim (tudo bem, nós) precisam de acesso a centenas ou milhares de outras contas AWS. Imagine se um invasor pudesse enganar a plataforma para que ela fizesse algo na conta errada, como executar uma avaliação de configuração em uma conta que não pertence ao usuário atual. Esta é a versão resumida do problema do confused deputy – o deputado é confiado por várias contas e o usuário o engana para obter acesso a uma conta que jamais deveria tocar.
A exploração mais prática ocorre quando a plataforma permite que um usuário informe o ID de uma conta que não controla, adicione-a ao seu perfil e então abuse da confiança concedida à plataforma.
A AWS inclui um mecanismo de defesa contra isso chamado AWS ExternalID. Trata-se de um segredo compartilhado arbitrário que o provedor da plataforma e o cliente trocam fora de banda. Esse ID é um atributo transmitido em qualquer requisição para assumir a role na conta do cliente, e a política de confiança da role nessa conta contém uma condição que verifica se o segredo compartilhado está correto. Quando implementado corretamente, isso significa que ninguém pode simplesmente adicionar ao deputado uma conta que não controla, já que o invasor não consegue estabelecer nem conhecer o segredo compartilhado na conta do cliente.
A menos que…
Você já percebe aonde isso leva. A Praetorian identificou um grande número de provedores que usam AWS ExternalIds padrão ou permitem que os clientes definam um valor de ExternalId não exclusivo para toda a sua conta. Também encontrou produtos que não validavam se o cliente sequer impunha o External ID em sua política de confiança da role. A Praetorian encontrou plataformas ativamente exploráveis, permitindo ataques de confused deputy devido à segurança deficiente nas roles entre contas.
Hardening de conexões entre contas
Tudo isso fez parte da nossa modelagem de ameaças na DisruptOps, então estamos em boa situação, embora tenhamos aproveitado mais uma ou duas ideias para melhorar. Vamos analisar cada questão identificada pela Praetorian e examinar as melhores opções de hardening de segurança:
- O AWS ExternalID usa configurações padrão: Usamos um ExternalID aleatório.
- O AWS ExternalID é compartilhado entre várias contas de clientes:Usamos um ExternalID aleatório por conta, não por cliente.
- O AWS ExternalID é enumerável ou adivinhável: Usamos AWS ExternalIDs totalmente aleatórios e longos. Não me preocupo com nossa escolha de PRNG graças à limitação de taxa da API (para vocês, nerds de criptografia).
- Os clientes podem definir seu próprio ExternalID e podem repetir ou usar ExternalIDs fracos: Não permitimos que os clientes definam seu próprio ExternalID, embora certamente já tenhamos recebido esse pedido. É aqui que acredito que alguns outros provedores se complicaram. Os clientes querem esse recurso para automatizar por conta própria o provisionamento do produto; mas, para fazer isso com segurança, precisaríamos validar se o ExternalID atende a requisitos de comprimento e aleatoriedade. Com a validação correta, provavelmente é possível fazê-lo com segurança.
- A plataforma permite que a mesma conta AWS seja provisionada várias vezes: Não permitimos isso.
- A IAM Role não é restrita a uma única entidade na conta do provedor, mas a qualquer role na conta: Não tratamos disso neste texto, mas é possível conceder acesso de qualquer role da conta à role “worker” na conta do cliente, ou conceder acesso a um único recurso ou role. Limitamos nosso acesso às roles específicas que usamos para acesso entre contas.
- O nome da IAM Role é estático em todas as contas de clientes: O risco aqui é essencialmente que o nome de usuário (nome da role) seja adivinhável. Não considero isso um risco, a menos que haja outros erros bem fundamentais. Um exemplo: se um invasor souber o nome da role e obtiver acesso à conta do cliente, ele poderia se adicionar à política de confiança da role e então usar esses privilégios (ensino algo assim nas minhas aulas de treinamento em resposta a incidentes). É um risco potencial, mas que avaliamos como bastante baixo. Se um invasor tem esse nível de acesso, provavelmente consegue assumir qualquer role da conta.
- O provedor não valida se o ExternalID foi definido como condição de acesso: Fornecemos aos clientes um CloudFormation Template para provisionamento que garante a configuração correta. Vamos acrescentar suporte para validar que ele permaneça ali, especialmente à medida que continuamos a adicionar outras opções de provisionamento (fora do CloudFormation) para atender aos requisitos dos clientes.
Kesten parece preferir o modelo de credenciais estáticas e o uso de um bom cofre de segredos no lado do provedor para proteger a conexão. Pessoalmente, discordo e considero o modelo da AWS mais seguro de saída, desde que sejam seguidas as precauções básicas.
Atualmente adotamos duas precauções adicionais além das recomendações da Praetorian:
- Mascaramos o ExternalID no CloudFormation: Definimos o ExternalID como parâmetro em nossos templates do CloudFormation com a opção NoEcho ativada. Isso o mascara no console, nas ferramentas de linha de comando e na API. Assim, reduz-se o risco de exposição a quem tem permissão para executar o CloudFormation, mas não tem permissões de IAM.
- Restringimos o acesso ao template do CloudFormation apenas à conta de destino: Isso reduz o risco de alguém interceptar e capturar o ExternalID durante o processo de provisionamento.
Mesmo que o ExternalID seja exposto, isso não deveria importar – sua plataforma deve garantir que uma conta de destino seja registrada apenas uma vez e somente com um ExternalID aleatório. Ainda que o invasor conheça o nome da role e o ExternalID, ele não consegue fazer nada com essas informações, pois não há nenhum lugar na plataforma para inseri-las, e a própria AWS impõe que a conexão entre contas se origine da conta confiável. Isso não é algo que se possa falsificar.
Esperamos que ver como lidamos com isso traga ideias para suas próprias ferramentas. Recomendo os requisitos de registro de conta e de ExternalID aleatório mesmo que você use o AWS Organizations, pois adicionar uma condição para restringir o acesso somente à sua própria organização ainda pode expô-lo a ataques de uma conta de menor segurança contra uma conta de maior segurança.
E fique atento a esse novo projeto experimental! Devemos poder falar sobre ele em alguns meses e ele muda completamente o jogo para esse tipo de problema.