O blog da AWS
Como restringir o acesso do bucket do Amazon S3 a uma IAM Role específica
2 de abril de 2021: Na seção “Conceder acesso entre contas a um bucket para uma IAM Role específica”, atualizamos a segunda política para corrigir um erro.
Sou engenheiro de suporte de nuvem aqui na AWS, e os clientes geralmente me perguntam como podem limitar o acesso de um bucket do Amazon S3 à uma Role específica do AWS Identity and Access Management (IAM). Em geral, eles tentam fazer isso da mesma forma que fariam com um usuário do IAM: por meio de uma bucket policy para inserir Deny
explicitamente para todos os Principals (Usuários e Roles) dos quais não deseja conceder acesso. A desvantagem dessa abordagem é a manutenção necessária da bucket policy. Se um novo usuário do IAM for adicionado à conta com “s3:*” para a Action
, o usuário teria acesso ao bucket. Em vez de especificar a lista de usuários cujo acesso deseja bloquear, você pode inverter a lógica e aproveitar o elemento NotPrincipal
na instrução da bucket policy de Deny
. Esse elemento cria um Deny
explícito para qualquer usuário que não esteja listado neste campo.
No entanto, essa abordagem de lógica invertida se mostra problemática com as IAM Roles, pois o valor Principal da Role é composto por dois Amazon Resource Name (ARNs)
: o ARN role e o ARN assumed-role. O ARN role é o identificador do perfil do IAM em si, e o ARN assumed-role
é o que identifica a Role Session nos logs. Ao usar o elemento NotPrincipal
, você deve incluir ambos os ARNs para que essa abordagem funcione, e o segundo desses ARNs deve incluir um nome de variável. Normalmente, você especificaria um wildcard (*) para onde a variável da string iria, mas isso não é permitido em um elemento Principal ou NotPrincipal
. Nesta publicação no blog, mostro como você pode restringir o acesso do bucket do S3 a uma IAM Role ou usuário específico do IAM em uma conta com o Conditions,em vez de de usar o elemento NotPrincipal
. Mesmo que outro usuário na mesma conta tenha uma política Admin ou uma política com s3:*, eles serão negados se não estiverem explicitamente listados. Você pode usar essa abordagem, por exemplo, para configurar um bucket para acesso por instâncias em um grupo do Auto Scaling. Você também pode usar essa abordagem para limitar o acesso a um bucket com uma necessidade de segurança de alto nível.
Visão geral da solução
A solução nesta postagem usa uma política de bucket para controlar o acesso à um bucket do S3, mesmo que um recurso tenha acesso à API completa do S3. O diagrama a seguir ilustra como isso funciona para um bucket na mesma conta.
- A política do usuário do IAM e a política da Role concedem acesso a “s3:*”.
- A política de bucket do S3 restringe o acesso somente à Role.
- Tanto o usuário do IAM quanto a Role podem acessar buckets na conta. A Role pode acessar os dois buckets, mas o usuário pode acessar somente o bucket sem a política de bucket anexada a ele. Embora a Role e o usuário tenham permissões completas “s3:*”, a política de bucket nega o acesso ao bucket para qualquer pessoa que não tenha assumido a Role.
A principal diferença na abordagem entre contas é que cada bucket deve ter uma política de bucket anexada à ele. O diagrama a seguir ilustra como isso funciona em um cenário de implantação entre múltiplas contas.
- A política da IAM Role e a política de usuários do IAM na conta do bucket concedem acesso a “s3:*”
- A política de bucket nega acesso a qualquer pessoa se o
user:id
não for igual ao da Role, e a política define o que a Role tem permissão para fazer com o bucket. - A política de bucket permite o acesso à Role da outra conta.
- O usuário e a IAM Role podem acessar o bucket sem
Deny
na política do bucket. A Role pode acessar os dois buckets porqueDeny
é apenas para Principals cujouser:id
não é igual ao da Role.
Entender o elemento NotPrincipal e como usá-lo
Você pode usar o elemento NotPrincipal
de uma política de bucket do IAM ou do S3 para limitar o acesso de recursos a um conjunto específico de usuários. Esse elemento permite bloquear todos os usuários que não estão definidos em sua matriz de valores, mesmo que eles tenham um Allow
em suas próprias políticas de usuário do IAM. Como resultado, se você tiver um usuário que deve ter acesso a todos os buckets, exceto um no S3, poderá definir isso no próprio bucket, sem precisar editar a stack de políticas do usuário IAM.
No entanto, para uma IAM Role, isso é mais complexo porque a Role é definida por dois ARNs no Principal: o ARN role e o ARN assumed-role. O ARN role (arn:aws:iam::ACCOUNTNUMBER:role/ROLE-NAME) é estático e independe de quem iniciou a sessão da Role. (Ao longo deste post, lembre-se de substituir as informações de espaço reservado pelas informações da sua própria conta.) O ARN assumed-role (arn:aws:sts::ACCOUNTNUMBER:assumed-role/ROLE-NAME/ROLE-SESSION-NAME) variará de acordo com o que estiver definido para o nome da sessão da Role. Isso pode ser visto observando o seguinte elemento Identity em uma entrada do AWS CloudTrail para uma chamada de API feita por um usuário que assumiu uma Role.
{ "type": "AssumedRole", "principalId": "AROAJI4AVVEXAMPLE:ROLE-SESSION-NAME", "arn": "arn:aws:sts::ACCOUNTNUMBER:assumed-role/ROLE-NAME/ROLE-SESSION-NAME", "accountId": "ACCOUNTNUMBER", "accessKeyId": "ASIAEXAMPLEKEY", "sessionContext": { "attributes": { "mfaAuthenticated": "false", "creationDate": "XXXX-XX-XXTXX:XX:XXZ" }, "sessionIssuer": { "type": "Role", "principalId": "AROAJI4AVV3EXAMPLEID", "arn": "arn:aws:iam::ACCOUNTNUMBER:role/ROLE-NAME", "accountId": "ACCOUNTNUBMER", "userName": "ROLE-SESSION-NAME" } } }
Dentro desse elemento Identity
, você vê o ARN role e o ARN assumed-role. O ROLE-SESSION-NAME pode mudar com base em quem assumiu a Role. O valor PrincipalId
também inclui essas informações, mas é formatado de uma maneira que pode ser usado fora de um elemento Principal em uma política de bucket. Usarei essas informações ao criar a política de bucket.
Conceder acesso ao bucket da mesma conta a uma IAM Role específica
Ao acessar um bucket de dentro da mesma conta, não é necessário usar uma política de bucket, na maioria dos casos. Isso ocorre porque uma política de bucket define o acesso que já é concedido diretamente pela política do usuário do IAM. As políticas de bucket do S3 geralmente são usadas para acesso entre contas, mas você também pode usá-las para restringir o acesso por meio de uma Deny
explícita, que seria aplicada a todos os Principals
, estejam eles na mesma conta do bucket ou em uma conta diferente.
Cada entidade do IAM (usuário ou Role) tem uma variável aws:userid definida. Você precisará dessa variável para uso na política de bucket para especificar a Role ou o usuário como uma exceção em um elemento condicional. Um valor aws:userId de uma assumed-role é definido como UNIQUE-ROLE-ID:ROLE-SESSION-NAME (por exemplo, AROAEXAMPLEID:userdefinedsessionname).
Para obter AROAEXAMPLEID para a IAM Role, faça o seguinte:
- Instale a AWS CLI e abra um prompt de comando ou shell.
- Execute o seguinte comando: aws iam
get-role –role-name
ROLE-NAME. - Na saída, procure a string
RoleId
, que começa comAROA
. Você usará isso na política de bucket para definir o escopo do acesso ao bucket somente para essa Role.
No exemplo citado anteriormente no código do CloudTrail, esse ID é o elemento principalId
. O valor desse elemento é importante, pois as variáveis de política da AWS também podem ser verificadas como strings em uma política do IAM. Em vez de especificar os ARNs role e assumed-role
em um elemento NotPrincipal
, você pode usar o valor aws:userId
em uma condição StringNotLike
com uma string curinga (*). No valor de aws:userId
, você também precisará adicionar o usuário root da conta para que o bucket não se torne completamente inacessível se a Role definida por excluída. O userId
da conta root é o número da conta.
Usando o AROAEXAMPLEID que você acabou de recuperar por meio da AWS CLI, você pode criar uma lógica condicional para a política de bucket, afim de definir o escopo do acesso do bucket apenas para os usuários que estão usando essa Role ao acessar o bucket. O uso de lógica condicional em vez de um elemento NotPrincipal
permite o uso de uma string curinga (*) afim de permitir que qualquer nome de Role Session seja aceito.
Agora que você tem o ID da Role à qual deseja permitir o acesso, é necessário bloquear o acesso de outros usuários na mesma conta que o bucket. A política para bloquear o acesso ao bucket e seus objetos para usuários que não estão usando o perfil do IAM ou as credenciais da conta root seria semelhante à seguinte.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": [ "arn:aws:s3:::MyExampleBucket", "arn:aws:s3:::MyExampleBucket/*" ], "Condition": { "StringNotLike": { "aws:userId": [ "AROAEXAMPLEID:*", "111111111111" ] } } } ] }
Você também pode usar essa mesma política para usuários do IAM. Um usuário do IAM tem um ID exclusivo começando com AIDA que você pode usar para essa finalidade. Para encontrar esse ID exclusivo:
- Com a AWS CLI instalada, abra um prompt de comando ou shell.
- Execute o comando:
aws iam get-user -–user-name
USER-NAME - Na saída, procure a string
userId
, que começará com AIDAEXAMPLEID.
Quando tiver identificado a string userId
, você pode colocá-la no conjunto de condições “aws:userId
”, conforme mostrado no exemplo a seguir.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": [ "arn:aws:s3:::MyExampleBucket", "arn:aws:s3:::MyExampleBucket/*" ], "Condition": { "StringNotLike": { "aws:userId": [ "AROAEXAMPLEID:*", "AIDAEXAMPLEID", "111111111111" ] } } } ] }
Conceder acesso entre contas a um bucket para uma IAM Role específica
Na seção anterior, mostrei como restringir o acesso do bucket S3 à IAM Roles ou usuários específicos na mesma conta. Agora, vou mostrar como restringir o acesso a usuários e Roles específicos em outra conta. Ao conceder acesso ao bucket entre contas a um usuário ou IAM Role, você deve definir o que esse usuário ou IAM Role tem permissão para fazer com esse acesso. Anteriormente, no Blog de segurança da AWS, Jim Scharf escreveu sobre as permissões necessárias para permitir que uma entidade do IAM acesse um bucket por meio da CLI/API e da Console. Usando as informações encontradas nesta publicação anterior do blog, a política de bucket de acesso no nível da CLI/API seria semelhante à seguinte:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111111111111:role/ROLENAME" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::MyExampleBucket" }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111111111111:role/ROLENAME" }, "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::MyExampleBucket/*" }, { "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": [ "arn:aws:s3:::MyExampleBucket", "arn:aws:s3:::MyExampleBucket/*" ], "Condition": { "StringNotLike": { "aws:userId": [ "AROAEXAMPLEID:*", "111111111111" ] } } } ] }
As ações de serviço necessárias para acesso no nível da Console, como o que seria usado com a funcionalidade IAM Switch Role para a AWS Console, são mostradas na política a seguir.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111111111111:role/ROLENAME" }, "Action": [ "s3:GetBucketLocation" ], "Resource": "*" }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111111111111:role/ROLENAME" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::MyExampleBucket" }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111111111111:role/ROLENAME" }, "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::MyExampleBucket/*" }, { "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": [ "arn:aws:s3:::MyExampleBucket", "arn:aws:s3:::MyExampleBucket/*" ], "Condition": { "StringNotLike": { "aws:userId": [ "AROAEXAMPLEID:*", "111111111111" ] } } } ] }
Para conceder acesso de API/CLI a um usuário do IAM em outra conta, você precisaria adicionar AIDAEXAMPLEID para o usuário do IAM à condição “aws:userId
”, como fizemos na seção anterior. Além da condição “aws:userId
”, você também precisaria adicionar o ARN completo do usuário do IAM ao elemento Principal dessas políticas. Observe que você não pode conceder acesso entre contas via AWS Console a um usuário do IAM, porque esse usuário precisaria assumir uma Role na conta de destino, mas você pode conceder acesso ao bucket por meio da API/CLI. Isso seria o seguinte:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": [ { "AWS": [ "arn:aws:iam::222222222222:role/ROLENAME", "arn:aws:iam::222222222222:user/USERNAME" ] } ], "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::MyExampleBucket" }, { "Effect": "Allow", "Principal": [ { "AWS": [ "arn:aws:iam::222222222222:role/ROLENAME", "arn:aws:iam::222222222222:user/USERNAME" ] } ], "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::MyExampleBucket/*" }, { "Effect": "Deny", "Principal": "*", "Action": "s3:*", "Resource": [ "arn:aws:s3:::MyExampleBucket", "arn:aws:s3:::MyExampleBucket/*" ], "Condition": { "StringNotLike": { "aws:userId": [ "AROAEXAMPLEID:*", "AIDAEXAMPLEID", "111111111111" ] } } } ] }
Além de incluir permissões da Role na política do bucket, você precisa definir essas permissões nas políticas da IAM Role ou do usuário. As permissões podem ser adicionadas a uma política gerenciada pelo cliente e anexadas à Role ou ao usuário no console do IAM, com o seguinte documento de política.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:ListAllMyBuckets", "s3:GetBucketLocation" ], "Resource": "*" }, { "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::MyExampleBucket" }, { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::MyExampleBucket/*" } ] }
Seguindo as orientações desta publicação, você pode restringir o acesso do bucket do S3 a uma Role ou usuário específico do IAM em sua conta local e entre contas, mesmo que o usuário tenha uma política Admin ou uma política com s3:*. Existem muitas aplicações dessa lógica e os requisitos podem diferir entre os casos de uso. Você pode usar essa abordagem, por exemplo, para configurar um bucket para acesso por instâncias em um grupo do Auto Scaling. Você também pode usar essa abordagem para limitar o acesso a um bucket com uma necessidade de segurança de alto nível, como em um bucket com registros pessoais e informações contábeis. Lembre-se de que é sempre melhor conceder permissões somente aos recursos necessários para executar as tarefas necessárias.
Se você tiver comentários sobre esta postagem, envie-os na seção “Comentários” abaixo. Se você tiver dúvidas, inicie um novo tópico no fórum do IAM.
— Chris
Este artigo foi traduzido do Blog da AWS em Inglês.
Revisor
Bruno Lopes é Senior Solutions Architect no time da AWS LATAM. Trabalha com soluções de TI há mais de 14 anos, tendo em seu portfólio inúmeras experiências em workloads Microsoft, ambientes híbridos e capacitação técnica de clientes como Technical Trainer e Evangelista. Agora atua como um Arquiteto de Soluções, unindo todas as capacidades para desburocratizar a adoção das melhores tecnologias afim de ajudar os clientes em seus desafios diários.
Dan Rezende atualmente é Senior Technical Trainer no time da AWS LATAM. Ministra treinamentos diversos nos domínios de Arquitetura, Segurança e Migração. Dan também tem experiência prática, já trabalhou em diversos projetos implementando soluções e arquiteturas para suportar diversos workloads de missão crítica como SAP e apoiando projetos de migração, enquanto atuou como arquiteto no time de Serviços Profissionais antes de entrar para o time de Treinamento e Certificação.