问题描述
我需要执行 Terraform 模板来为我可以通过担任角色访问的 AWS 账户预置基础设施.
我现在遇到的问题是我在该 AWS 账户中没有 IAM 用户,因此我没有 aws_access_key_id
或 aws_secret_access_key
来设置另一个命名配置文件在我的 ~/.aws/credentials
中.当我运行命令 terraform apply
时,模板会为我的帐户而不是其他帐户创建基础架构.
如何使用您的帐户运行 Terraform 模板,该帐户具有访问另一个 AWS 帐户服务的角色?
这是我的 Terraform 文件:
# 输入变量变量aws_region"{类型 = 字符串"默认=我们-东-1"}变量管道名称"{类型 = 字符串"默认 =静态网站 terraform"}变量github_username"{类型 = 字符串"默认=公司"}变量github_token"{类型 = 字符串"}变量github_repo"{类型 = 字符串"}提供者aws"{区域 = "${var.aws_region}"假设角色{role_arn = "arn:aws:iam::<AWS-ACCOUNT-ID>:role/admin"配置文件 = 默认"}}# CodePipeline 资源资源aws_s3_bucket"build_artifact_bucket"{bucket = "${var.pipeline_name}-artifact-bucket"acl =私人"}数据aws_iam_policy_document"codepipeline_assume_policy"{陈述 {效果=允许"动作 = ["sts:AssumeRole"]校长{类型=服务"标识符 = [codepipeline.amazonaws.com"]}}}资源aws_iam_role"codepipeline_role"{name = "${var.pipeline_name}-codepipeline-role"假设角色策略 = "${data.aws_iam_policy_document.codepipeline_assume_policy.json}"}# 使用 CodeCommit 和 CodeBuild 所需的 CodePipeline 策略资源aws_iam_role_policy"attach_codepipeline_policy"{name = "${var.pipeline_name}-codepipeline-policy"角色 = "${aws_iam_role.codepipeline_role.id}"策略 = <<EOF{陈述": [{行动": ["s3:GetObject","s3:GetObjectVersion","s3:GetBucketVersioning",s3:放置对象"],资源":*",效果":允许"},{行动": [云观察:*","sns:*",平方:*",我:密码角色"],资源":*",效果":允许"},{行动": ["codebuild:BatchGetBuilds",代码构建:开始构建"],资源":*",效果":允许"}],版本":2012-10-17"}EOF}# CodeBuild IAM 权限资源aws_iam_role"codebuild_assume_role"{name = "${var.pipeline_name}-codebuild-role"假设角色策略 = <<EOF{版本":2012-10-17",陈述": [{效果":允许",主要的": {服务":codebuild.amazonaws.com"},动作":sts:AssumeRole"}]}EOF}资源aws_iam_role_policy"codebuild_policy"{name = "${var.pipeline_name}-codebuild-policy"角色 = "${aws_iam_role.codebuild_assume_role.id}"政策 = <<政策{版本":2012-10-17",陈述": [{行动": ["s3:PutObject","s3:GetObject","s3:GetObjectVersion",s3:GetBucketVersioning"],资源":*",效果":允许"},{效果":允许",资源":[${aws_codebuild_project.build_project.id}"],行动": [代码构建:*"]},{效果":允许",资源":[*"],行动": [日志:创建日志组","日志:CreateLogStream",日志:PutLogEvents"]}]}政策}# 打包阶段的 CodeBuild 部分资源aws_codebuild_project"build_project"{name = "${var.pipeline_name}-build"description = "${var.pipeline_name} 的 CodeBuild 项目"service_role = "${aws_iam_role.codebuild_assume_role.arn}"build_timeout = "60"文物{类型=代码管道"}环境 {compute_type = "BUILD_GENERAL1_SMALL"图像 = "aws/codebuild/nodejs:6.3.1"类型 = "LINUX_CONTAINER"}来源 {类型=代码管道"buildspec = "buildspec.yml"}}# 完整的 CodePipeline资源aws_codepipeline"codepipeline"{name = "${var.pipeline_name}-codepipeline"role_arn = "${aws_iam_role.codepipeline_role.arn}"artifact_store = {位置 = "${aws_s3_bucket.build_artifact_bucket.bucket}"类型 = "S3"}阶段 {名称=来源"行动 {名称=来源"类别 = 来源"所有者 = "第三方"提供者 = "GitHub"版本 = 1"output_artifacts = ["SourceArtifact"]配置 {所有者 = "${var.github_username}"OAuthToken = "${var.github_token}"回购 = "${var.github_repo}"分支 = 主"PollForSourceChanges = "真"}}}阶段 {名称 = 部署"行动 {名称 = DeployToS3"类别=测试"所有者 = AWS"提供者 = 代码构建"input_artifacts = ["SourceArtifact"]output_artifacts = ["OutputArtifact"]版本 = 1"配置 {项目名称 = "${aws_codebuild_project.build_project.name}"}}}}
更新:
按照下面达伦的回答(这很有意义),我补充说:
提供者aws"{地区=我们-东-1"shared_credentials_file = "${pathexpand("~/.aws/credentials")}"配置文件 = 默认"假设角色{role_arn = "arn:aws:iam::<OTHER-ACCOUNT>:role/<ROLE-NAME>"}}
但是,我遇到了这个错误:
provider.aws:无法承担角色arn:aws:iam:::role/".
有很多可能的原因 - 最常见的是:
- 用于担任该角色的凭据无效
- 凭据没有担任该角色的适当权限
- 角色 ARN 无效
我已经检查了另一个账户中的角色,我可以使用我账户中的 AWS 控制台切换到该角色.我还检查了 AWS 指南 这里
所以:该角色 ARN 是有效的,我确实拥有担任该角色的凭据以及运行堆栈所需的所有权限.
更新
我还尝试了一个拥有所有服务访问权限的新角色.但是,我遇到了这个错误:
错误:错误刷新状态:发生 2 个错误:
* aws_codebuild_project.build_project:发生 1 个错误:* aws_codebuild_project.build_project:aws_codebuild_project.build_project:检索项目时出错:
"InvalidInputException: 无效的项目 ARN: 账户 ID 不匹配调用者的帐户状态代码:400,请求 ID:..."* aws_s3_bucket.build_artifact_bucket:发生 1 个错误:
* aws_s3_bucket.build_artifact_bucket: aws_s3_bucket.build_artifact_bucket: 获取 S3 Bucket CORS 时出错
配置:AccessDenied:拒绝访问状态码:403,请求ID:...,主机ID:...
=====
2019 年 4 月 29 日更新:
根据@Rolando 的建议,我已将此策略添加到我尝试使用的 MAIN ACCOUNT 的用户,以承担我计划执行 terraform apply
OTHER ACCOUNT 的角色代码>.
{版本":2012-10-17",陈述": {效果":允许","动作": "sts:AssumeRole","资源": "arn:aws:iam::<OTHER-ACCOUNT-ID>:role/admin"}}
这是角色 admin
的 信任关系
属于 OTHER ACCOUNT:
{版本":2012-10-17",陈述": [{效果":允许",主要的": {"AWS": "arn:aws:iam::<MAIN_ACCOUNT_ID>:root"},"动作": "sts:AssumeRole",状况": {布尔":{aws:MultiFactorAuthPresent":真"}}}]}
但是,当我运行这个命令时:
aws sts 假定角色 --role-arn arn:aws:iam:::role/admin --role-session-name "RoleSession1" --profile default >假设角色输出.txt
我有这个错误:
调用 AssumeRole 操作时发生错误(AccessDenied):访问被拒绝
只要您想以特定角色(包括其他帐户)运行命令,我就有一个防弹解决方案.我假设您已安装 AWS CLI 工具.您还必须安装 jq(从 json 解析和提取数据的简单工具),尽管您可以按照自己的意愿解析数据.
aws_credentials=$(aws sts 假设角色 --role-arn arn:aws:iam::1234567890:role/nameOfMyrole --role-session-name "RoleSession1")导出 AWS_ACCESS_KEY_ID=$(echo $aws_credentials|jq '.Credentials.AccessKeyId'|tr -d '"')导出 AWS_SECRET_ACCESS_KEY=$(echo $aws_credentials|jq '.Credentials.SecretAccessKey'|tr -d '"')导出 AWS_SESSION_TOKEN=$(echo $aws_credentials|jq '.Credentials.SessionToken'|tr -d '"')
第一行分配来自 aws sts
命令的响应并将其放入变量中.最后 3 行将从第一个命令中选择值并将它们分配给 aws
cli 使用的变量.
注意事项:
如果您创建一个 bash 脚本,也可以在其中添加您的 terraform 命令.您也可以使用上面的行创建一个 bash,然后使用 '.' 运行它.在前面(即:../get-creds.sh
).这将在您当前的 bash shell 上创建变量.
角色过期,请记住角色的过期时间通常为一个小时.
您的 shell 现在将包含三个变量 AWS_ACCESS_KEY_ID
、AWS_SECRET_ACCESS_KEY
、AWS_SESSION_TOKEN
.这意味着它将覆盖您的 ~/.aws/credentials
.要清除这一点,最简单的方法就是开始一个新的 bash 会话.
我使用这篇文章作为我的来源来解决这个问题:https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html
I need to execute a Terraform template to provision infrastructure for an AWS account which I can access by assuming a role.
The problem I have now is I do not have an IAM user in that AWS account so I do not have an aws_access_key_id
or an aws_secret_access_key
to set up another named profile in my ~/.aws/credentials
. When I run command terraform apply
, the template creates the infrastructure for my account, not the other account.
How to run Terraform template using your account which has a role to access services of another AWS account?
Here's my Terraform file:
# Input variables
variable "aws_region" {
type = "string"
default = "us-east-1"
}
variable "pipeline_name" {
type = "string"
default = "static-website-terraform"
}
variable "github_username" {
type = "string"
default = "COMPANY"
}
variable "github_token" {
type = "string"
}
variable "github_repo" {
type = "string"
}
provider "aws" {
region = "${var.aws_region}"
assume_role {
role_arn = "arn:aws:iam::<AWS-ACCOUNT-ID>:role/admin"
profile = "default"
}
}
# CodePipeline resources
resource "aws_s3_bucket" "build_artifact_bucket" {
bucket = "${var.pipeline_name}-artifact-bucket"
acl = "private"
}
data "aws_iam_policy_document" "codepipeline_assume_policy" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["codepipeline.amazonaws.com"]
}
}
}
resource "aws_iam_role" "codepipeline_role" {
name = "${var.pipeline_name}-codepipeline-role"
assume_role_policy = "${data.aws_iam_policy_document.codepipeline_assume_policy.json}"
}
# CodePipeline policy needed to use CodeCommit and CodeBuild
resource "aws_iam_role_policy" "attach_codepipeline_policy" {
name = "${var.pipeline_name}-codepipeline-policy"
role = "${aws_iam_role.codepipeline_role.id}"
policy = <<EOF
{
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:GetBucketVersioning",
"s3:PutObject"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"cloudwatch:*",
"sns:*",
"sqs:*",
"iam:PassRole"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"codebuild:BatchGetBuilds",
"codebuild:StartBuild"
],
"Resource": "*",
"Effect": "Allow"
}
],
"Version": "2012-10-17"
}
EOF
}
# CodeBuild IAM Permissions
resource "aws_iam_role" "codebuild_assume_role" {
name = "${var.pipeline_name}-codebuild-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "codebuild.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy" "codebuild_policy" {
name = "${var.pipeline_name}-codebuild-policy"
role = "${aws_iam_role.codebuild_assume_role.id}"
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:GetObjectVersion",
"s3:GetBucketVersioning"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Effect": "Allow",
"Resource": [
"${aws_codebuild_project.build_project.id}"
],
"Action": [
"codebuild:*"
]
},
{
"Effect": "Allow",
"Resource": [
"*"
],
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
}
]
}
POLICY
}
# CodeBuild Section for the Package stage
resource "aws_codebuild_project" "build_project" {
name = "${var.pipeline_name}-build"
description = "The CodeBuild project for ${var.pipeline_name}"
service_role = "${aws_iam_role.codebuild_assume_role.arn}"
build_timeout = "60"
artifacts {
type = "CODEPIPELINE"
}
environment {
compute_type = "BUILD_GENERAL1_SMALL"
image = "aws/codebuild/nodejs:6.3.1"
type = "LINUX_CONTAINER"
}
source {
type = "CODEPIPELINE"
buildspec = "buildspec.yml"
}
}
# Full CodePipeline
resource "aws_codepipeline" "codepipeline" {
name = "${var.pipeline_name}-codepipeline"
role_arn = "${aws_iam_role.codepipeline_role.arn}"
artifact_store = {
location = "${aws_s3_bucket.build_artifact_bucket.bucket}"
type = "S3"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "ThirdParty"
provider = "GitHub"
version = "1"
output_artifacts = ["SourceArtifact"]
configuration {
Owner = "${var.github_username}"
OAuthToken = "${var.github_token}"
Repo = "${var.github_repo}"
Branch = "master"
PollForSourceChanges = "true"
}
}
}
stage {
name = "Deploy"
action {
name = "DeployToS3"
category = "Test"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["SourceArtifact"]
output_artifacts = ["OutputArtifact"]
version = "1"
configuration {
ProjectName = "${aws_codebuild_project.build_project.name}"
}
}
}
}
Following Darren's answer (it makes a lot of sense) below, I added:
provider "aws" {
region = "us-east-1"
shared_credentials_file = "${pathexpand("~/.aws/credentials")}"
profile = "default"
assume_role {
role_arn = "arn:aws:iam::<OTHER-ACCOUNT>:role/<ROLE-NAME>"
}
}
However, I ran into this error:
I've checked the role in the other account and I can switch to that role using the AWS Console from my account. I've also checked AWS guide here
So: that role ARN is valid, I do have credentials to assume the role and all the permissions I need to run the stack.
I've also tried with a new role that has all access to services. However, I ran into this error:
=====
Following @Rolando's suggestion, I've added this policy to the user of the MAIN ACCOUNT that I'm trying to use to assume the role of the OTHER ACCOUNT where I'm planning to execute terraform apply
.
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::<OTHER-ACCOUNT-ID>:role/admin"
}
}
This is the Trust Relationship
of the role admin
belongs to the OTHER ACCOUNT:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<MAIN_ACCOUNT_ID>:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
However, when I ran this command:
aws sts assume-role --role-arn arn:aws:iam::<OTHER-ACCOUNT-ID>:role/admin --role-session-name "RoleSession1" --profile default > assume-role-output.txt
I have this error:
An error occurred (AccessDenied) when calling the AssumeRole operation: Access denied
I have a bulletproof solution anytime you want to run commands as a specific role (including other accounts).I assume you have the AWS CLI tools installed.You will also have to install jq (easy tool to parse and extract data from json), although you can parse the data any way you wish.
aws_credentials=$(aws sts assume-role --role-arn arn:aws:iam::1234567890:role/nameOfMyrole --role-session-name "RoleSession1")
export AWS_ACCESS_KEY_ID=$(echo $aws_credentials|jq '.Credentials.AccessKeyId'|tr -d '"')
export AWS_SECRET_ACCESS_KEY=$(echo $aws_credentials|jq '.Credentials.SecretAccessKey'|tr -d '"')
export AWS_SESSION_TOKEN=$(echo $aws_credentials|jq '.Credentials.SessionToken'|tr -d '"')
First line assigns the response from the aws sts
command and puts it in a variable.Last 3 lines will select the values from the first command and assigned them to variables that the aws
cli uses.
Considerations:
If you create a bash script, add your terraform commands there as well. You can also just create a bash with the lines above, and run it with a '.' in front (ie: . ./get-creds.sh
). This will create the variables on your current bash shell.
Role expires, keep in mind that roles have expiration of usually an hour.
Your shell will now have the three variables AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
, AWS_SESSION_TOKEN
. This means that it will override your ~/.aws/credentials
. Easiest thing to do to clear this is to just start a new bash session.
I used this article as my source to figure this out: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html
这篇关于使用 AWS 承担角色执行 Terraform 应用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!