介绍
建立DynamoDB的交叉算法访问可能是一个复杂的任务,尤其是在浏览配置多个AWS帐户的复杂性时。但是,通过采用Terraform和Node.js的功能,您可以克服这一挑战并创建强大而有效的多学院设置。在本文中,我们将指导您使用Terraform和Node.js设置DynamoDB的交叉算法访问的过程,使您可以轻松地在两个单独的AWS帐户上管理和获取数据。
此设置的好处很多。它不仅简化了您的项目资源管理,而且通过隔离帐户之间的资源来大大提高安全性。此外,它允许更好的可扩展性,使您的基础架构随着项目的需求而增长和发展。因此,让我们踏上这一激动人心的旅程,探索跨学院DynamoDB访问的世界!
先决条件
在开始之前,至关重要的是要确保您拥有必要的工具和服务。对于本教程,您将需要以下内容:
-
两个AWS帐户:带有DDB表和消费者的主要AWS帐户可以空白。
-
Terraform:我们将使用Terraform自动化AWS资源的创建和管理。要安装Terraform,请按照official documentation中的说明。
-
node.js:我们将使用节点构建我们从DynamoDB获取数据的示例应用程序。另外,serverless将用于部署应用程序。
本指南假定您对AWS组件,Terraform和JavaScript语法有基本的了解。
现在您拥有所有必要的工具和服务,让我们向前迈进并设置我们的AWS环境,以供交叉插件dynamodb访问。
AWS设置概述
让我们在详细信息之前先审查AWS设置:
:主帐户帐户保留DDB表,我们需要访问
消费者帐户应该从主帐户中授予对DDB表的访问。
-
main aws帐户创建一个角色(consumer_account_role),该角色将允许消费者帐户为 main main 帐户提供凭证/strong>帐户。
-
在 main 帐户中创建一个策略(main_account_ddb_policies_fell),该策略将允许访问DDB表。
-
在 Main 帐户附加ain_account_ddb_policies_full to compution_account_role。
-
使用1个步骤,我们创建了一个信任策略规则,该规则允许消费者帐户使用commuter_account_role。
-
在消费者帐户中,我们创建了一项策略,该策略将允许消费者lambda使用commuter_account_role。
应用层概述
-
由于示例消费者lambda可以通过随附的consumer_account_access_policy访问consumer_role,我们需要访问issue temporary credentials using Security Token Service (STS)访问ddb表。
-
必须使用从STS呼叫返回的已发行凭据来实例化DDB客户端和查询数据。
现在我们已经熟悉所有移动的零件,最有趣的部分留给了所有这些代码!
Terraform配置
使用Terraform为Main帐户创建3件事:
-
aws_iam_role
,消费者帐户将使用 -
aws_iam_policy
,它将允许下面的角色访问DDB表来执行特定的操作。 -
aws_iam_policy_attachment
- 将角色和政策链接在一起。
此模块可以具有3个参数以输入:
-
消费者帐户ID。
-
ddb表名。
-
环境名称(以防万一)。
一次设置看起来很好。 1策略 - > 1个附件 - > 1个角色。但是,如果我们需要从一个表格上阅读并完全访问另一个表怎么办?
我们应该再复制此设置,但对于另一个表格?
让我们创建一个可以处理这些情况的模块:
# main.tf
resource "aws_iam_role" "ddb_access_role" {
name = "${var.env}-ddb_cross_acc_access_role-${var.consumer_account_id}"
description = "Role that provides access to DynamoDB tables for account ${var.consumer_account_id} on ${var.env} env"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${var.consumer_account_id}:root"
}
}
]
})
}
resource "aws_iam_policy" "ddb_table_policy" {
for_each = { for table_access in var.table_access_list : table_access.table_name => table_access }
name = "${var.env}-DynamoDBTableAccess-${var.consumer_account_id}-${each.key}"
description = "Access policy to DynamoDB ${each.key} table for account ${var.consumer_account_id} on ${var.env} env"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = lookup({
"Read" = [
"dynamodb:BatchGetItem",
"dynamodb:GetItem",
"dynamodb:Query",
"dynamodb:Scan"
],
"ReadWriteUpdate" = [
"dynamodb:BatchWriteItem",
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem"
],
"Full" = ["dynamodb:*"]
}, each.value.access_type, [])
Effect = "Allow"
Resource = [
"arn:aws:dynamodb:*:${data.aws_caller_identity.current.account_id}:table/${each.key}",
"arn:aws:dynamodb:*:${data.aws_caller_identity.current.account_id}:table/${each.key}/index/*"
]
}
]
})
}
resource "aws_iam_policy_attachment" "ddb_access_policy_attachment" {
for_each = aws_iam_policy.ddb_table_policy
policy_arn = each.value.arn
roles = [aws_iam_role.ddb_access_role.name]
name = "cross_acc_access_policy_attachment-${var.consumer_account_id}-${each.key}"
}
data "aws_caller_identity" "current" {}
IAM角色
创建的aws_iam_role.ddb_access_role
具有以下格式的名称:[var.env]-ddb_cross_acc_access_role-[var.consumer_account_id]
。
假设_role_policy IAM角色的属性设置为JSON编码的字符串,该字符串定义了担任角色的权限。在这种情况下,该政策授予指定AWS帐户(arn:aws:iam::${var.consumer_account_id}:root
)担任该角色的许可。应用Terraform后,您可以在IAM策略页面上的可信关系中查看此策略。
IAM政策
aws_iam_policy.ddb_table_policy
提供了对var.table_access_list
输入变量指定的DynamoDB表列表的访问。列表中的每个表都有关联的access_type
属性,该属性指定应授予哪种访问权限(Read, ReadWriteUpdate, Full
)。
策略授予基于access_type
属性的表访问。具体而言,该策略允许在表上定义的表上的某些DynamoDB操作(例如BatchGetItem, PutItem
等),该策略允许Lookup()函数,该功能返回相应的access_type的适当值。
for_each
属性用于为列表中的每个表创建单独的IAM策略。每个策略的名称都具有以下格式:[var.env]-DynamoDBTableAccess-[var.consumer_account_id]-${each.key}
。
需要制定一个策略,为每个帐户中的每个新表拥有一个唯一的名称,以便我们可以轻松地重用不同帐户和环境的模块,而不必担心名称重叠。
IAM政策附件
aws_iam_policy_attachment.ddb_access_policy_attachment
将IAM策略附加到较早创建的IAM角色。该附件是为每个IAM策略创建的作为aws_iam_policy.ddb_table_policy
资源块的一部分而创建的。
最后,data.aws_caller_identity.current
数据源用于检索Terraform用户的AWS帐户ID。帐户ID在IAM策略资源中使用,以授予该特定帐户的DynamoDB表访问。
不要忘记变量。tf
variable "consumer_account_id" {
type = string
description = "The AWS account ID of the account which gains access."
}
variable "env" {
type = string
description = "Environment name"
}
variable "table_access_list" {
description = "List of DynamoDB table names and access types"
type = list(object({
table_name = string,
access_type = string #allowed values are Read, ReadWriteUpdate, and Full
}))
}
用法
转到您的 main 帐户Terraform设置并使用我们刚创建的模块:
#.....
module "ddb_cross_acc_access" {
source = "path/to/module"
table_access_list = [
{
table_name = "my-table-1"
access_type = "ReadWriteUpdate"
},
{
table_name = "my-table-2"
access_type = "Read"
}
]
consumer_account_id = "123456789012"
env = "dev"
}
#.....
现在您可以看到,我们可以指定 main 帐户的访问级别将为消费者帐户提供DDB表!
Node.js应用程序设置
- 您可以使用很棒的serverless-iam-roles-per-function无服务器插件来创建每个功能的策略以访问STS:
ConsumerAccountExampleFunctions:
handler: src/handler.handler
name: ${self:provider.stage}-${self:service}-consumerAccountExampleFunctions
iamRoleStatements:
- Effect: 'Allow'
Action:
- 'sts:AssumeRole'
Resource:
- 'arn:aws:iam::${env:MAIN_ACCOUNT_ID}:role/${env:ENVIRONMENT}-ddb_cross_acc_access_role-${env:AWS_ACCOUNT_ID}'
是一个很好的安全惯例,因为我们严格控制了lambda可以访问的外部来源。
- 使用STS服务的授予凭证:
// get-sts-creds.ts
import {STS} from 'aws-sdk';
type CredentialsParams = {
RoleArn: string; // Optional - only required if assuming a role
RoleSessionName: string; // Optional - only required if assuming a role
};
export const getCredentials = async (params: CredentialsParams) => {
const stsClient = new STS();
// Assume the IAM role of the account that owns the target resource, if specified
const assumedRoleObject = await stsClient
.assumeRole({
RoleArn: params.RoleArn,
RoleSessionName: params.RoleSessionName,
})
.promise();
// Get temporary credentials
const credentials = {
accessKeyId: assumedRoleObject?.Credentials?.AccessKeyId || '',
secretAccessKey: assumedRoleObject?.Credentials?.SecretAccessKey || '',
sessionToken: assumedRoleObject?.Credentials?.SessionToken || '',
};
if (!credentials.accessKeyId && !credentials.secretAccessKey && !credentials.sessionToken) {
throw new Error('Credentials are not defined!');
}
return credentials;
};
- 使用凭据执行跨学会DDB调用!
import { DocumentClient } from 'aws-sdk/clients/dynamodb';
import { getCredentials } from './get-sts-creds.ts';
const tableName = 'ExampleDDBTableName';
// AWS_ACCOUNT_ID = Consumer account id
const roleArn = `arn:aws:iam::${process.env.MAIN_ACCOUNT_ID}:role/${process.env.ENVIRONMENT}-ddb_cross_acc_access_role-${process.env.AWS_ACCOUNT_ID}`;
const roleSessionName = 'my-session-name';
export const handler = async () => {
const credentials = await getCredentials({ RoleArn: roleArn, RoleSessionName: roleSessionName });
const ddbClient = new DocumentClient({
credentials
});
const params = { TableName: tableName };
const data = await ddbClient.scan(params).promise();
return data
};
概括
现在,您知道如何为粒状跨学会DDB创建Terraform模块:
-
在主帐户上,用消费者帐户可信关系创建角色
-
在主帐户上创建一个策略,其中包含DDB访问权限
-
在消费者帐户上创建一个策略,允许使用Mains帐户角色
-
在您的应用程序中使用STS客户端以从主帐户角色授予临时凭据
-
用授予的凭据执行DDB查询!