EFSをバックアップしてみた
現場でAWSバックアップを利用する機会があったので、自宅でもEFSをバックアップしてみた。
概要
現場でEFSを対象としている既存のAWSバックアップ(Vaultなど)をcloudformationの管理下におこうというのがことの始まりでした。 当初cloudformationのテンプレートを作成しそこにインポートしようとしたのですが、 既存のAWSバックアップはEFS側で「自動バックアップ」を有効化した際にAWS側で自動で作成されるBackUpのようで、 これをユーザー側でスタックにインポートなどはできないようでした。(AWSサポートからの回答) ですので、現場としてはEFSの「自動バックアップ」を無効化し、専用のBackUpVault/BackUpPlan/BackUpSelectionを作成しバックアップしたいEFSを対象とすることにしました。
これを自宅でもやってみます。 ただ、cloudformationではなくterraformで構築します。
この記事はそのメモやまとめです。 自分の環境用のメモでもあるので、省略している記載もあります。 すでに設定済みの項目がいくつかある。 試行錯誤しながらやったので、手順として不要かもしれない。あくまでメモ用。
EFS
まずはバックアップ対象のテスト用のEFSを作成します。 requirements.tfに以下を記載して、terraform_remote_stateで、 他のterraformディレクトリで作成してあるmainのVPCとSubnetの情報を参照できるようにします。 (あらかじめVPCとSubnet側でoutputを定義しておきます)
# VPC/subnet情報を取得
data "terraform_remote_state" "vpc" {
backend = "s3"
config = {
bucket = "xxxx"
key = "terraform_my_workspace/terraform.tfstate"
region = "ap-northeast-1"
}
}
出来上がったEFSのコードは以下です。出来だけコストはかけたくなく暗号化など行っていません。
# ----------------------------------------- #
# EFS
# ----------------------------------------- #
resource "aws_efs_file_system" "low_cost" {
creation_token = "my-efs"
performance_mode = "generalPurpose"
throughput_mode = "bursting"
encrypted = false
tags = {
Name = "low-cost-efs"
BackupEnabled = "true"
Environment = "test"
Owner = "terraform"
Project = "terraform_test"
}
}
# EFSマウントターゲット(プライベートサブネットに作成)
resource "aws_efs_mount_target" "private_a" {
file_system_id = aws_efs_file_system.low_cost.id
subnet_id = data.terraform_remote_state.vpc.outputs.private_subnet_ids[0]
security_groups = [aws_security_group.efs_sg.id]
}
resource "aws_efs_mount_target" "private_c" {
file_system_id = aws_efs_file_system.low_cost.id
subnet_id = data.terraform_remote_state.vpc.outputs.private_subnet_ids[1]
security_groups = [aws_security_group.efs_sg.id]
}
# ----------------------------------------- #
# EFS SG
# ----------------------------------------- #
resource "aws_security_group" "efs_sg" {
name = "efs-sg"
description = "Allow NFS access for EFS"
vpc_id = data.terraform_remote_state.vpc.outputs.vpc_id
ingress {
description = "NFS"
from_port = 2049
to_port = 2049
protocol = "tcp"
cidr_blocks = [data.terraform_remote_state.vpc.outputs.vpc_cidr_block]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "efs-sg"
}
}
上記をapplyして、EFSを構築しておきます。
BackUp
次のBackupのVault/Plan(Rule)/Selectionを作成します。
ざっくりとした認識ですが、
Vault → バックアップ格納先
Plan → Planの中にRuleがあり、Rule毎にいつバックアップを実行してどのVaultに格納するかなどを定義する
Selection → なにをバックアップするか対象を指定する
と言った感じです。
SelectionではIAMロールの指定も必要なので一緒に作成します。 ポリシーについてはすでにAWS側で用意されている以下のポリシーがあるので、それを利用します。
arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup
arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores
Planの注意点として、ruleの時間は何も指定しないとUTC時刻でバックアップを実行します。
なのでわかりやすくschedule_expression_timezoneで東京時刻にしてあげたほうがいいと思います。
rule {
rule_name = "immediate_test_backup"
target_vault_name = aws_backup_vault.efs_backup_vault.name
schedule = "cron(30 9 * * ? *)"
schedule_expression_timezone = "Asia/Tokyo"
start_window = 60
completion_window = 120
出来上がったEFSのコードは以下です。
補足として、テスト用の「immediate_test_backup」とデイリーで実行される「daily_backup」の2つを作成し、
EFSのIDが一致しており、BackupEnabled = “true"のタグがついている場合にバックアップされます。
# ----------------------------------------- #
# BackupVault
# ----------------------------------------- #
resource "aws_backup_vault" "efs_backup_vault" {
name = "efs-backup-vault"
}
# ----------------------------------------- #
# 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(30 9 * * ? *)"
schedule_expression_timezone = "Asia/Tokyo"
start_window = 60
completion_window = 120
lifecycle {
delete_after = 7
}
recovery_point_tags = {
BackupType = "Test"
}
}
# 通常の日次バックアップ(コールドストレージ制約を満たす設定)
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"
}
}
}
# ----------------------------------------- #
# 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"
}
}
}
上記でapplyしてリソースを作成する。
テスト用のバックアップの時間後、しばらくしてGUIを確認するとバックアップに成功していた。
詰まったところ
schedule_expression_timezoneが認識されない
terraformでschedule_expression_timezoneを記載planをかけるとこの記載がエラーとなりました。
╷
│ Error: Unsupported argument
│
│ on aws_efs_backup.tf line 28, in resource "aws_backup_plan" "efs_backup_plan":
│ 28: schedule_expression_timezone = "Asia/Tokyo"
│
│ An argument named "schedule_expression_timezone" is not expected here.
╵
╷
│ Error: Unsupported argument
│
│ on aws_efs_backup.tf line 46, in resource "aws_backup_plan" "efs_backup_plan":
│ 46: schedule_expression_timezone = "Asia/Tokyo"
│
│ An argument named "schedule_expression_timezone" is not expected here.
terraformのドキュメントをみてもしっかりと定義されていました。 https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_plan#schedule_expression_timezone-1
どうやらこのセクションは比較的新しく取り込まれたらしく、terraformのversionを上げてみると動きました。
terraform init -upgrade
Selectionの詳細確認
Selectionの詳細確認をCLIで行うのははちょっと面倒でした
SelectionIdはGUI上では表示されないので、コマンドを2回ほど実行する必要がある。
list-backup-plans で対象backupplanのIDを調べる
list-backup-selections で上記backupplanのIDを利用してbackupselectionのIDを調べる
at 13:31:15 ⬢ [Docker] ❯ aws backup --region ap-northeast-1 list-backup-plans
{
"BackupPlansList": [
{
"BackupPlanArn": "arn:aws:backup:ap-northeast-1:xxxx:backup-plan:2a26a5b0-a5ce-4e45-b377-46e52848026c",
"BackupPlanId": "2a26a5b0-a5ce-4e45-b377-46e52848026c",
"CreationDate": "2025-06-02T13:28:16.688000+09:00",
"VersionId": "NjI0NGZiZWEtMWQzYy00MjgwLWJiMzctMzkyNWViM2RiN2Vl",
"BackupPlanName": "efs-backup-plan"
}
]
}
terraform/terraform_test on master [📝🌚] via 💠 default
at 13:33:28 ⬢ [Docker] ❯ aws backup --region ap-northeast-1 list-backup-selections --backup-plan-id 2a26a5b0-a5ce-4e45-b377-46e52848026c | jq
{
"BackupSelectionsList": [
{
"SelectionId": "9676adfe-96cf-4fe8-b92d-c9dc88d1402d",
"SelectionName": "efs-backup-selection",
"BackupPlanId": "2a26a5b0-a5ce-4e45-b377-46e52848026c",
"CreationDate": "2025-06-02T12:11:22.139000+09:00",
"IamRoleArn": "arn:aws:iam::xxxx:role/efs-backup-role"
}
]
}
terraform/terraform_test on master [📝🌚] via 💠 default
at 13:33:29 ⬢ [Docker] ❯
を使用して初めてIDがわかる。 更に詳細を見たい場合は、get-backup-selectionで確認できる。
get-backup-selection で上記backupplanのIDとbackupselectionのIDを利用する
terraform/terraform_test on master [📝🌚] via 💠 default took 2s
at 14:23:58 ⬢ [Docker] ❯ aws backup --region ap-northeast-1 get-backup-selection --backup-plan-id 2a26a5b0-a5ce-4e45-b377-46e52848026c --selection-id 9676adfe-96cf-4fe8-b92d-c9dc88d1402d | jq
{
"BackupSelection": {
"SelectionName": "efs-backup-selection",
"IamRoleArn": "arn:aws:iam::xxxx:role/efs-backup-role",
"Resources": [
"arn:aws:elasticfilesystem:ap-northeast-1:xxxx:file-system/fs-05d3e738e6a46d167"
],
"ListOfTags": [],
"NotResources": [],
"Conditions": {
"StringEquals": [
{
"ConditionKey": "aws:ResourceTag/BackupEnabled",
"ConditionValue": "true"
}
],
"StringNotEquals": [],
"StringLike": [],
"StringNotLike": []
}
},
"SelectionId": "9676adfe-96cf-4fe8-b92d-c9dc88d1402d",
"BackupPlanId": "2a26a5b0-a5ce-4e45-b377-46e52848026c",
"CreationDate": "2025-06-02T12:11:22.139000+09:00"
}
terraform/terraform_test on master [📝🌚] via 💠 default
at 14:24:03 ⬢ [Docker] ❯
他にやりたいこと
- vaultで他リージョンへのレプリケーション設定を有効にする
- Selectionでtag名に「develop*」の名前がつくリソースのみをバックアップの対象とする
終わりに
現場でAWS BackUpを触る機会があったので、自宅でも触ってみました。
一度も触ったことがなかったサービスなので、非常によう経験に鳴ったかと思います。