这是 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
口,从而允许这些对象在访问策略中互换使用。但是,从安全意义上讲,并非所有人都是主体。这些对象包括:
授权
每个表示可以访问的资源(例如 Amazon S3 存储桶或 Amazon DynamoDB 表)的结构都有向其他实体授予访问权限的方法。所有这些方法的名称都以 g rant 开头。
例如,Amazon S3 存储桶具有方法grantRead
和 grantReadWrite
(Python:grant_read
,grant_read_write
),用于分别启用实体对存储桶的读取和读/写访问权限。该实体不必确切知道执行这些操作需要哪些 Amazon S3 IAM 权限。
授予方法的第一个参数始终为类型IGrantable。此接口表示可以被授予权限的实体。也就是说,它表示具有角色的资源,例如IAM对象Role
User
、和Group
。
也可以向其他实体授予权限。例如,在本主题的后面部分,我们将介绍如何向 CodeBuild项目授予对 Amazon S3 存储桶的访问权限。通常,关联角色是通过被授予访问权限的实体的role
属性获得的。
使用执行角色的资源(例如)也会实现 lambda.Function
IGrantable
,因此您可以直接向他们授予访问权限,而不必向其角色授予访问权限。例如,如果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
),传入定义要添加的规则的addToPolicy
PolicyStatement
方法来为该角色添加权限。该语句将添加到角色的默认策略中;如果没有,则创建一个。
以下示例在授权服务为条件下,向角色添加操作ec2:SomeAction
和s3:AnotherAction
资源bucket
和 otherRole
(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对象有多种添加委托人、资源、条件和操作的方法。
如果您使用的构造需要角色才能正常运行,则可以执行以下操作之一:
- 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 存储桶向角色bucket
授s3: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对象。