【AWS】もう二度と忘れない。RDS(for MySQL)のパラメータ with Teraform。

September 11, 2020

TerraformでRDSを作成する時に使用するリソースとそのリソースのパラメータについて解説します。

目次

  • 概要
  • DBインスタンスの解説
  • 拡張モニタリングに必要なIAMロールの解説(aws_iam_*
  • ストレージの暗号化に必要なKMSの解説(aws_kms_key

概要

今回作成する予定の構成です。

全体像

ポイント!

  • マルチAZ配置を行うことで、高可用性を実現!
    → マルチAZを有効化することで、手動で作成したインスタンスとは別に、異なるAZにスタンバイ用のインスタンスが自動的に作成されます。

また、今回使用するリソースは下記になります。

- aws_db_instance
 ⇒ RDSインスタンスを作成するためのリソース。

- aws_db_option_group
 ⇒ 作成したインスタンスのオプショングループを作成するためのリソース。

- aws_db_parameter_group
 ⇒ 作成したインスタンスのパラメータグループを作成するためのリソース。

- aws_db_subnet_group
 ⇒ RDSインスタンスを配置するサブネットを作成するリソース。

- aws_iam_policy_document, aws_iam_role, aws_iam_role_policy_attachment
 ⇒ 拡張モニタリングを有効化するにあたり必要なIAMロールを作成するリソース。

- aws_kms_key
 ⇒ ストレージの暗号化に使用する鍵を作成するリソース。

それではそれぞれ解説していきます。


DBインスタンスの解説

メインとなるDBインスタンス。インスタンスの他に、サブネット、オプショングループ、パラメータグループが存在するため順に解説していきます。

※ 設定項目に対する説明もコメントで入れているため、行数が多くなっています。時間のない方は、必要な箇所だけ拾い読みでOKです。

DBインスタンス(aws_db_instance

############################################
# DB instance
############################################
resource "aws_db_instance" "main" {
  # データベース名。英数字、ハイフンのみ使用可能。
  name                        = "main"

  # ストレージタイプ。
  #  - 汎用SSDを使用。IOでより高いパフォーマンスが必要になったらプロビジョンIOPS(io1)の利用を考える。
  storage_type                = "gp2"

  # IOPSの設定。ストレージタイプがプロビジョンIOPS(io1)の時指定可能。
  #  - 今回は、ストレージタイプは汎用SSDのため無効。
  # iops                                = 10000

  # 割り当てるストレージのサイズ(GB)。
  #  - 今回は20GBを設定。
  allocated_storage           = 20

  # メジャーバージョンのアップデート有無。(例: 9.6 → 9.7)
  #  - 後続で指定するMySQLのメジャーバージョンを使用するため、今回は無効。
  allow_major_version_upgrade = false

  # マイナージョンの自動アップデート有無。(例: 9.6.11 → 9.6.12)
  #  - 自動で行いたいため有効。
  auto_minor_version_upgrade  = true

  # RDSへの設定変更を即時反映するかどうかの設定。即時反映しない場合は、次回のメンテナンスウィンドウで反映される。
  # https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html
  apply_immediately           = false

  # バックアップの保持期間(日)。0〜35が指定可能。
  # ※ リードレプリカのソースとして、このインスタンスを使用する場合、0より大きい値を設定する必要がある。
  backup_retention_period     = 1

  # 自動バックアップの時間帯(バックアップウィンドウ)の設定。指定した時間帯に毎日実行される。また、メンテナンスウィンドウと被らないように設定する必要がある。時刻はUTC。
  # ※ デフォルトは 13:00〜21:00 の間で30分。(東京リージョンの場合)
  backup_window               = "10:00-10:30"

  # メンテナンの実行時間帯(メンテナンスウィンドウ)の設定。この時間帯にOSやデータベースエンジン等のメンテナンスが行われる。時刻はUTC。
  maintenance_window          = "Sun:11:00-Sun:11:30"

  # インスタンスに設定されているタグ情報をスナップショットに引き継ぐかどうかの設定。
  #  - 今回はそのまま引き継ぎたいため有効にする。
  copy_tags_to_snapshot               = true

  # インスタンスを配置するサブネットグループを設定。
  #  - aws_db_subnet_group を使用する。詳細は後述。
  db_subnet_group_name                = aws_db_subnet_group.main.name

  # インスタンスを削除する時にバックアップも削除するかどうかの設定。
  #  - コスト節約のため削除する。
  delete_automated_backups            = true

  # データベース削除保護設定。
  #  - Terraform経由で削除したいため無効。
  deletion_protection                 = false

  # データベースエンジン。
  #  - 今回は「MySQL 8.0」を利用する。
  engine                              = "mysql"
  engine_version                      = "8.0"

  # MySQLの各種ログをCloudWatchに発行するための設定。
  #  - エラーログ、一般ログ、スロークエリログをそれぞれCloudWatchに発行する。
  enabled_cloudwatch_logs_exports     = [
    "error",
    "general",
    "slowquery"
  ]

  # インスタンス削除時にスナップショットの取得をスキップするかどうかの設定。
  #  - コスト節約のためスキップする。
  skip_final_snapshot                 = true

  # skip_final_snapshot が有効な時、その取得するスナップショットの名称を設定する。
  #  - 今回、skip_final_snapshot は無効なためこの設定も無効。
  # final_snapshot_identifier           = "${var.db_name}-final"

  # データベースアクセスユーザーをIAMで管理するかどうかの設定。
  #  - IAMで管理したいため有効。
  iam_database_authentication_enabled = true

  # RDSインスタンスに付ける名前。
  identifier                          = "main"

  max_allocated_storage = 0

  # インスタンスクラスを設定する。
  instance_class                      = "db.t3.micro"

  # モニタリングの間隔。
  monitoring_interval   = 60

  # モニタリングを行うためのIAMロール設定。(※ 詳細は後述)
  monitoring_role_arn   = aws_iam_role.rds_monitoring_role.arn

  # マルチAZ配置の利用有無。
  #  - スタンバイ用インスタンスも建てたいのえ、有効。
  multi_az              = true

  # オプショングループ設定。
  #  - aws_db_option_group を使用する。
  option_group_name    = aws_db_option_group.main.name

  # パラメータグループ設定。
  #  - aws_db_parameter_group を使用する。
  parameter_group_name = aws_db_parameter_group.main.name

  # DBユーザーとパスワード設定。
  #  - セキュリティの観点から、パスワードはインスタンス構築後に手動で変更する予定。
  username             = "root"
  password             = "zaq!2WSX"

  # DBへの接続を許可するポート。
  port                 = 3306

  # インターネットからのアクセスを許可するかどうかの設定。
  #  - インターネットからのアクセスは許可しないため無効。
  publicly_accessible  = false

  # レプリカの元になるDBを指定する設定。
  #  - レプリカではないため無効。
  # replicate_source_db  = aws_db_instance.db.identifier

  # ストレージの暗号化有無。
  #  - セキュリティの観点から暗号化したいため有効。
  storage_encrypted = true

  # ストレージの暗号化に使用するKMSのキー設定。
  #  - aws_kms_key を使用する。
  kms_key_id        = aws_kms_key.rds_storage.arn

  # セキュリティグループ設定。
  #  - 今回は別でDB用のセキュリティグループを作成していたので、それを使用。解説は省略。
  vpc_security_group_ids = [
    var.security_group_db
  ]

  # パフォーマンスインサイト設定。
  #  - 今回使用する db.t3.micro では対応していないため無効。
  performance_insights_enabled          = false
  # performance_insights_kms_key_id       = aws_kms_key.rds_performance_insight.arn
  # performance_insights_retention_period = 7

  # ライフサイクル設定。
  lifecycle {
    # passwordの変更はTerraformとして無視する。セキュリティの観点からインスタンス構築後、手動でパスワードを変更するため。
    ignore_changes = [password]
  }

  tags = {
    Env  = "dev"
  }
}

DBサブネットグループ(aws_db_subnet_group

DBインスタンスを配置するためのサブネットグループリソースを解説します。
※事前に aws_subnet でサブネットを作成しておく必要があります。

resource "aws_db_subnet_group" "main" {
  name = "db"
  subnet_ids = [
    # aws_subnet リソースで作成したサブネットを指定する。
    # マルチAZを使用するため、異なるAZに所属しているサブネットを指定します。
    var.subnet_id_private_db_a,
    var.subnet_id_private_db_c
  ]

  tags = {
    Env = var.env
  }
}

DBパラメータグループ(aws_db_parameter_group

DBパラメータグループを解説します。

resource "aws_db_parameter_group" "main" {
  name   = "main"

  # DBパラメータグループが適用されるファミリーを設定する。
  #  - 今回は、MySQL8.0を使用する。
  family = "mysql8.0"

  # スロークエリログを有効にする。
  parameter {
    name = "slow_query_log"
    value = 1
  }

  # 一般クエリログを有効にする。
  parameter {
    name = "general_log"
    value = 1
  }

  # スロークエリと判断する秒数を設定する。
  parameter {
    name = "long_query_time"
    value = 5
  }
}

設定できるパラメータはたくさんありますが、今回は以下の設定をしています。

スロークエリログの有効化
システムの性能が悪い時、遅いクエリを探すためによく利用されるスロークエリログ。デフォルトだと無効になっているため、有効にしています。

一般クエリログの有効化 一般クエリログも取得したいため有効にしています。
※ログの量が増えるため、パフォーマンスが低下することがあります。(必要に応じて、無効化する)

スロークエリと判断する秒数の指定 スロークエリと判断する秒数を設定します。一旦5秒を設定して、システムへの要求次第で調整。デフォルトは10秒。


DBオプショングループ(aws_db_option_group

DBオプショングループを解説します。
今回はオプションを設定しないため、空のオプショングループを作成します。

resource "aws_db_option_group" "main" {
  name = "main"

  # DBインスタンスに使用するエンジンを設定する。
  #  - MySQLを設定。
  engine_name = "mysql"

  # エンジンのメジャーバージョンを設定する。
  #  - MySQL8.0のため、「8.0」を設定する。
  major_engine_version = "8.0"
}

拡張モニタリングに必要なIAMロールの解説(aws_iam_*

インスタンスの拡張モニタリングを使用するためのIAMロールを解説します。

############################################
# IAM
############################################
# IAMロールの信頼ポリシーを作成する。
#  - 「monitoring.rds.amazonaws.com」がAssumeRoleすることを許可するポリシーを作成。
data "aws_iam_policy_document" "rds_monitoring_policy" {
  statement {
    effect = "Allow"
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["monitoring.rds.amazonaws.com"]
    }
  }
}

# IAMロールを作成する。
resource "aws_iam_role" "rds_monitoring_role" {
  name               = "rds_monitoring_role"

  # 上で作成した信頼ポリシーをロールにアタッチする。
  assume_role_policy = data.aws_iam_policy_document.rds_monitoring_policy.json
}

# RDS拡張モニタリングを実行するためのAWS管理ポリシーをIAMロールにアタッチする。
resource "aws_iam_role_policy_attachment" "default" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
  role       = aws_iam_role.rds_monitoring_role.name
}

ストレージの暗号化に必要なKMSの解説(aws_kms_key

KMSの解説をします。

※「KMSって何?」って方は、こちらの記事を1度読むことをオススメします!図解もされていて、初心者でもすごく分かりやすいです。
https://dev.classmethod.jp/articles/10minutes-kms/

############################################
# KMS
############################################
resource "aws_kms_key" "rds_storage" {
  description             = "key to encrypt rds storage."

  # CMKの使用方法を設定する。データの暗号化/復号化(ENCRYPT_DECRYPT)、メッセージの署名および署名の検証(SIGN_VERIFY)が設定できる。
  #  - データの暗号化を行うため、「ENCRYPT_DECRYPT」を設定する。
  key_usage               = "ENCRYPT_DECRYPT"

  # リソースが削除されてからキーを完全に削除するまでの期間(日)。7〜30を指定することができる。
  deletion_window_in_days = 7
  
  # マスターキーをローテーションするかどうかの設定。
  # (動作)
  # ローテーション後は、新規のデータはローテーション後のキーで暗号化/復号化される。ローテーション以前に暗号化したデータは、ローテーション前の古いキーで復号化する。
  enable_key_rotation     = true

  tags = {
    Env  = "dev"
  }
}

解説は以上になります。

最後までご覧頂きありがとうございました。