下記で作成したカスタムヘッダー設定したCloudFront+ALB+EC2(Nginx)の構成をterraformのimportを使用してコードに起こしてみた。
CloudFront+ALBでカスタムヘッダーを利用して、ALBでCloudFrontからの接続のみ許可する - あめがえるのITブログ
terraform importとは
対象リソースの実機の状態を確認し、terraform.tfstateファイルに記載するコマンド。
terraform.tfstateファイルとは
terraformが管理しているリソースの実機の状態が記載されているファイル。
やること
terraformのimportを使用して、GUIで設定した項目をコードに反映する。
GUIで設定した項目
・CloudFrontにカスタムヘッダーを追加
・ALB リスナーのデフォルトルールを変更
・ALB リスナールール追加
実践
1.import用のtfファイルを作成
# mkdir test # cd test # vi main_import.tf
◆フォルダ階層
┬ main.tf
└ test
└ main_import.tf
provider "aws" { region = "ap-northeast-1" } resource "aws_cloudfront_distribution" "example" { } resource "aws_alb_listener" "front_end" { } resource "aws_alb_listener_rule" "example_rule" { }
2.既存設定を取り込み
# terraform import aws_cloudfront_distribution.example <CloudFront_ID> # terraform import aws_alb_listener.front_end <ALB LIstener_ARN> # terraform import aws_alb_listener_rule.example_rule <ALB LIstenerRule_ARN> 例) # terraform import aws_cloudfront_distribution.example E1NJUMXWBXFRFD # terraform import aws_alb_listener.front_end arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:listener/app/example-lb/fe53e34ffb6fb477/4c63c7290b9cec19 # terraform import aws_alb_listener_rule.example_rule arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:listener-rule/app/example-lb/fe53e34ffb6fb477/4c63c7290b9cec19/55ef9d73d2c42a85
3.実機の状態を確認
※terraform.tfstateファイルを直接参照してもよいが、若干見づらいのでterraform state showコマンドを使用する。
# terraform state show aws_cloudfront_distribution.example # terraform state show aws_alb_listener.front_end # terraform state show aws_alb_listener_rule.example_rule
resource "aws_cloudfront_distribution" "example" { aliases = [] arn = "arn:aws:cloudfront::xxxxxxxxxxxx:distribution/E174NEIVEFBPQK" caller_reference = "terraform-20231025214734494700000004" default_root_object = "index.html" domain_name = "d33artyks7ocby.cloudfront.net" enabled = true etag = "EK0PM9EUD4U96" hosted_zone_id = "Z2FDTNDATAQYW2" http_version = "http2" id = "E174NEIVEFBPQK" in_progress_validation_batches = 0 is_ipv6_enabled = false last_modified_time = "2023-10-25 22:09:07.036 +0000 UTC" price_class = "PriceClass_100" retain_on_delete = false staging = false status = "Deployed" tags = {} tags_all = {} trusted_key_groups = [ { enabled = false items = [] }, ] trusted_signers = [ { enabled = false items = [] }, ] wait_for_deployment = true default_cache_behavior { allowed_methods = [ "GET", "HEAD", ] cached_methods = [ "GET", "HEAD", ] compress = false default_ttl = 3600 max_ttl = 86400 min_ttl = 0 smooth_streaming = false target_origin_id = "exampleALBOrigin" trusted_key_groups = [] trusted_signers = [] viewer_protocol_policy = "redirect-to-https" forwarded_values { headers = [] query_string = false query_string_cache_keys = [] cookies { forward = "none" whitelisted_names = [] } } } origin { connection_attempts = 3 connection_timeout = 10 domain_name = "example-lb-1651121157.ap-northeast-1.elb.amazonaws.com" origin_id = "exampleALBOrigin" custom_header { name = "testHeader" value = "testValue" } custom_origin_config { http_port = 80 https_port = 443 origin_keepalive_timeout = 5 origin_protocol_policy = "http-only" origin_read_timeout = 30 origin_ssl_protocols = [ "TLSv1", "TLSv1.1", "TLSv1.2", ] } } restrictions { geo_restriction { locations = [] restriction_type = "none" } } viewer_certificate { cloudfront_default_certificate = true minimum_protocol_version = "TLSv1" } } resource "aws_alb_listener" "front_end" { arn = "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:listener/app/example-lb/82c90710d722cdd6/ad1b56b6e38c5d38" id = "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:listener/app/example-lb/82c90710d722cdd6/ad1b56b6e38c5d38" load_balancer_arn = "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:loadbalancer/app/example-lb/82c90710d722cdd6" port = 80 protocol = "HTTP" tags = {} tags_all = {} default_action { order = 1 type = "fixed-response" fixed_response { content_type = "text/plain" message_body = "No direct access to ALB" status_code = "403" } } } resource "aws_alb_listener_rule" "example_rule" { arn = "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:listener-rule/app/example-lb/82c90710d722cdd6/ad1b56b6e38c5d38/e51e72464b2c4ab7" id = "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:listener-rule/app/example-lb/82c90710d722cdd6/ad1b56b6e38c5d38/e51e72464b2c4ab7" listener_arn = "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:listener/app/example-lb/82c90710d722cdd6/ad1b56b6e38c5d38" priority = 1 tags = { "Name" = "testRule" } tags_all = { "Name" = "testRule" } action { order = 1 target_group_arn = "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:targetgroup/example-tg/5c435cf2c280a363" type = "forward" } condition { http_header { http_header_name = "testHeader" values = [ "testValue", ] } } }
4.差分をコードに反映、必要に応じてリソースのARNをリソース参照に変更
※コードに反映させたのが下記
provider "aws" { region = "ap-northeast-1" profile = "testvault" } variable "env" { default = { env_name = "test" vpc_cidr = "10.0.0.0/16" sb_az1a = "ap-northeast-1a" sb_az1a_cidr = "10.0.1.0/24" sb_az1c = "ap-northeast-1c" sb_az1c_cidr = "10.0.2.0/24" } } ### VPC resource "aws_vpc" "vpc" { cidr_block = "${var.env.vpc_cidr}" tags = { Name = "${var.env.env_name}_vpc" } } ### Subnet resource "aws_subnet" "public_1a" { vpc_id = "${aws_vpc.vpc.id}" availability_zone = "${var.env.sb_az1a}" cidr_block = "${var.env.sb_az1a_cidr}" tags = { Name = "${var.env.env_name}_public_1a" } } resource "aws_subnet" "public_1c" { vpc_id = "${aws_vpc.vpc.id}" availability_zone = "${var.env.sb_az1c}" cidr_block = "${var.env.sb_az1c_cidr}" tags = { Name = "${var.env.env_name}_public_1c" } } ### InternetGateway resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.vpc.id tags = { Name = "${var.env.env_name}_igw" } } ### RouteTable resource "aws_route_table" "public" { vpc_id = aws_vpc.vpc.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.igw.id } tags = { Name = "${var.env.env_name}_public_route_table" } } resource "aws_route_table_association" "public_1a" { subnet_id = aws_subnet.public_1a.id route_table_id = aws_route_table.public.id } resource "aws_route_table_association" "public_1c" { subnet_id = aws_subnet.public_1c.id route_table_id = aws_route_table.public.id } ### SecurityGroup(ALB) resource "aws_security_group" "example_alb_sg" { name = "example_alb_sg" vpc_id = aws_vpc.vpc.id } resource "aws_security_group_rule" "ingress_alb_http" { type = "ingress" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.example_alb_sg.id } resource "aws_security_group_rule" "egress_alb_all" { type = "egress" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.example_alb_sg.id } ### SecurityGroup(EC2) resource "aws_security_group" "example_ec2_sg" { name = "example_ec2_sg" vpc_id = aws_vpc.vpc.id } resource "aws_security_group_rule" "ingress_ec2_http" { type = "ingress" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.example_ec2_sg.id } resource "aws_security_group_rule" "ingress_ec2_ssh" { type = "ingress" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.example_ec2_sg.id } resource "aws_security_group_rule" "egress_ec2_all" { type = "egress" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.example_ec2_sg.id } ### IAM Role(EC2) resource "aws_iam_role" "example-ec2-ssm-role" { name = "example-ec2-ssm-role" assume_role_policy = data.aws_iam_policy_document.example-ec2-assume-role.json } data "aws_iam_policy_document" "example-ec2-assume-role" { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ec2.amazonaws.com"] } } } data "aws_iam_policy" "example-ec2-policy_ssm_managed_instance_core" { arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" } resource "aws_iam_role_policy_attachment" "example-ec2-ssm_managed_instance_core" { role = aws_iam_role.example-ec2-ssm-role.name policy_arn = data.aws_iam_policy.example-ec2-policy_ssm_managed_instance_core.arn } # インスタンスプロファイルを作成 resource "aws_iam_instance_profile" "example-ec2-profile" { name = "example-ec2-profile" role = aws_iam_role.example-ec2-ssm-role.name } ### EC2 resource "aws_instance" "example" { ami = "ami-06180cd4edb6844d2" instance_type = "t2.micro" subnet_id = aws_subnet.public_1a.id security_groups = [aws_security_group.example_ec2_sg.id] associate_public_ip_address = true iam_instance_profile = aws_iam_instance_profile.example-ec2-profile.name user_data = <<-EOF #!/bin/bash sudo yum update -y sudo amazon-linux-extras install epel -y sudo yum install nginx -y sudo systemctl start nginx sudo systemctl enable nginx EOF tags = { Name = "example-instance" } } ### ALB resource "aws_alb" "example" { name = "example-lb" internal = false load_balancer_type = "application" security_groups = [aws_security_group.example_alb_sg.id] subnets = [aws_subnet.public_1a.id, aws_subnet.public_1c.id] enable_deletion_protection = false enable_http2 = true idle_timeout = 60 ip_address_type = "ipv4" enable_cross_zone_load_balancing = true } resource "aws_alb_listener" "front_end" { load_balancer_arn = aws_alb.example.arn port = "80" protocol = "HTTP" default_action { ## ※ここから差し替え type = "fixed-response" order = 1 fixed_response { content_type = "text/plain" message_body = "No direct access to ALB" status_code = "403" } ## ここまで target_group_arn = aws_alb_target_group.example.arn } } resource "aws_alb_listener_rule" "example_rule" { ## ※ここから追加 listener_arn = aws_alb_listener.front_end.arn action { type = "forward" target_group_arn = aws_alb_target_group.example.arn } condition { http_header { http_header_name = "testHeader" values = ["testValue"] } } tags = { Name = "testRule" } tags_all = { Name = "testRule" } } ## ここまで resource "aws_alb_target_group" "example" { name = "example-tg" port = 80 protocol = "HTTP" vpc_id = aws_vpc.vpc.id } resource "aws_alb_target_group_attachment" "example" { target_group_arn = aws_alb_target_group.example.arn target_id = aws_instance.example.id } # CloudFront resource "aws_cloudfront_distribution" "example" { origin { domain_name = aws_alb.example.dns_name origin_id = "exampleALBOrigin" custom_header { ## ※ここから追加 name = "testHeader" value = "testValue" } ## ここまで custom_origin_config { http_port = 80 https_port = 443 origin_protocol_policy = "http-only" origin_ssl_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2"] } } enabled = true default_root_object = "index.html" default_cache_behavior { allowed_methods = ["GET", "HEAD"] cached_methods = ["GET", "HEAD"] target_origin_id = "exampleALBOrigin" forwarded_values { query_string = false cookies { forward = "none" } } viewer_protocol_policy = "redirect-to-https" min_ttl = 0 default_ttl = 3600 max_ttl = 86400 } price_class = "PriceClass_100" restrictions { geo_restriction { restriction_type = "none" } } viewer_certificate { cloudfront_default_certificate = true } }
5.terraform planを実行し、差分がないことを確認
# terraform plan
感想
なんかごちゃごちゃした記事になってしもうた。。。
わかりやすいサンプル使えばよかった(´Д`)