AWS AppSync API キャッシュにおける保管時の暗号化について

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

この記事では、AWS AppSync API キャッシュは保管時に暗号化する必要がありますについて、リスクと対策を解説します。

ポリシーの説明

AWS AppSyncのAPIキャッシュは、GraphQLクエリの応答を一時的に保存することで、パフォーマンスを向上させ、バックエンドデータソースへの呼び出しを削減する重要な機能です。このキャッシュには、APIレスポンスデータ、ユーザー情報、ビジネスロジックなどの機密情報が含まれる可能性があります。

AWS Security HubコントロールAppSync.1では、AppSync APIキャッシュが保管時に暗号化されているかをチェックし、暗号化が有効でない場合は非準拠として検出されます。2025年6月以降、AWSは新規作成されるAppSync APIキャッシュに対して、保管時暗号化を自動的に有効化し、無効化できない仕様に変更されています。

リスク

保管時暗号化が有効でないAppSync APIキャッシュには、以下のセキュリティリスクがあります:

データ漏洩リスク

  • キャッシュされたAPIレスポンスが平文で保存されるため、基盤となるストレージが侵害された場合、機密データが露出する可能性があります
  • キャッシュメモリからディスクへのスワップ操作時に、暗号化されていないデータが一時的にディスクに書き込まれるリスクがあります

内部脅威への脆弱性

  • 権限を持つ内部ユーザーが、暗号化されていないキャッシュデータに不正アクセスする可能性があります
  • 監査証跡が不十分な場合、不正アクセスの検出が困難になります

修復方法

コンソールでの修復手順

AWSのコンソールを使用して、AppSync APIキャッシュの保管時暗号化を有効にします。

重要な注意事項: 既存の暗号化されていないキャッシュは、暗号化設定を変更できません。一度削除してから再作成する必要があります。

既存の暗号化されていないキャッシュの修復手順:

  1. AWS管理コンソールにログインし、サービス検索バーで「AppSync」を検索してクリックします
  2. 対象のGraphQL APIを選択
    • AppSyncダッシュボードで、修復が必要なAPIの名前をクリックします
  1. キャッシュ設定に移動
    • 左側のナビゲーションペインで「設定」をクリックします
    • 「キャッシング」セクションまでスクロールします
  2. 既存キャッシュの削除
    • 現在のキャッシュ設定を確認します
    • 「キャッシュを無効化」または「削除」ボタンをクリックします
    • 確認ダイアログで削除を実行します
    • 注意: この操作によりキャッシュされたデータがすべて失われます
  3. 新しい暗号化されたキャッシュの作成
    • 「キャッシングを有効化」ボタンをクリックします
    • 以下の設定を行います(用途に応じて最適な値で設定するようにしましょう)
      • キャッシング動作: 選択肢から選びます
        • 「完全リクエストキャッシング」(FULL_REQUEST_CACHING)
        • 「リゾルバー単位のキャッシング」(PER_RESOLVER_CACHING)
        • 「操作レベルのキャッシング」(OPERATION_LEVEL_CACHING)
      • インスタンスタイプ: キャッシュサイズを選択(SMALL、MEDIUM、LARGE等)
      • TTL(秒): 1~3600秒の間で設定
  1. 保存して適用
    • 「保存」または「キャッシュを作成」ボタンをクリックします
    • 2025年以降は保管時暗号化が自動的に有効化されます(手動設定不要)
  2. 設定の確認
    • キャッシュ設定画面で暗号化が有効になっていることを確認します
    • AWS Security Hubでコントロールのステータスが「準拠」に変わることを確認します

Terraformでの修復手順

AWS AppSync APIキャッシュの保管時暗号化を有効にするTerraformコードと、主要な修正ポイントを説明します。

# AppSync GraphQL API
resource "aws_appsync_graphql_api" "main" {
  name                = "secure-graphql-api"
  authentication_type = "API_KEY"

  # ロギング設定(推奨)
  log_config {
    cloudwatch_logs_role_arn = aws_iam_role.appsync_logs.arn
    field_log_level          = "ERROR"
  }

  tags = {
    Name        = "secure-graphql-api"
    Environment = "production"
    Security    = "encrypted"
  }
}

# APIキー
resource "aws_appsync_api_key" "main" {
  api_id      = aws_appsync_graphql_api.main.id
  description = "API key for secure GraphQL API"
  expires     = timeadd(timestamp(), "365d")
}

# 暗号化されたキャッシュの設定(重要な部分)
resource "aws_appsync_api_cache" "main" {
  api_id                     = aws_appsync_graphql_api.main.id
  type                       = "SMALL"  # SMALL, MEDIUM, LARGE, XLARGE等から選択
  api_caching_behavior       = "FULL_REQUEST_CACHING"
  ttl                        = 300  # 5分(1-3600秒の範囲で設定)

  # 保管時暗号化を有効化(必須)
  at_rest_encryption_enabled = true

  # 転送時暗号化も有効化(推奨)
  transit_encryption_enabled = true
}

# CloudWatch Logs用のIAMロール
resource "aws_iam_role" "appsync_logs" {
  name = "appsync-cloudwatch-logs-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "appsync.amazonaws.com"
        }
      }
    ]
  })
}

# CloudWatch Logsポリシー
resource "aws_iam_role_policy" "appsync_logs" {
  name = "appsync-cloudwatch-logs-policy"
  role = aws_iam_role.appsync_logs.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = "arn:aws:logs:*:*:*"
      }
    ]
  })
}

# 既存の暗号化されていないキャッシュを置き換える場合
# 1. まず既存のキャッシュリソースを削除
# 2. 上記の新しい暗号化されたキャッシュリソースを作成

# 条件付きでキャッシュを作成する例
variable "enable_caching" {
  description = "AppSyncキャッシングを有効にするかどうか"
  type        = bool
  default     = true
}

resource "aws_appsync_api_cache" "conditional" {
  count = var.enable_caching ? 1 : 0

  api_id                     = aws_appsync_graphql_api.main.id
  type                       = "MEDIUM"
  api_caching_behavior       = "PER_RESOLVER_CACHING"
  ttl                        = 600

  # セキュリティのため必ず有効化
  at_rest_encryption_enabled = true
  transit_encryption_enabled = true
}

# キャッシュ設定の出力
output "cache_encryption_status" {
  value = {
    at_rest_encryption  = aws_appsync_api_cache.main.at_rest_encryption_enabled
    transit_encryption  = aws_appsync_api_cache.main.transit_encryption_enabled
    cache_type         = aws_appsync_api_cache.main.type
    ttl                = aws_appsync_api_cache.main.ttl
  }
  description = "AppSyncキャッシュの暗号化ステータス"
}

Terraformでの移行手順:

  1. 既存の暗号化されていないキャッシュがある場合: # 既存のキャッシュリソースを削除 terraform destroy -target=aws_appsync_api_cache.existing_cache
  2. 新しい暗号化されたキャッシュ設定を適用: # 計画を確認 terraform plan # 変更を適用 terraform apply

修復の確認方法

修復が正しく適用されたことを確認するには、以下のコマンドを実行します:

# 1. キャッシュ暗号化設定の確認
aws appsync get-api-cache \\\\
  --api-id $API_ID \\\\
  --query 'apiCache.[atRestEncryptionEnabled,transitEncryptionEnabled]' \\\\
  --output json

# 2. AWS Security Hubでの検証
aws securityhub get-findings \\\\
  --filters '{
    "ProductArn": [{"Value": "arn:aws:securityhub:*:*:product/aws/securityhub", "Comparison": "EQUALS"}],
    "ComplianceStatus": [{"Value": "FAILED", "Comparison": "EQUALS"}],
    "Title": [{"Value": "*AppSync*cache*encryption*", "Comparison": "CONTAINS"}]
  }' \\\\
  --query 'Findings[*].[Title,Compliance.Status,Resources[0].Id]' \\\\
  --output table

# 3. 組織全体のAppSyncキャッシュ暗号化状態の監査
#!/bin/bash
echo "=== AppSync API キャッシュ暗号化監査レポート ==="
echo "日付: $(date)"
echo ""

total_apis=0
cached_apis=0
encrypted_caches=0
unencrypted_caches=0

for api_id in $(aws appsync list-graphql-apis --query 'graphqlApis[*].apiId' --output text); do
  total_apis=$((total_apis + 1))
  api_name=$(aws appsync get-graphql-api --api-id $api_id --query 'graphqlApi.name' --output text)
  cache_info=$(aws appsync get-api-cache --api-id $api_id 2>/dev/null)

  if [ $? -eq 0 ]; then
    cached_apis=$((cached_apis + 1))
    at_rest=$(echo $cache_info | jq -r '.apiCache.atRestEncryptionEnabled')
    transit=$(echo $cache_info | jq -r '.apiCache.transitEncryptionEnabled')

    if [ "$at_rest" = "true" ]; then
      encrypted_caches=$((encrypted_caches + 1))
      echo "[準拠] $api_name - 保管時暗号化: 有効, 転送時暗号化: $transit"
    else
      unencrypted_caches=$((unencrypted_caches + 1))
      echo "[非準拠] $api_name - 保管時暗号化: 無効"
    fi
  fi
done

echo ""
echo "=== サマリー ==="
echo "総API数: $total_apis"
echo "キャッシュ有効API数: $cached_apis"
echo "暗号化済みキャッシュ: $encrypted_caches"
echo "未暗号化キャッシュ: $unencrypted_caches"

セキュリティのベストプラクティス

  1. 暗号化の多層防御:
    • 保管時暗号化(at-rest encryption)と転送時暗号化(in-transit encryption)の両方を有効化
    • API自体もHTTPS経由でのみアクセス可能に設定
  2. キャッシュポリシーの適切な設定:
    • TTL(Time To Live)を業務要件に応じて最小限に設定
    • 機密性の高いデータはキャッシュから除外することを検討
  3. 監査とモニタリング:
    • CloudTrailでキャッシュ設定の変更を記録
    • CloudWatchメトリクスでキャッシュヒット率を監視
  4. アクセス制御:
    • IAMポリシーで最小権限の原則を適用
    • APIキーの定期的なローテーション
  5. データ分類とタグ付け:
    • APIとキャッシュにデータ分類タグを付与
    • 機密度に応じた管理ポリシーの適用

最後に

この記事では、AWS AppSync API キャッシュは保管時に暗号化する必要がありますについて、リスクと対策を解説しました。

AppSync APIキャッシュの保管時暗号化を有効にすることで、キャッシュされたデータの機密性を確保し、コンプライアンス要件を満たすことができます。2025年6月以降、AWSは新規キャッシュに対して暗号化を自動的に有効化していますが、既存の暗号化されていないキャッシュについては、手動での再作成が必要です。

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

参考資料

この記事をシェアする

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

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

料金プランを詳しく見る