Выполнить Terraform применить с AWS взять на себя роль - PullRequest
3 голосов
/ 12 марта 2019

Мне нужно выполнить шаблон Terraform для подготовки инфраструктуры для учетной записи AWS, к которой я могу получить доступ, приняв на себя роль.

Проблема, с которой я столкнулся сейчас, заключается в том, что у меня нет учетной записи IAM в этой учетной записи AWS, поэтому у меня нет aws_access_key_id или aws_secret_access_key для настройки другого именованного профиля в моем ~/.aws/credentials. Когда я запускаю команду terraform apply, шаблон создает инфраструктуру для моей учетной записи, а не другой учетной записи.

Как запустить шаблон Terraform, используя вашу учетную запись, у которой есть роль для доступа к службам другой учетной записи AWS?

Вот мой файл 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}"
            }
        }
    }
}

Обновление:

Следуя ответу Даррена (это имеет большой смысл) ниже, я добавил:

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>"
  }
}

Однако я столкнулся с этой ошибкой:

  • provider.aws: Роль "arn: aws: iam ::: role /" не может быть принята.

    Существует несколько возможных причин этого, наиболее распространенными из которых являются:

    • Учетные данные, используемые для принятия роли, являются недействительными
    • У учетных данных нет соответствующих прав для принятия роли
    • Роль ARN недействительна

Я проверил роль в другой учетной записи и могу перейти на эту роль с помощью консоли AWS из своей учетной записи. Я также проверил руководство 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:

"InvalidInputException: неверный ARN проекта: идентификатор учетной записи не совпадает учетная запись вызывающего абонента \ n \ tstatus code: 400, идентификатор запроса: ... " * aws_s3_bucket.build_artifact_bucket: 1 произошла ошибка (и):

    * aws_s3_bucket.build_artifact_bucket: aws_s3_bucket.build_artifact_bucket: error getting S3 Bucket CORS

конфигурация: AccessDenied: доступ запрещен код состояния: 403, идентификатор запроса: ..., идентификатор хоста: ...

=====

ОБНОВЛЕНИЕ 29 апреля 2019 г .:

Следуя предложению @ Rolando, я добавил эту политику для пользователя ОСНОВНОГО СЧЕТА, который я пытаюсь использовать, чтобы взять на себя роль ДРУГОГО СЧЕТА, где я планирую выполнить terraform apply.

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

Это Trust Relationship роли admin принадлежит ДРУГОЙ УЧЕТНОЙ ЗАПИСИ:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<MAIN_ACCOUNT_ID>:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}

Однако, когда я запустил эту команду:

aws sts assume-role --role-arn arn:aws:iam::<OTHER-ACCOUNT-ID>:role/admin --role-session-name "RoleSession1" --profile default > assume-role-output.txt

У меня есть эта ошибка:

An error occurred (AccessDenied) when calling the AssumeRole operation: Access denied

Ответы [ 3 ]

1 голос
/ 18 марта 2019

Вы должны быть в состоянии сделать это следующим образом: в 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"
  }
}

"profile" - это именованный профиль в ~ / .aws / credentials, имеющий AWSКлючи доступа.Например,

[default]
region = us-east-1
aws_access_key_id = AKIAJXXXXXXXXXXXX
aws_secret_access_key = Aadxxxxxxxxxxxxxxxxxxxxxxxxxxxx    

Это не пользователь IAM в учетной записи, к которой вы хотите получить доступ.Он находится в учетной записи «источника» (в определенный момент вам нужны ключи для доступа к клиенту AWS).

"accept_role.role_arn" - это роль в учетной записи, которую вы хотите взять на себя.Пользователь IAM в «профиле» должен иметь возможность выполнять эту роль.

1 голос
/ 25 апреля 2019

У меня есть пуленепробиваемое решение в любое время, когда вы хотите запускать команды с определенной ролью (включая другие учетные записи). Я предполагаю, что у вас установлены инструменты 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 '"')

Первая строка присваивает ответ от команды aws sts и помещает его в переменную. Последние 3 строки будут выбирать значения из первой команды и назначать их переменным, которые использует aws cli.

Вопросы:

Если вы создаете скрипт bash, добавьте туда свои команды terraform. Вы также можете просто создать bash с вышеприведенными строками и запустить его с «.» впереди (то есть: . ./get-creds.sh). Это создаст переменные в вашей текущей оболочке bash.

Срок действия роли истекает, имейте в виду, что срок действия роли обычно составляет час.

Ваша оболочка теперь будет иметь три переменные 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

0 голосов
/ 13 марта 2019

Вообще говоря, вам нужно загрузить целевой аккаунт. В минимальном смысле это означает создание роли, которая предполагается из роли конвейера, но может включать некоторые другие ресурсы.

...