目次

AWSアンチパターン集

周辺資料: 学習インデックス · AWSサービス一覧(2026) · サービス選定ガイド · アーキテクチャパターン集


AWS設計・運用で頻出するアンチパターンを領域別に整理。なぜ起きるか・何が問題か・正しい設計を具体的に示す。


1. セキュリティのアンチパターン

IAM ワイルドカード権限

[アンチパターン]
  "Action": "*",  "Resource": "*"
  理由: 「とりあえず動かしたい」「IAMを調べるのが面倒」

[問題]
  - 攻撃者に侵害された場合の被害が全アカウントに及ぶ
  - コンプライアンス審査で必ず指摘される
  - 誰が何をできるか把握できなくなる

[正しい設計]
  必要なサービス・アクション・リソースを最小化して明示:
  {
    "Effect": "Allow",
    "Action": [
      "s3:GetObject",
      "s3:PutObject"
    ],
    "Resource": "arn:aws:s3:::my-bucket/uploads/*"
  }

  Permission Boundary を使い開発者が作成できるロールの範囲を制限
  IAM Access Analyzer で意図しない外部公開リソースを定期検出

ハードコードされた認証情報

[アンチパターン]
  # ソースコードや環境変数に直書き
  AWS_ACCESS_KEY_ID = "AKIAIOSFODNN7EXAMPLE"
  AWS_SECRET_ACCESS_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
  DB_PASSWORD = "my-prod-password"

[問題]
  - Git に混入すると即座に悪用される(GitHub には常時スキャナーが動いている)
  - ローテーションが困難になる
  - 複数の環境で同じ認証情報を使うリスク

[正しい設計]
  AWS サービスには IAM ロール(EC2/ECS/Lambda に直接アタッチ)
  DB パスワード → Secrets Manager(自動ローテーション付き)
  設定値 → SSM Parameter Store(SecureString)
  
  # Lambda での正しい実装
  import boto3, json
  
  def get_secret(secret_name: str) -> dict:
      client = boto3.client('secretsmanager')
      return json.loads(client.get_secret_value(SecretId=secret_name)['SecretString'])
  
  # 関数起動時にキャッシュして API コールを最小化
  _secret_cache = {}
  def get_db_password():
      if 'db' not in _secret_cache:
          _secret_cache['db'] = get_secret('prod/myapp/db')
      return _secret_cache['db']['password']

ルートアカウントの日常利用

[アンチパターン]
  ルートアカウントで日常の AWS 操作を行う
  ルートアカウントへの MFA 未設定

[問題]
  - ルートアカウントは全権限を持ち、SCP でも制限できない
  - 漏洩時の影響範囲が最大

[正しい設計]
  ルートアカウント:
    MFA を必ず設定(ハードウェアMFAを推奨)
    アクセスキーを作成しない
    IAM Identity Center の初期設定時のみ使用
    使用後はロック(MFAデバイスを安全な場所に保管)
  
  日常操作:
    IAM Identity Center → SSO でアクセス
    各環境に対応した IAM ロールに AssumeRole

S3 パブリックバケット

[アンチパターン]
  bucket.set_acl('public-read')
  または ACL: public-read でバケット全体を公開

[問題]
  - 機密データの意図しない公開
  - データ漏洩インシデントの主要原因の1つ
  - コンプライアンス違反

[正しい設計]
  1. アカウントレベルで S3 パブリックアクセスブロックを有効化(全バケット)
  2. 静的サイトなど公開必要なものは CloudFront + OAC で限定公開
  3. Config ルール s3-bucket-public-read-prohibited で継続監視
  4. SCP で s3:PutBucketPublicAccessBlock の変更を Deny

2. 可用性のアンチパターン

単一 AZ 構成

[アンチパターン]
  EC2 を1つのAZにのみ配置
  RDS Single-AZ
  ALB のターゲットが1 AZ のみ

[問題]
  AWS は年に数回 AZ 単位の障害を起こすことがある
  AZ 障害時にサービスが完全停止する

[正しい設計]
  最低限:
    EC2: ASG で 2AZ 以上
    RDS: Multi-AZ 有効化
    ALB: 2AZ 以上のターゲット登録

  推奨:
    3AZ 構成(ap-northeast-1a/1c/1d)
    DynamoDB: リージョン内で自動 3AZ 複製(設定不要)
    Lambda: リージョン内で自動 Multi-AZ(設定不要)

ヘルスチェックの不備

[アンチパターン]
  ALB ヘルスチェックが / (ルート) のみで、実際のアプリロジックを確認しない
  ヘルスチェックのタイムアウトが長すぎる(デフォルト30秒のまま)
  ECS タスクの unhealthy 時に再起動しない設定

[問題]
  - アプリが実質停止していても「正常」と判定してトラフィックを送り続ける
  - 障害の検知が遅れる

[正しい設計]
  /health エンドポイントを実装:
    DB 接続確認(ping クエリ)
    外部依存サービスの疎通確認
    レスポンス: {"status": "ok", "db": "ok", "cache": "ok"}

  ALB ヘルスチェック設定:
    Path: /health
    Interval: 15秒
    Timeout: 5秒
    HealthyThreshold: 2
    UnhealthyThreshold: 3
  
  ECS タスク定義:
    healthCheck:
      command: ["CMD-SHELL", "curl -f http://localhost/health || exit 1"]
      interval: 15
      timeout: 5
      retries: 3

デプロイ時の全停止

[アンチパターン]
  ECS サービスの minimumHealthyPercent = 0
  直接 ALB のターゲットグループを変更してデプロイ
  デプロイ中にリクエストが失敗する

[問題]
  - デプロイのたびにサービス停止(ダウンタイム発生)
  - ロールバックに時間がかかる

[正しい設計]
  ECS Rolling Update:
    minimumHealthyPercent: 100
    maximumPercent: 200
    DeregistrationDelay: 30秒(既存接続のドレイン)

  Blue/Green デプロイ(CodeDeploy + ECS):
    新タスクセットを起動 → テスト → トラフィック切替 → 旧タスク削除
    失敗時は15秒でロールバック可能

  Lambda のエイリアス + 重み付き設定:
    prod エイリアス: v1=90%, v2=10% でカナリアリリース

3. パフォーマンスのアンチパターン

N+1 クエリ問題(RDS)

[アンチパターン]
  # ユーザー一覧を取得後、1件ずつ注文を取得
  users = db.query("SELECT * FROM users LIMIT 100")
  for user in users:
      orders = db.query(f"SELECT * FROM orders WHERE user_id = {user.id}")
      # → 101回のクエリが発生

[問題]
  - RDS 接続数が増大(接続プールを圧迫)
  - レイテンシが線形増加
  - RDS CPU 使用率が高騰

[正しい設計]
  JOIN または IN クエリで一括取得:
  users_with_orders = db.query("""
    SELECT u.*, o.order_id, o.amount
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.id IN (SELECT id FROM users LIMIT 100)
  """)

  または RDS Proxy で接続プール最適化
  + Read Replica にクエリを分散(参照系)

DynamoDB のスキャン多用

[アンチパターン]
  # テーブル全体をスキャンして条件でフィルタ
  response = dynamodb.scan(
      TableName='Orders',
      FilterExpression=Attr('status').eq('pending')
  )

[問題]
  - テーブル全体をスキャン → コスト爆発(読み取りキャパシティ全消費)
  - テーブルが大きくなるほど遅くなる
  - FilterExpression はスキャン後に適用(コスト削減にならない)

[正しい設計]
  アクセスパターンを先に定義し、GSI/LSI で対応:
  
  GSI: status-createdAt-index
    HASH KEY: status
    RANGE KEY: createdAt
  
  # GSI を使ったクエリ
  response = dynamodb.query(
      TableName='Orders',
      IndexName='status-createdAt-index',
      KeyConditionExpression=Key('status').eq('pending')
  )
  
  → スキャンではなくクエリ → 必要なデータのみ読み取り

Lambda コールドスタート放置

[アンチパターン]
  API Gateway + Lambda(Provisioned Concurrency なし)を P99 SLO < 500ms 要件で使用

[問題]
  - Node.js: コールドスタート 100〜500ms
  - Java: コールドスタート 1〜5秒
  - VPC 内 Lambda: さらに追加で 1〜2秒

[正しい設計]
  選択肢A: Provisioned Concurrency(コストかかるが確実)
    常時暖機状態を維持
    最小: 1〜2 ユニット(スパイク前に手動調整 or Auto Scaling)

  選択肢B: Lambda SnapStart(Java のみ、起動時間を大幅短縮)
    .zip デプロイ時にスナップショット作成
    コールドスタート: 5秒 → 200ms に短縮

  選択肢C: ECS Fargate へ移行
    常時稼働が必要で SLO が厳しい場合

  選択肢D: アーキテクチャで回避
    コールドスタートが許容できる非同期処理にオフロード

ElastiCache の接続数爆発

[アンチパターン]
  Lambda から直接 Redis(ElastiCache)に接続
  高トラフィック時に接続数が急増

[問題]
  Redis のデフォルト最大接続数は 65,000
  Lambda が 1000 同時実行 → 1000 接続が同時に発生
  接続確立のオーバーヘッドでレイテンシが増大

[正しい設計]
  Lambda の場合: ElastiCache Serverless(接続管理をマネージドに)
  ECS/EC2 の場合: 接続プール(valkey-py の ConnectionPool)を適切に設定

  # Lambda 外での初期化(コンテナ再利用で接続を使い回す)
  import redis
  
  # Lambdaのグローバルスコープに配置(ハンドラの外)
  _redis_client = None
  
  def get_redis():
      global _redis_client
      if _redis_client is None:
          _redis_client = redis.Redis(
              host=os.environ['REDIS_HOST'],
              port=6379,
              max_connections=10,  # コンテナあたりの接続数を制限
              decode_responses=True
          )
      return _redis_client

4. コストのアンチパターン

「とりあえず EC2」症候群

[アンチパターン]
  すべてのワークロードを EC2 + Auto Scaling で実装
  理由: 「慣れているから」「何でもできるから」

[問題]
  - OS パッチ適用・セキュリティ対応が必要
  - スケールが遅い(AMI 起動に数分かかる)
  - 利用率が低い時間帯も固定コストが発生

[正しい設計]
  ワークロード別の最適なコンピュート選択:
  
  イベント駆動・散発的処理 → Lambda
  常時起動 HTTP サービス → ECS Fargate
  大規模バッチ → AWS Batch (Fargate Spot)
  GPU 機械学習 → EC2 G インスタンス or SageMaker
  Kubernetes 必須 → EKS
  → EC2 は「上記で対応できない場合」の選択肢

RI/SP 未購入でオンデマンド常用

[アンチパターン]
  本番環境で安定稼働している EC2/RDS/Lambda が
  すべてオンデマンド料金のまま運用

[問題]
  Compute Savings Plans で最大66%の割引機会を逃す
  例: EC2 m5.xlarge を東京で1年24/7稼働
      オンデマンド: $1,314/年
      1年 No Upfront SP: $855/年(35%削減)
      3年 All Upfront SP: $527/年(60%削減)

[正しい設計]
  安定稼働から3ヶ月後に購入判断を行う(パターンが把握できてから)
  まず Compute Savings Plans(最も柔軟)を70%カバレッジから
  RDS は Reserved Instances(1年)で固定

  Cost Explorer の RI/SP Purchase Recommendations を活用

データ転送コストの見落とし

[アンチパターン]
  - 同一リージョン内で複数 AZ にまたがるトラフィックが多い
  - EC2 から S3 へのアクセスにインターネット経由(NAT Gateway 経由)
  - マルチリージョンでデータを頻繁に複製

[問題]
  AZ 間転送: $0.01/GB × 双方向 = $0.02/GB
  NAT Gateway: $0.045/GB(S3 アクセスに不要)
  リージョン間: $0.02/GB(方向による)

[正しい設計]
  S3/DynamoDB へのアクセスは VPC Gateway エンドポイント(無料)
  EC2 → S3 は Interface ではなく Gateway エンドポイント使用
  AZ 間転送はアプリ側の AZ Affinity で最小化
  CloudFront を使用してアウトバウンド転送コストを削減

5. 運用のアンチパターン

監視後付け設計

[アンチパターン]
  本番リリース後に「障害が起きてから」監視を追加する
  アラートがメール垂れ流しで誰も確認しない

[問題]
  - 障害が起きても気づくのが遅い
  - 原因調査に必要なログが取れていない
  - アラートが多すぎて重要なものを見逃す

[正しい設計]
  設計フェーズから監視項目を定義(Well-Architected レビューに組み込む):
  
  必須メトリクス(MVP でも必ず設定):
    可用性: ALB 5XX エラー率 > 1%
    レイテンシ: P99 > 2秒
    エラー: CloudWatch Logs エラーカウント急増
  
  アラート送信先:
    P1/P2 → PagerDuty/Opsgenie(即時電話)
    P3 → Slack(テキスト通知)
  
  1週間以内に誰も対応しないアラートは削除または P3 に格下げ

IaC なしの手動管理

[アンチパターン]
  マネジメントコンソールで手動でリソースを作成・変更
  「ドキュメントに書いてあるから大丈夫」という管理

[問題]
  - ドキュメントと実態がズレる(ドリフト)
  - 環境の再現が困難
  - 誰がいつ何を変えたか追跡できない
  - 開発・検証・本番の差異が増大する

[正しい設計]
  IaC ファースト(コードなしでリソースを作らない):
    AWS CDK(TypeScript/Python)または Terraform を使用
    すべてのリソース変更は PR レビュー必須
    本番直接変更は SCP で Deny し CI/CD 経由のみに制限
  
  既存リソースの IaC 化:
    AWS CloudFormation IaC Generator でドリフトをインポート
    Terraformer(Terraform 用)でリバースエンジニアリング

シークレットローテーション未実装

[アンチパターン]
  DB パスワードを2年以上変更していない
  アクセスキーを削除した従業員の分が残ったまま

[問題]
  - 漏洩した場合の被害が長期間続く
  - 退職者のアクセスが残る
  - コンプライアンス(PCI DSS/SOC2)で指摘

[正しい設計]
  Secrets Manager の自動ローテーション:
    RDS: マネージドローテーション(Lambda 不要)
    その他: カスタム Lambda ローテーター
    周期: 90日以内(PCI DSS 要件)
  
  IAM アクセスキーの定期棚卸し:
    IAM Credential Report を月次確認
    90日以上未使用のキーを無効化 → 削除
    AWS Config ルール: access-keys-rotated でアラーム

6. アーキテクチャのアンチパターン

モノリスをそのままリフト&シフト

[アンチパターン]
  オンプレのモノリシックアプリを EC2 に "そのまま" 移行
  クラウドの恩恵(Auto Scaling / マネージドサービス)を得られない

[問題]
  - クラウドの弾力性・耐障害性を活かせない
  - 運用負荷はオンプレと変わらずコストだけ増加
  - 一部のコンポーネントが全体のボトルネックになる

[正しい設計]
  段階的移行の 3R アプローチ:
  
  Phase 1 Rehost(リホスト):
    まず EC2 に移行してリスクを下げる
    RDS への DB 移行(DMS 活用)

  Phase 2 Replatform(リプラットフォーム):
    DB → RDS/Aurora(マネージド化)
    ファイルストレージ → S3
    セッション → ElastiCache

  Phase 3 Refactor(リファクタ):
    スケール/コストのボトルネックになっている部分を
    マイクロサービス / サーバーレスに分離

同期呼び出しの連鎖

[アンチパターン]
  API → Service A → Service B → Service C → DB
  (全サービスが同期的に直列接続)

[問題]
  - Service B が遅いと全体が遅くなる
  - Service C が落ちると API が 5XX を返す
  - タイムアウトの設定が難しい(最長チェーンに合わせると長すぎる)

[正しい設計]
  読み取り: 同期 OK(即時レスポンスが必要)
    Circuit Breaker パターン(フォールバックを用意)
  
  書き込み: 非同期化
    API → SQS → Lambda(Consumer)→ DB
    失敗時: DLQ → リトライ → アラーム
  
  EventBridge で疎結合化:
    Order Service → EventBridge(OrderCreated)
    ├── Inventory Service(在庫引当)
    ├── Notification Service(メール送信)
    └── Analytics Service(ログ集計)
    → Order Service はイベントを発火するだけ

バックアップなし / 未テスト

[アンチパターン]
  RDS の自動バックアップ保持期間 = 1日(デフォルト)
  「バックアップ取ってます」と言うが復元テストをしたことがない

[問題]
  - RDS バックアップはリストアに1〜4時間かかる(規模による)
  - 保持期間1日 → 翌日に気づいた障害に対応できない
  - 復元テストなしのバックアップは「あると思っていたが実は機能していなかった」リスクがある

[正しい設計]
  AWS Backup でバックアップを一元管理:
    保持期間: RDS 最低7日(本番は35日推奨)
    クロスリージョンバックアップ: 重要データは別リージョンにコピー
    S3: Object Lock で削除・改ざんを防止
  
  定期的な復元テスト(四半期1回):
    RDS: スナップショットからステージング環境を復元
    目標: RTO/RPO の達成を確認して記録に残す

7. アンチパターン早見表

カテゴリ アンチパターン 影響 優先度
Security IAM ワイルドカード権限 高(全権限漏洩) ★★★
Security 認証情報ハードコード 高(資格情報漏洩) ★★★
Security S3 パブリックバケット 高(データ漏洩) ★★★
Reliability 単一AZ構成 高(AZ障害で停止) ★★★
Reliability バックアップ未テスト 高(復旧不能) ★★★
Performance DynamoDB スキャン多用 中(コスト爆発) ★★☆
Performance Lambda コールドスタート放置 中(SLO 違反) ★★☆
Performance N+1 クエリ 中(RDS 負荷増) ★★☆
Cost オンデマンド常用 中(コスト増) ★★☆
Cost NAT 経由 S3 アクセス 低〜中(転送費) ★☆☆
Operations 監視後付け 高(障害気づかず) ★★★
Operations IaC なし手動管理 中(ドリフト) ★★☆
Architecture 同期呼び出し連鎖 中(連鎖障害) ★★☆
Architecture リフト&シフトのみ 低(クラウド恩恵なし) ★☆☆