はじめに
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_proxy
のrole_arn
には、↑で作成したロールのARNを設定しておこう。
また、auth
のsecret_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_query
とsession_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インスタンスに対してもプロキシを作ってしまっていることが分かる。
あくまでも参照処理のみさせたい場合、これではよろしくないので、自分でエンドポイントを作成しよう。
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ポートを通しておくようにしよう。
試しに接続して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なプロキシエンドポイントから安全に接続できるようになったぞ!