Aurora AWS Backup DR 演習 FIS 障害 別クラスタ復元 Terraform ハンズオン

目次

1. シナリオ背景: DR 演習の必要性・AWS Backup 選択理由・既存記事との差別化

2026 年 4 月時点の AWS 公式ドキュメントおよび Terraform AWS Provider v5.70 を基準に記述しています。料金・API 仕様は変更の可能性があるため、実際の適用前に公式ページを必ず確認してください。

1-1. DR における RPO/RTO 設計

本番データベースの障害は予告なく発生する。Aurora クラスタの誤削除、アプリケーションバグによるデータ破損、アベイラビリティゾーン (AZ) 障害——いずれも「起きうる」ではなく「起きた場合に備える」視点で設計しなければならない。

DR 設計の出発点は RPO (Recovery Point Objective: 復旧時点目標)RTO (Recovery Time Objective: 復旧時間目標) の定義だ。この 2 つを定義しないまま「バックアップを取っている」状態は、DR 対応とは言えない。

指標定義本記事の演習シナリオ
RPO障害発生時点からどれだけ過去まで遡って復旧を許容するか1 時間 (hourly + PITR 組み合わせ)
RTO障害発生から業務再開までの許容時間4 時間 (復元 30-60 分 + 切替・検証 2-3 時間)

RPO=1h / RTO=4h はミッションクリティカル系には及ばないが、製造業・EC 系では十分に厳格な SLA 目標として採用されることが多い現実的なシナリオだ。

業務影響と RPO/RTO の階層設計例:

業務影響度RPO 目標RTO 目標対応手段
高 (決済・在庫)5 分以内30 分以内PITR + マルチ AZ + Aurora Global DB
中 (受注・顧客DB)1 時間以内4 時間以内AWS Backup + PITR (本記事シナリオ)
低 (ログ・分析DB)24 時間以内8 時間以内日次スナップショットのみ

本記事では「中」ランクの RPO=1h / RTO=4h を演習シナリオに採用し、AWS Backup + FIS + Terraform による再現可能な DR Runbook を構築する。

DR演習全体構成図 prod-backup-restore 3stack + Route53切替フロー

1-2. AWS Backup の位置付け: 3 種の復旧手段比較

Aurora には主に 3 種の復旧手段がある。それぞれの特性を理解したうえで AWS Backup を選択する根拠を整理する。

復旧手段仕組み最大保持期間RPO の実力主な用途
自動スナップショットAurora が自動で日次取得・無料枠あり35 日最短 1 日単純な日次バックアップ
AWS Backupバックアップ計画で管理・cross-account/region 対応計画設定次第cron 最短 1 時間監査・組織横断管理
PITR (Continuous Backup)WAL ストリームを継続保管・秒単位復元可最大 35 日約 5 分高 RPO 要件
3 手段の使い分け基準 (2026 年 4 月時点)

  • 自動スナップショットのみ: RPO=24h で許容できる、監査要件なし、単一アカウント運用で十分な場合
  • AWS Backup 採用: バックアップ計画のコード化・監査証跡 (Vault Lock)・cross-account 隔離保管・他サービス (DynamoDB/EFS) との統合管理が必要な場合
  • PITR 追加: RPO=5 分以内が求められる場合。AWS Backup の Continuous Backup として組み込み可能だが WAL 保管の追加課金に注意
  • 本記事: RPO=1h シナリオで AWS Backup (hourly plan) + PITR を組み合わせて採用

自動スナップショット単体では不足する場面:

  • cross-account コピーで隔離バックアップを保管したい (ランサムウェア対策)
  • Vault Lock でバックアップ削除を防止したい (コンプライアンス・監査要件)
  • バックアップ計画を Terraform でコード管理し PR レビュー対象にしたい
  • DynamoDB / EFS / S3 等と統合してバックアップ状況を一元監視したい

これらすべてに対応できるのが AWS Backup の強みだ。本記事では Vault + Plan + Selection の 3 層構造を Terraform で完全コード化し、再現性の高い DR Runbook として構築する。

1-3. FIS 障害演習を組み込む理由

DR Runbook は「作成する」だけでは機能しない。演習しなければ有事に使えない——これは実際の DR 対応現場で繰り返し確認されてきた教訓だ。DR 手順書が存在していても、初めて実行する本番障害では想定外の操作ミスや手順漏れが頻発する。

AWS FIS (Fault Injection Service) を使うと、Aurora クラスタに対して以下の疑似障害を安全に発動できる (2026 年 4 月時点)。

FIS アクション模擬障害の内容典型復旧時間
aws:rds:reboot-db-instancesDB インスタンス再起動約 2 分
aws:rds:stop-db-clusterクラスタ完全停止 (手動 start が必要)約 5 分
aws:rds:force-failover-db-clusterWriter 強制フェイルオーバー約 30 秒

★ 演習用アカウント分離必須: FIS 実験は必ず演習用 AWS アカウント内、または ChaosEngineering=enabled タグで対象リソースを明示的に限定して実行すること。本番アカウントで無制限に実行すると本番 DB が停止する危険がある。詳細は §5 で解説する。

FIS 疑似障害 → CloudWatch Alarm 検知 → 復元判断 → 別クラスタ復元 → Route 53 切替 の一連フローを演習することで、有事に「手が動く状態」になる。静的な復元手順だけを持っているのと、実際に演習を経た Runbook を持っているのとでは、障害対応の質に雲泥の差がある。

本記事では §5 で FIS の Terraform コード化・演習アカウント分離・CloudWatch 監視の 3 点セットを解説し、「演習できる DR 環境」を提供する。

1-4. 既存記事との位置付け: 平時運用 vs 有事復旧

本記事は独立した DR 演習記事として設計しているが、aurora-no-human-login 記事と合わせて読むことで Aurora 運用ライフサイクルが完結する。

観点aurora-no-human-login本記事
軸足平時運用 (日常の DB アクセス管理)有事復旧 (DR 演習 + 別クラスタ復元)
主要技術IAM database authentication + Secrets ManagerAWS Backup + FIS + Terraform import
RPO/RTO非対象 (運用品質指標)RPO=1h / RTO=4h (演習シナリオ)
読者が得るもの人手ログイン削減の Runbook災害復旧の Runbook
読了後の次のステップ本記事で DR 演習へaurora-no-human-login で平時運用へ

2 記事を合わせ読むことで Aurora 運用ライフサイクル (構築 → 平時 → 有事 → 復旧) が完結する。

aurora-no-human-login 記事では IAM database authentication による human login 削減・Secrets Manager を使った認証情報の安全な管理を扱っている。本記事は「その Aurora クラスタが障害に遭遇したとき、どう復元するか」というフェーズを担う。両記事は直交するテーマでありながら相互補完関係にある。

「平時の運用品質を高める (aurora-no-human-login)」と「有事の復旧能力を演習する (本記事)」の両輪が揃って初めて、Aurora を本番で安心して運用できる体制となる。

1-5. 本記事の演習シナリオと到達範囲

本記事では以下の 8 章構成で terraform apply → FIS 疑似障害 → 別クラスタ復元 → Route 53 切替 の一連フローを演習する。

タイトル演習で得られるもの
§1シナリオ背景RPO/RTO 設計・AWS Backup 選択理由・位置付け整理
§2既存クラスタ構成整理Terraform state 棚卸・backup 対象識別・別 stack 設計
§3AWS Backup Vault 設計Vault + KMS + Plan + Selection の Terraform コード化
§4バックアップ計画設計Snapshot vs PITR・リテンション階層・コスト試算
§5FIS 障害演習疑似障害発動 → CloudWatch 検知 → 復元判断フロー
§6復元ハンズオン別クラスタ新規作成 + Terraform import (論点 A + B)
§7データ整合性検証・切替Route 53 段階切替 + Secrets Manager + 旧クラスタ隔離
§8まとめ・運用注意点Vault Lock 誤設定・FIS 誤爆・二重課金の注意点

この記事を完走した状態:

  • terraform apply で AWS Backup Vault + Plan + Selection + FIS template が構成済み
  • FIS 疑似障害を発動し CloudWatch Alarm で検知・Performance Insights で確認できた
  • AWS Backup Recovery Point から別クラスタに復元し restore/ Terraform stack で管理
  • Route 53 alias weighted routing で旧クラスタから新クラスタへ段階的に切替完了
前提環境チェックリスト (2026 年 4 月時点)

  • AWS アカウント: ★ 演習用アカウントの利用を強く推奨 (本番アカウントでの FIS 実験は重大リスク)
  • Terraform: >= 1.9.0, < 2.0.0
  • AWS Provider: hashicorp/aws ~> 5.70 (aws_fis_experiment_template v2 対応済)
  • AWS CLI: 2.15+
  • psql: PostgreSQL クライアント (データ整合性検証 §7 で使用)
  • jq: JSON パーサー (terraform show -json / AWS CLI 出力解析で使用)
  • IAM 権限: AWSBackupFullAccess / AmazonRDSFullAccess / AWSFaultInjectionSimulatorRDSAccess

事前確認コマンド:

# ツールバージョンと接続先アカウントを確認するterraform versionaws --versionaws sts get-caller-identity  # 演習用アカウント ID であることを必ず確認psql --versionjq --version

aurora-no-human-login 記事と合わせて読む — 平時の Aurora 運用 (IAM DB 認証・human login 削減)

2. 既存 Aurora クラスタ構成整理: Terraform state 棚卸・backup 対象リソース列挙

2026 年 4 月時点の Terraform AWS Provider v5.70 / Aurora PostgreSQL 16.x を基準に記述しています。

2-1. 既存 prod stack の棚卸

AWS Backup を設定する前に、バックアップ対象となる Aurora クラスタのリソース構成を正確に把握しておく。terraform state listprod/ stack の現状を確認することが出発点だ。

cd terraform/prodterraform state list

典型的な Aurora PostgreSQL クラスタの state に含まれるリソース一覧:

aws_db_subnet_group.mainaws_kms_key.auroraaws_kms_alias.auroraaws_rds_cluster.mainaws_rds_cluster_instance.writeraws_rds_cluster_instance.reader_1aws_rds_cluster_instance.reader_2aws_rds_cluster_parameter_group.mainaws_db_parameter_group.mainaws_security_group.auroraaws_secretsmanager_secret.aurora_credentialsaws_secretsmanager_secret_version.aurora_credentials

クラスタ ARN と KMS キー ARN は §3 の Backup Selection と §6 の復元ハンズオンで必要になる。事前に記録しておく。

# Aurora クラスタの ARN・エンドポイント・暗号化情報を抽出するterraform show -json | jq '  .values.root_module.resources[]  | select(.type == "aws_rds_cluster")  | {cluster_arn: .values.arn, kms_key_id: .values.kms_key_id,  endpoint: .values.endpoint, engine_version: .values.engine_version}'# AWS CLI でクラスタ状態を確認するaws rds describe-db-clusters \  --query 'DBClusters[*].{ID:DBClusterIdentifier,ARN:DBClusterArn,Status:Status}' \  --output table

2-2. backup 対象リソースの識別

AWS Backup が管理できるリソースと対象外リソースを区別しておく。

リソースAWS Backup の対応備考
aws_rds_cluster✅ スナップショット + Continuous BackupARN: arn:aws:rds:*:*:cluster:*
aws_rds_cluster_instance✅ クラスタ単位でまとめて取得インスタンス個別バックアップは不可
aws_rds_cluster_parameter_group❌ Backup 対象外Terraform state が実質バックアップ
aws_db_subnet_group❌ Backup 対象外Terraform state で保全
aws_kms_key❌ Backup 対象外Terraform state + KMS 自動ローテーション

Aurora クラスタのバックアップは クラスタレベルで取得される。整合性スナップショットが 1 つの Recovery Point として Vault に保管される仕組みだ。

parameter group・subnet group・KMS キーは AWS Backup の対象外のため、Terraform state が実質的なバックアップとなる。prod/ stack の S3 backend でバージョニングを有効化しておくことが前提条件だ。

Aurora 自動バックアップと AWS Backup 管理の違い:

  • Aurora 自動バックアップ: Aurora 内部管理。Vault とは独立した保管場所。cross-account copy 不可
  • AWS Backup 管理スナップショット: Vault 内に保管。Vault Lock・cross-account copy の対象
  • PITR (Continuous Backup): WAL ストリームを継続保管。AWS Backup の enable_continuous_backup=true で統合可能。ただし WAL 保管の追加課金に注意

KMS 暗号化キーについて: Vault 専用の CMK (§3 で作成) と prod クラスタの CMK は別管理する。cross-account copy 時は destination account の Vault にも適切な KMS 権限設定が必要だ。

2-3. 論点 B: 別 stack 疎結合の設計思想

本記事の中核設計判断が 論点 B: Terraform state を別 stack で疎結合管理する という方針だ。

既存 prod/ stack に backup/restore リソースを terraform import で取り込む案も考えられるが、以下の理由から却下した。

別 stack 採用の 4 つの根拠:

  1. prod state への侵襲リスク排除: backup リソースを prod state に混在させると terraform apply が prod Aurora を変更する事故リスクが生まれる
  2. destroy の独立性: 演習後に restore/ stack だけを terraform destroy できる。prod に影響ゼロ
  3. 責務分離: インフラの「本番稼働 (prod)」「バックアップ管理 (backup)」「復元 (restore)」を明確に分離
  4. state 軽量化: 各 stack の state ファイルが小さく保たれ、terraform plan の実行速度が向上する

ディレクトリレイアウト (論点 B 実装):

terraform/├── prod/  # 既存 Aurora クラスタ (本記事では触らない)│├── main.tf│├── outputs.tf  # cluster_arn / vpc_id / subnet_ids を output│└── backend.tf  # state key: state/prod/terraform.tfstate│├── backup/# 本記事 §3-§5: Vault + Plan + FIS template│├── backend.tf  # state key: state/backup/terraform.tfstate│├── main.tf│├── locals.tf│├── variables.tf│└── remote_state.tf# prod outputs を参照│└── restore/  # 本記事 §6: 復元クラスタ (演習後 destroy) ├── backend.tf  # state key: state/restore/terraform.tfstate ├── main.tf  # aws_rds_cluster (terraform import 後) └── remote_state.tf# prod outputs を参照

Terraform state分離モデル prod-backup-restore 3stack terraform_remote_state参照

別 stack 疎結合の 4 つの利点

  • 安全性: prod state への侵襲なし。backup/restore の apply が prod を変更しない
  • 独立 destroy: 演習後に cd restore && terraform destroy だけで復元クラスタを削除できる
  • 責務分離: backup/ と restore/ を異なるチーム・IAM ロールで管理できる
  • state 軽量化: 各 stack の state が小さく保たれ plan 速度が向上する

2-4. prod/ stack から backup/ stack が参照する情報

backup/ stack と restore/ stack は terraform_remote_state データソースで prod/ stack の出力値を参照する。prod リソースへの変更は一切行わない読み取り専用の参照だ。

まず prod/outputs.tf にクラスタ ARN などを output として定義する。

# terraform/prod/outputs.tfoutput "aurora_cluster_arn" {  value = aws_rds_cluster.main.arn}output "vpc_id" {  value = aws_vpc.main.id}output "private_subnet_ids" {  value = aws_db_subnet_group.main.subnet_ids}output "aurora_sg_id" {  value = aws_security_group.aurora.id}output "kms_key_arn" {  value = aws_kms_key.aurora.arn}

backup/remote_state.tf で prod の出力値を読み込む。

# terraform/backup/remote_state.tfdata "terraform_remote_state" "prod" {  backend = "s3"  config = { bucket = var.tfstate_bucket key = "state/prod/terraform.tfstate" region = "ap-northeast-1"  }}locals {  prod_cluster_arn = data.terraform_remote_state.prod.outputs.aurora_cluster_arn  prod_vpc_id= data.terraform_remote_state.prod.outputs.vpc_id  prod_subnet_ids  = data.terraform_remote_state.prod.outputs.private_subnet_ids  prod_kms_key_arn = data.terraform_remote_state.prod.outputs.kms_key_arn}

2-5. タグ戦略: AWS Backup Selection と FIS 対象の分離

AWS Backup Selection はタグベースでバックアップ対象リソースを識別する。必須タグの設計:

タグキータグ値用途
BackupPolicydaily-1hAWS Backup Selection がこのタグで対象を選択
ChaosEngineeringenabledFIS 実験対象を限定 (演習アカウントのみに付与)
Environmentdr-lab / prod環境識別
ManagedByterraform管理方式識別

aws_rds_cluster の tags に BackupPolicy タグを追加する:

# terraform/prod/main.tf — tags ブロックのみ変更resource "aws_rds_cluster" "main" {  # ... 既存の設定 (変更なし) ...  tags = merge(local.common_tags, { BackupPolicy  = "daily-1h"  # Backup Selection の選択条件 ChaosEngineering = "enabled"# FIS 対象 (★演習アカウントのみに付与)  })}

ChaosEngineering=enabled の取り扱い: このタグが付与されたリソースが FIS 実験の対象になる。本番アカウントの Aurora クラスタには絶対に付与しないこと。§5 で IAM policy の Condition でタグ絞り込みを追加する手順も解説する。

タグ設計と Backup Selection の連動ルール

  • BackupPolicy=daily-1h を Aurora クラスタに付与 → backup/ stack の aws_backup_selection が自動的にこのクラスタを対象化する
  • ChaosEngineering=enabled は演習用アカウントのクラスタのみに付与。本番クラスタへの付与禁止をコードレビューでチェックする運用を推奨
  • 複数 Aurora クラスタがある場合、BackupPolicy タグ値を使い分けて Backup Plan の適用範囲を制御できる

2-6. 現状確認チェックリスト

§3 (Vault 設計) に進む前に以下のコマンドで現状を確認し記録しておく。

# 既存の自動スナップショット一覧を確認するaws rds describe-db-cluster-snapshots \  --snapshot-type automated \  --query 'DBClusterSnapshots[*].{ID:DBClusterSnapshotIdentifier,Created:SnapshotCreateTime,Status:Status}' \  --output table# Route 53 alias record の現行ターゲット (§7 切替準備)aws route53 list-resource-record-sets \  --hosted-zone-id <ZONE_ID> \  --query 'ResourceRecordSets[?Type==`A`].[Name,AliasTarget.DNSName]' \  --output table
確認項目確認方法用途
クラスタ ARNterraform output aurora_cluster_arn§3 Backup Selection
KMS CMK ARNterraform output kms_key_arn§3 Vault KMS 設定
S3 backend bucket 名cat prod/backend.tfbackup/remote_state.tf 設定
writer endpointaws rds describe-db-clusters ...§7 Route 53 切替の現行 alias 確認
Secrets Manager secret 名aws secretsmanager list-secrets§6-5 Secrets Manager 切替準備

3. AWS Backup Vault 設計 + Terraform

3-1. Vault + KMS CMK 設計

backup/ stack に Vault と CMK を定義する。KMS key policy には backup.amazonaws.com プリンシパルを明示的に追加することで、Backup サービスが CMK を使用してデータを暗号化できるようにする。

resource "aws_kms_key" "backup" {  description = "CMK for Aurora DR backup vault (${var.environment})"  deletion_window_in_days = 30  enable_key_rotation  = true  policy = jsonencode({ Version = "2012-10-17" Statement = [{  Sid = "AllowAccountRoot"  Effect = "Allow"  Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" }  Action = "kms:*"  Resource  = "*"},{  Sid = "AllowBackupService"  Effect = "Allow"  Principal = { Service = "backup.amazonaws.com" }  Action = ["kms:GenerateDataKey", "kms:Decrypt", "kms:DescribeKey"]  Resource  = "*"} ]  })  tags = local.common_tags}resource "aws_kms_alias" "backup" {  name = "alias/aurora-dr-backup-${var.environment}"  target_key_id = aws_kms_key.backup.key_id}resource "aws_backup_vault" "main" {  name  = "${var.backup_vault_name}-${var.environment}"  kms_key_arn = aws_kms_key.backup.arn  tags  = local.common_tags}

Vault 名は aurora-dr-vault-prod / aurora-dr-vault-staging の命名規約に従い var.backup_vault_name + var.environment で一意性を担保する。enable_key_rotation = true で CMK の年次自動ローテーションを有効化すること(2026年4月時点、AWS 管理デフォルト)。

AWS Backup Vault Plan Selection関係図 KMS暗号化 daily/weekly/monthly 3ルール DAG

3-2. Vault Lock ★危険注記

Vault Lock は backup vault に WORM (Write Once Read Many) ポリシーを適用し、recovery point を指定期間内に削除できなくする機能(2024 Q2 GA・provider 5.50+ で安定、2026年4月時点)。

2 種類のモード比較:

モード解除可否changeable_for_days推奨用途
governanceIAM backup:DeleteBackupVaultLockConfiguration で解除可指定可(猶予期間)初回設定・演習環境
complianceMinRetentionDays 経過まで削除不可・解除不可指定不可厳格な監査要件のみ
# 推奨: governance mode (初回・ChangeableForDays=3 で猶予を確保)resource "aws_backup_vault_lock_configuration" "main" {  backup_vault_name= aws_backup_vault.main.name  min_retention_days  = var.vault_lock_min_retention_days  # default: 7  max_retention_days  = 365  changeable_for_days = 3  # governance mode のみ有効: 3 日以内なら設定変更可}
⚠️ Vault Lock 誤設定で起きる3つの事故 (2026年4月時点)

  • 事故1: 意図しない永続課金 — compliance mode で max_retention_days = 2555(7年)を設定すると vault 内の全 recovery point を 7 年間削除できず、S3 ストレージ課金が数年間継続する。MinRetentionDays 経過まで Vault Lock 自体も削除不可。
  • 事故2: terraform destroy 失敗 — compliance mode の vault は Vault Lock 解除不可のため terraform destroy がエラーで中断する。演習環境のクリーンアップが不可能になる。
  • 事故3: DR テスト妨害 — Vault Lock がかかった vault では recovery point の手動削除ができない。DR 演習後の cost cleanup が行えなくなる。

初回は必ず governance mode + changeable_for_days = 3 で設定し、3 日以内に誤りを訂正できる猶予を確保すること。compliance mode への移行は本番監査要件が確定してから行う。

3-3. Backup Plan (daily+weekly+monthly)

local.backup_rulesfor_each で展開し、1 Plan に 3 ルールを統合する。スケジュールは AWS Backup の cron 記法(6 フィールド)を使用する。

resource "aws_backup_plan" "aurora_dr" {  name = "aurora-dr-plan-${var.environment}"  dynamic "rule" { for_each = local.backup_rules content {rule_name= rule.keytarget_vault_name = aws_backup_vault.main.nameschedule = rule.value.schedulestart_window= 60# スケジュール後 60 分以内に開始completion_window = 180  # 180 分以内に完了しなければ FAILEDlifecycle {  cold_storage_after = rule.value.cold_after_days  # null = 移行なし  delete_after = rule.value.retention_days} }  }  tags = local.common_tags}

local.backup_rules の map 構造は §4-3 で詳述する。monthly ルールのみ 90 日後に cold storage へ自動移行し、ストレージコストを約 80% 削減する(2026年4月時点、ap-northeast-1)。delete_aftercold_storage_after より大きい値を設定すること(小さいと apply 時にエラー)。

3-4. Backup Selection (タグベース)

BackupPolicy=daily-1h タグを持つ Aurora クラスタを自動的にバックアップ対象とする。IAM ロールには AWS 管理ポリシー AWSBackupServiceRolePolicyForBackup を attach する。

resource "aws_iam_role" "backup_service" {  name = "aurora-dr-backup-role-${var.environment}"  assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{Effect = "Allow"Principal = { Service = "backup.amazonaws.com" }Action = "sts:AssumeRole" }]  })  tags = local.common_tags}resource "aws_iam_role_policy_attachment" "backup_service" {  role = aws_iam_role.backup_service.name  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"}resource "aws_backup_selection" "aurora" {  name= "aurora-dr-selection-${var.environment}"  iam_role_arn = aws_iam_role.backup_service.arn  plan_id= aws_backup_plan.aurora_dr.id  selection_tag { type  = "STRINGEQUALS" key= "BackupPolicy" value = "daily-1h"  }}

prod Aurora クラスタのタグに BackupPolicy = "daily-1h" を追加するだけで選択対象に取り込まれる。iam:PassRole 権限は backup plan を実行する IAM エンティティ(Terraform 実行ロール等)に別途付与が必要。

3-5. cross-account / cross-region copy

演習では ap-northeast-1 → ap-northeast-3 (大阪) の cross-region copy を例示する。本番環境では cross-account copy(別 AWS アカウントへのコピー)を推奨し、アカウント侵害時のバックアップ喪失リスクを排除する。

# copy_action を追加した Backup Plan (monthly ルールのみ cross-region copy)resource "aws_backup_plan" "aurora_dr_with_copy" {  name = "aurora-dr-plan-xregion-${var.environment}"  rule { rule_name= "monthly-xregion" target_vault_name = aws_backup_vault.main.name schedule = local.backup_rules.monthly.schedule start_window= 60 completion_window = 360  # cross-region copy は完了に時間を要する lifecycle {cold_storage_after = 90delete_after = 365 } copy_action {destination_vault_arn = "arn:aws:backup:ap-northeast-3:${data.aws_caller_identity.current.account_id}:backup-vault:aurora-dr-vault-replica"lifecycle {  delete_after = 365} }  }  tags = local.common_tags}

cross-region 転送料金は $0.02/GB(2026年4月時点・ap-northeast-1 起点)。cross-account copy の場合は destination account 側の vault に trust policy(backup.amazonaws.com への backup:CopyIntoBackupVault 許可)が追加で必要となる。

cross-region copy で DR 強度を1段上げる

  • 単一リージョンリスク — 同一リージョン障害では vault と prod クラスタが同時に失われる可能性がある。ap-northeast-1 の AZ 全滅シナリオで backup が無効化されないよう副リージョンへのコピーが有効。
  • copy_action で自動コピー — ap-northeast-3(大阪)の vault に月次バックアップを自動コピー。転送は非同期でプライマリバックアップジョブの完了後に開始される。
  • cross-account をさらに推奨 — アカウント侵害時の保護として、重要なワークロードは別 AWS アカウントの vault へのコピーを推奨する。
  • 転送料金: $0.02/GB(2026年4月時点・公式 AWS Backup Pricing で最新値を確認)

3-6. 動作確認

terraform apply 完了後、以下のコマンドで Vault・バックアップジョブ・CloudTrail 監査ログを確認する。

# Vault ステータス確認aws backup describe-backup-vault \  --backup-vault-name aurora-dr-vault-dr-lab \  --region ap-northeast-1# バックアップジョブ一覧 (直近 24 時間)aws backup list-backup-jobs \  --by-backup-vault-name aurora-dr-vault-dr-lab \  --by-created-after "$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)" \  --region ap-northeast-1 \  --query 'BackupJobs[].{Status:State,Resource:ResourceArn,Started:StartBy}' \  --output table# recovery point 確認aws backup list-recovery-points-by-backup-vault \  --backup-vault-name aurora-dr-vault-dr-lab \  --region ap-northeast-1 \  --query 'RecoveryPoints[].{Status:Status,Created:CreationDate,Size:BackupSizeInBytes}' \  --output table# CloudTrail で backup API 呼び出し監査 (直近 1 時間)aws cloudtrail lookup-events \  --lookup-attributes AttributeKey=EventSource,AttributeValue=backup.amazonaws.com \  --start-time "$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)" \  --query 'Events[].{Time:EventTime,Name:EventName,User:Username}' \  --output table

バックアップジョブの StateCOMPLETED となることを確認する。FAILED の場合は IAM ロールのポリシー不足(AWSBackupServiceRolePolicyForBackup 未 attach)または KMS key policy の misconfiguration が主因。EXPIREDcompletion_window 内に完了しなかった場合に発生する。

4. バックアップ計画: スナップショット vs Continuous Backup・RPO 逆算・リテンション設計

4-1. Snapshot vs Continuous Backup

AWS Backup の Aurora 向けバックアップには 2 種類ある(2026年4月時点)。

方式仕組みRPO保持期間追加費用
SnapshotDB クラスタのスナップショットを cron スケジュールで定期取得スケジュール間隔(例: daily → 最大 24h)1–365 日スナップショットストレージのみ ($0.095/GB/月)
Continuous BackupWAL ストリームを継続的に保管し秒単位での PITR を提供数秒〜5 分(連続ストリーム)1–35 日Snapshot + WAL 保管分の追加課金

Aurora ネイティブの PITR(最大 35 日保持)は Snapshot と同じ cron ではなく連続ストリームで動作する。AWS Backup の Continuous Backup は Aurora PITR と同等機能をバックアップ計画(Terraform 管理)に統合できる点が差別化ポイントとなる。両機能を同時有効化すると WAL 保管が二重になりコストが増加するため、どちらを使うかを明示的に選択すること。

Snapshot と Continuous Backup の使い分け

  • Snapshot のみ — RPO=1h 以上で許容でき、コスト最小化を優先する場合。audit 目的の長期保管(365 日)も Snapshot が向く。
  • Continuous Backup (PITR) — RPO=数分が必要な金融・EC 系ワークロード。直近 35 日以内の任意時点に復元でき、ヒューマンエラー(誤 DELETE 等)への対応でも有効。
  • 両方併用 — Continuous で直近 35 日をカバーし、Snapshot で長期保管(365 日以上)を担う構成。二重課金に注意。
  • 本演習シナリオ(RPO=1h): daily Snapshot + Continuous Backup の併用で実装する。

4-2. RPO 逆算表

RPO 要件からバックアップ方式を逆算する。

RPO 要件推奨方式Terraform 実装備考
24 時間daily Snapshotschedule = "cron(0 18 * * ? *)"コスト最小
1 時間hourly SnapshotAWS Backup cron では最小 1h 間隔可代替: Lambda + start-backup-job で任意間隔
5 分Continuous Backup (PITR)enable_continuous_backup = trueWAL 保管料金追加
数秒Aurora Global DB (別記事)本記事スコープ外・次回予告参照Multi-Region レプリカ必要

演習シナリオ(RPO=1h)の実装方針: AWS Backup の Backup Plan では cron(0 * * * ? *) で 1 時間毎の Snapshot を設定できる(2026年4月時点・最小間隔は 1 時間)。さらに Continuous Backup を有効化することで最終 Snapshot から次 Snapshot までの間も WAL で保護する。Lambda + aws backup start-backup-job を使う代替構成は §4-4 の enable_continuous_backup で不要となる。

Lambda 代替構成(参考): AWS Backup の cron 最小間隔が要件を満たさない場合(例: 30 分 RPO)は EventBridge Scheduler + Lambda から aws backup start-backup-job を呼び出す構成で対応できる。ただし Lambda 起動レイテンシとバックアップジョブのキューイング遅延(最大数分)が加算されるため、RPO 設計時は余裕を持たせること。

4-3. リテンション階層設計

監査要件(7 年保持)まで対応できるよう locals.backup_rules を 4 階層で設計する。

locals {  backup_rules = { daily = {schedule  = "cron(0 18 * * ? *)"# UTC 18:00 = JST 03:00retention_days  = 7cold_after_days = null } weekly = {schedule  = "cron(0 18 ? * SUN *)" # 毎週日曜 JST 03:00retention_days  = 30cold_after_days = null } monthly = {schedule  = "cron(0 18 1 * ? *)"# 毎月 1 日 JST 03:00retention_days  = 365cold_after_days = 90  # 90 日後に cold storage 移行 (~80% 料金削減) } yearly = {schedule  = "cron(0 18 1 1 ? *)"# 毎年 1/1 JST 03:00retention_days  = 2555  # 7 年 (監査要件)cold_after_days = 90 }  }}

cold storage 移行(90 日後)は monthly / yearly のみ適用する。cold storage に移行した recovery point は delete_after 日まで保持されるが、復元前に warm storage への移行が必要(数分〜数十分) という制約がある。RPO 要件が厳しいバックアップルールには cold_storage_after = null を維持すること。

リテンション階層: 3-2-1 rule 準拠

  • 3 コピー — daily (vault 内) + cross-region copy (§3-5) + optional cross-account copy = 最低 3 箇所に保管。
  • 2 種類のメディア — AWS Backup (S3 ベース warm) + cold storage (Glacier 相当) の 2 層。
  • 1 つはオフサイト — cross-region copy (ap-northeast-3) または cross-account copy で地理的分離を実現。
  • yearly=2555 日(7 年)は金融・医療・公共機関の監査要件に対応。cold storage への 90 日移行でコストを抑制できる(2026年4月時点、公式 Backup Pricing で最新料金を確認)。

4-4. Continuous Backup 有効化

rule ブロックに enable_continuous_backup = true を追加するだけで有効化できる。

resource "aws_backup_plan" "aurora_dr_continuous" {  name = "aurora-dr-plan-continuous-${var.environment}"  rule { rule_name = "daily-continuous" target_vault_name  = aws_backup_vault.main.name schedule  = "cron(0 18 * * ? *)" enable_continuous_backup = true  # PITR 有効化 lifecycle {delete_after = 35  # Continuous Backup 最大 35 日 (2026年4月時点) }  }  tags = local.common_tags}

料金目安(2026年4月時点・ap-northeast-1):

項目単価100GB クラスタの月額概算
Snapshot ストレージ$0.095/GB/月$9.50
Continuous Backup (WAL 保管)$0.200/GB/月$20.00

必ず AWS Pricing Calculator で実際のクラスタサイズ・保持日数を入力して概算を確認すること。 Aurora のストレージは使用量ベースで変動するため上記は参考値。

4-5. バックアップ取得テスト

スケジュール前に即時取得でバックアップ・復元パスを検証する。

# 即時バックアップ取得CLUSTER_ARN=$(aws rds describe-db-clusters \  --db-cluster-identifier aurora-dr-cluster \  --query 'DBClusters[0].DBClusterArn' --output text)JOB_ID=$(aws backup start-backup-job \  --backup-vault-name aurora-dr-vault-dr-lab \  --resource-arn "${CLUSTER_ARN}" \  --iam-role-arn "arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/aurora-dr-backup-role-dr-lab" \  --start-window-minutes 60 \  --lifecycle DeleteAfterDays=1 \  --query 'BackupJobId' --output text)echo "Backup Job ID: ${JOB_ID}"# ジョブ完了待ち (COMPLETED になるまでポーリング)while true; do  STATUS=$(aws backup describe-backup-job --backup-job-id "${JOB_ID}" \ --query 'State' --output text)  echo "$(date): ${STATUS}"  [ "${STATUS}" = "COMPLETED" ] && break  [ "${STATUS}" = "FAILED" ] && { echo "BACKUP FAILED"; exit 1; }  sleep 30done# recovery point 一覧で成果物確認aws backup list-recovery-points-by-backup-vault \  --backup-vault-name aurora-dr-vault-dr-lab \  --query 'RecoveryPoints[?ResourceType==`Aurora`].{ARN:RecoveryPointArn,Status:Status,Created:CreationDate}' \  --output table

CloudWatch Events で成功・失敗通知を受け取るには aws.backup ソースの EventBridge ルールを設定し、SNS トピックへ連携する。

# EventBridge ルール: バックアップジョブ成功/失敗を SNS へ通知aws events put-rule \  --name "aurora-dr-backup-notify" \  --event-pattern '{"source":["aws.backup"],"detail-type":["Backup Job State Change"],"detail":{"state":["COMPLETED","FAILED"]}}' \  --state ENABLEDaws events put-targets \  --rule "aurora-dr-backup-notify" \  --targets "Id=sns,Arn=arn:aws:sns:ap-northeast-1:$(aws sts get-caller-identity --query Account --output text):aurora-dr-alerts"

バックアップジョブ完了の通知なしに §6 の復元ハンズオンへ進むと recovery point が存在しない状態で復元ジョブが失敗するため、必ずこのテストで COMPLETED を確認してから次章へ進むこと。

5. 障害シナリオ発動: FIS 疑似障害 + CloudWatch/Performance Insights 監視

2026 年 4 月時点情報: FIS action ID・aws_fis_experiment_template 仕様は hashicorp/aws ~> 5.70 準拠。API 仕様は公式ドキュメントを一次ソースとして確認すること。

5-1. FIS 概論 + 演習アカウント分離

AWS FIS (Fault Injection Service) は 2020 年 GA の疑似障害注入サービス。Aurora 向け aws:rds:* アクションは 2024 年 Q4 に 3 種追加され、2025 年 Q2 に action ID の一部が改名された。

時期変更内容
2024 Q4 GAaws:rds:reboot-db-instances / aws:rds:stop-db-cluster / aws:rds:force-failover-db-cluster 追加
2025 Q2 改名aws:rds:failover-db-clusteraws:rds:force-failover-db-cluster (後方互換なし)

古い action ID は aws fis list-actions --filters key=id,values=aws:rds に表示されなくなる。既存テンプレートは force-failover-db-cluster への更新が必須。

演習用アカウント分離が絶対前提: FIS は Aurora クラスタを実際に停止・再起動する破壊的操作を実行する。タグ指定のミス一つで本番クラスタが停止するため、必ず演習用アカウントを分離するか、最低でも ChaosEngineering=enabled タグ限定で実行すること。 IAM ポリシーでタグ条件を強制する例:

{  "Effect": "Allow",  "Action": ["fis:StartExperiment"],  "Resource": "*",  "Condition": { "StringEquals": { "aws:ResourceTag/ChaosEngineering": "enabled" }  }}
FIS 本番誤爆防止の 3 原則

  • 演習用アカウント分離を強く推奨: 本番アカウントでの FIS 実行は厳禁。専用 DR ラボアカウントを用意すること。
  • タグ絞り込み必須: FIS target に ChaosEngineering=enabled タグ条件を必ず設定。IAM Condition block でタグなしリソースへの適用を禁止すること。
  • IAM 最小権限 + SCP 二重防護: FIS 実行 IAM role に aws:ResourceTag/ChaosEngineering: enabled Condition を付与。Organizations SCP で本番 OU からの FIS StartExperiment API を Deny して二重防護とする。

5-2. FIS Experiment Template (reboot) — v2 形式

aws_fis_experiment_template は 2024 Q4 に action ブロック内の target 参照方式が v2 形式に変更された (hashicorp/aws ~> 5.70 で安定)。以下は v2 形式の reboot テンプレート:

resource "aws_fis_experiment_template" "reboot" {  description = "Aurora DB instance reboot experiment (DR 演習用・2026-04)"  role_arn = aws_iam_role.fis.arn  stop_condition { source = "none"  }  target { name  = "aurora-instances" resource_type  = "aws:rds:db" selection_mode = "ALL" resource_tag {key= "ChaosEngineering"value = "enabled" }  }  action { name= "reboot-aurora-instances" action_id = "aws:rds:reboot-db-instances" target {key= "DBInstances"value = "aurora-instances" } parameter {key= "duration"value = "PT5M" }  }  tags = { ChaosEngineering = "enabled" ManagedBy  = "Terraform"  }}

stop_condition.source = "none" は duration 到達まで継続する設定。本番に近い環境では source = "aws:cloudwatch:alarm" で CloudWatch Alarm をトリップ条件に追加することを推奨する。

5-3. FIS Stop + Failover シナリオ — 3 種 for_each 展開

local.fis_experiments map で reboot / stop / force-failover の 3 テンプレートを一括展開する。

locals {  fis_experiments = { reboot= { action_id = "aws:rds:reboot-db-instances", resource_type = "aws:rds:db",target_key = "DBInstances", duration = "PT5M"  } stop  = { action_id = "aws:rds:stop-db-cluster",  resource_type = "aws:rds:cluster", target_key = "Clusters", duration = "PT10M" } force_failover = { action_id = "aws:rds:force-failover-db-cluster", resource_type = "aws:rds:cluster", target_key = "Clusters", duration = "PT5M"  }  }}resource "aws_fis_experiment_template" "aurora" {  for_each = local.fis_experiments  description = "FIS ${each.key} experiment (DR 演習用・2026-04)"  role_arn = aws_iam_role.fis.arn  stop_condition { source = "none" }  target { name  = "aurora-target" resource_type  = each.value.resource_type selection_mode = "ALL" resource_tag {key= "ChaosEngineering"value = "enabled" }  }  action { name= "fis-action-${each.key}" action_id = each.value.action_id target {key= each.value.target_keyvalue = "aurora-target" } parameter {key= "duration"value = each.value.duration }  }  tags = merge(local.common_tags, { ChaosEngineering = "enabled" })}

force-failover の動作特性 (2026-04 時点): writer ノードを強制降格し任意の reader を writer に昇格させる。フェイルオーバー完了時間の目安は典型 20-30 秒。stop-db-cluster との違い: stop は完全停止 (復旧に start-db-cluster が必要) / force-failover はフェイルオーバーのみで稼働継続。

5-4. CloudWatch Metrics 監視

障害発動後の検知は CloudWatch Alarm で自動化する。Aurora 主要 4 メトリクスに Alarm を設定し SNS トピックへ通知する。

locals {  aurora_alarms = { db_connections  = { metric = "DatabaseConnections", threshold = 100  } cpu_utilization = { metric = "CPUUtilization",threshold = 80} read_iops = { metric = "ReadIOPS",threshold = 5000 } write_iops= { metric = "WriteIOPS",  threshold = 2000 }  }}resource "aws_cloudwatch_metric_alarm" "aurora" {  for_each = local.aurora_alarms  alarm_name = "aurora-dr-${each.key}"  comparison_operator = "GreaterThanOrEqualToThreshold"  evaluation_periods  = 2  metric_name= each.value.metric  namespace  = "AWS/RDS"  period  = 60  statistic  = "Average"  threshold  = each.value.threshold  alarm_actions = [aws_sns_topic.aurora_alerts.arn]  dimensions = { DBClusterIdentifier = "aurora-dr-cluster" }}

FIS疑似障害→検知→復元判断フロー start-experiment/reboot/stop/failover CloudWatch SNS Performance Insights

5-5. Performance Insights

Performance Insights を有効にすることで、障害発生中の待機イベント・上位 SQL をリアルタイム可視化できる。

resource "aws_rds_cluster_instance" "writer" {  identifier= "aurora-dr-writer"  cluster_identifier = aws_rds_cluster.main.id  instance_class  = "db.r6g.large"  engine = aws_rds_cluster.main.engine  engine_version  = aws_rds_cluster.main.engine_version  performance_insights_enabled = true  performance_insights_retention_period = 7  # 無料枠: 7 日 / 長期: 731 日 (有料)  monitoring_interval = 60  monitoring_role_arn = aws_iam_role.rds_monitoring.arn}

FIS 演習中の確認手順: コンソール → RDS → 対象クラスタ → Performance Insights で「DB load」グラフを開き FIS 実験開始時刻前後の山を確認する。「上位 SQL」タブで遅延 SQL を特定し、「待機イベント」で I/O ボトルネック / CPU ボトルネックを切り分ける。フェイルオーバー完了後に DB load が正常レベルに戻ることを確認したら §6 復元ハンズオンへ進む。

5-6. 演習実行フロー

# 1. FIS experiment template ID を取得aws fis list-experiment-templates \  --query "experimentTemplates[?tags.ChaosEngineering=='enabled'].{id:id,desc:description}" \  --output table# 2. force-failover 演習を開始TEMPLATE_ID=$(aws fis list-experiment-templates \  --query "experimentTemplates[?contains(description,'failover')].id | [0]" \  --output text)EXPERIMENT_ID=$(aws fis start-experiment \  --experiment-template-id "$TEMPLATE_ID" \  --tags Purpose=DR-drill,Date="$(date +%Y%m%d)" \  --query "experiment.id" --output text)# 3. ステータス監視 (completed / stopped になるまで待つ)aws fis get-experiment --id "$EXPERIMENT_ID" \  --query "experiment.{state:state.status,startTime:startTime}"# 4. フェイルオーバー完了後に writer を確認して §6 へaws rds describe-db-clusters \  --db-cluster-identifier aurora-dr-cluster \  --query "DBClusters[0].DBClusterMembers[?IsClusterWriter==\`true\`].DBInstanceIdentifier"

演習ステータスが completed または stopped になってから §6 復元ハンズオンへ進む。stop-db-cluster を実施した場合は aws rds start-db-cluster --db-cluster-identifier <id> で再起動してから進むこと。

演習チェックリスト: 実施前に確認すべき 5 項目

  • 演習用アカウント or タグ分離: 本番リソースへの ChaosEngineering=enabled タグ誤付与がないか最終確認
  • CloudWatch Alarm 通知先: SNS サブスクリプションが有効で通知受信を確認済みか
  • Performance Insights 有効化: 全インスタンスで performance_insights_enabled=true を確認
  • FIS IAM ロール権限: FIS trust relationship + 必要な RDS 権限が設定済みか確認
  • 演習時間帯と関係者周知: ピークタイムを避け、stop-db-cluster は最低 10 分の停止が発生することを事前周知すること

6. 復元ハンズオン: 別クラスタ新規作成 + restore/ stack

6-1. 論点A: 別クラスタ復元を採用する理由

本記事では Recovery Point からの復元先を 既存クラスタへの上書きではなく、別クラスタの新規作成 に統一している。
その理由を最初に明示しておく。

同一クラスタ上書き復元の問題点

AWS Backup が既存 Aurora クラスタへの上書き復元を実行すると、復元処理が完了するまでの間、
対象クラスタの Writer インスタンスが長時間 (modifying または restoring) 状態となる。
1 TB クラスタでは 30〜60 分以上の接続不能時間が発生し得る (2026-04 時点 AWS doc より)。
本番系では「復元の動作確認をしたいだけで本番データベースを停止させる」事態になるため、
同一クラスタ上書き方式は採用しない。

別クラスタ新規作成の優位性

比較項目同一クラスタ上書き別クラスタ新規作成 (本記事採用)
既存クラスタへの影響復元中は接続不能影響なし・本番系は稼働継続
切替方法自動 (復元完了 = 切替完了)Route 53 alias 変更 (§7 で説明)
復元後の並行確認不可可能 (新旧クラスタを同時に参照)
DR 演習の再現性再演習は既存クラスタを再度停止Restore 繰り返し可能
別クラスタ復元が本番系で絶対安全な理由

  • 既存 Writer インスタンスをそのまま稼働させたまま復元を並行実行できる
  • 復元先の動作確認が完了するまで Route 53 の向き先を変えない運用が可能
  • 問題が検出された場合は Route 53 を戻すだけでロールバック完了 — 既存クラスタは無傷
  • DR 演習を繰り返しても本番クラスタに副作用が生じない

6-2. AWS Backup コンソール操作: Recovery Point から新規クラスタを作成する

前提: §3 で作成した Vault に Aurora クラスタの Recovery Point が 1 件以上存在すること。

手順

  1. AWS マネジメントコンソール → AWS Backup → 左メニュー Backup vaults を開く
  2. aurora-dr-vault をクリック → Recovery points タブで対象のバックアップを選択
  3. Actions → Restore をクリック
  4. Restore typeNew DB cluster を選択 (既存クラスタ選択 = 同一上書きのため 選択しない)
  5. DB cluster identifier-restored 接尾辞付きの識別子を入力
  6. 例: aurora-prod-cluster-restored
  7. VPC は prod と同一の VPC を選択
  8. DB subnet group は prod と同一のサブネットグループを選択
  9. 新規 SG を作成する場合: 復元クラスタ専用の aurora-restored-sg を用意し、アプリ側 SG からのみ 3306/5432 を許可
  10. 既存 SG を流用する場合: prod と同じ SG でも接続検証は可能だが、切替後は SG を分離推奨
  11. DB cluster parameter group は prod と同じグループを指定
  12. Restore backup をクリック → バックグラウンドで restore-testing-job が開始

進捗確認: AWS Backup コンソール → Jobs → Restore jobs でステータスを確認。
COMPLETED になると RDS コンソールにクラスタが出現する。

6-3. CLI 復元代替手順: aws backup start-restore-job

コンソール操作の代替として CLI での復元手順を示す。
CI/CD パイプラインや自動 DR テストに組み込む場合はこちらを使用する。

まず復元に必要なメタデータを JSON ファイルに記述する。

{  "VpcId": "vpc-0a1b2c3d4e5f67890",  "DBSubnetGroupName": "aurora-prod-subnet-group",  "VpcSecurityGroupIds": "sg-0a1b2c3d4e5f67890",  "DBClusterIdentifier": "aurora-prod-cluster-restored",  "Engine": "aurora-mysql",  "EngineVersion": "8.0.mysql_aurora.3.05.2",  "DBClusterParameterGroupName": "aurora-mysql8-param-group",  "Port": "3306",  "KmsKeyId": "arn:aws:kms:ap-northeast-1:123456789012:key/mrk-xxxxxxxx"}
# Recovery Point の ARN を取得VAULT_NAME="aurora-dr-vault"RECOVERY_POINT_ARN=$(aws backup list-recovery-points-by-backup-vault \  --backup-vault-name "$VAULT_NAME" \  --query 'RecoveryPoints[0].RecoveryPointArn' \  --output text)# 復元ジョブを開始RESTORE_JOB_ID=$(aws backup start-restore-job \  --recovery-point-arn "$RECOVERY_POINT_ARN" \  --iam-role-arn "arn:aws:iam::123456789012:role/AWSBackupRestoreRole" \  --resource-type "Aurora" \  --metadata file://metadata.json \  --query 'RestoreJobId' \  --output text)echo "Restore Job ID: $RESTORE_JOB_ID"# 完了まで待機 (1 TB クラスタで 30-60 分が目安 — 2026-04 時点)while true; do  STATUS=$(aws backup describe-restore-job \ --restore-job-id "$RESTORE_JOB_ID" \ --query 'Status' --output text)  echo "$(date): $STATUS"  [ "$STATUS" = "COMPLETED" ] && break  [ "$STATUS" = "FAILED" ] && { echo "Restore failed"; exit 1; }  sleep 60done

復元フロー時系列図 RecoveryPoint→RestoreJob→新クラスタ→TerraformImport→Endpoint取得 RTO90分

6-4. 論点B: restore/ stack を別 Terraform stack で管理する

既存 prod/ stack に触れない ことが論点 B の核心。
復元クラスタは専用の restore/ ディレクトリを新規作成し、state を完全に分離して管理する。

ディレクトリ構成は terraform/prod/ (既存・変更禁止) と terraform/restore/ (新規作成) の二段構え。

# restore/backend.tfterraform {  required_version = ">= 1.9.0"  required_providers { aws = {source  = "hashicorp/aws"version = "~> 5.70" }  }  backend "s3" { bucket = "my-tfstate-bucket" key = "state/restore/terraform.tfstate"# prod/ とは別 key region = "ap-northeast-1"  }}
# restore/main.tfdata "terraform_remote_state" "prod" {  backend = "s3"  config = { bucket = "my-tfstate-bucket" key = "state/prod/terraform.tfstate" region = "ap-northeast-1"  }}locals {  vpc_id  = data.terraform_remote_state.prod.outputs.vpc_id  subnet_ids = data.terraform_remote_state.prod.outputs.subnet_ids  sg_id= data.terraform_remote_state.prod.outputs.sg_id}resource "aws_db_subnet_group" "restored" {  name = "aurora-restored-subnet-group"  subnet_ids = local.subnet_ids}resource "aws_rds_cluster" "restored" {  cluster_identifier= "aurora-cluster-restored"  engine= "aurora-mysql"  engine_version = "8.0.mysql_aurora.3.05.2"  db_subnet_group_name = aws_db_subnet_group.restored.name  vpc_security_group_ids  = [local.sg_id]  skip_final_snapshot  = true  lifecycle { prevent_destroy = false# restore stack は演習後に destroy 可  }}

6-5. Terraform import: 復元済みクラスタを restore/ state に取り込む

AWS Backup がコンソール/CLI 経由で作成した復元クラスタは Terraform 管理外の状態にある。
terraform importrestore/ state に取り込み、以降の変更を Terraform で管理できるようにする。

cd terraform/restore# 初期化terraform init# import 前に plan でドリフトを事前確認terraform plan# クラスタを restore/ state に importterraform import aws_rds_cluster.restored aurora-cluster-restored# import 後の state 検証 (import_state_verify 相当)terraform plan -out=restore.tfplan# plan で差分なし ("No changes") を確認してから applyterraform apply restore.tfplan

import 後の差分吸収パターン

terraform plan で差分が検出された場合は locals で既存設定を吸収する。

# restore/main.tf — 差分吸収パターン例locals {  existing_parameter_group = "aurora-mysql8-param-group"}resource "aws_rds_cluster" "restored" {  # ... 省略 ...  db_cluster_parameter_group_name = local.existing_parameter_group}

注意 (2026-04 時点): terraform import 実行後に apply しても state が破壊されないことを
terraform plan の出力 (No changes) で必ず確認してから次の工程に進むこと。
import_state_verify が失敗するケースは engine_version のマイナーバージョン不一致が多い。

Terraform import の落とし穴: state drift の予兆

  • engine_version ズレ: AWS Backup は復元時に minor patch を自動適用することがある。import 後に engine_version 差分が出たら HCL 側を AWS 実態に合わせる
  • parameter group 差分: AWS が default parameter group に自動変換するケースあり。aws_rds_clusterdb_cluster_parameter_group_name を明示指定して解消
  • subnet group 名の衝突: import 前に aws rds describe-db-clusters で実際の subnet group 名を確認し、HCL と一致させること
  • apply 前に必ず plan を確認: import 後に No changes が出ない場合は apply せず差分を調査する

6-6. 復元後の検証コマンド

復元クラスタが利用可能になったことを確認し、§7 のアプリ切替準備を整える。

# ステータスと Writer/Reader エンドポイントを一括取得aws rds describe-db-clusters \  --db-cluster-identifier aurora-cluster-restored \  --query 'DBClusters[0].{Status:Status,Writer:Endpoint,Reader:ReaderEndpoint}' \  --output table

Status: available の確認後、取得した WRITER_ENDPOINT を §7 の Route 53 alias 切替手順に渡す。
切替前にアプリ側から復元クラスタへの接続テストを実施し、データ整合性を確認してから切替を実行すること。

7. データ整合性検証 + アプリ切替: 行数/チェックサム → Route 53/Secrets Manager → 旧クラスタ隔離

§6 で復元クラスタが available になったら、データ整合性を確認してから本番トラフィックを切り替える。検証 → 段階切替 → 旧クラスタ隔離 の順序を守ること。

焦って切り替えると、RPO=1h 外の欠損データが原因で本番障害が再発するリスクがある。このセクションでは切替後の問題発覚に備えた rollback 手順も含めて、DR 演習の後半フローを網羅する。

7-1. データ整合性検証 3 手法

手法 (a): 行数比較 — prod/復元クラスタ双方で実行し差分を比較する

\c myappSELECT schemaname, relname, n_live_tup AS row_countFROM pg_stat_user_tablesORDER BY n_live_tup DESC;

手法 (b): スキーマ diff — DDL 変更を伴う障害シナリオで必須

pg_dump --schema-only --no-owner --no-privileges \  -h ${PROD_ENDPOINT} -U ${DB_USER} myapp > /tmp/prod_schema.sqlpg_dump --schema-only --no-owner --no-privileges \  -h ${RESTORE_ENDPOINT} -U ${DB_USER} myapp > /tmp/restore_schema.sqldiff /tmp/prod_schema.sql /tmp/restore_schema.sql

手法 (c): 最新トランザクション時刻確認 — RPO=1h (3600 秒) 以内なら正常

-- 復元クラスタで実行 (PostgreSQL 14+・Aurora PostgreSQL 14 以上前提)SELECT  pg_last_committed_xact()AS last_committed_xact,  now() AS current_time,  now() - (pg_last_committed_xact()).timestamp AS lag_from_now;

許容 diff: RPO=1h なら lag_from_now < 3600s が合格基準。超えていたら切替中断を検討。

データ整合性検証 3 手法の優先順位

  • (c) 最新トランザクション時刻 を最初に確認 — RPO 超過を最速で検出
  • (a) 行数比較 を次に実施 — テーブル単位の欠損を特定
  • (b) スキーマ diff は DDL 変更シナリオのみ必須 (DML のみなら省略可)
  • 3 手法すべて合格して初めて Route 53 切替に進む
  • 2026 年 4 月時点: pg_last_committed_xact() は PostgreSQL 14+ で利用可

7-2. Route 53 切替戦略

アプリ切替+旧クラスタ隔離フロー Route53 weighted 10/50/100% SecretsManager更新 SG遮断

alias record TTL=60 秒を推奨 (Route 53 alias は TTL=0 指定不可・60 秒が AWS 推奨、2026 年 4 月時点)。演習では weighted routing で 10% → 50% → 100% と段階移行する。各ステップで §7-1 を再確認する。

# restore/route53.tf (hashicorp/aws ~> 5.70・2026-04 時点)resource "aws_route53_record" "aurora_restored" {  zone_id = var.hosted_zone_id  name = "aurora.${var.domain_name}"  type = "CNAME"  weighted_routing_policy { weight = 10 }  # 初期 10%・段階的に 50→100 へ  set_identifier = "aurora-restored"  ttl= 60  records  = [aws_rds_cluster.restored.reader_endpoint]}resource "aws_route53_record" "aurora_prod" {  zone_id = var.hosted_zone_id  name = "aurora.${var.domain_name}"  type = "CNAME"  weighted_routing_policy { weight = 90 }  # 初期 90%・移行完了後は 0  set_identifier = "aurora-prod"  ttl= 60  records  = [data.terraform_remote_state.prod.outputs.aurora_reader_endpoint]}

7-3. Secrets Manager ローテーション

# restore/secrets.tfresource "aws_secretsmanager_secret_version" "aurora_restore_creds" {  secret_id = aws_secretsmanager_secret.aurora_restore.id  secret_string = jsonencode({ username = var.db_user password = var.db_password host  = aws_rds_cluster.restored.endpoint port  = 5432 dbname= var.db_name  })}

既存 secret を CLI で更新する場合 (Terraform 管理外の secret に対応):

aws secretsmanager put-secret-value \  --secret-id "aurora/prod/credentials" \  --secret-string "{\"username\":\"${DB_USER}\",\"password\":\"${DB_PASS}\", \"host\":\"${RESTORE_ENDPOINT}\",\"port\":\"5432\",\"dbname\":\"myapp\"}"# 更新確認aws secretsmanager describe-secret \  --secret-id "aurora/prod/credentials" --query 'LastChangedDate'

アプリが SDK で GetSecretValue を呼ぶ場合、更新後の値は次回 API 呼び出し時 (+ アプリ側キャッシュ TTL) で反映される。

自動化オプション: rotation lambda

AWS Secrets Manager の rotation lambda を設定済みの場合は手動 put-secret-value が不要になる。aws secretsmanager rotate-secret を実行すると rotation lambda が新エンドポイントで接続検証 → 成功したら AWSCURRENT バージョンを切り替える。ただし復元 → rotation 完了まで AWSPENDING / AWSCURRENT が混在する 両価期間 (typically 数十秒〜数分) が発生するため、アプリが両バージョンを許容する実装か確認すること。

7-4. 旧クラスタ隔離パターン

100% 移行後も prod クラスタをすぐに削除してはいけない。rollback (§7-5) に備えて 7 日以上の隔離観察期間を設ける。

3 つの手順を組み合わせて「接続は遮断しつつクラスタ自体は残す」状態を作る。

(a) SG inbound を削除 (完全遮断)

PROD_SG_ID=$(aws rds describe-db-clusters \  --db-cluster-identifier aurora-prod \  --query 'DBClusters[0].VpcSecurityGroups[0].VpcSecurityGroupId' \  --output text)# 現在の inbound ルールを JSON で保存してから削除aws ec2 describe-security-groups --group-ids ${PROD_SG_ID} \  --query 'SecurityGroups[0].IpPermissions' > /tmp/prod_sg_inbound.jsonaws ec2 revoke-security-group-ingress \  --group-id ${PROD_SG_ID} --ip-permissions file:///tmp/prod_sg_inbound.json

(b) tag Status=isolated-YYYYMMDD 付与 + (c) CloudWatch Alarm 一時無効化

ISOLATION_DATE=$(date +%Y%m%d)aws rds add-tags-to-resource \  --resource-name "arn:aws:rds:ap-northeast-1:${ACCOUNT_ID}:cluster:aurora-prod" \  --tags "[{\"Key\":\"Status\",\"Value\":\"isolated-${ISOLATION_DATE}\"}]"aws cloudwatch disable-alarm-actions \  --alarm-names "aurora-prod-cpu-high" "aurora-prod-connections-high"
旧クラスタ隔離: 7 日観察ルールの根拠

  • 隠れた問題は切替後 1〜2 日で表面化する — バッチ処理・週次集計が動いて初めて発覚する不整合がある
  • Secrets Manager rotation 間隔 (最短 1 日) — rotation 後に接続エラーが判明するケースへの備え
  • 7 日 = 1 週間サイクル完走 — 週次バッチ正常完了を確認してから旧クラスタを削除するのが最安全
  • コスト: 7 日の二重課金は +$90-120 (§8-2 参照)。RTO 超過時の業務損失より安い保険
  • 2026 年 4 月時点: Aurora クラスタ削除後は復元不可。7 日観察を経てから destroy すること

7-5. 切戻し (rollback) 手順

復元クラスタで問題が発覚した場合、prod クラスタが隔離期間中であれば以下の順で戻せる。

  1. Route 53 weight: restored=0 / prod=100 に変更 → terraform apply
  2. Secrets Manager を prod エンドポイントに書き戻す (aws secretsmanager put-secret-value)
  3. prod SG inbound を復旧 (aws ec2 authorize-security-group-ingress --ip-permissions file:///tmp/prod_sg_inbound.json)
  4. CloudWatch Alarm を再有効化 (aws cloudwatch enable-alarm-actions)
  5. 復元クラスタを隔離 → 問題原因特定後に terraform destroy (restore stack)

完了目安: TTL=60 秒 + アプリ再接続で 2〜5 分以内。rollback 実施後は §7-6 チェックリストを再度実行し prod クラスタへのトラフィック復帰を確認する。原因分析が完了したら、翌日以降に改めて復元クラスタで段階切替を再試行することが可能。

7-6. 切替完了チェックリスト

チェック項目確認方法合格基準
アプリ接続数CloudWatch DatabaseConnections復元クラスタで通常時と同等
HTTP エラーレートALB アクセスログ / CloudWatch5xx < 0.1%
レイテンシCloudWatch TargetResponseTimep99 が通常時の 2 倍以内
バッチ処理完了ジョブスケジューラのログ直近ジョブが正常終了
Secrets Manager 更新aws secretsmanager describe-secretLastChangedDate が切替後の日時
ビジネスメトリクスアプリ固有ダッシュボード前日比で正常範囲
旧クラスタ隔離完了タグ確認 + SG 確認Status=isolated-YYYYMMDD / inbound 削除済

8. まとめ・運用注意点・次回予告

8-1. 到達点サマリ

§1〜§7 を通じて以下が実現できる状態になった。

  1. RPO/RTO 設計 — 自組織の許容時間から RPO=1h / RTO=4h のシナリオを定義し、AWS Backup 取得頻度を逆算できる
  2. Terraform state 疎結合設計 (論点 B) — prod/ / backup/ / restore/ の 3 stack を分離し、本番 state を一切汚さずに DR 演習インフラを管理できる
  3. AWS Backup Vault 設計 — KMS CMK・Vault Lock・Backup Plan (daily/weekly/monthly)・cross-region copy を Terraform でコード化できる
  4. Continuous Backup (PITR) 統合 — WAL レベルの秒単位復元と AWS Backup 計画の組み合わせ方を理解できる
  5. FIS 疑似障害発動 (論点 C) — aws_fis_experiment_template で reboot / stop / force-failover の 3 シナリオを実行し、CloudWatch / Performance Insights で障害検知できる
  6. 別クラスタ復元 (論点 A) — AWS Backup Recovery Point から新クラスタを作成し、terraform import で restore stack に取り込める
  7. データ整合性検証 — 行数比較・スキーマ diff・最新トランザクション時刻の 3 手法でデータ欠損を定量評価できる
  8. 段階的アプリ切替 — Route 53 weighted routing + Secrets Manager 更新で 10%→50%→100% の安全な切替と 7 日隔離による rollback 保険を実装できる

8-2. 運用注意点 3 大論点

論点 1 — 二重課金期間 (論点 A 派生)

別クラスタ新規作成中は、prod クラスタと復元クラスタの 2 クラスタ分の料金が同時発生する。切替完了まで典型 2〜4 時間・7 日隔離観察期間も含めると最大 7 日分の追加コストが発生する。演習前にコスト予算へ明示的に含めること。

フェーズ追加コスト目安期間
復元ジョブ実行復元クラスタ起動分 (db.r6g.large × 2)30〜60 分
切替完了まで新旧 2 クラスタ同時稼働典型 2〜4 時間
7 日隔離観察prod クラスタ維持 + 旧クラスタ維持最長 7 日
合計概算+$90〜120 (USD)2026 年 4 月・ap-northeast-1 参考値

論点 2 — Vault Lock compliance mode 誤設定

aws_backup_vault_lock_configuration の compliance mode は 設定後 MinRetentionDays 経過まで削除不可・解除不可。MaxRetentionDays を過大設定すると数年分のストレージ課金が意図せず発生する。初回は governance mode + changeable_for_days = 3 で動作確認後に compliance mode へ移行すること。

論点 3 — FIS 誤爆 (演習用アカウント/タグ分離)

FIS は 本番 Aurora クラスタに直接適用されると即座に障害が発生する。演習用アカウント分離が理想。最低でも ChaosEngineering=enabled タグで対象を絞り込んだ IAM policy condition を設定すること (§5-1 参照)。

8-3. 次回予告: Aurora Global DB (論点 D)

本記事では意図的にスコープ外とした Aurora Global DB は次回記事で扱う。

項目本記事 (AWS Backup DR)次回 (Aurora Global DB)
DR 方式Backup からの別クラスタ復元Secondary region への継続レプリケーション
RPO〜1h (バックアップ頻度依存)〜1 秒 (WAL ストリーム連続転送)
RTO30〜60 分 (復元ジョブ)〜1 分 (region failover promotion)
コスト増+$40〜120 (演習期間のみ)+$200〜400/月 (Secondary クラスタ常時稼働)
Terraform 複雑度中 (3 stack 分離)高 (Global Cluster + 2 Region 管理)
向く場面コスト重視 / 演習文化の醸成金融・医療等の RPO=秒以下要件

次回記事では aws_rds_global_cluster + aws_rds_cluster (secondary) の Terraform 構成と、aws rds failover-global-cluster を使った計画的フェイルオーバーの実装を扱う予定。

8-4. 既存記事との相互リンク

本記事は 有事復旧 (DR 演習) を扱ったが、平時の Aurora 運用 については別記事で解説している。

Aurora × IAM database authentication — ヒューマンログイン排除で操作ミスを防ぐ

観点aurora-no-human-login本記事
軸足平時運用 (日常の DB アクセス制御)有事復旧 (DR 演習 + 復元)
主要技術IAM database auth + Secrets ManagerAWS Backup + FIS + Terraform import
読者が得るもの人手ログイン削減 Runbook災害復旧 Runbook

2 記事を合わせ読むことで Aurora 運用ライフサイクル (構築 → 平時有事 → 復旧) が完結する。

8-5. terraform destroy 完全手順

演習終了後はリソースを確実に破棄する。削除順序を守ること — vault に recovery point が残っていると vault destroy が失敗する。

# 1. restore stack を先に destroy (復元クラスタ・Terraform import 済みリソース)cd terraform/restoreterraform destroy -auto-approve# 2. backup vault 内の recovery points を全削除VAULT_NAME="aurora-dr-vault"RECOVERY_POINT_ARNS=$(aws backup list-recovery-points-by-backup-vault \  --backup-vault-name ${VAULT_NAME} \  --query 'RecoveryPoints[].RecoveryPointArn' --output text)for ARN in ${RECOVERY_POINT_ARNS}; do  aws backup delete-recovery-point \ --backup-vault-name ${VAULT_NAME} \ --recovery-point-arn ${ARN}done# 3. FIS experiment template + backup vault + KMS 等を destroycd ../backupterraform destroy -auto-approve# 4. prod stack は destroy 対象外 (本番クラスタを維持)# cd ../prod && terraform destroy は実行しないこと

注意: prod/ stack は本番環境のため destroy 対象外。restore/ と backup/ のみ破棄する。