【Aurora】【Terraform】Secret Manager でマスターユーザーのパスワードを管理する環境で、Aurora の Blue/Green デプロイを実施する

記事タイトルとURLをコピーする

こんにちは😺 カスタマーサクセス部の山本です。

AWS Summit Tokyo の「Amazon Aurora の技術とイノベーションDeep dive」というセッションで、Aurora の Blue/Green デプロイメントについて学びました。

参考リンク:Amazon Aurora の技術とイノベーションDeep dive

実際に試してみたところ、以下の制約に引っかかってしまいました。

ブルー/グリーンデプロイでは、AWS Secrets Manager を使用したマスターユーザーのパスワード管理はサポートされていません。

参考:Aurora 用 Amazon RDS ブルー/グリーンデプロイの概要

この制約は、ブルー環境で Secrets Manager を使用して管理しているマスターユーザーのパスワードを、グリーン環境には引き継げないという意味だと考えました。 そこで、一度自身で作成したパスワードで マスターユーザーのパスワードを管理するようにクラスターを変更し、Blue/Green デプロイを実施することにしました。デプロイ完了後に再び AWS Secrets Manager を使用したパスワード管理に戻しました。
もし、デプロイ後にマスターユーザーのパスワードが変わることでアプリケーションに問題が発生する場合、この手順は参考にならないかもしれません。 ただし、アプリケーションでマスターユーザーを使用することは推奨されていないため、そのようなケースは稀だと思います。

アプリケーションではマスターユーザーを直接使用しないことを強くお勧めします。代わりに、アプリケーションに必要な最小の特権で作成されたデータベースユーザーを使用するというベストプラクティスに従ってください。

参考:マスターユーザーアカウント権限 - Amazon Aurora

目次です。

検証シナリオ

Terraform を使用して Aurora Postgres Serverless v2 を作成しています。
切り替え後に、ブルー環境のクラスターを削除して Terraform の管理から外し、グリーン環境のクラスターを Terraform にインポートします。
ブルー環境は Aurora Postgres v15 で作成しています。
グリーン環境作成時に v16 にアップグレードします。

ブルー環境の Aurora クラスター作成

  • Terraform バージョン

    • Terraform v1.9.3 on darwin_arm64
  • AWS Provider

    • 5.60.0

  • provider.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.60.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}
  • rds.tf
    • vpc_security_group_idssubnet_ids には検証環境に作成済みの実際のリソース ID を入れて実行しました。
    • パラメータグループは、v15 と v16 のもの、両方を作成しています。
    • Blue/Green デプロイをするため、クラスターパラメータグループでは、rds.logical_replication を 1 に設定しています。
resource "aws_rds_cluster" "test" {
  cluster_identifier              = "provisioning-rds"
  db_subnet_group_name            = aws_db_subnet_group.test.name
  db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.test15.name
  engine_version                  = "15.4"
  engine                          = "aurora-postgresql"
  engine_mode                     = "provisioned"
  enable_http_endpoint            = true
  iam_roles                       = []
  master_username                 = "postgres"
  manage_master_user_password     = true
  enable_global_write_forwarding  = false
  network_type = "IPV4"
  serverlessv2_scaling_configuration {
    max_capacity = 16
    min_capacity = 2
  }
  vpc_security_group_ids = ["sg-xxxxx"]
  skip_final_snapshot = true
}
resource "aws_rds_cluster_instance" "test" {
  cluster_identifier      = aws_rds_cluster.test.cluster_identifier
  db_subnet_group_name    = aws_rds_cluster.test.db_subnet_group_name
  db_parameter_group_name = aws_db_parameter_group.test15.name
  engine                  = aws_rds_cluster.test.engine
  engine_version          = aws_rds_cluster.test.engine_version
  identifier              = "rds-1"
  instance_class          = "db.serverless"
}
resource "aws_db_subnet_group" "test" {
  name       = "test_db_group"
  subnet_ids = ["subnet-xxxxx","subnet-xxxxx"]
}
resource "aws_rds_cluster_parameter_group" "test15" {
  name        = "test-aurora-postgresql15-cluster"
  family      = "aurora-postgresql15"
  description = "for aurora-postgresql15"
  parameter {
    name  = "rds.logical_replication"
    value = "1"
    apply_method = "pending-reboot"
  }
}
resource "aws_db_parameter_group" "test15" {
  name        = "test-aurora-postgresql15-instance"
  family      = "aurora-postgresql15"
  description = "for aurora-postgresql15"
}
resource "aws_rds_cluster_parameter_group" "test16" {
  name        = "test-aurora-postgresql16-cluster"
  family      = "aurora-postgresql16"
  description = "for aurora-postgresql16"
  parameter {
    name  = "rds.logical_replication"
    value = "1"
    apply_method = "pending-reboot"
  }
}
resource "aws_db_parameter_group" "test16" {
  name        = "test-aurora-postgresql16-instance"
  family      = "aurora-postgresql16"
  description = "for aurora-postgresql16"
}
resource "aws_ssm_parameter" "db_endpoint" {
  name = "jdbc_url"
  type = "String"
  value = aws_rds_cluster.test.endpoint
}
resource "aws_ssm_parameter" "reference_test" {
  name  = "reference"
  type  = "String"
  value = aws_ssm_parameter.db_endpoint.value
}

Blue/Green デプロイでは、AWS Secrets Manager を使用したマスターユーザーのパスワード管理はサポートされていない

Terraform で作成した Aurora クラスターで Blue/Green デプロイを実行してみましょう。 実際に、Secrets Manager を使用してマスターユーザーを管理している状態では、Blue/Green デプロイを実行できません。

ブルー環境のクラスターで、マスターユーザーのパスワードを自身で作成したパスワードに変更する

クラスターを変更します。
セルフマネージドにチェックを入れます。

任意のパスワードを設定します。既存の Secrets Manager から取得したものを設定し、現在のパスワードと同じにしました。

「すぐに適用」にチェックを入れ、更新します。

変更中になります。

変更が完了しました。

Blue/Green デプロイを実施する

Blue/Green デプロイを実施します。

同意します。

Terraform で作成したパラメータグループを指定します。

「ステージング環境の作成」を押します。

プロビジョニングしています。

v15 から v16 にアップデートしています。

「ステージング環境の作成」を押してから 30 分ほどで、切り替え可能な状態になりました。

切り替え前にグリーン環境を使用して、アプリケーションのテストを十分に実施します。
ブルー環境からグリーン環境へのレプリケーションとの競合が発生しないよう、グリーン環境では可能な限り読み取り操作のみテストします。
その後、切り替えます。

切り替えが完了しました。

EC2 から psql で接続していたセッションでは、一回コネクションが終了し、再接続しました。

新しいクラスターでマスターユーザーのパスワードを Secret Manager で管理するように変更する

新しいクラスターでマスターユーザーのパスワードを Secret Manager で管理するように変更します。 ここで、マスターユーザーのパスワードが変わります。

変更が完了しました。

ブルー環境のクラスターを削除する

まず、Blue/Green デプロイを削除します。

次に、古くなり未使用のブルー環境のインスタンスを削除します。

古くなり未使用のブルー環境のクラスターを削除します。

切り替えたグリーン環境のクラスターを Terraform にインポートする

state ファイルから旧クラスター・インスタンスと terraform のリソースの関連付けを削除

state ファイルでは旧クラスター・インスタンスと terraform のリソースが関連づいているため、削除します。

terraform state rm aws_rds_cluster.test

terraform state rm aws_rds_cluster_instance.test

rds.tf の編集

新しいクラスターの設定内容に合わせ、以下の編集をしました。

  • engine_version
    • 15.4 から 16.2 に変更
  • db_cluster_parameter_group_name
    • 15 を 16 に変更
  • db_parameter_group_name
    • 15 を 16 に変更
  • v15 用のクラスター・DBパラメータグループのリソースを削除
resource "aws_rds_cluster" "test" {
  cluster_identifier              = "provisioning-rds"
  db_subnet_group_name            = aws_db_subnet_group.test.name
  db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.test16.name
  engine_version                  = "16.2"
  engine                          = "aurora-postgresql"
  engine_mode                     = "provisioned"
  enable_http_endpoint            = true
  iam_roles                       = []
  master_username                 = "postgres"
  manage_master_user_password     = true
  enable_global_write_forwarding  = false
  network_type = "IPV4"
  serverlessv2_scaling_configuration {
    max_capacity = 16
    min_capacity = 2
  }
  vpc_security_group_ids = ["sg-xxxxxx"]
  skip_final_snapshot = true
}
resource "aws_rds_cluster_instance" "test" {
  cluster_identifier      = aws_rds_cluster.test.cluster_identifier
  db_subnet_group_name    = aws_rds_cluster.test.db_subnet_group_name
  db_parameter_group_name = aws_db_parameter_group.test16.name
  engine                  = aws_rds_cluster.test.engine
  engine_version          = aws_rds_cluster.test.engine_version
  identifier              = "rds-1"
  instance_class          = "db.serverless"
}
resource "aws_db_subnet_group" "test" {
  name       = "test_db_group"
  subnet_ids = ["subnet-xxxxx","subnet-xxxxx"]
}
resource "aws_rds_cluster_parameter_group" "test16" {
  name        = "test-aurora-postgresql16-cluster"
  family      = "aurora-postgresql16"
  description = "for aurora-postgresql16"
  parameter {
    name  = "rds.logical_replication"
    value = "1"
    apply_method = "pending-reboot"
  }
}
resource "aws_db_parameter_group" "test16" {
  name        = "test-aurora-postgresql16-instance"
  family      = "aurora-postgresql16"
  description = "for aurora-postgresql16"
}
resource "aws_ssm_parameter" "db_endpoint" {
  name = "jdbc_url"
  type = "String"
  value = aws_rds_cluster.test.endpoint
}
resource "aws_ssm_parameter" "reference_test" {
  name  = "reference"
  type  = "String"
  value = aws_ssm_parameter.db_endpoint.value
}

import.tf の作成

新しいクラスターをインポートする tf を作成します。

import {
  to = aws_rds_cluster.test
  id = "provisioning-rds"
}
import {
  to = aws_rds_cluster_instance.test
  id = "rds-1"
}

terraform applyし切り替えたグリーン環境のクラスターを Terraform にインポートする

terraform apply し、インポートします。

v15 用のパラメータグループ2つが destroy となり、新クラスター・インスタンスがインポートされます。
1 件の change は enable_global_write_forwarding に関する既知の事象でした。詳細は以下の記事を確認ください。
【Terraform】Aurora クラスターをリストアする - サーバーワークスエンジニアブログ

無事、完了しました。
最後に、今後の apply では import.tf は不要になるため、削除しました。

まとめ

Secret Manager でマスターユーザーのパスワードを管理する環境で、Aurora の Blue/Green デプロイを実施しました。
ひと手間かかるものの、Blue/Green デプロイの恩恵を受けることができます。

最後に、Blue/Green デプロイには様々な制約がございますので、以下のドキュメントは十分にご参照ください。
Aurora 用 Amazon RDS ブルー/グリーンデプロイの概要 - Amazon Aurora

余談

一度はやってみたかった、八ヶ岳の南北縦走をしてきました。
山梨県の小淵沢から、長野県の蓼科山までの 42 km 、ひたすら山を走りました。
標高 1000m の道の駅から、最高峰である標高 2899m の赤岳まで登り上げ、その後も最後までアップダウンが続く厳しいコースでした。 岩場が多く、かなり神経を使いました。 16 時間も走ったので、その後のお風呂も気持ちよく、夜もよく眠れていい休日でした。 なかなか達成感もあります。

赤岳

南アルプス

登山を楽しむ人達

天狗岳

蓼科山

山本 哲也 (記事一覧)

カスタマーサクセス部のインフラエンジニア。

山を走るのが趣味です。