Permissões e o AWS CDK - AWS Cloud Development Kit (AWS CDK) v2

Este é o Guia do Desenvolvedor AWS CDK v2. A CDK v1 mais antiga entrou em manutenção em 1º de junho de 2022 e encerrou o suporte em 1º de junho de 2023.

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Permissões e o AWS CDK

A Biblioteca de Constructos da AWS usa alguns idiomas comuns e amplamente implementados para gerenciar o acesso e as permissões. O módulo IAM fornece as ferramentas necessárias para usar esses idiomas.

O AWS CDK usa AWS CloudFormation para implantar mudanças. Cada implantação envolve um ator (um desenvolvedor ou um sistema automatizado) que inicia uma implantação AWS CloudFormation. Ao fazer isso, o ator assumirá uma ou mais identidades do IAM (usuário ou perfil) e, opcionalmente, passará uma função para o AWS CloudFormation.

Se você usa o AWS IAM Identity Center para se autenticar como usuário, o provedor de login único fornece credenciais de sessão de curta duração que autorizam você a atuar como um perfil do IAM predefinido. Para saber como o AWS CDK obtém credenciais AWS da autenticação da Central de Identidade IAM, consulte Compreender a autenticação da Central de Identidade IAM no Guia de referência de ferarmentas e SDKs da AWS.

Entidades principais

Uma entidade principal do IAM é uma entidade AWS autenticada que representa um usuário, serviço ou aplicativo que pode chamar APIs AWS. A Biblioteca de Constructos da AWS é compatível com a especificação de entidades principais de várias maneiras flexíveis para conceder a elas acesso aos seus recursos da AWS.

Em contextos de segurança, o termo “entidade principal” se refere especificamente a entidades autenticadas, como usuários. Objetos como grupos e funções não representam usuários (e outras entidades autenticadas), mas os identificam indiretamente com o objetivo de conceder permissões.

Por exemplo, se você criar um grupo do IAM, poderá conceder ao grupo (e, portanto, a seus membros) acesso de gravação a uma tabela do Amazon RDS. No entanto, o grupo em si não é uma entidade principal porque não representa uma única entidade (além disso, você não pode fazer login em um grupo).

Na biblioteca IAM do CDK, classes que identificam direta ou indiretamente as entidades principais implementam a interface IPrincipal, permitindo que esses objetos sejam usados de forma intercambiável nas políticas de acesso. No entanto, nem todos são entidades principais no sentido de segurança. Esses objetos incluem:

  1. Recursos do IAM como Role, User e Group

  2. Entidades principais de serviço (new iam.ServicePrincipal('service.amazonaws.com'))

  3. Entidades principais federadas (new iam.FederatedPrincipal('cognito-identity.amazonaws.com'))

  4. Entidades principais da conta (new iam.AccountPrincipal('0123456789012')))

  5. Entidades principais de usuários canônicos (new iam.CanonicalUserPrincipal('79a59d[...]7ef2be'))

  6. Entidades principais do AWS Organizations (new iam.OrganizationPrincipal('org-id'))

  7. Entidades principais arbitrárias do ARN (new iam.ArnPrincipal(res.arn))

  8. Um iam.CompositePrincipal(principal1, principal2, ...) para confiar em várias entidades principais

Concessões

Cada constructo que representa um recurso que pode ser acessado, como um bucket do Amazon S3 ou uma tabela do Amazon DynamoDB, tem métodos que concedem acesso a outra entidade. Todos esses métodos têm nomes que começam com grant.

Por exemplo, os buckets do Amazon S3 têm os métodos grantRead e grantReadWrite (Python:grant_read, grant_read_write) para permitir o acesso de leitura e leitura/gravação, respectivamente, de uma entidade ao bucket. A entidade não precisa saber exatamente quais permissões do Amazon S3 IAM são necessárias para realizar essas operações.

O primeiro argumento de um método grant é sempre do tipo IGrantable. Essa interface representa entidades que podem receber permissões. Ou seja, ela representa recursos com funções, como os objetos do IAM Role, User e Group.

Outras entidades também podem receber permissões. Por exemplo, mais adiante neste tópico, mostraremos como conceder acesso a um bucket do Amazon S3 para um projeto do CodeBuild. Geralmente, a função associada é obtida por meio de uma propriedade role na entidade que está recebendo acesso.

Recursos que usam funções de execução, como o lambda.Function, também implementam o IGrantable, para que você possa conceder acesso direto a eles em vez de conceder acesso à função deles. Por exemplo, se bucket for um bucket do Amazon S3 e function for uma função do Lambda, o código a seguir concede à função acesso de leitura ao bucket.

TypeScript
bucket.grantRead(function);
JavaScript
bucket.grantRead(function);
Python
bucket.grant_read(function)
Java
bucket.grantRead(function);
C#
bucket.GrantRead(function);

Às vezes, as permissões precisam ser aplicadas enquanto sua pilha está sendo implantada. Um desses casos é quando você concede a um recurso personalizado AWS CloudFormation acesso a algum outro recurso. O recurso personalizado será invocado durante a implantação, portanto, ele deve ter as permissões especificadas no momento da implantação.

Outro caso é quando um serviço verifica se a função que você passa para ele tem as políticas corretas aplicadas. (Vários serviços AWS fazem isso para garantir que você não se esqueça de definir as políticas.) Nesses casos, a implantação pode falhar se as permissões forem aplicadas tarde demais.

Para forçar a aplicação das permissões da concessão antes da criação de outro recurso, você pode adicionar uma dependência da concessão em si, conforme mostrado aqui. Embora o valor de retorno dos métodos de concessão seja geralmente descartado, todo método de concessão na verdade retorna um objeto iam.Grant.

TypeScript
const grant = bucket.grantRead(lambda); const custom = new CustomResource(...); custom.node.addDependency(grant);
JavaScript
const grant = bucket.grantRead(lambda); const custom = new CustomResource(...); custom.node.addDependency(grant);
Python
grant = bucket.grant_read(function) custom = CustomResource(...) custom.node.add_dependency(grant)
Java
Grant grant = bucket.grantRead(function); CustomResource custom = new CustomResource(...); custom.node.addDependency(grant);
C#
var grant = bucket.GrantRead(function); var custom = new CustomResource(...); custom.node.AddDependency(grant);

Funções

O pacote do IAM contém um constructo Role que representa os perfis do IAM. O código a seguir cria uma nova função, confiando no serviço Amazon EC2.

TypeScript
import * as iam from 'aws-cdk-lib/aws-iam'; const role = new iam.Role(this, 'Role', { assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'), // required });
JavaScript
const iam = require('aws-cdk-lib/aws-iam'); const role = new iam.Role(this, 'Role', { assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com') // required });
Python
import aws_cdk.aws_iam as iam role = iam.Role(self, "Role", assumed_by=iam.ServicePrincipal("ec2.amazonaws.com")) # required
Java
import software.amazon.awscdk.services.iam.Role; import software.amazon.awscdk.services.iam.ServicePrincipal; Role role = Role.Builder.create(this, "Role") .assumedBy(new ServicePrincipal("ec2.amazonaws.com")).build();
C#
using Amazon.CDK.AWS.IAM; var role = new Role(this, "Role", new RoleProps { AssumedBy = new ServicePrincipal("ec2.amazonaws.com"), // required });

Você pode adicionar permissões a uma função chamando o método addToPolicy da função (Python: add_to_policy), passando um PolicyStatement que define a regra a ser adicionada. A declaração é adicionada à política padrão da função; se não tiver nenhuma, uma será criada.

O exemplo a seguir adiciona uma declaração de política Deny ao perfis para as ações ec2:SomeAction e s3:AnotherAction dos recursos bucket e otherRole (Python: other_role), sob a condição de que o serviço autorizado seja AWS CodeBuild.

TypeScript
role.addToPolicy(new iam.PolicyStatement({ effect: iam.Effect.DENY, resources: [bucket.bucketArn, otherRole.roleArn], actions: ['ec2:SomeAction', 's3:AnotherAction'], conditions: {StringEquals: { 'ec2:AuthorizedService': 'codebuild.amazonaws.com', }}}));
JavaScript
role.addToPolicy(new iam.PolicyStatement({ effect: iam.Effect.DENY, resources: [bucket.bucketArn, otherRole.roleArn], actions: ['ec2:SomeAction', 's3:AnotherAction'], conditions: {StringEquals: { 'ec2:AuthorizedService': 'codebuild.amazonaws.com' }}}));
Python
role.add_to_policy(iam.PolicyStatement( effect=iam.Effect.DENY, resources=[bucket.bucket_arn, other_role.role_arn], actions=["ec2:SomeAction", "s3:AnotherAction"], conditions={"StringEquals": { "ec2:AuthorizedService": "codebuild.amazonaws.com"}} ))
Java
role.addToPolicy(PolicyStatement.Builder.create() .effect(Effect.DENY) .resources(Arrays.asList(bucket.getBucketArn(), otherRole.getRoleArn())) .actions(Arrays.asList("ec2:SomeAction", "s3:AnotherAction")) .conditions(java.util.Map.of( // Map.of requires Java 9 or later "StringEquals", java.util.Map.of( "ec2:AuthorizedService", "codebuild.amazonaws.com"))) .build());
C#
role.AddToPolicy(new PolicyStatement(new PolicyStatementProps { Effect = Effect.DENY, Resources = new string[] { bucket.BucketArn, otherRole.RoleArn }, Actions = new string[] { "ec2:SomeAction", "s3:AnotherAction" }, Conditions = new Dictionary<string, object> { ["StringEquals"] = new Dictionary<string, string> { ["ec2:AuthorizedService"] = "codebuild.amazonaws.com" } } }));

No exemplo anterior, criamos uma nova linha PolicyStatement com a chamada addToPolicy (Python: add_to_policy). Você também pode transmitir uma declaração de política existente ou uma que você tenha modificado. O objeto PolicyStatement tem vários métodos para adicionar entidades principais, recursos, condições e ações.

Se estiver usando um constructo que requer uma função para funcionar corretamente, você pode executar uma das seguintes ações:

  • Passar uma função existente ao instanciar o objeto de constructo.

  • Deixar que o constructo crie uma nova função para você, confiando na entidade principal de serviço apropriada. O exemplo a seguir usa esse constructo: um projeto CodeBuild.

TypeScript
import * as codebuild from 'aws-cdk-lib/aws-codebuild'; // imagine roleOrUndefined is a function that might return a Role object // under some conditions, and undefined under other conditions const someRole: iam.IRole | undefined = roleOrUndefined(); const project = new codebuild.Project(this, 'Project', { // if someRole is undefined, the Project creates a new default role, // trusting the codebuild.amazonaws.com service principal role: someRole, });
JavaScript
const codebuild = require('aws-cdk-lib/aws-codebuild'); // imagine roleOrUndefined is a function that might return a Role object // under some conditions, and undefined under other conditions const someRole = roleOrUndefined(); const project = new codebuild.Project(this, 'Project', { // if someRole is undefined, the Project creates a new default role, // trusting the codebuild.amazonaws.com service principal role: someRole });
Python
import aws_cdk.aws_codebuild as codebuild # imagine role_or_none is a function that might return a Role object # under some conditions, and None under other conditions some_role = role_or_none(); project = codebuild.Project(self, "Project", # if role is None, the Project creates a new default role, # trusting the codebuild.amazonaws.com service principal role=some_role)
Java
import software.amazon.awscdk.services.iam.Role; import software.amazon.awscdk.services.codebuild.Project; // imagine roleOrNull is a function that might return a Role object // under some conditions, and null under other conditions Role someRole = roleOrNull(); // if someRole is null, the Project creates a new default role, // trusting the codebuild.amazonaws.com service principal Project project = Project.Builder.create(this, "Project") .role(someRole).build();
C#
using Amazon.CDK.AWS.CodeBuild; // imagine roleOrNull is a function that might return a Role object // under some conditions, and null under other conditions var someRole = roleOrNull(); // if someRole is null, the Project creates a new default role, // trusting the codebuild.amazonaws.com service principal var project = new Project(this, "Project", new ProjectProps { Role = someRole });

Depois que o objeto é criado, a função (seja a função passada ou a padrão criada pelo constructo) fica disponível como propriedade role. No entanto, essa propriedade não está disponível em recursos externos. Portanto, esses constructos têm um método addToRolePolicy (Python: add_to_role_policy).

O método não faz nada se o constructo for um recurso externo e, caso contrário, chama o método addToPolicy (Python: add_to_policy) da propriedade role. Isso evita que você precise lidar com o caso indefinido de forma explícita.

O exemplo a seguir demonstra:

TypeScript
// project is imported into the CDK application const project = codebuild.Project.fromProjectName(this, 'Project', 'ProjectName'); // project is imported, so project.role is undefined, and this call has no effect project.addToRolePolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, // ... and so on defining the policy }));
JavaScript
// project is imported into the CDK application const project = codebuild.Project.fromProjectName(this, 'Project', 'ProjectName'); // project is imported, so project.role is undefined, and this call has no effect project.addToRolePolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW // ... and so on defining the policy }));
Python
# project is imported into the CDK application project = codebuild.Project.from_project_name(self, 'Project', 'ProjectName') # project is imported, so project.role is undefined, and this call has no effect project.add_to_role_policy(iam.PolicyStatement( effect=iam.Effect.ALLOW, # ... and so on defining the policy )
Java
// project is imported into the CDK application Project project = Project.fromProjectName(this, "Project", "ProjectName"); // project is imported, so project.getRole() is null, and this call has no effect project.addToRolePolicy(PolicyStatement.Builder.create() .effect(Effect.ALLOW) // .. and so on defining the policy .build();
C#
// project is imported into the CDK application var project = Project.FromProjectName(this, "Project", "ProjectName"); // project is imported, so project.role is null, and this call has no effect project.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, // ... and so on defining the policy }));

Políticas de recursos

Alguns recursos AWS, como buckets do Amazon S3 e perfis do IAM, também têm uma política de recursos. Esses constructos têm um método addToResourcePolicy (Python: add_to_resource_policy), que usa PolicyStatement como argumento. Cada declaração de política adicionada a uma política de recursos deve especificar pelo menos uma entidade principal.

No exemplo a seguir, o bucket do Amazon S3 concede ao bucket um perfil com a permissão s3:SomeAction para si mesmo.

TypeScript
bucket.addToResourcePolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['s3:SomeAction'], resources: [bucket.bucketArn], principals: [role] }));
JavaScript
bucket.addToResourcePolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['s3:SomeAction'], resources: [bucket.bucketArn], principals: [role] }));
Python
bucket.add_to_resource_policy(iam.PolicyStatement( effect=iam.Effect.ALLOW, actions=["s3:SomeAction"], resources=[bucket.bucket_arn], principals=role))
Java
bucket.addToResourcePolicy(PolicyStatement.Builder.create() .effect(Effect.ALLOW) .actions(Arrays.asList("s3:SomeAction")) .resources(Arrays.asList(bucket.getBucketArn())) .principals(Arrays.asList(role)) .build());
C#
bucket.AddToResourcePolicy(new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Actions = new string[] { "s3:SomeAction" }, Resources = new string[] { bucket.BucketArn }, Principals = new IPrincipal[] { role } }));

Usando objetos externos do IAM

Se você definiu um usuário do IAM, entidade principal, grupo ou perfil do IAM fora do seu aplicativo AWS CDK, você pode usar esse objeto do IAM em seu aplicativo AWS CDK. Para fazer isso, crie uma referência a ele usando seu ARN ou seu nome. (Use o nome para usuários, grupos e perfis.) A referência retornada pode então ser usada para conceder permissões ou criar declarações de política, conforme explicado anteriormente.

As políticas (incluindo políticas gerenciadas) podem ser usadas de forma semelhante usando os métodos a seguir. Você pode usar referências a esses objetos em qualquer lugar em que uma política do IAM seja necessária.

nota

Como acontece com todas as referências a recursos externos AWS, você não pode modificar objetos externos do IAM em seu aplicativo CDK.