posts

Tornando o Acesso Cross-Account Mais Seguro e Gerenciável com ABAC

Já faz algum tempo que eu tirei a minha certificação AWS Security Specialty. Naquela época, aprofundando nos estudos para a prova, conheci uma excelente estratégia para gerenciar acessos na AWS de uma maneira bem simples, o Attribute-Based Access Control (ABAC).

Como Funciona

Como o nome diz, ele se baseia em controlar acessos utilizando-se de atributos da entidade que tenta acessar aquele recurso.

Na AWS, esse conceito de atributo é materializado através das tags, que são os metadados de um recurso, em formato chave-valor. A tag Name, por exemplo, é o que define o que vai ser exibido como o nome do recurso no Console.

No que diz respeito a controle de acesso, as tags serão usadas para estabelecer a condição que garante o acesso do usuário ao recurso.

Vejamos abaixo uma representação visual, onde temos 3 tipos de usuários de diferentes equipes, cada um possuindo acesso a recursos que competem a sua jurisdição:

  • Infraestrutura Team=Infrastructure (Tag Vermelha)
    • Acesso a instâncias EC2 e gerenciamento de políticas.
  • Dados Team=Data (Tag Azul)
    • Acesso aos buckets S3 da conta e painéis analíticos.
  • Desenvolvedor Team=Dev (Tag Verde)
    • Acesso à sua aplicação, rodando no ECS e ao File System por ela utilizado.

Representação visual do ABAC

Créditos da Imagem: https://aws.amazon.com/blogs/security/control-access-to-amazon-elastic-container-service-resources-by-using-abac-policies/

Apesar de simples, as tags são extremamente úteis para gerenciar recursos na nuvem, estabelecer a relação semântica entre eles e até filtrar custos, utilizando a feature de Cost Allocation Tags.

Minha Aplicação Prática do ABAC

Assim que tive conhecimento desta estratégia, vi que ela encaixava muito bem no dia a dia do meu ambiente de trabalho, onde costumávamos lidar com a necessidade da edição manual da Trust Relationship da role de acesso dos clientes (sim, diversos clientes).

Funcionava da seguinte forma:

  • Tínhamos uma role solution-provider-infra-access na conta do cliente.
  • Essa role continha uma Trust Relationship que seguia o seguinte exemplo, listando todos os usuários da equipe de infraestrutura que precisavam assumir aquela role:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::123456789012:user/fulano",
          "arn:aws:iam::123456789012:user/cicrano",
          "arn:aws:iam::123456789012:user/beltrano"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
  • O problema é que, se a equipe tivesse um novo membro, essa política precisava ser atualizada... Nos cento e tantos clientes que possuíam essa mesma policy.

  • Tínhamos aí um problema grave de inconsistência, com a necessidade da policy ser atualizada conforme o novo membro acessava as contas.

Para destravar esse processo, desenhei uma nova versão, pensada da seguinte forma:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAssumptionByInfrastructureTaggedPrincipals",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        },
        "StringEquals": {
          "aws:PrincipalTag/Team": "Infrastructure"
        }
      }
    }
  ]
}

A definição acima permite que qualquer Principal (entidade) da conta de ID 123456789012 tenha acesso, desde que ambas condições sejam verdadeiras:

  • Tenha a tag Team com o valor Infrastructure.
  • Tenha se autenticado com MFA na sessão atual.

Ao apresentar minha ideia para a gestão, houve uma certa dúvida inicial quanto a questões de auditoria, sendo solicitados alguns testes iniciais para comprovar a segurança e a confiabilidade desta solução.

Após comprovar, em uma conta de teste, que o acesso era mais prático e não prejudicava a auditoria (todas as ações continuavam registradas no CloudTrail), adotamos a estratégia e atualizamos as Trust Relationships pela última vez.

Controlando a Escalação de Privilégios

Mesmo com essa solução, ainda existe um risco: um usuário, em tese, poderia escalar privilégios se conseguisse adicionar a tag Team com o valor Infrastructure à sua própria entidade.

Para mitigar esse risco, é importante garantir que apenas administradores possam adicionar ou modificar tags sensíveis.

Isso pode ser feito com uma SCP (Service Control Policy), um recurso do AWS Organizations que limita o que as identidades de uma conta podem fazer, mesmo as administrativas. Essa é uma política aplicada a partir da conta gerenciadora do Organizations, ou seja, ninguém consegue remover a política tendo apenas acesso à conta onde o usuário está. Use uma política que negue explicitamente a alteração da tag Team, como no exemplo abaixo:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyTeamTagChangesExceptAdmins",
      "Effect": "Deny",
      "Action": [
        "iam:TagUser",
        "iam:TagRole",
        "iam:UntagUser",
        "iam:UntagRole",
        "sts:TagSession"
      ],
      "Resource": "*",
      "Condition": {
        "ForAnyValue:StringEquals": {
          "aws:TagKeys": ["Team"]
        },
        "ArnNotLike": {
          "aws:PrincipalARN": "arn:aws:iam::*:role/iam-admin"
        }
      }
    }
  ]
}

A política acima nega qualquer tentativa de alteração da tag Team por qualquer entidade que não seja a role administradora do IAM (nesse exemplo, a role iam-admin).


Para quem achou interessante e quer aplicar de sua própria maneira, recomendo a leitura da documentação oficial da AWS sobre o ABAC, disponível aqui.