gosaaan1 / hokulea-garage

AWS とTerraform を学ぶための箱庭
Apache License 2.0
1 stars 0 forks source link

AWS CDKを使ってCodeBuildを構築してみた #14

Open gosaaan1 opened 11 months ago

gosaaan1 commented 11 months ago

Terraformのコードと比較すると、AWS CDK(今回はPythonで記述)の方が圧倒的に行数が少なくなります。TerraformがJSON形式をベースにしていることもあるのですが、縦が短くなるのは見通しの良さ(可読性)の面で見ても有利ですね。 特にポリシー、ロールまわりがシンプルに書ける(Terraformだとこの辺がまどろっこしい…)のが嬉しいですし、クラスをスタック単位に分離して書くスタイルはシンプルでわかりやすいです。Terraformはモジュールという概念があるのですが、共通部品として使いまわせるようにするとかえって可読性が悪くなる傾向があるような…

AWS CDKはCloudFormationを抽象化したものなので、スタック管理やロールバックなどCloudFomationの機能がそのまま使えること、AWS純正のIaCということで安心感も大きいと思います。

gosaaan1 commented 11 months ago

Terraformの場合

1ファイル(main.tf)に書くこともできるのですが、可読性が悪くなるので分割しています。 モジュールのI/Fを定義しないといけなかったりするので、このあたりの設計が結構面倒だったりします。

The default provider configuration; resources that begin with aws_ will use

it as the default, and it can be referenced as aws.

provider "aws" { region = "ap-northeast-1" }

Additional provider configuration

provider "aws" { alias = "virginia" region = "us-east-1" }

module "codebuild" { source = "./codebuild" repositories = { terraform-mfa = { repository_name = "hokulea" source_version = "master" buildspec = "./buildspec_terraform_mfa.yml" } }/workspaces/hokulea/your-iac/.terraform }

- codebuild/aws_codebuild_project.docker_builder.tf

resource "aws_codebuild_project" "docker_builder" { for_each = var.repositories name = "docker-builder-${each.key}" service_role = aws_iam_role.codebuild.arn artifacts { type = "NO_ARTIFACTS" } environment { compute_type = "BUILD_GENERAL1_SMALL" image = "aws/codebuild/amazonlinux2-x86_64-standard:3.0" type = "LINUX_CONTAINER" privileged_mode = true environment_variable { name = "AWS_DEFAULT_REGION" value = data.aws_region.current.name } environment_variable { name = "AWS_ACCOUNT_ID" value = data.aws_caller_identity.current.account_id } } logs_config { cloudwatch_logs { group_name = "codebuild" stream_name = "docker-builder-${each.key}" } s3_logs { status = "DISABLED" } } source { type = "CODECOMMIT" location = "https://git-codecommit.${data.aws_region.current.name}.amazonaws.com/v1/repos/${each.value.repository_name}" buildspec = each.value.buildspec } source_version = each.value.source_version }

- codebuild/aws_iam_role_policy.codebuild.tf

resource "aws_iam_role_policy" "codebuild" { name = "codebuild-policy" role = aws_iam_role.codebuild.id policy = <<-POLICY { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Resource": [ "" ], "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ] }, { "Effect": "Allow", "Resource": [ "arn:aws:s3:::codepipeline-${data.aws_region.current.name}-" ], "Action": [ "s3:PutObject", "s3:GetObject", "s3:GetObjectVersion", "s3:GetBucketAcl", "s3:GetBucketLocation" ] } ] } POLICY }

resource "aws_iam_role_policy" "ecr" { name = "codebuild-policy-ecr" role = aws_iam_role.codebuild.id

SEE => https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/security-iam-awsmanpol.html#security-iam-awsmanpol-AmazonEC2ContainerRegistryPowerUser

policy = data.aws_iam_policy_document.ecr_power_user.json }

resource "aws_iam_role_policy" "public_ecr" { name = "codebuild-policy-public-ecr" role = aws_iam_role.codebuild.id policy = data.aws_iam_policy_document.public_ecr_power_user.json }

- codebuild/aws_iam_role.codebuild.tf

resource "aws_iam_role" "codebuild" { name = "CodebuildServiceRole" assume_role_policy = <<-EOF { "Version" : "2012-10-17", "Statement" : [ { "Effect" : "Allow", "Principal" : { "Service" : "codebuild.amazonaws.com" }, "Action" : "sts:AssumeRole" } ] } EOF }

- codebuild/data.aws_caller_identity.current.tf

data "aws_caller_identity" "current" {}

- codebuild/data.aws_iam_policy_document.ecr_power_user.tf

data "aws_iam_policy_document" "ecr_power_user" { source_json = data.aws_iam_policy.ecr_power_user.policy }

- codebuild/data.aws_iam_policy_document.public_ecr_power_user.tf

data "aws_iam_policy_document" "public_ecr_power_user" { source_json = data.aws_iam_policy.public_ecr_power_user.policy }

- codebuild/data.aws_iam_policy.ecr_power_user.tf

data "aws_iam_policy" "ecr_power_user" { arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser" }

- codebuild/data.aws_iam_policy.public_ecr_power_user.tf

data "aws_iam_policy" "public_ecr_power_user" { arn = "arn:aws:iam::aws:policy/AmazonElasticContainerRegistryPublicPowerUser" }

- codebuild/data.aws_region.current.tf

data "aws_region" "current" {}

- codebuild/main.tf
- codebuild/variables.tf

variable "repositories" { type = map(object({ repository_name = string source_version = string buildspec = string })) }

gosaaan1 commented 11 months ago

AWS CDKの場合

app = cdk.App() AwsStack(app, "AwsStack",

If you don't specify 'env', this stack will be environment-agnostic.

# Account/Region-dependent features and context lookups will not work,
# but a single synthesized template can be deployed anywhere.

# Uncomment the next line to specialize this stack for the AWS Account
# and Region that are implied by the current CLI configuration.

#env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')),

# Uncomment the next line if you know exactly what Account and Region you
# want to deploy the stack to. */

#env=cdk.Environment(account='123456789012', region='us-east-1'),

# For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html
)

CodeBuildTerraformMFAStack(app, "CodeBuildTerraformMFAStack") # 追記

app.synth()

- aws/code_build_terraform_mfa_stack.py ※こちらはフルスクラッチ

from aws_cdk import (

Duration,

Stack,
# aws_sqs as sqs,
aws_codebuild as codebuild,
aws_codecommit as codecommit,
aws_iam as iam,

) from constructs import Construct

class CodeBuildTerraformMFAStack(Stack):

def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
    super().__init__(scope, construct_id, **kwargs)

    # CodeCommit レポジトリの作成または既存のレポジトリを指定
    repo = codecommit.Repository.from_repository_name(
        self, 'Hokulea', 'hokulea')

    project = codebuild.Project(self, 'BuildTerraformMFA',
        project_name='BuildTerraformMFA',
        source=codebuild.Source.code_commit(
            repository=repo,
            # branch_or_ref="master",   # 効かない
        ),
        environment=dict(
            build_image=codebuild.LinuxBuildImage.STANDARD_5_0,
            environment_variables={
                # 必要に応じて環境変数を設定
                'IMAGE_NAME': codebuild.BuildEnvironmentVariable(value='terraform-mfa'),
                'VERSION': codebuild.BuildEnvironmentVariable(value='2023.12'),
            },
            privileged=True,
        ),
        build_spec=codebuild.BuildSpec.from_source_filename('buildspec_terraform_mfa.yml')  # buildspec ファイルを指定
    )

    # CodeBuildのロールにECR Power Userポリシーをアタッチ
    ecr_policy = iam.ManagedPolicy.from_aws_managed_policy_name('AmazonElasticContainerRegistryPublicPowerUser')
    project.role.add_managed_policy(ecr_policy)
gosaaan1 commented 11 months ago

IaCのプロジェクトを作ってデプロイ~破棄するまでの流れ

コマンドでIaCのプロジェクトのテンプレートが作れます。 あとインフラへの変更点はterraform planよりも見やすいです。

mkdir aws
cd aws
cdk init language=python  #使い慣れたプログラミング言語が選べる
# write code...
cdk bootstrap
cdk synth    # CloudFormationのテンプレートを生成してくれる
cdk deploy CodeBuildTerraformMFAStack

IAM Statement Changes
┌───┬────────────────────────────────────────────────┬────────┬────────────────────────────────────────────────┬──────────────────────────────────────────────────┬───────────┐
│   │ Resource                                       │ Effect │ Action                                         │ Principal                                        │ Condition │
├───┼────────────────────────────────────────────────┼────────┼────────────────────────────────────────────────┼──────────────────────────────────────────────────┼───────────┤
│ + │ ${BuildTerraformMFA/Role.Arn}                  │ Allow  │ sts:AssumeRole                                 │ Service:codebuild.amazonaws.com                  │           │
├───┼────────────────────────────────────────────────┼────────┼────────────────────────────────────────────────┼──────────────────────────────────────────────────┼───────────┤
│ + │ arn:${AWS::Partition}:codebuild:${AWS::Region} │ Allow  │ codebuild:BatchPutCodeCoverages                │ AWS:${BuildTerraformMFA/Role}                    │           │
│   │ :${AWS::AccountId}:report-group/${BuildTerrafo │        │ codebuild:BatchPutTestCases                    │                                                  │           │
│   │ rmMFABA2E009A}-*                               │        │ codebuild:CreateReport                         │                                                  │           │
│   │                                                │        │ codebuild:CreateReportGroup                    │                                                  │           │
│   │                                                │        │ codebuild:UpdateReport                         │                                                  │           │
├───┼────────────────────────────────────────────────┼────────┼────────────────────────────────────────────────┼──────────────────────────────────────────────────┼───────────┤
│ + │ arn:${AWS::Partition}:codecommit:${AWS::Region │ Allow  │ codecommit:GitPull                             │ AWS:${BuildTerraformMFA/Role}                    │           │
│   │ }:${AWS::AccountId}:hokulea                    │        │                                                │                                                  │           │
├───┼────────────────────────────────────────────────┼────────┼────────────────────────────────────────────────┼──────────────────────────────────────────────────┼───────────┤
│ + │ arn:${AWS::Partition}:logs:${AWS::Region}:${AW │ Allow  │ logs:CreateLogGroup                            │ AWS:${BuildTerraformMFA/Role}                    │           │
│   │ S::AccountId}:log-group:/aws/codebuild/${Build │        │ logs:CreateLogStream                           │                                                  │           │
│   │ TerraformMFABA2E009A}                          │        │ logs:PutLogEvents                              │                                                  │           │
│   │ arn:${AWS::Partition}:logs:${AWS::Region}:${AW │        │                                                │                                                  │           │
│   │ S::AccountId}:log-group:/aws/codebuild/${Build │        │                                                │                                                  │           │
│   │ TerraformMFABA2E009A}:*                        │        │                                                │                                                  │           │
└───┴────────────────────────────────────────────────┴────────┴────────────────────────────────────────────────┴──────────────────────────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬───────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                  │ Managed Policy ARN                                                                  │
├───┼───────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${BuildTerraformMFA/Role} │ arn:${AWS::Partition}:iam::aws:policy/AmazonElasticContainerRegistryPublicPowerUser │
└───┴───────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)?

cdk destroy CodeBuildTerraformMFAStack