4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TerraformでAmazon Auroraクラスタを自動構築する(RDSプロキシ編)

Last updated at Posted at 2021-07-25

はじめに

Amazon Aurora記事第2弾。

前回に続き、今回は作成したAuroraクラスタにRDSプロキシを追加する。
RDSプロキシは、接続負荷を下げるためにLambdaからAuroraに接続するときは必須になる。一方で、常時接続するようなコネクションプールを持ったコンテナアプリケーションの場合は不要でありつつ、AutoScalingした際の管理の手間を省くには便利な機能だったりする(接続のオーバーヘッドがあるため、大量の処理を捌くようなワークロードには使いにくいと思われる)。

今回の記事では、前回記事で作ったTerraformのHCLに付け加える前提であるため、実際に触ってみる場合はまずは前回記事から読んでいただきたい。

Secrets Manager

いきなりだが、RDSプロキシのユーザの接続管理にはSecrets Managerを使う。
これがないと構築ができないので、まずは作成しておこう。

resource "aws_secretsmanager_secret" "dbproxy" {
  name = local.secret_manager_name

  recovery_window_in_days = 0
}

resource "aws_secretsmanager_secret_version" "dbproxy" {
  secret_id = aws_secretsmanager_secret.dbproxy.id

  secret_string = jsonencode({
    username : aws_rds_cluster.example.master_username
    password : aws_rds_cluster.example.master_password
    engine : aws_rds_cluster.example.engine
    host : aws_rds_cluster.example.endpoint
    port : aws_rds_cluster.example.port
    dbInstanceIdentifier : aws_rds_cluster.example.id
  })
}

recovery_window_in_days については、設定しなくても良い(削除時に何日間残しておくかという設定)。
ただし、検証環境のように何度か作っては消して、とやるケースでは、設定していないと、再構築時にシークレットの名前が重複してエラーになってしまう。

もし、消せなくなってしまった場合は、このページを参考にしつつ削除しておこう。デフォルトだと、削除予約中のシークレットはマネージメントコンソールでも参照できないので、ちょっと戸惑うことになる。

IAM

さらに、RDSプロキシがSecrets ManagerにアクセスするためにIAMの設定が必要になる。
以下のような感じで設定しておこう。resourcesはもう少し真面目に設定しておいた方が良いかもしれない。

resource "aws_iam_role" "dbproxy" {
  name               = local.iam_dbproxy_role_name
  assume_role_policy = data.aws_iam_policy_document.dbproxy_assume.json
}

data "aws_iam_policy_document" "dbproxy_assume" {
  statement {
    effect = "Allow"

    actions = [
      "sts:AssumeRole",
    ]

    principals {
      type = "Service"
      identifiers = [
        "rds.amazonaws.com",
      ]
    }
  }
}

resource "aws_iam_role_policy" "dbproxy" {
  name   = local.iam_dbproxy_policy_name
  role   = aws_iam_role.dbproxy.id
  policy = data.aws_iam_policy_document.dbproxy_custom.json
}

data "aws_iam_policy_document" "dbproxy_custom" {
  statement {
    effect = "Allow"

    actions = [
      "secretsmanager:GetResourcePolicy",
      "secretsmanager:GetSecretValue",
      "secretsmanager:DescribeSecret",
      "secretsmanager:ListSecretVersionIds"
    ]

    resources = [
      "arn:aws:secretsmanager:*:*:*",
    ]
  }
  statement {
    effect = "Allow"

    actions = [
      "kms:Decrypt",
    ]

    resources = [
      "*",
    ]
  }
}

Aurora

RDSプロキシの基本設定

さて、あとはRDSプロキシの設定だけだ。
リソースは以下のものを使う。

  • aws_db_proxy
  • aws_db_proxy_default_target_group
  • aws_db_proxy_target

aws_db_proxyrole_arnには、↑で作成したロールのARNを設定しておこう。
また、authsecret_arn には、↑で作成したSecrets ManagerのARNを設定する。
vpc_security_group_idsはMySQLであればインバウンドの3306ポートが空いていれば良い。
debug_loggingは、いったんtrueで構築するが、接続テストまで終わったらfalseにしよう。設定が間違っていた時等、CloudWatch Logsでエラー状況が確認できるので便利だ。このCloudWatch Logsはterraform destroyで自動削除はされない上に、デフォルトでは失効しない設定なので注意が必要だ。

ちなみに、Terraformの公式ドキュメントの通りに設定すると、MySQLのクライアントでSQL実行時にUnknown Errorが発生する。どうやら、init_querysession_pinning_filtersが悪さをするようだ。ここは、ちゃんと理解をした上で適宜必要に応じて設定をしていこう。

resource "aws_db_proxy" "example" {
  depends_on = [
    aws_rds_cluster_instance.example,
  ]

  name                   = local.rds_proxy_name
  debug_logging          = true
  engine_family          = "MYSQL"
  idle_client_timeout    = 60
  require_tls            = false
  role_arn               = aws_iam_role.dbproxy.arn
  vpc_security_group_ids = [aws_security_group.aurora.id]
  vpc_subnet_ids         = data.aws_subnet_ids.my_vpc.ids

  auth {
    auth_scheme = "SECRETS"
    iam_auth    = "DISABLED"
    secret_arn  = aws_secretsmanager_secret.dbproxy.arn
  }
}

resource "aws_db_proxy_default_target_group" "example" {
  db_proxy_name = aws_db_proxy.example.name

  connection_pool_config {
    connection_borrow_timeout    = 120
    max_connections_percent      = 100
    max_idle_connections_percent = 50
  }
}

resource "aws_db_proxy_target" "example" {
  db_proxy_name         = aws_db_proxy.example.name
  db_cluster_identifier = aws_rds_cluster.example.id
  target_group_name     = aws_db_proxy_default_target_group.example.name
}

これで、RDSプロキシが設定され接続可能になる。
RDSプロキシはVPC内からしかアクセスができないため、接続確認はEC2等を立てて確認しよう。

ReadOnlyなエンドポイントの追加

さて、作成したプロキシエンドポイントをマネージメントコンソールで確認してみると、以下の通り、Writerインスタンスに対してもプロキシを作ってしまっていることが分かる。

キャプチャ4.png

あくまでも参照処理のみさせたい場合、これではよろしくないので、自分でエンドポイントを作成しよう。

resource "aws_db_proxy_endpoint" "example" {
  db_proxy_name          = aws_db_proxy.example.name
  db_proxy_endpoint_name = "${local.rds_proxy_name}-ro"
  vpc_security_group_ids = [aws_security_group.aurora.id]
  vpc_subnet_ids         = data.aws_subnet_ids.my_vpc.ids
  target_role            = "READ_ONLY"
}

これまたTerraform公式ドキュメントの罠なのだが、例にはvpc_security_group_idsが設定されていないものの、これを設定していないと通信ができずにエラーになる。ちゃんと3306ポートを通しておくようにしよう。

キャプチャ5.png

試しに接続してCREATE TABLEしてみると…

MySQL [COMPANY]> CREATE TABLE EMPLOYEE (
    ->   id CHAR(5) PRIMARY KEY,
    ->   name CHAR(20) NOT NULL,
    ->   age INTEGER
    -> );
ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement

ちゃんとエラーになってくれた。
これで、ReadOnlyなプロキシエンドポイントから安全に接続できるようになったぞ!

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?