AWS CDK - 无法在 Lambda 中承担细粒度授权的角色
AWS CDK - Cannot assume role in Lambda for fine grained authorization
我对 AWS 的细节还很陌生,所以请原谅我的愚蠢问题。
我一直在寻找答案,但没有找到任何问题来回答我的问题。
我正在构建一个项目,我正在尝试使用此 AWS 教程正确完成权限:https://aws.amazon.com/blogs/apn/partitioning-pooled-multi-tenant-saas-data-with-amazon-dynamodb/
我已经创建了角色和策略:
const tenantUserRole = new Role(this, "TenantUserRole", {
assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
});
table.grantReadWriteData(tenantUserRole);
然后,在我的 Lambda 中,我试图:
const role = await stsClient.send(
new AssumeRoleCommand({
Policy: getPolicy("tenant"),
RoleArn: process.env.TENANT_ROLE_ARN,
RoleSessionName: "foo",
})
);
这不起作用,因为我在 Lambda 中遇到错误:
{
"errorType": "AccessDenied",
"errorMessage": "User: arn:aws:sts::xxx:assumed-role/ProjectStack-createUserServiceRoleB9D8AADE-GRDI6MWXA5MY/ProjectStack-createUserC6ED88E6-K0S95UXTN9MH is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::xxx:role/ProjectStack-TenantUserRoleB79B8D3A-11N644X7UF0SR",
"trace": [
"AccessDenied: User: arn:aws:sts::xxx:assumed-role/ProjectStack-createUserServiceRoleB9D8AADE-GRDI6MWXA5MY/ProjectStack-createUserC6ED88E6-K0S95UXTN9MH is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::xxx:role/ProjectStack-TenantUserRoleB79B8D3A-11N644X7UF0SR",
目标是始终根据用户上下文解析权限,那么我应该在我的 CDK 堆栈中做什么才能使我的所有 Lambda 执行必须完成的操作?
关于谁是校长似乎存在误解
当您在 Lambda 函数中尝试调用其他 AWS API 操作时,实际上 而不是 服务 lambda.amazonaws.com
进行调用,而是 Lambda 函数承担的角色。
这意味着您不能允许服务 lambda.amazonaws.com
代入您的 TenantUserRole
,而是需要允许该函数使用的角色代入该角色。
您需要同时配置代入角色策略以及 lambda 函数角色的权限,以允许它调用 sts:AssumeRole
。
如@Maurice 所述,应该信任角色而不是服务主体(llambda.amazonaws.com
)。
下面是CDK代码。
TenantUserRole
受 apiRole
信任,aws lambda
正在使用
import * as cdk from '@aws-cdk/core';
import * as iam from '@aws-cdk/aws-iam';
export class CdkWorkshopStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// aws lambda role
const lambdaRole = new iam.Role(this, 'apiRole', {
roleName: 'apiRole',
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});
// trusted by TenantUserRole for access
const tenantUserRole = new iam.Role(this, 'TenantUserRole', {
roleName: 'TenantUserRole',
assumedBy: new iam.ArnPrincipal(lambdaRole.roleArn),
});
// policy to allow assume role TenantUserRole
lambdaRole.addToPolicy(
new iam.PolicyStatement({
resources: [tenantUserRole.roleArn],
actions: ['sts:AssumeRole'],
})
);
}
}
这里看起来像在角色的信任策略中。
❯❯ aws iam get-role --role-name TenantUserRole
{
"Role": {
"Path": "/",
"RoleName": "TenantUserRole",
"RoleId": "AROA2WXKNDTKKGFADASD",
"Arn": "arn:aws:iam::1234567890:role/TenantUserRole",
"CreateDate": "2021-03-03T23:34:13+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::1234567890:role/apiRole"
},
"Action": "sts:AssumeRole"
}
]
},
"Description": "",
"MaxSessionDuration": 3600,
"RoleLastUsed": {}
}
}
允许 aws lambda 角色承担的政策TenantUserRole
❯❯ aws iam get-role-policy --role-name apiRole --policy-name apiRoleDefaultPolicy771DC0DD
{
"RoleName": "apiRole",
"PolicyName": "apiRoleDefaultPolicy771DC0DD",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::1234567890:role/TenantUserRole",
"Effect": "Allow"
}
]
}
}
在 lambda 中,您需要在假设 TenantUserRole
之后使用这些凭据并创建 dynamodb
客户端,然后使用该客户端进行 api 调用 putItem
import boto3
def lambda_handler(event, context):
sts = boto3.client('sts')
// assume TenantUserRole
creds = sts.assume_role(
RoleArn='arn:aws:iam::1234567890:role/TenantUserRole',
RoleSessionName="tempsession"
)
// Use Credentials from the assume call to make dynamodb client
tenant_user_dyanmodb_client = boto3.client(
'dynamodb',
aws_access_key_id=creds.get('Credentials').get('AccessKeyId'),
aws_secret_access_key=creds.get('Credentials').get('SecretAccessKey'),
aws_session_token=creds.get('Credentials').get('SessionToken')
)
// call put item
tenant_user_dyanmodb_client.put_item(TableName='fruitSalad', Item={'fruitName':{'S':'Banana'},'key2':{'N':'value2'}})
我对 AWS 的细节还很陌生,所以请原谅我的愚蠢问题。 我一直在寻找答案,但没有找到任何问题来回答我的问题。
我正在构建一个项目,我正在尝试使用此 AWS 教程正确完成权限:https://aws.amazon.com/blogs/apn/partitioning-pooled-multi-tenant-saas-data-with-amazon-dynamodb/
我已经创建了角色和策略:
const tenantUserRole = new Role(this, "TenantUserRole", {
assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
});
table.grantReadWriteData(tenantUserRole);
然后,在我的 Lambda 中,我试图:
const role = await stsClient.send(
new AssumeRoleCommand({
Policy: getPolicy("tenant"),
RoleArn: process.env.TENANT_ROLE_ARN,
RoleSessionName: "foo",
})
);
这不起作用,因为我在 Lambda 中遇到错误:
{ "errorType": "AccessDenied", "errorMessage": "User: arn:aws:sts::xxx:assumed-role/ProjectStack-createUserServiceRoleB9D8AADE-GRDI6MWXA5MY/ProjectStack-createUserC6ED88E6-K0S95UXTN9MH is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::xxx:role/ProjectStack-TenantUserRoleB79B8D3A-11N644X7UF0SR", "trace": [ "AccessDenied: User: arn:aws:sts::xxx:assumed-role/ProjectStack-createUserServiceRoleB9D8AADE-GRDI6MWXA5MY/ProjectStack-createUserC6ED88E6-K0S95UXTN9MH is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::xxx:role/ProjectStack-TenantUserRoleB79B8D3A-11N644X7UF0SR",
目标是始终根据用户上下文解析权限,那么我应该在我的 CDK 堆栈中做什么才能使我的所有 Lambda 执行必须完成的操作?
关于谁是校长似乎存在误解
当您在 Lambda 函数中尝试调用其他 AWS API 操作时,实际上 而不是 服务 lambda.amazonaws.com
进行调用,而是 Lambda 函数承担的角色。
这意味着您不能允许服务 lambda.amazonaws.com
代入您的 TenantUserRole
,而是需要允许该函数使用的角色代入该角色。
您需要同时配置代入角色策略以及 lambda 函数角色的权限,以允许它调用 sts:AssumeRole
。
如@Maurice 所述,应该信任角色而不是服务主体(llambda.amazonaws.com
)。
下面是CDK代码。
TenantUserRole
受 apiRole
信任,aws lambda
import * as cdk from '@aws-cdk/core';
import * as iam from '@aws-cdk/aws-iam';
export class CdkWorkshopStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// aws lambda role
const lambdaRole = new iam.Role(this, 'apiRole', {
roleName: 'apiRole',
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});
// trusted by TenantUserRole for access
const tenantUserRole = new iam.Role(this, 'TenantUserRole', {
roleName: 'TenantUserRole',
assumedBy: new iam.ArnPrincipal(lambdaRole.roleArn),
});
// policy to allow assume role TenantUserRole
lambdaRole.addToPolicy(
new iam.PolicyStatement({
resources: [tenantUserRole.roleArn],
actions: ['sts:AssumeRole'],
})
);
}
}
这里看起来像在角色的信任策略中。
❯❯ aws iam get-role --role-name TenantUserRole
{
"Role": {
"Path": "/",
"RoleName": "TenantUserRole",
"RoleId": "AROA2WXKNDTKKGFADASD",
"Arn": "arn:aws:iam::1234567890:role/TenantUserRole",
"CreateDate": "2021-03-03T23:34:13+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::1234567890:role/apiRole"
},
"Action": "sts:AssumeRole"
}
]
},
"Description": "",
"MaxSessionDuration": 3600,
"RoleLastUsed": {}
}
}
允许 aws lambda 角色承担的政策TenantUserRole
❯❯ aws iam get-role-policy --role-name apiRole --policy-name apiRoleDefaultPolicy771DC0DD
{
"RoleName": "apiRole",
"PolicyName": "apiRoleDefaultPolicy771DC0DD",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::1234567890:role/TenantUserRole",
"Effect": "Allow"
}
]
}
}
在 lambda 中,您需要在假设 TenantUserRole
之后使用这些凭据并创建 dynamodb
客户端,然后使用该客户端进行 api 调用 putItem
import boto3
def lambda_handler(event, context):
sts = boto3.client('sts')
// assume TenantUserRole
creds = sts.assume_role(
RoleArn='arn:aws:iam::1234567890:role/TenantUserRole',
RoleSessionName="tempsession"
)
// Use Credentials from the assume call to make dynamodb client
tenant_user_dyanmodb_client = boto3.client(
'dynamodb',
aws_access_key_id=creds.get('Credentials').get('AccessKeyId'),
aws_secret_access_key=creds.get('Credentials').get('SecretAccessKey'),
aws_session_token=creds.get('Credentials').get('SessionToken')
)
// call put item
tenant_user_dyanmodb_client.put_item(TableName='fruitSalad', Item={'fruitName':{'S':'Banana'},'key2':{'N':'value2'}})