关于 aws-iam
面向云管理员和开发者的 AWS 身份与访问管理技能,提供实用配置指导。内容涵盖最小权限策略、角色、联合身份、跨账户访问及审计,并附 AWS CLI 示例。
主要功能
- 01最小权限 IAM 策略
- 02角色创建与管理
- 03配置 OIDC 联合身份
- 04权限边界
- 05跨账户角色访问
- 06访问分析与审计
适用场景
- 01为 EC2、Lambda 或 ECS 创建角色
- 02限制 GitHub Actions 权限
- 03通过边界委派访问权限
- 04检查可从外部访问的资源
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill aws-iam安装后在 Claude Code 中输入/aws-iam确认已加载。
详细介绍
AWS IAM
使用权限最小化策略、角色、联合身份验证和权限边界管理 AWS 中的身份与访问权限。
何时使用此技能
- 为 EC2 实例、Lambda 函数或 ECS 任务创建角色
- 编写具有最小权限访问能力的自定义 IAM 策略
- 为 GitHub Actions 或其他 CI/CD 系统设置 OIDC 联合身份验证
- 为委派管理实施权限边界
- 使用 IAM Access Analyzer 和凭证报告审计访问权限
- 使用 AssumeRole 模式配置跨账户访问
- 强制实施 MFA 和会话策略
前提条件
- 已安装并配置 AWS CLI v2
- IAM 权限:
iam:*(或按最小权限原则限定为特定操作) - 对于 OIDC:能够创建身份提供商(
iam:CreateOpenIDConnectProvider) - 拥有 AWS Organizations 访问权限,以使用服务控制策略(SCP)
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 = "*"
}
]
})
}
服务控制策略(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 调用时被拒绝访问 | 缺少策略或策略不正确 | 使用 simulate-principal-policy 进行测试;检查资源 ARN 格式 |
| 无法代入角色 | 信任策略中未包含调用方 | 确认信任策略中的 Principal 与调用方 ARN 相符 |
| OIDC 联合身份验证失败 | 指纹或受众不匹配 | 确认 OIDC 提供商 URL、客户端 ID 列表和条件键 |
| 权限边界阻止操作 | 边界中未包含该操作 | 将该操作添加到边界;有效权限 = 身份策略 AND 边界 |
| 凭证报告显示密钥过期未轮换 | 密钥超过 90 天未轮换 | 轮换密钥;禁用未使用的访问密钥 |
| 创建服务关联角色失败 | 组织 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