RDSインスタンスタイプ変更

db.t2.smallをdb.t3.small に変更。6分位

April 23, 2024, 12:01 (UTC+09:00)	Applying modification to database instance class
April 23, 2024, 12:03 (UTC+09:00)	DB instance shutdown
April 23, 2024, 12:06 (UTC+09:00)	DB instance restarted
April 23, 2024, 12:06 (UTC+09:00)	DB instance restarted
April 23, 2024, 12:06 (UTC+09:00)	Finished applying modification to DB instance class
April 23, 2024, 12:06 (UTC+09:00)	DB instance shutdown
April 23, 2024, 12:07 (UTC+09:00)	DB instance restarted

SES メール受信 S3

data "aws_caller_identity" "current" {}

locals {
  domain    = "example.com"
}

resource "aws_ses_domain_identity" "this" {
  domain = local.domain
}

resource "aws_route53_zone" "this" {
  name = local.domain
}

resource "aws_route53_record" "ses_verification" {
  zone_id = aws_route53_zone.this.zone_id
  name    = "_amazonses.${local.domain}"
  type    = "TXT"
  ttl     = "300"
  records = [aws_ses_domain_identity.this.verification_token]
}

resource "aws_route53_record" "apex_mx" {
  zone_id = aws_route53_zone.this.zone_id
  name    = ""
  type    = "MX"
  ttl     = "60"
  records = ["10 inbound-smtp.ap-northeast-1.amazonaws.com"]
}

resource "aws_s3_bucket" "ses_rcpt_test" {
  bucket = "ses_rcpt_test"
}

resource "aws_s3_bucket_policy" "ses_s3_allow_put" {
  bucket = aws_s3_bucket.ses_rcpt_test.bucket

  policy = <<-EOF
{
  "Version":"2012-10-17",
  "Statement": [
    {
      "Sid":"AllowSESPuts",
      "Effect":"Allow",
      "Principal":{
        "Service":"ses.amazonaws.com"
      },
      "Action":"s3:PutObject",
      "Resource":"arn:aws:s3:::${aws_s3_bucket.ses_rcpt_test.bucket}/*",
      "Condition":{
        "StringEquals":{
          "aws:Referer":"${data.aws_caller_identity.current.account_id}"
        }
      }
    }
  ]
}
EOF
}

resource "aws_ses_receipt_rule_set" "default" {
  rule_set_name = "default"
}

resource "aws_ses_receipt_rule" "ses_to_s3" {
  name          = "store"
  rule_set_name = aws_ses_receipt_rule_set.default.rule_set_name
  recipients    = ["ses-rcpt-test@example.com"]
  enabled       = true
  scan_enabled  = true

  s3_action {
    bucket_name = aws_s3_bucket.ses_rcpt_test.bucket
    position    = 2
  }
  depends_on = [aws_s3_bucket_policy.ses_s3_allow_put]
}

resource "aws_ses_active_receipt_rule_set" "default" {
  rule_set_name = aws_ses_receipt_rule_set.default.rule_set_name
}

AWSで独自ドメインへのメールをSES→S3で受け取るterraformの最小設定 - 技術と魚 2021

[アップデート] Amazon SES のメール受信機能がついに東京リージョンでも使えるようになりました | DevelopersIO 2023

InvalidS3Configuration error in aws_ses_receipt_rule · Issue #7917 · hashicorp/terraform-provider-aws · GitHub

EC2 NITRO世代にインスタンスタイプを変更 (EBSを追加マウントしている場合)

旧世代のインスタンスタイプをNITRO世代以降に変更する場合はOSのNVMeドライバのバージョンとENA有効化に注意する必要があるようです。
https://dev.classmethod.jp/articles/change-type-to-m5-nitro-generation/

m4.large (旧世代) → m5.large (NITRO世代) に変更するとデバイス名が変わる

EBSボリュームを追加、デバイス名(/dev/xvdg1など)でマウントしている場合は /etc/fstab の書き換えが必要になる

/dev/xvdg1 /data ext4 defaults,discard,nofail 0 2
↓
/dev/nvme1n1p1 /data ext4 defaults,discard,nofail 0 2

書き換えしないでnofailオプションなしだとOSが起動しない

UUIDでマウントしておくのが無難?

参考

https://wiki.archlinux.jp/index.php/Fstab

今使っているクラウドでは、マウントを正常に行う為に/etc/fstabに下記のようにUUIDを明記してボリュームをマウントしておく事が推奨されている。

UUID=f4713aa1-3a33-4933-85e8-94c421269a98 /     ext4    defaults        1 1

fstab間違えてOSが起動しない時の対処(クラウドでマシン複製する時とか) #Linux - Qiita 2015

LinuxでUUIDでHDDをマウントする - プログラミングとかLinuxとかの備忘録 2019

バイス名でマウント
EC2インスタンスに追加でEBSボリュームをアタッチする。 #AWS - Qiita 2018

Terraform for_each

aws_subnet.tf

resource "aws_subnet" "environment_example_subnet" {
  vpc_id            = aws_vpc.environment_example.id
  availability_zone = each.value.zone

  for_each = var.environment_example_subnets

  cidr_block              = each.value.cidr
  map_public_ip_on_launch = each.value.launch

  tags = {
    Name        = each.value.name
    Service     = "environment_example"
    Description = "Managed by Terraform"
  }
}

variables.tf

variable "environment_example_subnets" {
  type = map

  default = {
    public-1a = {
      cidr   = "172.20.0.0/19"
      zone   = "ap-northeast-1a"
      launch = "true"
      name   = "environment-example-public-a"
    }
    public-1c = {
      cidr   = "172.20.32.0/19"
      zone   = "ap-northeast-1c"
      launch = "true"
      name   = "environment-example-public-c"
    }
    private-1a = {
      cidr   = "172.20.64.0/19"
      zone   = "ap-northeast-1a"
      launch = "false"
      name   = "environment-example-private-a"
    }
    private-1c = {
      cidr   = "172.20.128.0/19"
      zone   = "ap-northeast-1c"
      launch = "false"
      name   = "environment-example-private-c"
    }
  }
}

[Terraform]同一リソース内で複数作成する場合、countよりfor_eachを使う #Terraform - Qiita 2020

AWS EventBridge Scheduler RDSの自動定期停止

【5分で簡単!】Amazon EventBridge SchedulerでRDSの自動定期停止を実装してみた | DevelopersIO 2022

AWS WAF 特定ドメイン IP制限 Basic認証 Cloudfront

Terraform

↓ WAFルール

Basic認証のユーザは bar-user パスワードは bar-pass

echo -n bar-user:bar-pass | base64
YmFyLXVzZXI6YmFyLXBhc3M=

terraform

resource "aws_wafv2_ip_set" "foo" {
  provider = aws.us-east-1
  name               = "foo"
  description        = "foo IP set"
  scope              = "CLOUDFRONT"
  ip_address_version = "IPV4"
  addresses          = ["1.2.3.4/32", "5.6.7.8/32"]
}

resource "aws_wafv2_web_acl" "waf" {
  provider = aws.us-east-1
  name     = "waf"
  scope    = "CLOUDFRONT"

  default_action {
    allow {}
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "waf"
    sampled_requests_enabled   = true
  }

  rule {
    name     = "foo-block-ip"
    priority = 1

    action {
      block {}
    }

    statement {
      and_statement {

        statement {
          byte_match_statement {
            field_to_match {
              single_header {
                name = "host"
              }
            }
            positional_constraint = "EXACTLY"
            search_string         = "foo.example.com"
            text_transformation {
              priority = 0
              type     = "LOWERCASE"
            }
          }
        }

        statement {
          not_statement {
            statement {
              ip_set_reference_statement {
                arn = aws_wafv2_ip_set.foo.arn
              }
            }
          }
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "foo-block-ip"
      sampled_requests_enabled   = true
    }
  }

  rule {
    name     = "bar-basic-auth"
    priority = 0

    action {
      block {
        custom_response {
          response_code = 401
          response_header {
            name  = "www-authenticate"
            value = "Basic"
          }
        }
      }
    }

    statement {
      and_statement {

        statement {
          byte_match_statement {
            field_to_match {
              single_header {
                name = "host"
              }
            }
            positional_constraint = "EXACTLY"
            search_string         = "bar.example.com"
            text_transformation {
              priority = 0
              type     = "LOWERCASE"
            }
          }
        }

        statement {
          not_statement {
            statement {
              byte_match_statement {
                positional_constraint = "EXACTLY"
                search_string         = "Basic YmFyLXVzZXI6YmFyLXBhc3M="
                field_to_match {
                  single_header {
                    name = "authorization"
                  }
                }
                text_transformation {
                  priority = 0
                  type     = "NONE"
                }
              }
            }
          }
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name                = "bar-basic-auth"
      sampled_requests_enabled   = true
    }
  }
}

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_ip_set
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl

参考

IP制限、Basic認証Apache等の設定でも実装可能ですが、本記事では下記を考慮しWAFでの実装とします。

  • AWS のセキュリティベストプラクティスに記載のある「全レイヤーでセキュリティを適⽤する」に則り、WAFによるセキュリティをCloudfrontに適⽤します。
  • Webページをホストしているサーバーにトラフィックが届かないため、サーバーの負荷軽減が期待できます。

...
「許可IPセットで指定したIP以外が指定のパスにアクセスした場合ブロックする」
...
「指定のパスにアクセスがあった場合、Basic認証を要求し認証失敗したものはブロックする」

AWS WAF で特定のパスに対してIP制限と Basic認証を実装する | iret.media 2023

↑とても参考になる

CloudfrontのIP制限をAWS/WAFで行う 2023

TerraformでAWS WAFを構築するサンプルコードを書いてみた #AWS - Qiita 2022

WAFで特定ドメインのIP制限をする(Terraform) #AWS - Qiita 2022