通过AWS担任Terraform的执行角色

Vie*_*iet 6 amazon-web-services terraform aws-codepipeline terraform-provider-aws

我需要执行一个Terraform模板为我可以通过担任角色来访问的AWS账户配置基础架构。

我现在遇到的问题是,该AWS账户中没有IAM用户,因此我没有aws_access_key_idaws_secret_access_key来在中设置另一个命名配置文件~/.aws/credentials。当我运行command时terraform apply,模板将为我的帐户而不是其他帐户创建基础结构。

如何使用具有访问另一个AWS账户服务角色的账户运行Terraform模板?

这是我的Terraform文件:

# 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}"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:

在遵循达伦的回答(很有意义)之后,我补充道:

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>"
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,我遇到了这个错误:

  • provider.aws:不能假定角色“ arn:aws:iam ::: role /”。

    造成这种情况的原因有很多-最常见的是:

    • 用于承担角色的凭据无效
    • 凭据没有适当的权限以担任该角色
    • 角色ARN无效

我已经检查了另一个帐户中的角色,并且可以使用我的帐户中的AWS Console切换到该角色。我也在这里检查了AWS指南

因此:该角色ARN是有效的,我确实具有承担该角色和运行堆栈所需的所有权限的凭据。

更新资料

我还尝试过使用可以访问所有服务新角色。但是,我遇到了这个错误:

错误:错误刷新状态:发生2个错误:

    * aws_codebuild_project.build_project: 1 error(s) occurred:

    * aws_codebuild_project.build_project: aws_codebuild_project.build_project: Error retreiving Projects:
Run Code Online (Sandbox Code Playgroud)

“ InvalidInputException:无效的项目ARN:帐户ID与调用者的帐户不匹配\ n \ tstatus代码:400,请求ID:...” * aws_s3_bucket.build_artifact_bucket:1个错误:

    * aws_s3_bucket.build_artifact_bucket: aws_s3_bucket.build_artifact_bucket: error getting S3 Bucket CORS
Run Code Online (Sandbox Code Playgroud)

配置:AccessDenied:访问被拒绝状态代码:403,请求ID:...,主机ID:...

=====

2019年4月29日更新:

遵循@Rolando的建议,我已将此策略添加到主要帐户的用户中,我正尝试使用该策略来承担我打算执行的其他帐户的角色terraform apply

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "arn:aws:iam::<OTHER-ACCOUNT-ID>:role/admin"
    }
}
Run Code Online (Sandbox Code Playgroud)

Trust Relationship角色admin属于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"
        }
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

但是,当我运行此命令时:

aws sts assume-role --role-arn arn:aws:iam::<OTHER-ACCOUNT-ID>:role/admin --role-session-name "RoleSession1" --profile default > assume-role-output.txt
Run Code Online (Sandbox Code Playgroud)

我有这个错误:

An error occurred (AccessDenied) when calling the AssumeRole operation: Access denied
Run Code Online (Sandbox Code Playgroud)

Rol*_*ron 13

无论何时您想以特定角色(包括其他帐户)运行命令,我都有一个防弹解决方案。我假设您已安装 AWS CLI 工具。您还必须安装jq(从 json 解析和提取数据的简单工具),尽管您可以按您希望的任何方式解析数据。

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 '"')
Run Code Online (Sandbox Code Playgroud)

第一行分配来自aws sts命令的响应并将其放入变量中。最后 3 行将从第一个命令中选择值并将它们分配给awscli 使用的变量。

注意事项:

如果您创建了 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

  • 仅供参考,您可以使用“jq -r”消除到“tr”的管道,例如“export AWS_ACCESS_KEY_ID=$(echo $aws_credentials | jq -r '.Credentials.AccessKeyId')” (2认同)

小智 5

您应该可以这样做:在 Terraform 中,配置 aws 提供程序以使用您的本地 shared_credentials_file

provider "aws" {
  region                  = "us-east-1"
  shared_credentials_file = "${pathexpand("~/.aws/credentials")}"
  profile                 = "default"

  assume_role {
    role_arn = "arn:aws:iam::1234567890:role/OrganizationAccountAccessRole"
  }
}
Run Code Online (Sandbox Code Playgroud)

“profile”是 ~/.aws/credentials 中具有 AWS 访问密钥的命名配置文件。例如

[default]
region = us-east-1
aws_access_key_id = AKIAJXXXXXXXXXXXX
aws_secret_access_key = Aadxxxxxxxxxxxxxxxxxxxxxxxxxxxx    
Run Code Online (Sandbox Code Playgroud)

这不是您要访问的账户中的 IAM 用户。它位于“源”帐户中(您有时需要密钥才能访问 AWS cli)。

“assume_role.role_arn”是您要承担的帐户中的角色。需要允许“配置文件”中的 IAM 用户担任该角色。