カスタムヘッダーを利用して、CloudFrontからの接続のみALBで許可する設定を入れてみた。
やること
TerraformでCloudFront+ALB+EC2(Nginx)の環境を構築し、CloudFrontからの接続のみをALBで許可するようカスタムヘッダーに設定を入れて、CloudFront、ALBそれぞれに接続し挙動を確認する。
構成
Client ⇒ CloudFront - ALB - EC2(Nginx)
↑
Client
Terraformで作成するもの
1.VPC作成
2.Subnet作成
3.InternetGW作成
4.RouteTable作成
5.SecurityGroup作成
6.IAM Role作成
7.EC2作成
8.ALB作成
9.TargetGroup作成
10.CloudFront作成
※この時点ではカスタムヘッダーの設定は入れない。
実践!
1.環境作成
1-1.terraformコード作成
# vi main.tf
provider "aws" { region = "ap-northeast-1" } 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 = "forward" target_group_arn = aws_alb_target_group.example.arn } } ### TargetGroup 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_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 } }
1-2.terraform 実行
# terraform plan # terraform apply
1-3.アクセス確認
下記へアクセスし、接続できることを確認
※URLはGUIを確認
・CloudFront:https://xxxxxxxx.cloudfront.net/
・ALB:http://xxxx.ap-northeast-1.elb.amazonaws.com
※httpで接続すること。
2.カスタムヘッダー設定
2-1.CloudFrontカスタムヘッダー設定
[CloudFront]-[ディストリビューション]-作成したディストリビューションを選択
[オリジン]タブ-作成したオリジンを選択し、[編集]
[カスタムヘッダーを追加]で下記を入力
・ヘッダー名:testHeader
・値:testValue
[変更を保存]
2-2.ALB リスナールールにカスタムヘッダー設定
[ALB]-作成したALBを選択
[リスナーとルール]タブ-[1個のルール]を押下
[ルールを追加する]を押下
下記を入力
・名前とタグ:testRule
[次へ]
[条件の追加]を押下
下記を入力
・条件の選択:HTTPヘッダー
・HTTPヘッダー名:testHeader
・HTTPヘッダー値:testValue
[確認]
[次へ]
アクションで下記を選択
・Routing actions:ターゲットグループへ転送
・ターゲットグループ:作成したターゲットグループ ※今回はexample-tg
[次へ]
下記を入力
・優先度:1
[次へ]
[作成]
2-3.ALB リスナーのデフォルトルールを変更
[デフォルト]を選択し、[アクション]-[ルールの編集]
下記へ変更
・デフォルトアクション-Routing acitons:固定レスポンスを返す
・レスポンスコード:403
・レスポンス本文:No direct access to ALB
[変更内容の保存]
2-4.アクセス確認
下記へアクセスし、CloudFrontのみ接続できること
ALBでは「No direct access to ALB」メッセージが返ることを確認
※キャッシュで接続できる可能性あるので、Google Chromeのシークレットウインドウなどで接続する。
CloudFront:https://xxxxxxx.cloudfront.net/
ALB:http://xxxxxxxx.ap-northeast-1.elb.amazonaws.com
感想
意外と簡単だった!コードに組み込みたい。(´Д`)