ElastiCache for Redisクラスターで自動バックアップを有効化する手順

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。
この記事では、ElastiCache for Redisクラスターで自動バックアップを有効化する手順について、リスクと対策を解説します。

ポリシーの説明
Amazon ElastiCache for Redisでは、クラスターのデータを定期的にバックアップし、障害発生時に迅速にデータを復旧できる自動バックアップ機能を提供しています。しかし、多くの環境でこの重要な機能が無効のまま運用されており、データ損失のリスクにさらされています。本ポリシーでは、すべてのElastiCache for Redisクラスターで自動バックアップが適切に設定されているかを確認します。
修復方法
コンソールでの修復手順
AWSのコンソールを使用して、ElastiCache for Redisクラスターの自動バックアップを有効化します。
ステップ1: 現在のクラスター設定の確認
- AWSマネジメントコンソールにログイン
- Amazon ElastiCacheサービスに移動
- 左側メニューから 「Redis OSS キャッシュ」 を選択
- バックアップ設定が必要なクラスターを特定
- クラスター名をクリックして詳細を表示
- 「バックアップ」 タブで現在の設定を確認
ステップ2: レプリケーショングループの確認
自動バックアップを有効にする前に確認:
- クラスターがレプリケーショングループである必要があります
- スタンドアロンクラスターではバックアップ機能が利用できません
- スタンドアロンクラスターの場合は、まずレプリケーショングループへの移行が必要
- 移行時はデータ移行とアプリケーション接続先の変更が必要
- クラスターモード: 有効(シャーディング)/無効どちらでもバックアップ可能
ステップ3: バックアップ設定の変更
- 対象クラスターの詳細画面で 「変更」 ボタンをクリック
- 「バックアップ」 セクションまでスクロール
- 以下の設定を行います:
自動バックアップ設定:
- 自動バックアップの有効化: チェックを入れる
- バックアップ保持期間: 7~35日(最大値)の範囲で設定
- 本番環境: 15日以上を推奨
- 開発環境: 7日程度でも可
- コンプライアンス要件(SOC2、PCI-DSS等)に応じて調整
- バックアップウィンドウ: 最低60分の時間枠を指定
- 例:
03:00-05:00 UTC
(日本時間12:00-14:00) - トラフィックが最も少ない時間帯を選択
- バックアップサイズに応じて時間枠を調整
- 例:
- バックアップノード ID: 読み取りレプリカのノードIDを指定
- プライマリノードを選択するとパフォーマンスに影響あり
- 複数のレプリカがある場合は最も負荷の低いものを選択
Terraformでの修復手順
ElastiCache for Redisクラスターの自動バックアップを有効にするTerraformコードと、主要な修正ポイントを説明します。
# ElastiCache サブネットグループ
resource "aws_elasticache_subnet_group" "redis" {
name = "${var.environment}-redis-subnet-group"
subnet_ids = var.private_subnet_ids
tags = {
Name = "${var.environment}-redis-subnet-group"
Environment = var.environment
}
}
# セキュリティグループ
resource "aws_security_group" "redis" {
name = "${var.environment}-redis-sg"
description = "Security group for ElastiCache Redis"
vpc_id = var.vpc_id
ingress {
from_port = 6379
to_port = 6379
protocol = "tcp"
cidr_blocks = [var.vpc_cidr]
description = "Redis access from VPC"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.environment}-redis-sg"
Environment = var.environment
}
}
# パラメータグループ(バックアップ用メモリ設定含む)
resource "aws_elasticache_parameter_group" "redis" {
family = var.redis_family # redis7, redis6.2等
name = "${var.environment}-redis-params"
# バックアップ用のメモリ確保(重要: OOMエラー防止)
parameter {
name = "reserved-memory-percent"
value = "25" # バックアップ用に25%のメモリを予約
}
# maxmemory-policyの設定(データ退避戦略)
parameter {
name = "maxmemory-policy"
value = "volatile-lru" # TTL付きキーからLRUで削除
}
# スナップショット作成時の設定
parameter {
name = "stop-writes-on-bgsave-error"
value = "yes" # バックアップエラー時に書き込みを停止
}
tags = {
Name = "${var.environment}-redis-params"
Environment = var.environment
}
}
# ElastiCache レプリケーショングループ(自動バックアップ有効)
resource "aws_elasticache_replication_group" "redis" {
replication_group_id = "${var.environment}-redis-cluster"
description = "Redis cluster with automatic backup for ${var.environment}"
# エンジン設定
engine = "redis"
engine_version = var.redis_version # 7.0以降を推奨
node_type = var.node_type # cache.r6g.large等
port = 6379
# レプリケーション設定
num_cache_clusters = var.num_cache_nodes # 最低2以上(プライマリ+レプリカ)
automatic_failover_enabled = true
multi_az_enabled = true
# 自動バックアップ設定(重要)
snapshot_retention_limit = var.backup_retention_days # 7-35日(0は無効化)
snapshot_window = var.backup_window # 最低60分の時間枠(例: "03:00-05:00" UTC)
maintenance_window = var.maintenance_window # バックアップウィンドウと重複しないよう設定
# 最終スナップショットの作成(クラスター削除時)
final_snapshot_identifier = var.create_final_snapshot ? "${var.environment}-redis-final-${formatdate("YYYYMMDD-hhmmss", timestamp())}" : null
# バックアップからの復元時に使用
snapshot_name = var.restore_from_snapshot # 既存スナップショットから復元する場合
# 暗号化設定(セキュリティ強化)
at_rest_encryption_enabled = true
kms_key_id = var.kms_key_id
transit_encryption_enabled = true
auth_token = var.enable_auth ? random_password.redis_auth[0].result : null
# ネットワーク設定
subnet_group_name = aws_elasticache_subnet_group.redis.name
security_group_ids = [aws_security_group.redis.id]
# パラメータグループ
parameter_group_name = aws_elasticache_parameter_group.redis.name
# 通知設定
notification_topic_arn = aws_sns_topic.redis_notifications.arn
# ログ配信(監査用)
log_delivery_configuration {
destination = aws_cloudwatch_log_group.redis_slow_log.name
destination_type = "cloudwatch-logs"
log_format = "json"
log_type = "slow-log"
}
# タグ
tags = {
Name = "${var.environment}-redis-cluster"
Environment = var.environment
BackupEnabled = "true"
BackupRetentionDays = var.backup_retention_days
}
# ライフサイクル設定
lifecycle {
ignore_changes = [engine_version] # マイナーバージョン自動更新を許可
}
}
# 手動バックアップ(追加保護)
resource "aws_elasticache_snapshot" "manual_backup" {
count = var.enable_manual_backup ? 1 : 0
replication_group_id = aws_elasticache_replication_group.redis.id
snapshot_name = "${var.environment}-redis-manual-${formatdate("YYYY-MM-DD", timestamp())}"
tags = {
Name = "${var.environment}-redis-manual-backup"
Environment = var.environment
Type = "Manual"
CreatedAt = timestamp()
}
}
# SNSトピック(バックアップ通知用)
resource "aws_sns_topic" "redis_notifications" {
name = "${var.environment}-redis-backup-notifications"
tags = {
Name = "${var.environment}-redis-notifications"
Environment = var.environment
}
}
# SNSサブスクリプション
resource "aws_sns_topic_subscription" "redis_email" {
topic_arn = aws_sns_topic.redis_notifications.arn
protocol = "email"
endpoint = var.notification_email
}
# CloudWatch アラーム(バックアップ監視)
resource "aws_cloudwatch_metric_alarm" "backup_failed" {
alarm_name = "${var.environment}-redis-backup-failed"
comparison_operator = "LessThanThreshold"
evaluation_periods = "1"
metric_name = "SnapshotCreateSuccessful"
namespace = "AWS/ElastiCache"
period = "86400" # 24時間
statistic = "Sum"
threshold = "1"
alarm_description = "Alert when Redis backup fails"
alarm_actions = [aws_sns_topic.redis_notifications.arn]
dimensions = {
ReplicationGroupId = aws_elasticache_replication_group.redis.id
}
}
# CloudWatch ロググループ
resource "aws_cloudwatch_log_group" "redis_slow_log" {
name = "/aws/elasticache/${var.environment}/redis/slow-log"
retention_in_days = 30
tags = {
Name = "${var.environment}-redis-slow-log"
Environment = var.environment
}
}
# 認証トークン(オプション)
resource "random_password" "redis_auth" {
count = var.enable_auth ? 1 : 0
length = 32
special = true
}
# AWS Secrets Managerに認証トークンを保存
resource "aws_secretsmanager_secret" "redis_auth" {
count = var.enable_auth ? 1 : 0
name = "${var.environment}-redis-auth-token"
tags = {
Name = "${var.environment}-redis-auth"
Environment = var.environment
}
}
resource "aws_secretsmanager_secret_version" "redis_auth" {
count = var.enable_auth ? 1 : 0
secret_id = aws_secretsmanager_secret.redis_auth[0].id
secret_string = jsonencode({
auth_token = random_password.redis_auth[0].result
})
}
# variables.tf
variable "environment" {
description = "環境名(dev/staging/prod)"
type = string
}
variable "redis_version" {
description = "Redisエンジンバージョン"
type = string
default = "7.0"
}
variable "redis_family" {
description = "Redisパラメータグループファミリー"
type = string
default = "redis7"
}
variable "node_type" {
description = "ElastiCacheノードタイプ"
type = string
default = "cache.r6g.large"
}
variable "num_cache_nodes" {
description = "キャッシュノード数(最低2以上)"
type = number
default = 2
}
variable "backup_retention_days" {
description = "バックアップ保持期間(日数)"
type = number
default = 30
validation {
condition = var.backup_retention_days >= 7 && var.backup_retention_days <= 35
error_message = "バックアップ保持期間は7〜35日の間で設定してください(0で無効化)。"
}
}
variable "create_final_snapshot" {
description = "クラスター削除時に最終スナップショットを作成"
type = bool
default = true
}
variable "backup_window" {
description = "バックアップウィンドウ(UTC)"
type = string
default = "03:00-05:00" # 日本時間12:00-14:00
}
variable "maintenance_window" {
description = "メンテナンスウィンドウ"
type = string
default = "sun:05:00-sun:07:00"
}
variable "notification_email" {
description = "バックアップ通知用メールアドレス"
type = string
}
# outputs.tf
output "redis_endpoint" {
value = aws_elasticache_replication_group.redis.primary_endpoint_address
description = "Redis primary endpoint"
}
output "redis_reader_endpoint" {
value = aws_elasticache_replication_group.redis.reader_endpoint_address
description = "Redis reader endpoint"
}
output "backup_retention_days" {
value = aws_elasticache_replication_group.redis.snapshot_retention_limit
description = "Backup retention period in days"
}
主要な修正ポイント
- snapshot_retention_limit:
- 最低7日、最大35日の保持期間を設定
- 本番環境では15日以上を推奨
- コンプライアンス要件に応じて調整
- snapshot_window:
- 最低60分の時間枠を確保
- システムの最低負荷時間帯に設定
- メンテナンスウィンドウと重複しないよう注意
- 読み取りレプリカからのバックアップ:
- num_cache_nodesを2以上に設定
- automatic_failover_enabledをtrueに設定
- バックアップノードIDに読み取りレプリカを指定
- 監視とアラート:
- CloudWatchメトリクス「SnapshotCreateSuccessful」を監視
- バックアップ失敗時の即座のアラート通知
- SNSトピックによるメール/Slack通知
- 暗号化の併用:
- at_rest_encryption_enabledでデータ暗号化
- transit_encryption_enabledで通信暗号化
- KMSキーによる鍵管理
- メモリ管理:
- reserved-memory-percentで十分なメモリを確保
- maxmemory-policyで適切なデータ退避戦略を設定
最後に
この記事では、ElastiCache for Redisクラスターで自動バックアップを有効化する手順について、リスクと対策を解説しました。
自動バックアップの設定は、単にsnapshot_retention_limitを設定するだけでなく、適切なバックアップウィンドウの選択、レプリカからのバックアップ、メモリ管理、監視体制の構築など、包括的な対策が必要です。特に本番環境では、定期的な復旧テストを実施し、RPOとRTOの要件を満たすことを確認することが重要です。
また、バックアップは多層防御戦略の一部として位置づけ、レプリケーション、自動フェイルオーバー、暗号化、アクセス制御などの他のセキュリティ対策と組み合わせて実装することを強く推奨します。
この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。