这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。
本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用 CDK 定义 L2 构造的权限 AWS
使用 Cloud Development Ki AWS t (CDK) 时,为 L2 结构定义 AWS 身份和访问管理 (IAM) 角色和策略。AWS
使用授予方法定义权限
使用构造库中的 L2 构 AWS 造定义基础设施时,您可以使用提供的授权方法来指定您的资源所需的权限。 AWS CDK 将自动为所有需要这些角色的 AWS 资源创建所需的 IAM 角色。
以下示例定义了 AWS Lambda 函数和亚马逊简单存储服务 (Amazon S3) 存储桶之间的权限。在本例中,存储桶 L2 构造的 grants.read 方法将用于定义以下权限:
例
- TypeScript
-
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as kms from 'aws-cdk-lib/aws-kms';
export class CdkDemoStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const key = new kms.Key(this, 'BucketKey');
const bucket = new s3.Bucket(this, 'Bucket', {
encryptionKey: key,
});
const handler = new lambda.Function(this, 'Handler', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
});
// Define permissions between function and S3 bucket using the read method from BucketGrants
bucket.grants.read(handler);
}
}
- JavaScript
-
const { Stack, Duration } = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');
const lambda = require('aws-cdk-lib/aws-lambda');
const kms = require('aws-cdk-lib/aws-kms');
class CdkDemoStack extends Stack {
constructor(scope, id, props) {
super(scope, id, props);
const key = new kms.Key(this, 'BucketKey');
const bucket = new s3.Bucket(this, 'Bucket', {
encryptionKey: key,
});
const handler = new lambda.Function(this, 'Handler', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
});
// Define permissions between function and S3 bucket using read method from BucketGrants
bucket.grants.read(handler);
}
}
// ...
- Python
-
from aws_cdk import (
Stack,
aws_s3 as s3,
aws_lambda as _lambda,
aws_kms as kms,
)
from constructs import Construct
class CdkDemoStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
key = kms.Key(self, 'BucketKey')
bucket = s3.Bucket(self, 'Bucket')
handler = _lambda.Function(
self,
'Handler',
runtime = _lambda.Runtime.NODEJS_20_X,
handler = 'index.handler',
code = _lambda.Code.from_asset('lambda'),
)
# Define permissions between function and S3 bucket using the read method from BucketGrants
bucket.grants.read(handler)
- Java
-
package com.myorg;
import software.amazon.awscdk.core.App;
import software.amazon.awscdk.core.Stack;
import software.amazon.awscdk.core.StackProps;
import software.amazon.awscdk.services.kms.Key;
import software.amazon.awscdk.services.kms.KeyProps;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.s3.BucketProps;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.FunctionProps;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.lambda.Code;
import software.constructs.Construct;
public class CdkDemoStack extends Stack {
public CdkDemoStack(final Construct scope, final String id) {
this(scope, id, null);
}
public CdkDemoStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
Key key = new Key(this, "BucketKey", KeyProps.builder().build());
Bucket bucket = new Bucket(this, "Bucket", BucketProps.builder()
.encryptionKey(key)
.build());
Function handler = new Function(this, "Handler", FunctionProps.builder()
.runtime(Runtime.NODEJS_20_X)
.handler("index.handler")
.code(Code.fromAsset("lambda"))
.build());
// Define permissions between function and S3 bucket using the read method from BucketGrants
bucket.getGrants().read(handler);
}
public static void main(final String[] args) {
App app = new App();
new CdkDemoStack(app, "CdkDemoStack");
app.synth();
}
}
- C#
-
using Amazon.CDK;
using Amazon.CDK.AWS.KMS;
using Amazon.CDK.AWS.S3;
using Amazon.CDK.AWS.Lambda;
namespace CdkDemo
{
public class CdkDemoStack : Stack
{
internal CdkDemoStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
var key = new Key(this, "BucketKey");
var bucket = new Bucket(this, "Bucket", new BucketProps
{
EncryptionKey = key
});
var handler = new Function(this, "Handler", new FunctionProps
{
Runtime = Runtime.NODEJS_20_X,
Handler = "index.handler",
Code = Code.FromAsset("lambda")
});
// Define permissions between function and S3 bucket using the Read method from BucketGrants
bucket.Grants.Read(handler);
}
}
}
- Go
-
package main
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awskms"
"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
"github.com/aws/aws-cdk-go/awscdk/v2/awslambda"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
// ...
func NewCdkDemoStack(scope constructs.Construct, id string, props *CdkDemoStackProps) awscdk.Stack {
stack := awscdk.NewStack(scope, &id, &props.StackProps)
key := awskms.NewKey(stack, jsii.String("BucketKey"), nil)
bucket := awss3.NewBucket(stack, jsii.String("Bucket"), &awss3.BucketProps{
EncryptionKey: key,
})
handler := awslambda.NewFunction(stack, jsii.String("Handler"), &awslambda.FunctionProps{
Runtime: awslambda.Runtime_NODEJS_20_X(),
Handler: jsii.String("index.handler"),
Code: awslambda.Code_FromAsset(jsii.String("lambda"), &awss3assets.AssetOptions{}),
})
bucket.Grants().Read(handler)
return stack
}
// ...
当您使用 L2 结构的授予方法来定义资源之间的权限时, AWS CDK 将根据您指定的方法创建具有最低权限策略的角色。作为一项安全最佳实践,我们建议您使用仅应用您所需权限的方法。例如,如果您只需要授予 Lambda 函数从 Amazon S3 存储桶读取数据的权限,请使用 grants.read 方法而不是 grants.readWrite。
对于您使用的每种方法,CDK 都会为指定资源创建唯一的 IAM 角色。如有必要,您还可以直接修改将附加到该角色的策略。以下是示例:
例
- TypeScript
-
import { aws_iam as iam } from 'aws-cdk-lib';
handler.addToRolePolicy(new iam.PolicyStatement({
actions: ['s3:GetObject', 's3:List*'],
resources: [
bucket.bucketArn,
bucket.arnForObjects('*'),
]
}));
- JavaScript
-
const iam = require('aws-cdk-lib/aws-iam');
handler.addToRolePolicy(new iam.PolicyStatement({
actions: ['s3:GetObject', 's3:List*'],
resources: [
bucket.bucketArn,
bucket.arnForObjects('*'),
]
}));
- Python
-
from aws_cdk import aws_iam as iam
handler.add_to_role_policy(iam.PolicyStatement(
actions=['s3:GetObject', 's3:List*'],
resources=[
bucket.bucket_arn,
bucket.arn_for_objects('*'),
]
))
- Java
-
import software.amazon.awscdk.services.iam.PolicyStatement;
import software.amazon.awscdk.services.iam.PolicyStatementProps;
handler.addToRolePolicy(PolicyStatement.Builder.create()
.actions(Arrays.asList("s3:GetObject", "s3:List*"))
.resources(Arrays.asList(
bucket.getBucketArn(),
bucket.arnForObjects("*")
))
.build());
- C#
-
using Amazon.CDK.AWS.IAM;
using Amazon.CDK.AWS.S3;
using Amazon.CDK.AWS.Lambda;
handler.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps
{
Actions = new[] { "s3:GetObject", "s3:List*" },
Resources = new[] { bucket.BucketArn, bucket.ArnForObjects("*") }
}));
- Go
-
package main
import (
// ...
"github.com/aws/aws-cdk-go/awscdk/v2/awsiam"
// ...
)
// ...
func NewCdkDemoStack(scope constructs.Construct, id string, props *CdkDemoStackProps) awscdk.Stack {
// ...
handler.AddToRolePolicy(awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{
Actions: jsii.Strings("s3:GetObject", "s3:List*"),
Resources: jsii.Strings(bucket.BucketArn(), bucket.ArnForObjects("*")),
}))
// ...
}
但是,我们建议您在可用时使用该grants属性中的方法。
手动创建和使用 IAM 角色
如果您不想使用 CDK grant 方法创建和管理权限,则必须手动创建和配置权限。您可以使用 AWS 管理控制台、 AWS CLI 或创建 IAM 角色 AWS SDKs。然后,您可以手动将它们传入 CDK 应用程序中,也可以使用角色自定义功能。
手动引用和管理所有角色
需要角色的构造有一个可选 role 属性,可用于传入角色对象。
- 手动引用角色
-
-
使用 Role.fromRoleName() 引用已有色。以下是示例:
const existingRole = Role.fromRoleName(stack, 'Role', 'my-pre-existing-role', {
mutable: false // Prevent CDK from attempting to add policies to this role
})
-
在定义资源时传递已有角色。以下是示例:
const handler = new lambda.Function(stack, 'Handler', { runtime: lambda.Runtime.NODEJS_20_XZ, handler:
'index.handler', code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')), // Pass in pre-existing role
role: existingRole, });
使用角色自定义功能
AWS CDK 角色自定义功能会生成 CDK 应用程序中角色和策略的报告。您可以使用此功能生成报告。然后您可以用预先创建的角色代替它们。
- 使用角色自定义功能
-
-
在 CDK 应用程序顶部某处添加 Role.customizeRoles()。以下是示例:
const stack = new Stack(app, 'LambdaStack');
// Add this to use the role customization feature
iam.Role.customizeRoles(stack);
// Define your resources using L2 constructs
const key = new kms.Key(stack, 'BucketKey');
const bucket = new s3.Bucket(stack, 'Bucket', {
encryptionKey: key,
});
const handler = new lambda.Function(stack, 'Handler', {
runtime: lambda.Runtime.NODEJS_16_X,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')),
});
// The grants.read() is still important. Even though it actually doesn't mutate
// any policies, it indicates the need for them.
bucket.grants.read(handler);
-
合成应用程序时,CDK 会抛出一个错误,表示您需要向 Role.customizeRoles() 提供预先创建的角色名。以下是生成的报告的示例:
<missing role> (LambdaStack/Handler/ServiceRole)
AssumeRole Policy:
[
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
]
Managed Policy ARNs:
[
"arn:(PARTITION):iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
Managed Policies Statements:
NONE
Identity Policy Statements:
[
{
"Action": [
"s3:GetObject*",
"s3:GetBucket*",
"s3:List*"
],
"Effect": "Allow",
"Resource": [
"(LambdaStack/Bucket/Resource.Arn)",
"(LambdaStack/Bucket/Resource.Arn)/*"
]
}
]
-
创建角色后,您可以将其传入应用程序中以应用于资源。例如,如果为 LambdaStack/Handler/ServiceRole 创建的角色名称为 lambda-service-role,则应按如下方式更新 CDK 应用程序:
const stack = new Stack(app, 'LambdaStack');
// Add this to pass in the role
iam.Role.customizeRoles(stack, {
usePrecreatedRoles: {
'LambdaStack/Handler/ServiceRole': 'lambda-service-role',
},
});
现在,CDK 将在 CDK 应用程序中引用角色的任何位置使用预先创建的角色名称。它还将继续生成报告,以便可以参考未来的任何策略更改。
您会注意到,报告中对 Amazon S3 存储桶 ARN 的引用显示为(LambdaStack/Bucket/Resource.Arn),而不是存储桶的实际 ARN。这是因为存储桶 ARN 是一个部署时间值,在合成时(存储桶尚未创建)未知。这是我们为何建议允许 CDK 使用提供的 grant 方法管理 IAM 角色和权限的又一个示例。要使用初始策略创建角色,管理员必须创建具有更广泛权限的策略(例如,arn:aws:s3:::*)。