EFSをバックアップを別リージョンにレプリケーションする
AWSバックアップを別リージョンにレプリケーションしてみます。
概要
前回の続きです。
https://inugami-techlab.com/posts/20250603/
今回はバックアップを別リージョンにレプリケーション(今回は大阪リージョン)にしてみます。
この記事はそのメモやまとめです。
自分の環境用のメモでもあるので、省略している記載もあります。
すでに設定済みの項目がいくつかある。
試行錯誤しながらやったので、手順として不要かもしれない。あくまでメモ用。
EFS
EFSは前回と同じものを利用するので、省略します。
BackUp
他リージョンへのレプリケーション設定はplanから設定します。
requirements.tfに大阪リージョン用のProviderを記載することで、リージョンを複数利用できるようにします。
provider "aws" {
region = "ap-northeast-1"
}
provider "aws" {
alias = "osaka"
region = "ap-northeast-3"
}
大阪用のvault記載時にこのproviderを指定することで大阪リージョンにvaultを作成することができる。
resource "aws_backup_vault" "efs_backup_vault_osaka" {
provider = aws.osaka
name = "efs-backup-vault-osaka"
}
各Ruleで以下のようにcopy_actionでレプリケーション先のvaultの指定とライフサイクルを設定させます。
今回はレプリケーションではないバックアップと同じ期間でライフサイクルを設定しました。
copy_action {
destination_vault_arn = aws_backup_vault.efs_backup_vault_osaka.arn
lifecycle {
delete_after = 7
}
}
}
出来上がったEFSのコードは以下です。
レプリケーション用のIAMロールも追加しています。
# ----------------------------------------- #
# BackupVault
# ----------------------------------------- #
resource "aws_backup_vault" "efs_backup_vault" {
name = "efs-backup-vault"
}
resource "aws_backup_vault" "efs_backup_vault_osaka" {
provider = aws.osaka
name = "efs-backup-vault-osaka"
}
# ----------------------------------------- #
# BackupPlan
# ----------------------------------------- #
resource "aws_backup_plan" "efs_backup_plan" {
name = "efs-backup-plan"
rule {
rule_name = "immediate_test_backup"
target_vault_name = aws_backup_vault.efs_backup_vault.name
schedule = "cron(50 10 * * ? *)"
schedule_expression_timezone = "Asia/Tokyo"
start_window = 60
completion_window = 120
lifecycle {
delete_after = 7
}
recovery_point_tags = {
BackupType = "Test"
}
copy_action {
destination_vault_arn = aws_backup_vault.efs_backup_vault_osaka.arn
lifecycle {
delete_after = 7
}
}
}
# 通常の日次バックアップ(コールドストレージ制約を満たす設定)
rule {
rule_name = "daily_backup"
target_vault_name = aws_backup_vault.efs_backup_vault.name
schedule = "cron(0 2 * * ? *)" # 毎日午前2時
schedule_expression_timezone = "Asia/Tokyo"
lifecycle {
cold_storage_after = 30 # 30日後にコールドストレージ
delete_after = 120 # 120日で削除(90日間隔を満たす)
}
recovery_point_tags = {
BackupType = "Daily"
}
copy_action {
destination_vault_arn = aws_backup_vault.efs_backup_vault_osaka.arn
lifecycle {
cold_storage_after = 30 # 30日後にコールドストレージ
delete_after = 120 # 120日で削除(90日間隔を満たす)
}
}
}
}
# ----------------------------------------- #
# BackupSelection
# ----------------------------------------- #
resource "aws_iam_role" "backup_role" {
name = "efs-backup-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "backup.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "backup_policy" {
role = aws_iam_role.backup_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
}
resource "aws_iam_role_policy_attachment" "restore_policy" {
role = aws_iam_role.backup_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"
}
resource "aws_backup_selection" "efs_backup_selection" {
iam_role_arn = aws_iam_role.backup_role.arn
name = "efs-backup-selection"
plan_id = aws_backup_plan.efs_backup_plan.id
resources = [
aws_efs_file_system.low_cost.arn
]
condition {
string_equals {
key = "aws:ResourceTag/BackupEnabled"
value = "true"
}
}
}
# ----------------------------------------- #
# レプリケーション用のIAMロール
# ----------------------------------------- #
resource "aws_iam_role" "backup_replication_role" {
name = "efs-backup-replication-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "backup.amazonaws.com"
}
}
]
})
tags = {
Name = "EFS Backup Replication Role"
}
}
resource "aws_iam_role_policy_attachment" "backup_replication_policy" {
role = aws_iam_role.backup_replication_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
}
resource "aws_iam_role_policy_attachment" "backup_replication_restore_policy" {
role = aws_iam_role.backup_replication_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"
}
# クロスリージョンレプリケーション用の追加ポリシー
resource "aws_iam_role_policy" "backup_cross_region_policy" {
name = "backup-cross-region-policy"
role = aws_iam_role.backup_replication_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"backup:CopyIntoBackupVault",
"backup:DescribeBackupVault",
"backup:DescribeRecoveryPoint"
]
Resource = "*"
}
]
})
}
上記でapplyしてリソースを作成する。
GUIを確認するとバックアップとレプリケーションに成功していた。
CLIでも確認する
terraform/terraform_test on master [📝] via 💠 default took 2s
at 11:36:01 ⬢ [Docker] ❯ aws backup list-copy-jobs --region ap-northeast-1
{
"CopyJobs": [
{
"AccountId": "xxxx",
"CopyJobId": "E3DE69BA-8FC6-ED34-D18A-A3588A9BF60A",
"SourceBackupVaultArn": "arn:aws:backup:ap-northeast-1:xxxx:backup-vault:efs-backup-vault",
"SourceRecoveryPointArn": "arn:aws:backup:ap-northeast-1:xxxx:recovery-point:c53909a1-b8b2-4144-8ef6-25242913bee4",
"DestinationBackupVaultArn": "arn:aws:backup:ap-northeast-3:xxxx:backup-vault:efs-backup-vault-osaka",
"DestinationRecoveryPointArn": "arn:aws:backup:ap-northeast-3:xxxx:recovery-point:2580eca4-f799-4504-bd13-af63392fc355",
"ResourceArn": "arn:aws:elasticfilesystem:ap-northeast-1:xxxx:file-system/fs-040c3f105bf89e47e",
"CreationDate": "2025-06-04T11:09:21.202000+09:00",
"CompletionDate": "2025-06-04T11:30:26.891000+09:00",
"State": "COMPLETED",
"BackupSizeInBytes": 73,
"IamRoleArn": "arn:aws:iam::xxxx:role/efs-backup-role",
"CreatedBy": {
"BackupPlanId": "32299a85-0ead-41cd-9be6-c8b8ec867496",
"BackupPlanArn": "arn:aws:backup:ap-northeast-1:xxxx:backup-plan:32299a85-0ead-41cd-9be6-c8b8ec867496",
"BackupPlanVersion": "NGNkNGM5Y2YtMjYzOC00MTFmLTkzMmEtY2NlOTYwNzhlMjll",
"BackupRuleId": "4277d50e-0443-4ca3-9317-6228fbf237bb"
},
"ResourceType": "EFS",
"IsParent": false,
"ResourceName": "low-cost-efs"
}
]
}
terraform/terraform_test on master [📝] via 💠 default
at 11:36:07 ⬢ [Docker] ❯
terraform/terraform_test on master [📝] via 💠 default
at 11:37:21 ⬢ [Docker] ❯ aws backup list-backup-vaults --region ap-northeast-3
{
"BackupVaultList": [
{
"BackupVaultName": "efs-backup-vault-osaka",
"BackupVaultArn": "arn:aws:backup:ap-northeast-3:xxxx:backup-vault:efs-backup-vault-osaka",
"CreationDate": "2025-06-04T10:42:04.489000+09:00",
"EncryptionKeyArn": "arn:aws:kms:ap-northeast-3:xxxx:key/a95338a8-6879-481d-baa8-31c60dffc969",
"NumberOfRecoveryPoints": 1,
"Locked": false
}
]
}
terraform/terraform_test on master [📝] via 💠 default
at 11:37:28 ⬢ [Docker] ❯
terraform/terraform_test on master [📝] via 💠 default
at 11:37:28 ⬢ [Docker] ❯ aws backup list-recovery-points-by-backup-vault --backup-vault-name efs-backup-vault-osaka --region ap-northeast-3
{
"RecoveryPoints": [
{
"RecoveryPointArn": "arn:aws:backup:ap-northeast-3:xxxx:recovery-point:2580eca4-f799-4504-bd13-af63392fc355",
"BackupVaultName": "efs-backup-vault-osaka",
"BackupVaultArn": "arn:aws:backup:ap-northeast-3:xxxx:backup-vault:efs-backup-vault-osaka",
"SourceBackupVaultArn": "arn:aws:backup:ap-northeast-1:xxxx:backup-vault:efs-backup-vault",
"ResourceArn": "arn:aws:elasticfilesystem:ap-northeast-1:xxxx:file-system/fs-040c3f105bf89e47e",
"ResourceType": "EFS",
"CreatedBy": {
"BackupPlanId": "32299a85-0ead-41cd-9be6-c8b8ec867496",
"BackupPlanArn": "arn:aws:backup:ap-northeast-1:xxxx:backup-plan:32299a85-0ead-41cd-9be6-c8b8ec867496",
"BackupPlanVersion": "NGNkNGM5Y2YtMjYzOC00MTFmLTkzMmEtY2NlOTYwNzhlMjll",
"BackupRuleId": "4277d50e-0443-4ca3-9317-6228fbf237bb"
},
"IamRoleArn": "arn:aws:iam::xxxx:role/efs-backup-role",
"Status": "COMPLETED",
"CreationDate": "2025-06-04T10:50:00+09:00",
"CompletionDate": "2025-06-04T11:30:22.969000+09:00",
"BackupSizeInBytes": 73,
"CalculatedLifecycle": {
"DeleteAt": "2025-06-11T10:50:00+09:00"
},
"Lifecycle": {
"DeleteAfterDays": 7
},
"EncryptionKeyArn": "arn:aws:kms:ap-northeast-3:xxxx:key/a95338a8-6879-481d-baa8-31c60dffc969",
"IsEncrypted": true,
"IsParent": false,
"ResourceName": "low-cost-efs"
}
]
}
terraform/terraform_test on master [📝] via 💠 default
at 11:37:53 ⬢ [Docker] ❯
メモ
- レプリケーションは通常のバックアップ完了後、レプリケーション完了まで少しラグがある
- レプリケーションが完了したかはジョブ一覧の「コピージョブ」から確認できる
他にやりたいこと
- Selectionでtag名に「develop*」の名前がつくリソースのみをバックアップの対象とする
参考記事
https://dev.classmethod.jp/articles/terraform-backup-copy-other-region/
終わりに
やっぱりterraformのほうが使いやすいと感じる。
現状通常業務であればterraformを利用し続けることにはなると思うので、もう少しterraformには強くなりたい
(OpenTofuを触るのは必要が出てきたらでも間に合いそう)