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

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、AWS CLI、Terraformなど)まで、分かりやすく解説します。

この記事では、ElastiCache for Redisクラスターで自動バックアップを有効化する手順について、リスクと対策を解説します。

ポリシーの説明

Amazon ElastiCache for Redisでは、クラスターのデータを定期的にバックアップし、障害発生時に迅速にデータを復旧できる自動バックアップ機能を提供しています。しかし、多くの環境でこの重要な機能が無効のまま運用されており、データ損失のリスクにさらされています。本ポリシーでは、すべてのElastiCache for Redisクラスターで自動バックアップが適切に設定されているかを確認します。

修復方法

コンソールでの修復手順

AWSのコンソールを使用して、ElastiCache for Redisクラスターの自動バックアップを有効化します。

ステップ1: 現在のクラスター設定の確認

  1. AWSマネジメントコンソールにログイン
  2. Amazon ElastiCacheサービスに移動
  3. 左側メニューから 「Redis OSS キャッシュ」 を選択
  4. バックアップ設定が必要なクラスターを特定
  5. クラスター名をクリックして詳細を表示
  6. 「バックアップ」 タブで現在の設定を確認

ステップ2: レプリケーショングループの確認

自動バックアップを有効にする前に確認:

  1. クラスターがレプリケーショングループである必要があります
    • スタンドアロンクラスターではバックアップ機能が利用できません
  2. スタンドアロンクラスターの場合は、まずレプリケーショングループへの移行が必要
    • 移行時はデータ移行とアプリケーション接続先の変更が必要
  3. クラスターモード: 有効(シャーディング)/無効どちらでもバックアップ可能

ステップ3: バックアップ設定の変更

  1. 対象クラスターの詳細画面で 「変更」 ボタンをクリック
  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"
}

 

主要な修正ポイント

  1. snapshot_retention_limit:
    • 最低7日、最大35日の保持期間を設定
    • 本番環境では15日以上を推奨
    • コンプライアンス要件に応じて調整
  2. snapshot_window:
    • 最低60分の時間枠を確保
    • システムの最低負荷時間帯に設定
    • メンテナンスウィンドウと重複しないよう注意
  3. 読み取りレプリカからのバックアップ:
    • num_cache_nodesを2以上に設定
    • automatic_failover_enabledをtrueに設定
    • バックアップノードIDに読み取りレプリカを指定
  4. 監視とアラート:
    • CloudWatchメトリクス「SnapshotCreateSuccessful」を監視
    • バックアップ失敗時の即座のアラート通知
    • SNSトピックによるメール/Slack通知
  5. 暗号化の併用:
    • at_rest_encryption_enabledでデータ暗号化
    • transit_encryption_enabledで通信暗号化
    • KMSキーによる鍵管理
  6. メモリ管理:
    • reserved-memory-percentで十分なメモリを確保
    • maxmemory-policyで適切なデータ退避戦略を設定

最後に

この記事では、ElastiCache for Redisクラスターで自動バックアップを有効化する手順について、リスクと対策を解説しました。

自動バックアップの設定は、単にsnapshot_retention_limitを設定するだけでなく、適切なバックアップウィンドウの選択、レプリカからのバックアップ、メモリ管理、監視体制の構築など、包括的な対策が必要です。特に本番環境では、定期的な復旧テストを実施し、RPOとRTOの要件を満たすことを確認することが重要です。

また、バックアップは多層防御戦略の一部として位置づけ、レプリケーション、自動フェイルオーバー、暗号化、アクセス制御などの他のセキュリティ対策と組み合わせて実装することを強く推奨します。

この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。

参考情報

AWS公式ドキュメント

この記事をシェアする

クラウドセキュリティ対策実践集一覧へ戻る

貴社の利用状況に合わせた見積もりを作成します。

料金プランを詳しく見る