あめがえるのITブログ

頑張りすぎない。ほどほどに頑張るブログ。

terraformのimportを使用して手動で設定した項目をコードに起こしてみた


下記で作成したカスタムヘッダー設定した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



感想

なんかごちゃごちゃした記事になってしもうた。。。
わかりやすいサンプル使えばよかった(´Д`)

CloudFront+ALBでカスタムヘッダーを利用して、ALBでCloudFrontからの接続のみ許可する

カスタムヘッダーを利用して、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



感想

意外と簡単だった!コードに組み込みたい。(´Д`)

acm list-certificatesで取得できない証明書を取得する


AWS CLIで証明書の一覧を取得しようとしたが一部が取得されない状況を確認したので調べてみた

取得できない証明書

どうもキーアルゴリズムの「EC_prime256v1」が取得できない模様。

原因

リファレンスを読むとキーアルゴリズムRSA_2048」でフィルタがかかっているらしい。。
ぐぬぬ。。余計なことを(´Д`;;)

デフォルトのフィルタリングは証明書のみを返しますRSA_2048。 docs.aws.amazon.com

対策

--includes keyTypesで取得したいキーアルゴリズムを指定する

# aws acm list-certificates --includes keyTypes=RSA_2048,EC_prime256v1 ## 複数もいけるよ!
{
  "CertificateSummaryList": [
    {
      "CertificateArn": "arn:aws:acm:ap-northeast-1:xxxxxxxxxxxx:certificate/xxxxx-xxxx-xxx-xxx-xxxxx",
      "DomainName": "test.com.cn",
      "SubjectAlternativeNameSummaries": [
        "test.com"
      ],
      "HasAdditionalSubjectAlternativeNames": false,
      "Status": "ISSUED",
      "Type": "IMPORTED",
      "KeyAlgorithm": "EC-prime256v1",
・・・

※取得できた!


感想

やれやれ

AWS WAFのWebACLに設定されたタグを確認する方法

AWS WAFのWebACLに設定されたタグはGUIでは確認できないのでCLI確認する方法を調べてみた

実践!

1.環境作成
※下記を使用して環境を作成する。 amegaeru.hatenablog.jp

2.WebACLのARNを確認
※CloudShellで実行

# aws wafv2 list-web-acls --scope REGIONAL
{
    "NextMarker": "example-waf",
    "WebACLs": [
        {
            "Name": "example-waf",
            "Id": "e1b81942-64cb-4169-933e-3a576d9efa9d",
            "Description": "Example WAF for web application",
            "LockToken": "5c6f58c8-5e36-4d2e-8d81-5c651043935f",
            "ARN": "arn:aws:wafv2:ap-northeast-1:xxxxxxxxxxxx:regional/webacl/example-waf/e1b81942-64cb-4169-933e-3a576d9efa9d"
        }
    ]
}

3.タグ確認
※2で確認したARNを--resource-arnに記載する。

# aws wafv2 list-tags-for-resource --resource-arn "arn:aws:wafv2:ap-northeast-1:xxxxxxxxxxxx:regional/webacl/example-waf/e1b81942-64cb-4169-933e-3a576d9efa9d"
{
    "NextMarker": "",
    "TagInfoForResource": {
        "ResourceARN": "arn:aws:wafv2:ap-northeast-1:xxxxxxxxxxxx:regional/webacl/example-waf/e1b81942-64cb-4169-933e-3a576d9efa9d",
        "TagList": [
            {
                "Key": "test",
                "Value": "test"
            }
        ]
    }
}



感想

さて・・

terraformでS3バケットを消す際空っぽでないとエラーが出るのがうざい件


terraformで検証しているとS3バケットにオブジェクトがあると削除できずにエラーになるので都度GUIで削除するのが大変面倒で、調べてみたら方法があったのでやってみた。

症状

S3バケット内にオブジェクトがあると下記エラーがでる。

対策

S3バケットのコードに「force_destroy = true」を入れるといいらしい。

実践!

1.S3バケット作成

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

resource "aws_s3_bucket" "static_website" {
  bucket = "my-static-website-bucket123456789000"
  ## こんな感じ
  force_destroy = true
}
# terraform plan
# terraform apply


2.ファイルアップ

3.S3バケット削除

# terraform destory

※消えた!

補足

apply時点で設定していないと当然エラーになるので注意。


感想

なんだかな。

Amazon CloudFront+S3のWebサイトでOAIで送信元アクセス制御してみた

Amazon CloudFront+S3の構成で直接S3にアクセスさせたくないので、OAI(オリジンアクセスアイデンティティ)を設定してCloudFrontからの接続以外は受け付けないようにする。

Amazon CloudFrontとは

高いパフォーマンス、セキュリティ、デベロッパーの利便性のために構築されたコンテンツ配信ネットワーク(CDN)サービス。
aws.amazon.com

OAIとは

CloudFrontの分散恩典つを取得するためにS3バケットにアクセス際に使用される特殊なユーザー。

OAIとOACの違い

OAC(オリジンアクセスコントロール):細かなポリシー設定やAWS Signature Version 4(SigV4)を必要とするAWSリージョンでのPOSTメソッドを使用したHTTPおよびHTTPSリクエスト、SSE-KMSとの連携する場合に使用する。
aws.amazon.com



やること

terraformでCloudFrontとS3の静的Webサイトを作成し、CloudFrontのURLへ接続し接続ができ、S3のURLへ接続し接続できないことの確認する。

環境

※下記を作成

実践!

1.表示用htmlファイル作成

# vi index.html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Welcome to My Static Site</title>
</head>
<body>
    <h1>Welcome to My Static Site</h1>
    <p>This is the main page.</p>
</body>
</html>


2.エラー用htmlファイル作成

# vi error.html
<!-- error.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Error Page</title>
</head>
<body>
    <h1>Oops! Something went wrong.</h1>
    <p>We couldn't find the page you were looking for.</p>
</body>
</html>


3.環境構築

# vi main.html
provider "aws" {
  region  = "ap-northeast-1"
  profile = "testvault"
}

resource "aws_s3_bucket" "static_website" {
  bucket = "my-static-website-bucket123456789000"
}

## パブリックアクセスブロックは検証のためオフにする。
resource "aws_s3_bucket_public_access_block" "static_website" {
  bucket                  = aws_s3_bucket.static_website.id
  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}

resource "aws_s3_bucket_website_configuration" "website_config" {
  bucket = aws_s3_bucket.static_website.id
  
  index_document {
    suffix = "index.html"
  }

  error_document {
    key = "error.html"
  }
}

resource "aws_s3_object" "website_index" {
  bucket = aws_s3_bucket.static_website.bucket
  key    = "index.html"
  content_type = "text/html"
  source       = "index.html"
}

resource "aws_s3_object" "website_error" {
  bucket = aws_s3_bucket.static_website.bucket
  key    = "error.html"
  content_type = "text/html"
  source       = "error.html"
}

## OAIを設定
resource "aws_cloudfront_origin_access_identity" "oai" {
  comment = "OAI for my-static-website-bucket"
}

resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = aws_s3_bucket.static_website.bucket_regional_domain_name
    origin_id   = "S3Origin"

    ## CloudFrontにOAIを設定
    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.oai.cloudfront_access_identity_path
    }
  }

  enabled             = true
  is_ipv6_enabled     = true
  default_root_object = "index.html"

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "S3Origin"

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
}

# S3 Bucket Policy
resource "aws_s3_bucket_policy" "bucket_policy" {
  bucket = aws_s3_bucket.static_website.id

  policy = jsonencode({
    Version   = "2012-10-17",
    Statement = [
      {
        Sid       = "AllowCloudFrontAccess"
        Effect    = "Allow"
        Principal = {
          ## OAIを使用したアクセスのみ許可
          AWS = "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${aws_cloudfront_origin_access_identity.oai.id}"
        },
        Action    = "s3:GetObject",
        Resource  = "${aws_s3_bucket.static_website.arn}/*"
      }
    ]
  })
}

※フォルダ階層は下記のように同列に置く

┬ main.tf
├ index.html
└ error.html
# terraform plan
# terraform apply

※完成!

4.接続
4-1.CloudFrontのURLへ接続
※でけた!

4-2.S3バケットへ直接接続
※NG


感想

OACもそのうちやるか( ̄д ̄)

AWS WAFについて調べてみた

AWS WAFを使う機会があったのでちょいと調べてみた。

AWS WAFとは

 Web アプリケーションの通信をフィルター、監視、ブロックするためのソフトウェアまたは、ハードウェアのセキュリティ対策。
 一般のファイアウォールや IDS/IPS との違いは、アプリケーションレベルで通信の中身を解析し、特定の条件にマッチする通信を検知・遮断する。
 WAF の代表的な用途には、SQL インジェクション、クロスサイトスクリプティングなど、アプリケーションの脆弱性を悪用した攻撃の遮断やアプリケーション層の DDoS 対策、不正なボットによるアクセスの遮断などがある。
aws.amazon.com

AWS WAFコンポーネント

  • WebACL:WAF設定の塊。特定のAWSリソースに割り当てる。
  • ルール:リクエストに対する条件。
  • ルールグループ:ルールをまとめたもの。
  • アクション:ルールに合致した場合の行動を指定。Allow、Block、Countがある。

WebACLを割り当てることができるリソース

  • CloudFront
  • ALB
  • APIGateway

アクションの動作

  • Allow:AWSリソースへの転送が許可される
  • Block:リクエストをブロックする。
  • Count:リクエストをカウントするが許可するかブロックするかは決定しない。

docs.aws.amazon.com

AWS WAF料金(jp)

  • Web ACL :5.00USD/月
  • ルール  :1.00USD/月
  • リクエスト:0.60USD/100万リクエス

WAFv1とWAFv2とは

2019年末頃にバージョンが上がった模様。変更点としては、ルールの設定上限算出方法の変更(数から重みに変更)、マネージドルールの提供、記述方法の変更がある。旧バージョンは下記から設定可能。

terraformでWebACLだけ作ってみる

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

resource "aws_wafv2_web_acl" "example" {
  name        = "example-waf"
  description = "Example WAF for web application"
  scope       = "REGIONAL"

  default_action {
    allow {}
  }

  visibility_config {
    cloudwatch_metrics_enabled = false
    metric_name                = "exampleACLDefaultMetric"
    sampled_requests_enabled   = false
  }
  tags = {
    test = "test"
  }
}
# terraform plan
# terraform apply

※作れた



感想

どうでもいいが最近やる気がでない。これを楽しんでやっている人は頭がイカ〇ている気がする。あー、仕事変えたい( ̄д ̄)