書籍「実践Terraform AWSにおけるシステム設計とベストプラクティス」実践メモ
書籍「実践Terraform AWSにおけるシステム設計とベストプラクティス」の読書メモ
サンプルコードがGitHubで公開されている
自分で動かしているコード
IAMユーザーの作成
アクセスキーを生成しようとしたら以下のようなレコメンデーションが表示された
推奨された代替案
ブラウザベースの CLI である AWS CloudShell を使用してコマンドを実行します。
AWS CLI V2 を使用し、IAM Identity Center のユーザーによる認証を有効にします。
アクセスキーの漏洩事故を防ぐため代替案が示されるのは素晴らしい
IAM Indentity Centerによって管理するユーザーで認証するのが推奨されている模様。
しかし、脇道に逸れてしまうのでひとまずはアクセスキーを発行する方法を選択する。
git-secrets
git-secrets という秘匿情報をコミットしないようにできるツールがある模様。
以下のコマンドでインストール
brew install git-secrets
すべてのリポジトリでチェックするように設定
git secrets --register-aws --global
git secrets --install ~/.git-templates/git-secrets
git config --global init.templateDir ~/.git-templates/git-secrets
Terraformのバージョン
terraform -v
Terraform v1.9.8
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v5.77.0
2.2 リソースの更新
2.2.2 リソースの再作成
本ではApacheをインストールするためにuser_data
を追加するとEC2インスタンスが削除&作成されると書かれていた。
しかし、仕様変更があったのか既存のリソースが更新されるだけだった。
terraform apply
aws_instance.example: Refreshing state... [id=i-03e31efe04166ffaf]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_instance.example will be updated in-place
~ resource "aws_instance" "example" {
id = "i-03e31efe04166ffaf"
tags = {
"Name" = "example"
}
+ user_data = "5f11f9fb893f5c269243dd3d8efe2bc57983f538"
# (39 unchanged attributes hidden)
# (8 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_instance.example: Modifying... [id=i-03e31efe04166ffaf]
aws_instance.example: Still modifying... [id=i-03e31efe04166ffaf, 10s elapsed]
aws_instance.example: Still modifying... [id=i-03e31efe04166ffaf, 20s elapsed]
aws_instance.example: Still modifying... [id=i-03e31efe04166ffaf, 30s elapsed]
aws_instance.example: Still modifying... [id=i-03e31efe04166ffaf, 40s elapsed]
aws_instance.example: Modifications complete after 43s [id=i-03e31efe04166ffaf]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
3.6 参照
以下のようなコードでセキュリティグループの作成をしていた。
resource "aws_security_group" "example_ec2" {
name = "example-ec2"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
しかし最新のproviderではaws_security_group
のリソース内にingress
とegress
を設定する方法は非推奨になっていた。
You should not use the aws_security_group resource with in-line rules (using the ingress and egress arguments of aws_security_group) in conjunction with the aws_vpc_security_group_egress_rule and aws_vpc_security_group_ingress_rule resources or the aws_security_group_rule resource.
https://registry.terraform.io/providers/hashicorp/aws/5.77.0/docs/resources/security_group
代わりにaws_vpc_security_group_ingress_rule
とaws_vpc_security_group_egress_rule
リソースを使うように書かれていたので、それに従った。
resource "aws_security_group" "example_ec2" {
name = "example_ec2"
}
resource "aws_vpc_security_group_ingress_rule" "example_ec2" {
security_group_id = aws_security_group.example_ec2.id
from_port = 80
to_port = 80
ip_protocol = "tcp"
cidr_ipv4 = "0.0.0.0/0"
}
resource "aws_vpc_security_group_egress_rule" "example_ec2" {
security_group_id = aws_security_group.example_ec2.id
from_port = 0
to_port = 0
ip_protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
しかし、このコードでterraform apply
をするとエラーになってしまった。
terraform apply
aws_security_group.example_ec2: Refreshing state... [id=sg-0351ca048ea26443f]
aws_instance.example: Refreshing state... [id=i-00b940f0a5ea6a4f3]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_vpc_security_group_egress_rule.example_ec2 will be created
+ resource "aws_vpc_security_group_egress_rule" "example_ec2" {
+ arn = (known after apply)
+ cidr_ipv4 = "0.0.0.0/0"
+ from_port = 0
+ id = (known after apply)
+ ip_protocol = "-1"
+ security_group_id = "sg-0351ca048ea26443f"
+ security_group_rule_id = (known after apply)
+ tags_all = {}
+ to_port = 0
}
# aws_vpc_security_group_ingress_rule.example_ec2 will be created
+ resource "aws_vpc_security_group_ingress_rule" "example_ec2" {
+ arn = (known after apply)
+ cidr_ipv4 = "0.0.0.0/0"
+ from_port = 80
+ id = (known after apply)
+ ip_protocol = "tcp"
+ security_group_id = "sg-0351ca048ea26443f"
+ security_group_rule_id = (known after apply)
+ tags_all = {}
+ to_port = 80
}
Plan: 2 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_vpc_security_group_ingress_rule.example_ec2: Creating...
aws_vpc_security_group_egress_rule.example_ec2: Creating...
╷
│ Error: creating VPC Security Group Rule
│
│ with aws_vpc_security_group_ingress_rule.example_ec2,
│ on main.tf line 28, in resource "aws_vpc_security_group_ingress_rule" "example_ec2":
│ 28: resource "aws_vpc_security_group_ingress_rule" "example_ec2" {
│
│ operation error EC2: AuthorizeSecurityGroupIngress, https response error StatusCode: 400, RequestID: 876657b8-e486-4779-8ed4-ebb8637b60a5, api
│ error InvalidPermission.Duplicate: the specified rule "peer: 0.0.0.0/0, TCP, from port: 80, to port: 80, ALLOW" already exists
╵
╷
│ Error: creating VPC Security Group Rule
│
│ with aws_vpc_security_group_egress_rule.example_ec2,
│ on main.tf line 37, in resource "aws_vpc_security_group_egress_rule" "example_ec2":
│ 37: resource "aws_vpc_security_group_egress_rule" "example_ec2" {
│
│ operation error EC2: AuthorizeSecurityGroupEgress, https response error StatusCode: 400, RequestID: 2505842c-06f8-48bf-a657-1aa45db5edb3, api
│ error InvalidPermission.Duplicate: the specified rule "peer: 0.0.0.0/0, ALL, ALLOW" already exists
╵
このエラーはセキュリティグループのルールが重複していることを示している。
すでにインバウンドルールとアウトバウンドルールが作られていることがいけないので、一度AWSコンソールからルールを削除する。
(この方法が正しいのかは不明・・・。)
第6章 ストレージ
いくつか非推奨の設定があったので、下記のようにコードを書き換えた。
バージョニングの設定
resource "aws_s3_bucket_versioning" "private" {
bucket = aws_s3_bucket.private.id
versioning_configuration {
status = "Enabled"
}
}
暗号化の設定
resource "aws_s3_bucket_server_side_encryption_configuration" "private" {
bucket = aws_s3_bucket.private.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
ACLの設定
resource "aws_s3_bucket_acl" "public" {
bucket = aws_s3_bucket.public.id
acl = "public-read"
}
CORSの設定
resource "aws_s3_bucket_cors_configuration" "public" {
bucket = aws_s3_bucket.public.id
cors_rule {
allowed_origins = ["https://example.com"]
allowed_methods = ["GET"]
allowed_headers = ["*"]
max_age_seconds = 3000
}
}
Applyをしたところ、ACLの作成でエラー
terraform apply
をしたら以下のようなエラーが発生した。
Error: creating S3 Bucket (public-yuma-ito-bd-pragmatic-terraform) ACL: operation error S3: PutBucketAcl, https response error StatusCode: 403, RequestID: xxxxx, HostID: xxxxx, api error AccessDenied: User: arn:aws:iam::xxxxxxx is not authorized to perform: s3:PutBucketAcl on resource: "arn:aws:s3:::xxxx" because public access control lists (ACLs) are blocked by the BlockPublicAcls block public access setting.
│
│ with aws_s3_bucket_acl.public,
│ on s3_public.tf line 7, in resource "aws_s3_bucket_acl" "public":
│ 7: resource "aws_s3_bucket_acl" "public" {
│
╵
パブリックACLがブロックされていてエラーになっている模様。
しかし、下記のようにblock_public_acls
はfalse
に設定しているはずだが?
resource "aws_s3_bucket_public_access_block" "public" {
bucket = aws_s3_bucket.public.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
この設定が効かなかった理由は、aws_s3_bucket_public_access_block
のリソースよりも先にaws_s3_bucket_acl
を作成しようとしたからと思われる。
また、調べてみると、2023年の4月から新しく作られるS3バケットは自動的にS3パブリックアクセスブロックが有効化、アクセスコントロールリストが無効化されたとのこと。
今はACLの設定は推奨されていない[1]ため、バケットポリシーによって制御することにした。
後でポリシーはいじる必要があるかもしれないが、とりあえず以下のように設定した。
# パブリックアクセスを許可するIAMポリシー
data "aws_iam_policy_document" "public" {
statement {
effect = "Allow"
actions = ["s3:GetObject"]
resources = [
"${aws_s3_bucket.public.arn}/*",
]
principals {
type = "AWS"
identifiers = ["*"]
}
}
}
resource "aws_s3_bucket_policy" "public" {
bucket = aws_s3_bucket.public.id
policy = data.aws_iam_policy_document.public.json
# デフォルトではパブリックアクセスブロックが有効化されているので、先に無効化する必要がある
depends_on = [aws_s3_bucket_public_access_block.public]
}
depends_on
によって、先にパブリックアクセスブロックを無効化してからバケットポリシーを適用するようにしているのがポイント。
参考:
-
AWSのドキュメントには The majority of modern use cases in Amazon S3 do not require the use of ACLs. と記載されている。 ↩︎
第8章 ロードバランサーとDNS
ドメインを取得する手間やコストを考え、「8.3 Route53」〜「8.5 HTTPS用ロードバランサー」はスキップした。
PR:
第9章コンテナオーケストレーション
非推奨設定があったので書き換えた。
ECS実行ロールのポリシードキュメント (source_json
が非推奨)
data "aws_iam_policy_document" "ecs_task_execution" {
source_policy_documents = [data.aws_iam_policy.ecs_task_execution_role_policy.policy]
statement {
effect = "Allow"
actions = [
"ssm:GetParameters",
"kms:Decrypt"
]
resources = ["*"]
}
}
参考:aws_iam_policy_document | Data Sources | hashicorp/aws | Terraform | Terraform Registry
Applyをしてもタスク定義を更新しただけなので、動いているのは前のバージョンのタスクである。
「サービスの更新」から新しいリビジョンのタスク定義を指定してデプロイする必要があるので注意。