Open gosaaan1 opened 9 months ago
1ファイル(main.tf)に書くこともできるのですが、可読性が悪くなるので分割しています。 モジュールのI/Fを定義しないといけなかったりするので、このあたりの設計が結構面倒だったりします。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
# 複数のプロバイダ構成
# https://www.terraform.io/language/providers/configuration#alias-multiple-provider-configurations
configuration_aliases = "us-east-1"
}
}
}
aws_
will useaws
.provider "aws" { region = "ap-northeast-1" }
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
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 })) }
#!/usr/bin/env python3
import os
import aws_cdk as cdk
from aws.aws_stack import AwsStack
from aws.code_build_terraform_mfa_stack import CodeBuildTerraformMFAStack # 追記
app = cdk.App() AwsStack(app, "AwsStack",
# 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 (
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)
コマンドで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
Terraformのコードと比較すると、AWS CDK(今回はPythonで記述)の方が圧倒的に行数が少なくなります。TerraformがJSON形式をベースにしていることもあるのですが、縦が短くなるのは見通しの良さ(可読性)の面で見ても有利ですね。 特にポリシー、ロールまわりがシンプルに書ける(Terraformだとこの辺がまどろっこしい…)のが嬉しいですし、クラスをスタック単位に分離して書くスタイルはシンプルでわかりやすいです。Terraformはモジュールという概念があるのですが、共通部品として使いまわせるようにするとかえって可読性が悪くなる傾向があるような…
AWS CDKはCloudFormationを抽象化したものなので、スタック管理やロールバックなどCloudFomationの機能がそのまま使えること、AWS純正のIaCということで安心感も大きいと思います。