aws-iam について
クラウド管理者や開発者向けに、AWSのアイデンティティとアクセス管理を扱う実務スキルです。最小権限ポリシー、ロール、フェデレーション、クロスアカウントアクセス、監査をAWS CLIの例とともに説明します。
主な機能
- 01最小権限IAMポリシー
- 02ロールの作成と管理
- 03OIDCフェデレーションの設定
- 04アクセス許可境界
- 05クロスアカウントロールアクセス
- 06アクセス分析と監査
活用シーン
- 01EC2、Lambda、ECS用ロールの作成
- 02GitHub Actionsの権限制限
- 03境界によるアクセス権の委任
- 04外部公開リソースの確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill aws-iamインストール後、Claude Code で/aws-iamを入力して読み込まれたか確認します。
詳細
AWS IAM
最小権限のポリシー、ロール、フェデレーション、権限境界を使って、AWS の ID とアクセスを管理します。
このスキルを使用する場面
- EC2 インスタンス、Lambda 関数、ECS タスク用のロールを作成する
- 最小権限のアクセスを許可するカスタム IAM ポリシーを作成する
- GitHub Actions やその他の CI/CD システム向けに OIDC フェデレーションを設定する
- 委任管理用の権限境界を実装する
- IAM Access Analyzer と認証情報レポートを使ってアクセスを監査する
- Assume-role パターンを使ってクロスアカウントアクセスを設定する
- MFA とセッションポリシーを適用する
前提条件
- AWS CLI v2 がインストールされ、設定されていること
- IAM 権限:
iam:*(または最小権限のため、特定のアクションに範囲を限定) - OIDC の場合:ID プロバイダーを作成する権限(
iam:CreateOpenIDConnectProvider) - Service Control Policy(SCP)用の AWS Organizations アクセス権
IAM ポリシーの構造
すべての IAM ポリシーは同じ JSON 構造に従います。必要最小限のアクションとリソースを常に指定してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3ReadWrite",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-app-bucket",
"arn:aws:s3:::my-app-bucket/*"
],
"Condition": {
"StringEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
},
{
"Sid": "DenyUnencryptedUploads",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-app-bucket/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
}
]
}
ロールの作成と管理
# Create an EC2 instance role with trust policy
aws iam create-role \
--role-name EC2AppRole \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}' \
--tags '[{"Key":"Team","Value":"platform"},{"Key":"Environment","Value":"production"}]'
# Create and attach an inline policy
aws iam put-role-policy \
--role-name EC2AppRole \
--policy-name s3-access \
--policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::my-app-bucket/*"
}]
}'
# Attach a managed policy
aws iam attach-role-policy \
--role-name EC2AppRole \
--policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
# Create instance profile and associate the role
aws iam create-instance-profile --instance-profile-name EC2AppProfile
aws iam add-role-to-instance-profile \
--instance-profile-name EC2AppProfile \
--role-name EC2AppRole
# Create a Lambda execution role
aws iam create-role \
--role-name LambdaExecRole \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
aws iam attach-role-policy \
--role-name LambdaExecRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
クロスアカウントアクセス
# In Account B: create role that Account A can assume
aws iam create-role \
--role-name CrossAccountReadRole \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::111111111111:root"},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {"sts:ExternalId": "unique-external-id-12345"}
}
}]
}'
# In Account A: assume the role
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/CrossAccountReadRole \
--role-session-name cross-account-session \
--external-id unique-external-id-12345
# Use the temporary credentials
export AWS_ACCESS_KEY_ID="ASIAXXX"
export AWS_SECRET_ACCESS_KEY="xxx"
export AWS_SESSION_TOKEN="xxx"
GitHub Actions 用 OIDC フェデレーション
# Create the GitHub OIDC identity provider
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com \
--thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1"
# Create a role for GitHub Actions with repo-scoped trust
aws iam create-role \
--role-name GitHubActionsDeployRole \
--assume-role-policy-document '{
"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"
}
}
}]
}'
# Attach deployment permissions to the role
aws iam attach-role-policy \
--role-name GitHubActionsDeployRole \
--policy-arn arn:aws:iam::123456789012:policy/DeploymentPolicy
GitHub Actions ワークフローでの使用方法:
# .github/workflows/deploy.yml
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
aws-region: us-east-1
- run: aws sts get-caller-identity
権限境界
# Create a permission boundary policy
aws iam create-policy \
--policy-name DeveloperBoundary \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowedServices",
"Effect": "Allow",
"Action": [
"s3:*",
"lambda:*",
"dynamodb:*",
"sqs:*",
"sns:*",
"logs:*",
"cloudwatch:*",
"ecr:*",
"ecs:*"
],
"Resource": "*"
},
{
"Sid": "DenyIAMChanges",
"Effect": "Deny",
"Action": [
"iam:CreateUser",
"iam:DeleteUser",
"iam:CreateRole",
"iam:DeleteRole",
"iam:AttachRolePolicy",
"iam:PutRolePermissionsBoundary",
"iam:DeleteRolePermissionsBoundary"
],
"Resource": "*"
},
{
"Sid": "DenyOutsideRegion",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["us-east-1", "us-west-2"]
},
"ForAnyValue:StringNotLike": {
"aws:PrincipalArn": "arn:aws:iam::*:role/admin-*"
}
}
}
]
}'
# Create a role with the permission boundary
aws iam create-role \
--role-name DeveloperRole \
--assume-role-policy-document file://trust-policy.json \
--permissions-boundary "arn:aws:iam::123456789012:policy/DeveloperBoundary"
IAM Access Analyzer と監査
# Create an IAM Access Analyzer
aws accessanalyzer create-analyzer \
--analyzer-name account-analyzer \
--type ACCOUNT
# List findings (externally accessible resources)
aws accessanalyzer list-findings \
--analyzer-arn arn:aws:access-analyzer:us-east-1:123456789012:analyzer/account-analyzer
# Generate credential report
aws iam generate-credential-report
aws iam get-credential-report --output text --query Content | base64 -d > credential-report.csv
# Find users with console access but no MFA
aws iam list-users --query "Users[].UserName" --output text | while read user; do
mfa=$(aws iam list-mfa-devices --user-name "$user" --query "MFADevices" --output text)
if [ -z "$mfa" ]; then
echo "NO MFA: $user"
fi
done
# List all policies attached to a role
aws iam list-attached-role-policies --role-name EC2AppRole
aws iam list-role-policies --role-name EC2AppRole
# Get the last-accessed services for a role
aws iam generate-service-last-accessed-details --arn arn:aws:iam::123456789012:role/EC2AppRole
# Then retrieve results with the returned JobId
aws iam get-service-last-accessed-details --job-id "job-id-from-above"
# Simulate a policy to test access
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/EC2AppRole \
--action-names s3:GetObject s3:PutObject \
--resource-arns arn:aws:s3:::my-app-bucket/data.json
OIDC を使用した Terraform IAM ロール
# OIDC provider for GitHub Actions
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}
# Role for GitHub Actions
resource "aws_iam_role" "github_actions" {
name = "GitHubActionsDeployRole"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.github.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
}
StringLike = {
"token.actions.githubusercontent.com:sub" = "repo:my-org/my-repo:*"
}
}
}]
})
permissions_boundary = aws_iam_policy.boundary.arn
}
resource "aws_iam_role_policy_attachment" "deploy" {
role = aws_iam_role.github_actions.name
policy_arn = aws_iam_policy.deployment.arn
}
# Permission boundary
resource "aws_iam_policy" "boundary" {
name = "DeveloperBoundary"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AllowedServices"
Effect = "Allow"
Action = ["s3:*", "lambda:*", "dynamodb:*", "ecs:*", "logs:*"]
Resource = "*"
},
{
Sid = "DenyIAMEscalation"
Effect = "Deny"
Action = ["iam:CreateUser", "iam:CreateRole", "iam:AttachRolePolicy"]
Resource = "*"
}
]
})
}
Service Control Policy(Organizations)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRootAccount",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::*:root"
}
}
},
{
"Sid": "RequireIMDSv2",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotEquals": {
"ec2:MetadataHttpTokens": "required"
}
}
},
{
"Sid": "DenyRegionsOutsideUS",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["us-east-1", "us-west-2"]
},
"ForAnyValue:StringNotLike": {
"aws:PrincipalArn": ["arn:aws:iam::*:role/OrganizationAdmin"]
}
}
}
]
}
トラブルシューティング
| 問題 | 原因 | 解決方法 |
|---|---|---|
| API 呼び出しで Access Denied が発生する | ポリシーが不足しているか、正しくない | simulate-principal-policy を使ってテストし、リソース ARN の形式を確認します |
| ロールを引き受けられない | 信頼ポリシーに呼び出し元が含まれていない | 信頼ポリシーの Principal が呼び出し元の ARN と一致していることを確認します |
| OIDC フェデレーションに失敗する | サムプリントまたはオーディエンスが一致しない | OIDC プロバイダーの URL、クライアント ID リスト、条件キーを確認します |
| 権限境界によってアクションがブロックされる | 境界にアクションが含まれていない | 境界にアクションを追加します。有効な権限 = ID ポリシー AND 権限境界 |
| 認証情報レポートに古いキーが表示される | 90 日以上キーがローテーションされていない | キーをローテーションし、使用されていないアクセスキーを無効にします |
| サービスリンクロールの作成に失敗する | Organization SCP が iam:CreateServiceLinkedRole をブロックしている | 対象のサービスに対する例外を SCP に追加します |
| クロスアカウントのロール引き受けに失敗する | ExternalId がないか、アカウントが正しくない | ExternalId が一致していることを確認し、Principal のアカウント番号を確認します |
| MFA 条件が適用されない | ポリシーに条件キーがない | aws:MultiFactorAuthPresent 条件を追加します |
関連スキル
- terraform-aws - IAM リソースの IaC デプロイ
- aws-ec2 - インスタンスプロファイルとロール
- aws-lambda - Lambda 実行ロール
- aws-ecs-fargate - ECS タスクロールと実行ロール
- access-review - アクセス監査とガバナンス
コメント
Markdown 対応