权限和 AWS CDK - AWS Cloud Development Kit (AWS CDK) v2

这是 AWS CDK v2 开发者指南。较旧的 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

权限和 AWS CDK

C AWS onstruct Library 使用一些常见的、广泛实施的习语来管理访问和权限。该IAM模块为你提供了使用这些习语所需的工具。

AWS CDK AWS CloudFormation 用于部署更改。每次部署都涉及启动 AWS CloudFormation 部署的参与者(开发人员或自动化系统)。在执行此操作的过程中,角色将假设一个或多个IAM身份(用户或角色),并可以选择将角色传递给 AWS CloudFormation。

如果您使用 AWS IAM Identity Center 以用户身份进行身份验证,则单点登录提供程序会提供短期会话凭证,授权您充当预IAM定义的角色。要了解如何通过 Identity Center IAM 身份验证 AWS CDK 获取 AWS 凭证,请参阅AWS SDKs和工具参考指南中的了解IAM身份中心身份验证

主体

IAM委托人是经过身份验证的 AWS 实体,代表可以调用的用户、服务或应用程序 AWS APIs。 AWS 构造库支持以多种灵活的方式指定委托人,以授予他们访问您的 AWS 资源的权限。

在安全环境中,“委托人” 一词专门指经过身份验证的实体,例如用户。群组和角色之类的对象并不代表用户(以及其他经过身份验证的实体),而是为了授予权限而间接标识他们。

例如,如果您创建了一个IAM群组,则可以向该群组(以及其成员)授予对 Amazon RDS 表的写入权限。但是,群组本身不是委托人,因为它不代表单个实体(而且,您无法登录群组)。

在CDK的IAM库中,直接或间接标识主体的类实现了接IPrincipal口,从而允许这些对象在访问策略中互换使用。但是,从安全意义上讲,并非所有人都是主体。这些对象包括:

  1. IAM资源Role,例如User、和 Group

  2. 服务负责人 () new iam.ServicePrincipal('service.amazonaws.com')

  3. 联邦校长 () new iam.FederatedPrincipal('cognito-identity.amazonaws.com')

  4. 账户委托人 (new iam.AccountPrincipal('0123456789012'))

  5. 规范用户主体 () new iam.CanonicalUserPrincipal('79a59d[...]7ef2be')

  6. AWS Organizations 校长 () new iam.OrganizationPrincipal('org-id')

  7. 任意ARN主体 () new iam.ArnPrincipal(res.arn)

  8. 可以iam.CompositePrincipal(principal1, principal2, ...)信任多个委托人

授权

每个表示可以访问的资源(例如 Amazon S3 存储桶或 Amazon DynamoDB 表)的结构都有向其他实体授予访问权限的方法。所有这些方法的名称都以 g rant 开头。

例如,Amazon S3 存储桶具有方法grantReadgrantReadWrite (Python:grant_read,grant_read_write),用于分别启用实体对存储桶的读取和读/写访问权限。该实体不必确切知道执行这些操作需要哪些 Amazon S3 IAM 权限。

授予方法的第一个参数始终为类型IGrantable。此接口表示可以被授予权限的实体。也就是说,它表示具有角色的资源,例如IAM对象RoleUser、和Group

也可以向其他实体授予权限。例如,在本主题的后面部分,我们将介绍如何向 CodeBuild项目授予对 Amazon S3 存储桶的访问权限。通常,关联角色是通过被授予访问权限的实体的role属性获得的。

使用执行角色的资源(例如)也会实现 lambda.FunctionIGrantable,因此您可以直接向他们授予访问权限,而不必向其角色授予访问权限。例如,如果bucket是 Amazon S3 存储桶,并且function是 Lambda 函数,则以下代码授予该函数对该存储桶的读取权限。

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

有时,必须在部署堆栈时应用权限。其中一种情况是您向 AWS CloudFormation 自定义资源授予对其他资源的访问权限。自定义资源将在部署期间被调用,因此它在部署时必须具有指定的权限。

另一种情况是,当服务验证您传递给它的角色是否应用了正确的策略时。(许多 AWS 服务机构这样做是为了确保您不会忘记设置策略。) 在这种情况下,如果权限应用得太晚,部署可能会失败。

要强制在创建其他资源之前应用授予的权限,您可以添加对授权本身的依赖关系,如下所示。尽管通常会丢弃授予方法的返回值,但实际上每个授权方法都会返回一个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);

角色

该IAM软件包包含一个代表IAM角色的Role构造。以下代码创建了一个信任 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 });

您可以通过调用角色的方法 (Python:add_to_policy),传入定义要添加的规则的addToPolicyPolicyStatement方法来为该角色添加权限。该语句将添加到角色的默认策略中;如果没有,则创建一个。

以下示例在授权服务为条件下,向角色添加操作ec2:SomeActions3:AnotherAction资源bucketotherRole (Python:other_role) 的Deny策略声明 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" } } }));

在前面的示例中,我们使用 addToPolicy (Python:add_to_policy) 调用创建了一个新的PolicyStatement内联函数。您也可以传入现有的政策声明或您修改过的政策声明。该PolicyStatement对象有多种添加委托人、资源、条件和操作的方法

如果您使用的构造需要角色才能正常运行,则可以执行以下操作之一:

  • 在实例化构造对象时传入现有角色。

  • 让构造为您创建一个新角色,信任相应的服务主体。以下示例使用这样的构造: 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 });

创建对象后,角色(无论是传入的角色还是构造创建的默认角色)即可作为属性使用role。但是,此属性在外部资源上不可用。因此,这些构造有一个 addToRolePolicy (Python:add_to_role_policy) 方法。

如果构造是外部资源,则该方法不执行任何操作,否则它会调用该role属性的 addToPolicy (Python:add_to_policy) 方法。这样可以省去显式处理未定义案例的麻烦。

以下示例演示:

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 }));

资源策略

中的 AWS一些资源(例如 Amazon S3 存储桶和IAM角色)也有资源策略。这些构造有一个addToResourcePolicy方法 (Python:add_to_resource_policy),它以 a PolicyStatement 作为参数。添加到资源策略的每个策略声明都必须指定至少一个委托人。

在以下示例中,Amazon S3 存储桶向角色buckets3:SomeAction予了自身权限。

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 } }));

使用外部IAM对象

如果您在 AWS CDK 应用程序之外定义了IAM用户、委托人、群组或角色,则可以在 AWS CDK 应用程序中使用该IAM对象。为此,请使用其ARN或其名称创建对其的引用。(使用用户、组和角色的名称。) 然后,返回的引用可用于授予权限或构造策略声明,如前所述。

可以使用以下方法以类似的方式使用策略(包括托管策略)。您可以在需要IAM策略的任何地方使用对这些对象的引用。

注意

与对外部 AWS 资源的所有引用一样,您无法修改CDK应用程序中的外部IAM对象。