0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS IAMを整理した — 最小権限原則とロール設計

0
Posted at

はじめに

AWSを使い始めてから一番「ちゃんと理解しないといけない」と感じたのがIAMだった。

最初はとりあえずAdministratorAccessを付けて動かしていたが、それがどれだけ危険かを理解してから設計を見直した。PHPのバックエンドではあまり意識しなかった「誰が何にアクセスできるか」という概念が、AWSでは全てのサービスの基盤になっている。


IAMの構成要素を整理する

IAMの主な構成要素:

ユーザー(User)
  → 人間が使うアカウント
  → アクセスキーまたはパスワードで認証

グループ(Group)
  → ユーザーをまとめる入れ物
  → グループにポリシーをアタッチすると全メンバーに適用

ロール(Role)
  → AWSサービスや外部IDが使う権限
  → EC2・ECS・Lambdaなどがロールを「引き受ける」

ポリシー(Policy)
  → 何ができるかを定義するJSONドキュメント
  → ユーザー・グループ・ロールにアタッチ

IDプロバイダー(Identity Provider)
  → GitHub ActionsやGoogleなど外部の認証を信頼する

ポリシーの構造

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid":       "AllowS3ReadWrite",       // 任意のID(説明用)
            "Effect":    "Allow",                   // Allow または Deny
            "Action":    [                          // 許可するAPI操作
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource":  [                          // 操作対象のリソース
                "arn:aws:s3:::my-bucket/*"
            ],
            "Condition": {                          // 条件(任意)
                "StringEquals": {
                    "s3:prefix": ["uploads/"]
                }
            }
        }
    ]
}

ARN(Amazon Resource Name)

AWSリソースを一意に識別する文字列。

arn:aws:s3:::my-bucket              → S3バケット
arn:aws:s3:::my-bucket/*            → バケット内の全オブジェクト
arn:aws:iam::123456789012:user/john → IAMユーザー
arn:aws:iam::123456789012:role/my-role → IAMロール
arn:aws:ecs:ap-northeast-1:123456789012:cluster/production → ECSクラスター
arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:production/* → Secrets Manager

*でワイルドカードを使える。arn:aws:s3:::*は全バケットのすべてのオブジェクトという意味になるので、できるだけ絞った指定にする。


最小権限の原則

「必要最小限の権限だけを与える」という考え方。

// 悪い例  全権限を与える
{
    "Effect":   "Allow",
    "Action":   "*",
    "Resource": "*"
}

// 悪い例  S3の全操作を許可
{
    "Effect":   "Allow",
    "Action":   "s3:*",
    "Resource": "*"
}

// 良い例  特定バケットの特定操作のみ
{
    "Effect":   "Allow",
    "Action":   ["s3:GetObject", "s3:PutObject"],
    "Resource": "arn:aws:s3:::my-app-uploads/*"
}

最小権限を実践する手順:

① まず最小の権限でデプロイを試みる
② 権限エラーが出たら必要な権限を追加
③ CloudTrailで実際に使われたAPIを確認して不要な権限を削除

ロールの設計パターン

ECSタスクロール(アプリが使う権限)

// ecs-task-role-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid":       "S3Access",
            "Effect":    "Allow",
            "Action":    [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject",
                "s3:ListBucket"
            ],
            "Resource":  [
                "arn:aws:s3:::my-app-bucket",
                "arn:aws:s3:::my-app-bucket/*"
            ]
        },
        {
            "Sid":       "SecretsManagerAccess",
            "Effect":    "Allow",
            "Action":    ["secretsmanager:GetSecretValue"],
            "Resource":  [
                "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:production/*"
            ]
        },
        {
            "Sid":       "CloudWatchLogsAccess",
            "Effect":    "Allow",
            "Action":    [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource":  "*"
        }
    ]
}

タスク実行ロール(ECSがECRからイメージを取得するために必要)

// ecs-execution-role-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect":   "Allow",
            "Action":   [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage"
            ],
            "Resource": "*"
        },
        {
            "Effect":   "Allow",
            "Action":   [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/ecs/*"
        },
        {
            "Effect":   "Allow",
            "Action":   ["secretsmanager:GetSecretValue"],
            "Resource": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:production/*"
        }
    ]
}

タスクロールとタスク実行ロールを分けるのが重要。

タスク実行ロール (ecsTaskExecutionRole):
  ECSのコントロールプレーンが使う
  ECRからイメージを取得する
  CloudWatch Logsにログを送る
  Secrets Managerから環境変数を取得する

タスクロール (ecsTaskRole):
  コンテナ内のアプリが使う
  S3へのアクセス
  外部APIの呼び出し
  DynamoDBへのアクセスなど

GitHub Actionsロール

// github-actions-role-trust-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect":    "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action":    "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": [
                        "repo:my-org/my-repo:ref:refs/heads/main",
                        "repo:my-org/my-repo:ref:refs/heads/develop"
                    ]
                }
            }
        }
    ]
}
// github-actions-role-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect":   "Allow",
            "Action":   [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:PutImage",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:CompleteLayerUpload"
            ],
            "Resource": "*"
        },
        {
            "Effect":   "Allow",
            "Action":   [
                "ecs:DescribeTaskDefinition",
                "ecs:RegisterTaskDefinition",
                "ecs:UpdateService",
                "ecs:DescribeServices"
            ],
            "Resource": "*"
        },
        {
            "Effect":   "Allow",
            "Action":   ["iam:PassRole"],
            "Resource": [
                "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
                "arn:aws:iam::123456789012:role/ecsTaskRole"
            ]
        }
    ]
}

iam:PassRoleはECSのタスク定義を更新するときに必要。デプロイロールがECSタスクにロールを渡す権限。


ポリシーの種類

管理ポリシー(Managed Policy):
  AWS管理ポリシー  → AWSが作成・管理(例: AmazonS3FullAccess)
  カスタマー管理ポリシー → 自分で作成・複数のロールにアタッチ可能

インラインポリシー(Inline Policy):
  ユーザー/グループ/ロールに直接埋め込む
  1つのエンティティにしか使えない
  → 再利用しないポリシーに使う
# カスタマー管理ポリシーを作成
aws iam create-policy \
    --policy-name ECSTaskPolicy \
    --policy-document file://ecs-task-policy.json

# ロールにアタッチ
aws iam attach-role-policy \
    --role-name ecsTaskRole \
    --policy-arn arn:aws:iam::123456789012:policy/ECSTaskPolicy

IAMユーザーのベストプラクティス

ルートアカウントを使わない

AWSアカウントを作成すると「ルートユーザー」が作られる。
ルートユーザーは全権限を持つが日常的に使ってはいけない。

やること:
  ① ルートユーザーにMFAを設定する
  ② 管理者用のIAMユーザーを作る
  ③ 以降はIAMユーザーで作業する
  ④ ルートユーザーは請求設定の変更など必要な場面だけ使う

アクセスキーを使わない

アクセスキーは漏洩すると即悪用される。
GitHubに誤ってコミットした瞬間にAWSが検知してメールが来る(経験済み)。

アクセスキーの代替:
  EC2/ECS/Lambda → IAMロール(自動で取得)
  GitHub Actions → OIDC(前述)
  ローカル開発   → aws configure または aws-vault

やむを得ずアクセスキーを使う場合:
  → 必要最小限の権限のみ付与
  → 定期的にローテーション(90日以内)
  → 使わなくなったら即削除
# アクセスキーの一覧確認
aws iam list-access-keys --user-name my-user

# 最終使用日時の確認(使われていないキーを発見)
aws iam get-access-key-last-used \
    --access-key-id AKIAIOSFODNN7EXAMPLE

Permission Boundary

IAMユーザーやロールに設定できる権限の上限。

// permission-boundary.json
// このポリシーを境界として設定すると、
// S3とCloudWatchのみしか許可できなくなる

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect":   "Allow",
            "Action":   ["s3:*", "logs:*"],
            "Resource": "*"
        }
    ]
}
# ロールの作成時にPermission Boundaryを設定
aws iam create-role \
    --role-name limited-role \
    --assume-role-policy-document file://trust-policy.json \
    --permissions-boundary arn:aws:iam::123456789012:policy/PermissionBoundary

開発者にIAMロールの作成権限を与えるが、自分より強い権限のロールを作れないようにする場合に使う。


SCPでOrganization全体に制限をかける

複数のAWSアカウントを管理する場合、AWS OrganizationsのSCP(Service Control Policy)で全アカウントに制限をかけられる。

// 特定リージョン以外では全操作を禁止
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect":   "Deny",
            "Action":   "*",
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "aws:RequestedRegion": [
                        "ap-northeast-1",
                        "us-east-1"  // グローバルサービス用
                    ]
                }
            }
        }
    ]
}

CloudTrailでIAMの操作を監視する

import boto3

cloudtrail = boto3.client('cloudtrail', region_name='ap-northeast-1')

# 特定のユーザーの操作履歴を取得
response = cloudtrail.lookup_events(
    LookupAttributes=[
        {
            'AttributeKey':   'Username',
            'AttributeValue': 'my-user'
        }
    ],
    MaxResults = 10,
)

for event in response['Events']:
    print(f"{event['EventTime']} - {event['EventName']} - {event['Username']}")
# IAM関連の操作履歴をフィルタ
aws cloudtrail lookup-events \
    --lookup-attributes AttributeKey=EventSource,AttributeValue=iam.amazonaws.com \
    --query 'Events[*].{Time:EventTime,Event:EventName,User:Username}' \
    --output table

「誰がどのIAMロールを変更したか」を追跡できる。セキュリティインシデント発生時の調査に使う。


実務でよくあるIAMのミス

① ワイルドカード(*)を使いすぎる
   → 具体的なリソースARNを指定する

② 開発用のAdministratorAccessを本番に流用する
   → 環境ごとに権限を分ける

③ アクセスキーを.envやコードに書く
   → IAMロールやOIDCを使う

④ 使っていないユーザー/ロール/ポリシーを放置する
   → 定期的に棚卸しする

⑤ ロールにポリシーを直接書く(インラインポリシーの濫用)
   → 再利用するならカスタマー管理ポリシーにする

⑥ タスクロールとタスク実行ロールを混同する
   → ECSの場合は必ず分ける

⑦ 権限を追加するだけで削除しない
   → IAM Access Analyzerで不要な権限を検出する

IAM Access Analyzerの活用

# Access Analyzerを有効化
aws accessanalyzer create-analyzer \
    --analyzer-name my-analyzer \
    --type ACCOUNT

# 外部からアクセス可能なリソースの一覧
aws accessanalyzer list-findings \
    --analyzer-name my-analyzer \
    --filter '{"status": {"eq": ["ACTIVE"]}}'
# 実際に使用されていない権限を分析
aws iam generate-service-last-accessed-details \
    --arn arn:aws:iam::123456789012:role/my-role

# 結果を取得
aws iam get-service-last-accessed-details \
    --job-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
    --query 'ServicesLastAccessed[?TotalAuthenticatedEntities==`0`]'

使われていないサービスへの権限を検出して削除できる。


まとめ

  • ポリシーはEffect・Action・Resourceの3要素で構成される
  • 最小権限の原則を守り*の使用を最小化する
  • ECSはタスクロール(アプリ)とタスク実行ロール(ECS基盤)を分ける
  • GitHub ActionsはOIDCを使ってアクセスキーを排除する
  • ルートアカウントにMFAを設定し日常的に使わない
  • アクセスキーはIAMロールで代替できる場合は使わない
  • CloudTrailでIAM操作を監視する
  • IAM Access Analyzerで不要な権限を定期的に棚卸しする

AWSを触り始めた当初は「とりあえず動けばいい」でAdministratorAccessを付けていたが、最小権限を意識してから「このサービスに必要な権限は何か」を考える習慣がついた。IAMは地味だが全サービスの基盤なので、最初にちゃんと理解しておいてよかった。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?