AWS基礎 #6 セキュリティの基本 — MFA、キーローテーション、最小権限

読了 11分

#2 IAM で権限モデルを、#5 で SSO まで見ました。この記事はその上に 運用で通用するセキュリティのガードレール を一気に整理します。

AWS のセキュリティ事故の 90% は次のいずれかです。

  1. ルート / ユーザーパスワードの窃取 (フィッシング) — MFA がないため
  2. アクセスキーが git / Slack / ログに漏洩
  3. 広すぎる権限が侵害時に被害を膨らませる
  4. CloudTrail / GuardDuty が OFF で事件を発見できない

この 4 つにガードレールを敷けば事故確率は 1 桁台に落ちます。

MFA — もっとも大きな 1 つ #

パスワード 1 行で終わる認証は 2026 年の運用水準ではありません。 フィッシング 1 回でパスワードは流れます。MFA (Multi-Factor Authentication) は 2 番目の要素 (普通はスマホアプリ) の 6 桁コードを追加で要求します。

MFA の種類 #

種類何か推奨
Virtual MFA (TOTP)スマホアプリ (Google Authenticator、1Password、Authy)標準 — ほぼすべてのケース
ハードウェア MFAYubiKey のような USB キールート / 高権限 — 最強
U2F / WebAuthnブラウザ + ハードウェアキー運用認証の格上げ
SMSテキストメッセージ使用禁止 (SIM swap 攻撃)

ルートは ハードウェア MFA が理想、一般ユーザーは virtual MFA で十分。

ルートユーザーの MFA 有効化 #

登録直後に最初の作業として即実施。

ルート MFA
コンソール (ルートログイン) → 右上ユーザーメニュー → Security credentials
→ Multi-factor authentication (MFA) → Assign MFA device
→ Virtual MFA / Hardware MFA を選択
→ QR コードをスマホアプリでスキャン
→ 連続して 2 つのコードを入力 (アプリは 30 秒ごとに新コード)

以降ルートログインのたびにパスワード + 6 桁コード。

IAM ユーザーに MFA 強制 #

ルートだけ ON にするのは不十分。すべての IAM ユーザーに強制。2 通りの方法。

方法 1: ポリシーで — 「MFA セッションでないとほぼすべてのアクションを拒否」

IAM ユーザー MFA 強制ポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSelfManageCredentials",
      "Effect": "Allow",
      "Action": [
        "iam:ChangePassword",
        "iam:CreateVirtualMFADevice",
        "iam:EnableMFADevice",
        "iam:GetUser",
        "iam:ListMFADevices",
        "iam:ResyncMFADevice"
      ],
      "Resource": [
        "arn:aws:iam::*:user/${aws:username}",
        "arn:aws:iam::*:mfa/${aws:username}"
      ]
    },
    {
      "Sid": "DenyAllExceptListedIfNoMFA",
      "Effect": "Deny",
      "NotAction": [
        "iam:CreateVirtualMFADevice",
        "iam:EnableMFADevice",
        "iam:GetUser",
        "iam:ListMFADevices",
        "iam:ResyncMFADevice",
        "iam:ChangePassword",
        "sts:GetSessionToken"
      ],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": { "aws:MultiFactorAuthPresent": "false" }
      }
    }
  ]
}

このポリシーをすべてのユーザーが所属するグループに付ければ MFA なしでは事実上何もできなくなります。MFA 登録だけは例外です。

方法 2: SSO (#5)

IAM Identity Center ユーザーにはコンソール / CLI ログイン時に MFA が自動で強制されます。ポリシーを書く必要なし。

初回ログイン時 MFA 登録の強制フロー #

新規 IAM ユーザーが初めてログイン → 上のポリシーで MFA 登録以外は何もできない → 自分で MFA 登録 → その後は正常に使えます。この流れが標準です。

アクセスキーローテーション — 90 日が標準 #

#4 で見たアクセスキー。このキーは 時間が経つと漏洩リスクが累積 します。

ローテーションポリシー #

項目推奨ローテーション周期
ユーザーアクセスキー90 日
CI / CD のキー60 日 (または OIDC に移行)
サービスアカウントキー30~60 日
一時認証情報 (SSO / Role)ローテーション不要 (自動で短期発行)

ローテーション手順 #

キーを 1 度に 2 つ持てる IAM の特性を活用します。

安全なローテーション手順
# 1) 新キー発行 (これでアクティブキーが 2 つ)
aws iam create-access-key --user-name curtis

# 2) すべての環境で新キーに置換 (CI 環境変数、~/.aws/credentials など)

# 3) 数日モニタリング — 古いキーの使用がないか
#    CloudTrail または IAM credential report で確認

# 4) 古いキー無効化 (削除はまだしない — ロールバック用)
aws iam update-access-key --user-name curtis --access-key-id AKIA-OLD --status Inactive

# 5) 1 週間さらにモニタ → 本当に使われていなければ削除
aws iam delete-access-key --user-name curtis --access-key-id AKIA-OLD

IAM Credential Report — ローテーション点検 #

CSV 1 枚ですべてのユーザーのキー / MFA / 活動状態を見ます。

Credential Report の取得
aws iam generate-credential-report
aws iam get-credential-report --query Content --output text | base64 -d > report.csv
report.csv の興味深いカラム
user
mfa_active
access_key_1_active
access_key_1_last_rotated
access_key_1_last_used_date
access_key_2_active
access_key_2_last_rotated
password_last_used

90 日を超えたキー、MFA を有効化していないユーザー、1 ヶ月未使用ユーザー — 一目で見えます。

漏洩キー発見時 #

コードにキーを push してしまった場合、ボットが発見するまで通常は数分単位です。

即やるべきこと (時間順) #

0 分 — キー無効化
aws iam update-access-key --user-name <user> --access-key-id <キーID> --status Inactive
5 分 — 新キー発行、古いキーはそのまま無効
aws iam create-access-key --user-name <user>
10 分 — 古いキーの使用痕跡確認 (CloudTrail)
# コンソール → CloudTrail → Event history
# AccessKeyId で検索 → 意図しない使用があるか
30 分 — 古いキー削除
aws iam delete-access-key --user-name <user> --access-key-id <キーID>
git history のクリーンアップ
# BFG Repo-Cleaner または git filter-repo で history からキーを除去
# (すでに push 済みなら history のクリーンアップだけでは安全 X — キー削除の方が大事)

AWS が自動で助けてくれるしくみ #

AWS は GitHub などの公開リポジトリをスキャン していて、漏洩キーを発見すると:

  • ユーザーに即メール
  • 一部のケースでは自動でキーを無効化 + ポリシーをアタッチ

これは補助のセーフティネット — 自分で発見する方が速いです。

IAM Access Analyzer — 広すぎる権限を見つける #

自アカウントのポリシー / リソースポリシー (S3 バケットポリシー、KMS キーポリシーなど) を分析して 外部からアクセス可能なところ を見つけるツールです。無料です。

有効化 #

有効化
コンソール → IAM → Access Analyzer → Create analyzer
- Type: Account / Organization
- Name: my-account-analyzer

有効化後 24 時間以内に 外部アクセス可能なリソース のリストが出ます。

何を拾ってくれるか #

リソースリスク
S3 バケット — public read誰でもオブジェクト読み取り
S3 バケット — 別アカウントに権限意図した設定か確認が必要
KMS キー — 外部使用暗号化キーの漏洩
IAM Role — 外部 trust別アカウントが借りられる
Lambda — 外部呼び出し権限誰でも呼び出し可能
RDS スナップショット / SQS / SNS / Secrets Manager / EBS / ECR — publicデータ / メッセージ漏洩

ポリシー検証 #

新しいポリシーを作るとき Access Analyzer が 推奨事項 も見せてくれます。

  • 使われていない権限
  • 広すぎるワイルドカード
  • 条件のない場合への追加推奨

Action Last Accessed — 未使用権限を見つける #

各 IAM ユーザー / ロールについて 最後に使ったアクション を見せてくれます。90 日未使用の権限は絞り込み候補。

CLI で
aws iam generate-service-last-accessed-details --arn arn:aws:iam::123:role/MyRole
# (しばらくして)
aws iam get-service-last-accessed-details --job-id ...

最小権限 — 通用するパターン #

「必要なだけ、必要なところだけ。」理想は簡単ですが、運用でどう実践するかが鍵です。

パターン 1: 広く始めて → 絞る #

最初から完璧な権限を組むのは難しいです。次の流れが現実的。

  1. 開始は PowerUserAccess / 各サービスの *FullAccess
  2. 1 週間運用後に Access Analyzer の Action Last Accessed を確認
  3. 使っていないサービス / アクションを除去
  4. ワイルドカードを ARN に絞る
  5. 条件 (Condition) 追加

このサイクルを四半期ごとに繰り返します。

パターン 2: ユーザー ↔ ロール分離 #

#2 のパターン の再確認。

  • 人 = SSO (#5)
  • マシン = Role (インスタンスプロファイル、実行ロール、OIDC)
  • CI/CD = OIDC + Role (GitHub Actions、GitLab)

永続アクセスキーがほぼ消える構造です。

パターン 3: Permission Boundary (権限境界) #

「このユーザーは何をしてもこの限度内だけ。」新人開発者に IAM 権限を与えつつ、彼が新しいポリシー / ユーザーを作って自分の権限を上げる事故を遮断。

権限境界の形
{
  "Effect": "Allow",
  "Action": [
    "ec2:*",
    "s3:*",
    "rds:*",
    "logs:*"
  ],
  "Resource": "*",
  "Condition": {
    "StringEquals": { "aws:RequestTag/env": "dev" }
  }
}

この境界が付いたユーザーは dev 環境のリソース以外は作れません。自分のポリシーでも同じです。

パターン 4: 環境分離 #

  • アカウント分離 (Organizations) — もっとも強い防御線
  • VPC 分離 — 同じアカウントでも prod VPC と dev VPC を分離 (中級 #1)
  • タグ分離env=prod タグで権限 / コスト分離 (#3 のタグ戦略)

パターン 5: Break-glass ロール #

平時は ReadOnly のみ、事故時に一時的に Admin に格上げ。SSO Permission Set を 2 つに分離。

項目平時事故時
使用ReadOnlyBreak-glass-Admin (1 時間)
通知Slack チャンネルへ自動通知
監査CloudTrail ですべてのアクション記録

CloudTrail — 誰が何をしたか #

CloudTrail は アカウント内のすべての API 呼び出し を記録します。登録直後に自動で有効化 (過去 90 日のイベントを無料で照会)。運用用は Trail を作って S3 に永続保存。

登録直後の点検 #

有効化確認
コンソール → CloudTrail → Trails
→ Multi-region Trail を 1 つ作成 (運用標準)
- 名前: my-trail
- Storage: 新規 S3 バケット
- Log file SSE-KMS encryption: ON
- Log file validation: ON (改ざん検知)

CloudTrail の 2 種類のイベント #

種類何かコスト
Management eventsAPI 呼び出し (RunInstances、DeleteBucket など)無料 (1 回)
Data eventsS3 オブジェクトアクセス、Lambda 呼び出しなど有料 (量が多い)

ほとんどの Trail は management のみ。data events は特定のバケット / 関数だけに ON。

よく使うクエリ #

コンソール Event history で検索:

  • AccessKeyId — 漏洩キー使用の痕跡
  • UserName — あるユーザーがやったこと
  • EventName — ConsoleLoginDeleteBucketRunInstances
  • 時間範囲

CloudTrail Lake または Athena で SQL 分析も可能です (大きな組織)。

GuardDuty — 脅威検知の自動化 #

GuardDuty は CloudTrail / VPC Flow Logs / DNS ログを機械学習で分析して怪しい活動を拾ってくれます。

拾ってくれる例 #

パターン説明
EC2 が異常な地域と通信侵入 / C&C
アクセスキーが異常な地域で使用キー漏洩後の使用
仮想通貨マイニングのトラフィック侵入後のマイニング
EC2 の異常なポートスキャン横移動
Tor exit node との通信怪しいトラフィック
IAM ユーザーの異常行動認証情報の盗用

有効化 #

有効化
コンソール → GuardDuty → Get started → Enable
- 30 日無料評価
- 無料評価後はデータ量ベース課金 (普通 \$10~50 / 月 / 小さな運用)

運用段階では 必ず ON。価格対比で拾ってくれる事故が大きいです。

Security Hub — セキュリティ状態の統合 #

複数のセキュリティツールの結果を 1 ヶ所にまとめます。CIS Benchmark、AWS Foundational Security Best Practices などの標準点検を自動実行。

有効化
コンソール → Security Hub → Enable
- 推奨される標準すべてを ON
- GuardDuty / Access Analyzer / Inspector の結果が統合される

登録直後にはやや過剰です — 1 四半期後にリソースが一定水準以上になったら ON。

よく出会う事故事例 #

事例 1: GitHub にアクセスキー push → 仮想通貨マイニング #

もっともありがちなシナリオ。分単位でボット発見、時間単位でコスト累積。

対応: 即キー無効化 → 新キー → CloudTrail で使用痕跡 → 可能なら口座自体を隔離。請求紛争時には AWS サポートに連絡 — ほとんどの無料利用枠の事故は遡及免除 (繰り返しは不可)。

予防: pre-commit hook (gitleakstruffleHog)、GitHub secret scanning、ローカルにキー自体を置かない (SSO)。

事例 2: 広すぎる S3 バケットポリシー #

「会社の人みんなが見られるように」しようと Principal: "*" 追加 → public read になる → 検索エンジンにインデックス。

対応: Access Analyzer が拾ってくれる。S3 Block Public Access がアカウント / バケット単位で強制。

予防: S3 Block Public Access を常に ON、本当に public が必要な場合は CloudFront + Origin Access Control パターンです。

事例 3: MFA なしルートパスワードのフィッシング #

「AWS 請求アラーム」の偽メール → 偽ログインページ → パスワード入力。ルート MFA がなければそのまま侵害。

対応: パスワード即変更、すべてのリソース点検、AWS サポート連絡。

予防: ルート MFA 必須 (理想はハードウェア)、日常作業は IAM / SSO で。

事例 4: 退職者のアクセスキーが生きている #

退職処理後も IAM ユーザー / キーがそのまま。数ヶ月後に事故。

対応: 即ユーザー無効化 / 削除 + Trail 点検。

予防: 退職チェックリストに IAM 整理を含める。SSO なら IdP で無効化 1 ヶ所で完了。

事例 5: CloudTrail が OFF #

侵害調査を始めようとしたら事件時刻のログがない — 誰かが (意図的に) Trail を OFF にしたか最初から ON にしていなかった。

対応: もう遅い。可能なら他のログ (CloudWatch、GuardDuty findings) で部分復元。

予防: Trail 有効化 + Log file validation + S3 オブジェクトロック。SCP (Service Control Policy) で CloudTrail 無効化自体を拒否。

よく出会う落とし穴 #

1) MFA だけ ON にして終わり #

MFA が ON でもアクセスキーが漏れればキーはそのまま動作します (CLI 呼び出しは MFA と無関係、#4 の認証情報チェーン)。キーも併せてケアするか、SSO でキー自体を減らします。

2) ローテーションを約束だけして実施しない #

Credential Report で定期点検を自動化。90 日を超えたキーは Slack 通知。

3) iam:PassRole の広範な許可 #

iam:PassRole = * は事実上の権限昇格が可能です。Role ARN で絞ります。

4) 条件を強くしすぎて → 自分が締め出される #

aws:SourceIp で社内 IP のみ許可したのに自分が外出中ということもあります。コンソール IP ガードは最後に 適用し、迂回路 (VPN / 緊急ユーザー) を残します。

5) GuardDuty を OFF にする #

「コストもったいない」で OFF にする場合がありますが、1 件の事故が GuardDuty の 1 年分のコストより大きいです。運用では常に ON にします。

6) Security Hub の発見を見ない #

ON にして通知を見ないなら意味がありません。週次レビューや EventBridge で Slack に通知します。

まとめ #

今回つかんだもの:

  • MFA — すべてのユーザーに必須。ルートはできればハードウェア、一般は virtual TOTP。SMS は禁止
  • MFA 強制ポリシー — IAM ユーザーにポリシーで強制。SSO なら自動
  • アクセスキーローテーション 90 日 — 新キー発行 → 置換 → 旧キー無効化 → 1 週間後に削除。Credential Report で点検
  • 漏洩時 — 即無効化、CloudTrail で使用痕跡、新キー、その後削除
  • IAM Access Analyzer — 外部アクセス可能リソース、ポリシー検証、Action Last Accessed (未使用権限)
  • 最小権限パターン — 広く始めて絞る、ユーザー / ロール分離、権限境界、環境分離、Break-glass
  • CloudTrail — multi-region Trail 1 つ + S3 + log validation。SCP で無効化を遮断
  • GuardDuty — 機械学習による脅威検知。運用必須
  • Security Hub — 標準点検の統合。リソースが一定水準以上で
  • 事故事例 — キー push、広い S3 ポリシー、ルートフィッシング、退職者キー、Trail OFF
  • 落とし穴 — MFA だけで安全 X、ローテーション約束のみ、PassRole ワイルドカード、強すぎる IP 条件、GuardDuty OFF、Hub 結果未管理

次回 — CloudWatch #

このシリーズの最後です。すべての運用の目である CloudWatch を整理します。

#7 CloudWatch 入門 — ログ / メトリクス では Logs / Metrics / Alarms / Dashboards の構成、ロググループと retention、Metric Filter、Logs Insights クエリの基礎まで扱います。

X