本文作者: 封磊
Eclicktech SA | AWS Community Builder DevTool | AWS UGL | 亚马逊云科技云博主
阿里云&InfoQ&CSDN签约作者

前言
经过前五篇文章的学习,我们已经构建了一个功能完整的Web应用架构:EC2运行应用,RDS管理数据,S3存储资源,CloudFront提供全球加速。但是,随着架构的复杂化,一个关键问题浮现出来:如何安全地管理这些资源的访问权限?
想象一下:开发人员需要访问S3上传文件,运维人员需要管理EC2实例,财务人员需要查看账单,但每个人都不应该有超出职责范围的权限。今天,让我们请出"身份安全卫士"——AWS IAM(Identity and Access Management),为我们的云端架构构建一道坚固的安全防线。
权限管理的现实挑战
在没有合理权限管理的情况下,我们可能面临这些问题:
安全风险
# 危险的做法:使用root账户进行日常操作
aws s3 ls --profile root
# 风险:root账户拥有所有权限,一旦泄露后果严重
# 危险的做法:共享访问密钥
export AWS_ACCESS_KEY_ID="AKIA..."
export AWS_SECRET_ACCESS_KEY="..."
# 风险:密钥泄露、难以追踪操作来源
# 危险的做法:过度授权
aws iam attach-user-policy \
--user-name developer \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess
# 风险:开发人员获得管理员权限,可能误操作生产环境
管理复杂性
- 权限混乱:不清楚谁有什么权限
- 难以审计:无法追踪谁做了什么操作
- 权限膨胀:用户权限只增不减,越来越大
- 合规困难:无法满足安全合规要求
运维困扰
- 密钥管理:大量密钥难以管理和轮换
- 权限故障:权限不足导致应用无法正常工作
- 临时访问:难以为临时需求提供合适的权限
什么是AWS IAM?
AWS IAM是AWS的身份和访问管理服务,就像企业的"门禁系统",控制谁可以访问什么资源,以及可以执行什么操作。
IAM核心概念
用户(Users)
- 代表个人或应用程序
- 拥有永久的访问凭证
- 可以直接附加权限策略
组(Groups)
- 用户的集合
- 简化权限管理
- 用户可以属于多个组
角色(Roles)
- 临时身份
- 可以被用户、服务或外部身份承担
- 基于信任关系工作
策略(Policies)
- 定义权限的JSON文档
- 可以附加到用户、组或角色
- 支持精细的权限控制
AWS安全模型
AWS共享责任模型:
AWS负责:
├── 物理安全(数据中心、硬件)
├── 网络基础设施安全
├── 虚拟化层安全
└── 服务本身的安全
客户负责:
├── 操作系统安全(EC2)
├── 应用程序安全
├── 数据加密
├── 网络配置(VPC、安全组)
└── 身份和访问管理(IAM)
IAM最佳实践原则
1. 最小权限原则
只授予完成任务所需的最小权限:
// 错误示例:过度授权
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
// 正确示例:精确权限
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-wordpress-assets-20231201/wp-content/uploads/*"
}
]
}
2. 使用组管理权限
通过组简化权限管理:
# 创建开发组
aws iam create-group --group-name Developers
# 创建运维组
aws iam create-group --group-name Operations
# 创建只读组
aws iam create-group --group-name ReadOnly
3. 启用MFA多因素认证
为敏感操作添加额外安全层:
# 为用户启用MFA
aws iam enable-mfa-device \
--user-name john.doe \
--serial-number arn:aws:iam::123456789012:mfa/john.doe \
--authentication-code1 123456 \
--authentication-code2 789012
4. 定期轮换访问密钥
# 创建新的访问密钥
aws iam create-access-key --user-name john.doe
# 停用旧的访问密钥
aws iam update-access-key \
--user-name john.doe \
--access-key-id AKIA... \
--status Inactive
# 删除旧的访问密钥
aws iam delete-access-key \
--user-name john.doe \
--access-key-id AKIA...
实战案例:为WordPress架构配置IAM
让我们为之前搭建的WordPress架构配置合理的IAM权限体系。
步骤1:创建用户组
开发人员组
# 创建开发人员组
aws iam create-group --group-name WordPress-Developers
# 创建开发人员策略
cat > developer-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2ReadAccess",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeImages",
"ec2:DescribeSnapshots",
"ec2:DescribeVolumes"
],
"Resource": "*"
},
{
"Sid": "S3DevelopmentAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-wordpress-assets-20231201/wp-content/uploads/dev/*",
"arn:aws:s3:::my-wordpress-assets-20231201"
]
},
{
"Sid": "RDSReadAccess",
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:DescribeDBSnapshots"
],
"Resource": "*"
},
{
"Sid": "CloudFrontReadAccess",
"Effect": "Allow",
"Action": [
"cloudfront:GetDistribution",
"cloudfront:ListDistributions"
],
"Resource": "*"
}
]
}
EOF
# 创建策略
aws iam create-policy \
--policy-name WordPress-Developer-Policy \
--policy-document file://developer-policy.json
# 附加策略到组
aws iam attach-group-policy \
--group-name WordPress-Developers \
--policy-arn arn:aws:iam::123456789012:policy/WordPress-Developer-Policy
运维人员组
# 创建运维人员组
aws iam create-group --group-name WordPress-Operations
# 创建运维人员策略
cat > operations-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2FullAccess",
"Effect": "Allow",
"Action": [
"ec2:*"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Project": "WordPress"
}
}
},
{
"Sid": "RDSManagement",
"Effect": "Allow",
"Action": [
"rds:*"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"rds:ResourceTag/Project": "WordPress"
}
}
},
{
"Sid": "S3FullAccess",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::my-wordpress-assets-20231201",
"arn:aws:s3:::my-wordpress-assets-20231201/*"
]
},
{
"Sid": "CloudFrontManagement",
"Effect": "Allow",
"Action": [
"cloudfront:*"
],
"Resource": "*"
},
{
"Sid": "IAMReadAccess",
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:GetPolicy",
"iam:ListRoles",
"iam:ListPolicies"
],
"Resource": "*"
}
]
}
EOF
aws iam create-policy \
--policy-name WordPress-Operations-Policy \
--policy-document file://operations-policy.json
aws iam attach-group-policy \
--group-name WordPress-Operations \
--policy-arn arn:aws:iam::123456789012:policy/WordPress-Operations-Policy
只读用户组
# 创建只读用户组
aws iam create-group --group-name WordPress-ReadOnly
# 附加AWS托管的只读策略
aws iam attach-group-policy \
--group-name WordPress-ReadOnly \
--policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess
步骤2:创建用户并分配到组
# 创建开发人员用户
aws iam create-user --user-name alice.developer
aws iam add-user-to-group \
--user-name alice.developer \
--group-name WordPress-Developers
# 创建运维人员用户
aws iam create-user --user-name bob.operations
aws iam add-user-to-group \
--user-name bob.operations \
--group-name WordPress-Operations
# 创建只读用户
aws iam create-user --user-name charlie.readonly
aws iam add-user-to-group \
--user-name charlie.readonly \
--group-name WordPress-ReadOnly
# 为用户创建访问密钥
aws iam create-access-key --user-name alice.developer
aws iam create-access-key --user-name bob.operations
aws iam create-access-key --user-name charlie.readonly
步骤3:配置MFA多因素认证
# 创建MFA设备
aws iam create-virtual-mfa-device \
--virtual-mfa-device-name alice-mfa \
--outfile alice-mfa-qr.png \
--bootstrap-method QRCodePNG
# 启用MFA(需要用户扫描二维码后提供两个连续的验证码)
aws iam enable-mfa-device \
--user-name alice.developer \
--serial-number arn:aws:iam::123456789012:mfa/alice-mfa \
--authentication-code1 123456 \
--authentication-code2 789012
步骤4:创建服务角色
EC2实例角色
# 创建EC2信任策略
cat > ec2-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# 创建EC2角色
aws iam create-role \
--role-name WordPress-EC2-Role \
--assume-role-policy-document file://ec2-trust-policy.json
# 创建EC2权限策略
cat > ec2-permissions-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3Access",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-wordpress-assets-20231201/wp-content/uploads/*"
},
{
"Sid": "CloudWatchLogs",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Sid": "CloudWatchMetrics",
"Effect": "Allow",
"Action": [
"cloudwatch:PutMetricData"
],
"Resource": "*"
}
]
}
EOF
aws iam create-policy \
--policy-name WordPress-EC2-Policy \
--policy-document file://ec2-permissions-policy.json
aws iam attach-role-policy \
--role-name WordPress-EC2-Role \
--policy-arn arn:aws:iam::123456789012:policy/WordPress-EC2-Policy
# 创建实例配置文件
aws iam create-instance-profile \
--instance-profile-name WordPress-EC2-Profile
aws iam add-role-to-instance-profile \
--instance-profile-name WordPress-EC2-Profile \
--role-name WordPress-EC2-Role
Lambda执行角色
# 创建Lambda信任策略
cat > lambda-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# 创建Lambda角色
aws iam create-role \
--role-name WordPress-Lambda-Role \
--assume-role-policy-document file://lambda-trust-policy.json
# 附加基本执行策略
aws iam attach-role-policy \
--role-name WordPress-Lambda-Role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# 创建自定义Lambda权限策略
cat > lambda-permissions-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3Access",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-wordpress-assets-20231201/*"
},
{
"Sid": "CloudFrontInvalidation",
"Effect": "Allow",
"Action": [
"cloudfront:CreateInvalidation"
],
"Resource": "*"
}
]
}
EOF
aws iam create-policy \
--policy-name WordPress-Lambda-Policy \
--policy-document file://lambda-permissions-policy.json
aws iam attach-role-policy \
--role-name WordPress-Lambda-Role \
--policy-arn arn:aws:iam::123456789012:policy/WordPress-Lambda-Policy
步骤5:应用角色到资源
# 将角色附加到EC2实例
aws ec2 associate-iam-instance-profile \
--instance-id i-1234567890abcdef0 \
--iam-instance-profile Name=WordPress-EC2-Profile
# 验证角色附加
## 策略语法详解
### JSON策略结构
IAM策略使用JSON格式,包含以下关键元素:
```json
{
"Version": "2012-10-17", // 策略语言版本
"Id": "PolicyId", // 策略ID(可选)
"Statement": [ // 权限声明数组
{
"Sid": "StatementId", // 声明ID(可选)
"Effect": "Allow|Deny", // 允许或拒绝
"Principal": {}, // 主体(谁)
"Action": [], // 操作(做什么)
"Resource": [], // 资源(对什么)
"Condition": {} // 条件(什么情况下)
}
]
}
常用策略示例
S3访问策略
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-wordpress-assets-20231201",
"Condition": {
"StringLike": {
"s3:prefix": [
"wp-content/uploads/${aws:username}/*"
]
}
}
},
{
"Sid": "AllowUserFolderAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-wordpress-assets-20231201/wp-content/uploads/${aws:username}/*"
}
]
}
时间限制策略
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowWorkingHours",
"Effect": "Allow",
"Action": "ec2:*",
"Resource": "*",
"Condition": {
"DateGreaterThan": {
"aws:CurrentTime": "08:00Z"
},
"DateLessThan": {
"aws:CurrentTime": "18:00Z"
}
}
}
]
}
IP地址限制策略
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowFromOfficeIP",
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"203.0.113.0/24",
"198.51.100.0/24"
]
}
}
}
]
}
策略变量
使用策略变量实现动态权限控制:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowUserOwnFolder",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::user-data/${aws:username}/*"
},
{
"Sid": "AllowAssumeOwnRole",
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::123456789012:role/${aws:username}-role"
}
]
}
常用策略变量:
${aws:username}- 用户名${aws:userid}- 用户ID${aws:CurrentTime}- 当前时间${aws:SourceIp}- 源IP地址${aws:RequestedRegion}- 请求的区域
权限边界(Permission Boundaries)
权限边界定义了用户或角色的最大权限范围:
# 创建权限边界策略
cat > permission-boundary.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowedServices",
"Effect": "Allow",
"Action": [
"s3:*",
"ec2:Describe*",
"rds:Describe*",
"cloudfront:Get*",
"cloudfront:List*"
],
"Resource": "*"
},
{
"Sid": "DenyDangerousActions",
"Effect": "Deny",
"Action": [
"iam:*",
"ec2:TerminateInstances",
"rds:DeleteDBInstance",
"s3:DeleteBucket"
],
"Resource": "*"
}
]
}
EOF
aws iam create-policy \
--policy-name WordPress-Permission-Boundary \
--policy-document file://permission-boundary.json
# 为用户设置权限边界
aws iam put-user-permissions-boundary \
--user-name alice.developer \
--permissions-boundary arn:aws:iam::123456789012:policy/WordPress-Permission-Boundary
跨账户访问
跨账户角色
# 在账户A中创建跨账户角色
cat > cross-account-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT-B-ID:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "unique-external-id"
}
}
}
]
}
EOF
aws iam create-role \
--role-name CrossAccount-WordPress-Access \
--assume-role-policy-document file://cross-account-trust-policy.json
# 在账户B中承担角色
aws sts assume-role \
--role-arn arn:aws:iam::ACCOUNT-A-ID:role/CrossAccount-WordPress-Access \
--role-session-name CrossAccountSession \
--external-id unique-external-id
资源共享策略
# S3桶跨账户访问策略
cat > cross-account-s3-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCrossAccountAccess",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::ACCOUNT-B-ID:user/backup-user",
"arn:aws:iam::ACCOUNT-C-ID:role/backup-role"
]
},
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-wordpress-assets-20231201/backups/*"
}
]
}
EOF
aws s3api put-bucket-policy \
--bucket my-wordpress-assets-20231201 \
--policy file://cross-account-s3-policy.json
临时凭证和STS
临时访问密钥
# 获取临时凭证
aws sts get-session-token \
--duration-seconds 3600 \
--serial-number arn:aws:iam::123456789012:mfa/alice-mfa \
--token-code 123456
# 使用临时凭证
export AWS_ACCESS_KEY_ID="ASIA..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_SESSION_TOKEN="..."
# 验证临时凭证
aws sts get-caller-identity
联合身份访问
# 配置SAML身份提供商
aws iam create-saml-provider \
--saml-metadata-document file://saml-metadata.xml \
--name CompanySAMLProvider
# 创建SAML角色
cat > saml-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:saml-provider/CompanySAMLProvider"
},
"Action": "sts:AssumeRoleWithSAML",
"Condition": {
"StringEquals": {
"SAML:aud": "https://signin.aws.amazon.com/saml"
}
}
}
]
}
EOF
aws iam create-role \
--role-name SAML-WordPress-Developer \
--assume-role-policy-document file://saml-trust-policy.json
安全监控和审计
CloudTrail日志分析
# 查看IAM相关操作
aws logs filter-log-events \
--log-group-name CloudTrail/IAMEvents \
--filter-pattern "{ $.eventSource = iam.amazonaws.com }" \
--start-time 1701388800000 \
--end-time 1701475200000
# 查看失败的登录尝试
aws logs filter-log-events \
--log-group-name CloudTrail/IAMEvents \
--filter-pattern "{ $.eventName = ConsoleLogin && $.errorCode EXISTS }"
# 查看权限变更
aws logs filter-log-events \
--log-group-name CloudTrail/IAMEvents \
--filter-pattern "{ $.eventName = AttachUserPolicy || $.eventName = DetachUserPolicy || $.eventName = PutUserPolicy }"
Access Analyzer
# 创建访问分析器
aws accessanalyzer create-analyzer \
--analyzer-name WordPress-Access-Analyzer \
--type ACCOUNT
# 查看发现的问题
aws accessanalyzer list-findings \
--analyzer-arn arn:aws:access-analyzer:us-east-1:123456789012:analyzer/WordPress-Access-Analyzer
# 查看外部访问
aws accessanalyzer list-findings \
--analyzer-arn arn:aws:access-analyzer:us-east-1:123456789012:analyzer/WordPress-Access-Analyzer \
--filter criteria=resourceType,eq=AWS::S3::Bucket
权限使用分析
# 生成凭证报告
aws iam generate-credential-report
# 获取凭证报告
aws iam get-credential-report --output text --query Content | base64 -d > credential-report.csv
# 分析未使用的权限
aws iam generate-service-last-accessed-details \
--arn arn:aws:iam::123456789012:user/alice.developer
# 获取服务访问详情
aws iam get-service-last-accessed-details \
--job-id 12345678-1234-1234-1234-123456789012
自动化权限管理
使用AWS CLI脚本
#!/bin/bash
# user-lifecycle.sh - 用户生命周期管理脚本
create_user() {
local username=$1
local group=$2
echo "Creating user: $username"
aws iam create-user --user-name "$username"
echo "Adding user to group: $group"
aws iam add-user-to-group --user-name "$username" --group-name "$group"
echo "Creating access key"
aws iam create-access-key --user-name "$username"
echo "Setting up MFA device"
aws iam create-virtual-mfa-device \
--virtual-mfa-device-name "${username}-mfa" \
--outfile "${username}-mfa-qr.png" \
--bootstrap-method QRCodePNG
}
rotate_keys() {
local username=$1
echo "Rotating access keys for: $username"
# 创建新密钥
new_key=$(aws iam create-access-key --user-name "$username" --query 'AccessKey.AccessKeyId' --output text)
echo "New access key created: $new_key"
echo "Please update applications and test before running cleanup"
# 列出旧密钥(需要手动清理)
aws iam list-access-keys --user-name "$username"
}
cleanup_user() {
local username=$1
echo "Cleaning up user: $username"
# 删除访问密钥
aws iam list-access-keys --user-name "$username" --query 'AccessKeyMetadata[].AccessKeyId' --output text | \
while read key; do
aws iam delete-access-key --user-name "$username" --access-key-id "$key"
done
# 分离策略
aws iam list-attached-user-policies --user-name "$username" --query 'AttachedPolicies[].PolicyArn' --output text | \
while read policy; do
aws iam detach-user-policy --user-name "$username" --policy-arn "$policy"
done
# 从组中移除
aws iam get-groups-for-user --user-name "$username" --query 'Groups[].GroupName' --output text | \
while read group; do
aws iam remove-user-from-group --user-name "$username" --group-name "$group"
done
# 删除用户
aws iam delete-user --user-name "$username"
}
# 使用示例
case "$1" in
create)
create_user "$2" "$3"
;;
rotate)
rotate_keys "$2"
;;
cleanup)
cleanup_user "$2"
;;
*)
echo "Usage: $0 {create|rotate|cleanup} username [group]"
exit 1
;;
esac
权限审计脚本
#!/bin/bash
# permission-audit.sh - 权限审计脚本
audit_unused_permissions() {
echo "=== Unused Permissions Audit ==="
# 获取所有用户
aws iam list-users --query 'Users[].UserName' --output text | while read user; do
echo "Auditing user: $user"
# 生成服务访问详情
job_id=$(aws iam generate-service-last-accessed-details \
--arn "arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):user/$user" \
--query JobId --output text)
# 等待作业完成
while true; do
status=$(aws iam get-service-last-accessed-details --job-id "$job_id" --query JobStatus --output text)
if [ "$status" = "COMPLETED" ]; then
break
fi
sleep 5
done
# 获取未使用的服务
aws iam get-service-last-accessed-details --job-id "$job_id" \
--query 'ServicesLastAccessed[?LastAuthenticated==null].ServiceName' --output text
done
}
audit_overprivileged_users() {
echo "=== Overprivileged Users Audit ==="
# 查找有管理员权限的用户
aws iam list-entities-for-policy \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess \
--query 'PolicyUsers[].UserName' --output text | while read user; do
echo "WARNING: User $user has AdministratorAccess"
done
# 查找有PowerUser权限的用户
aws iam list-entities-for-policy \
--policy-arn arn:aws:iam::aws:policy/PowerUserAccess \
--query 'PolicyUsers[].UserName' --output text | while read user; do
echo "CAUTION: User $user has PowerUserAccess"
done
}
audit_mfa_compliance() {
echo "=== MFA Compliance Audit ==="
aws iam list-users --query 'Users[].UserName' --output text | while read user; do
mfa_devices=$(aws iam list-mfa-devices --user-name "$user" --query 'MFADevices' --output text)
if [ -z "$mfa_devices" ]; then
echo "WARNING: User $user does not have MFA enabled"
fi
done
}
audit_old_access_keys() {
echo "=== Old Access Keys Audit ==="
cutoff_date=$(date -d '90 days ago' +%Y-%m-%d)
aws iam list-users --query 'Users[].UserName' --output text | while read user; do
aws iam list-access-keys --user-name "$user" --query 'AccessKeyMetadata[]' --output json | \
jq -r --arg cutoff "$cutoff_date" '.[] | select(.CreateDate < $cutoff) | "\(.UserName): \(.AccessKeyId) created on \(.CreateDate)"'
done
}
# 运行所有审计
audit_unused_permissions
audit_overprivileged_users
audit_mfa_compliance
audit_old_access_keys
成本优化
权限相关成本
IAM本身是免费服务,但权限配置会影响其他服务的成本:
# 监控IAM相关的成本
aws ce get-cost-and-usage \
--time-period Start=2023-12-01,End=2023-12-31 \
--granularity MONTHLY \
--metrics BlendedCost \
--group-by Type=DIMENSION,Key=SERVICE \
--filter file://iam-cost-filter.json
# iam-cost-filter.json
{
"Dimensions": {
"Key": "SERVICE",
"Values": [
"AWS Identity and Access Management",
"AWS Security Token Service"
]
}
}
优化建议
- 减少不必要的STS调用
- 优化临时凭证的生命周期
- 合理使用跨区域复制权限
- 定期清理未使用的角色和策略
## 故障排除
### 常见权限问题
**问题1:Access Denied错误**
```bash
# 诊断步骤
# 1. 检查用户权限
aws iam list-attached-user-policies --user-name alice.developer
aws iam list-user-policies --user-name alice.developer
# 2. 检查组权限
aws iam get-groups-for-user --user-name alice.developer
aws iam list-attached-group-policies --group-name WordPress-Developers
# 3. 检查权限边界
aws iam get-user --user-name alice.developer --query 'User.PermissionsBoundary'
# 4. 模拟策略
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/alice.developer \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::my-wordpress-assets-20231201/wp-content/uploads/test.jpg
问题2:角色承担失败
# 检查信任关系
aws iam get-role --role-name WordPress-EC2-Role --query 'Role.AssumeRolePolicyDocument'
# 检查实例配置文件
aws ec2 describe-instances --instance-ids i-1234567890abcdef0 \
--query 'Reservations[0].Instances[0].IamInstanceProfile'
# 测试角色承担
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/WordPress-EC2-Role \
--role-session-name test-session
问题3:MFA验证失败
# 检查MFA设备状态
aws iam list-mfa-devices --user-name alice.developer
# 重新同步MFA设备
aws iam resync-mfa-device \
--user-name alice.developer \
--serial-number arn:aws:iam::123456789012:mfa/alice-mfa \
--authentication-code1 123456 \
--authentication-code2 789012
调试工具
# 策略模拟器
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/alice.developer \
--action-names ec2:DescribeInstances,s3:ListBucket \
--resource-arns "*" \
--context-entries ContextKeyName=aws:RequestedRegion,ContextKeyValues=us-east-1,ContextKeyType=string
# 解码授权消息
aws sts decode-authorization-message \
--encoded-message "encoded-error-message-here"
# 检查当前身份
aws sts get-caller-identity
合规性和最佳实践
合规框架对照
SOC 2合规
- 启用CloudTrail记录所有IAM操作
- 实施最小权限原则
- 定期权限审查
- MFA强制执行
PCI DSS合规
- 限制对敏感数据的访问
- 实施强密码策略
- 定期访问权限审查
- 监控和日志记录
GDPR合规
- 数据访问控制
- 数据处理权限管理
- 审计日志保留
- 数据删除权限控制
企业级IAM架构
# 多账户架构示例
# 主账户:IAM用户和组管理
# 开发账户:开发环境资源
# 测试账户:测试环境资源
# 生产账户:生产环境资源
# 在主账户创建跨账户角色
cat > multi-account-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::MAIN-ACCOUNT:user/alice.developer",
"arn:aws:iam::MAIN-ACCOUNT:user/bob.operations"
]
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
},
"NumericLessThan": {
"aws:MultiFactorAuthAge": "3600"
}
}
}
]
}
EOF
# 在各环境账户创建角色
aws iam create-role \
--role-name CrossAccount-Developer-Role \
--assume-role-policy-document file://multi-account-trust-policy.json
自动化合规检查
#!/usr/bin/env python3
# compliance-checker.py
import boto3
import json
from datetime import datetime, timedelta
class IAMComplianceChecker:
def __init__(self):
self.iam = boto3.client('iam')
self.sts = boto3.client('sts')
def check_mfa_compliance(self):
"""检查MFA合规性"""
print("=== MFA Compliance Check ===")
users = self.iam.list_users()['Users']
non_compliant_users = []
for user in users:
username = user['UserName']
mfa_devices = self.iam.list_mfa_devices(UserName=username)['MFADevices']
if not mfa_devices:
non_compliant_users.append(username)
if non_compliant_users:
print(f"Users without MFA: {', '.join(non_compliant_users)}")
else:
print("All users have MFA enabled")
def check_old_access_keys(self, days=90):
"""检查过期访问密钥"""
print(f"=== Access Keys Older Than {days} Days ===")
cutoff_date = datetime.now() - timedelta(days=days)
old_keys = []
users = self.iam.list_users()['Users']
for user in users:
username = user['UserName']
keys = self.iam.list_access_keys(UserName=username)['AccessKeyMetadata']
for key in keys:
if key['CreateDate'].replace(tzinfo=None) < cutoff_date:
old_keys.append({
'User': username,
'KeyId': key['AccessKeyId'],
'Age': (datetime.now() - key['CreateDate'].replace(tzinfo=None)).days
})
if old_keys:
for key in old_keys:
print(f"User: {key['User']}, Key: {key['KeyId']}, Age: {key['Age']} days")
else:
print("No old access keys found")
def check_unused_roles(self, days=90):
"""检查未使用的角色"""
print(f"=== Roles Unused for {days} Days ===")
cutoff_date = datetime.now() - timedelta(days=days)
unused_roles = []
roles = self.iam.list_roles()['Roles']
for role in roles:
role_name = role['RoleName']
try:
# 生成服务访问详情
response = self.iam.generate_service_last_accessed_details(
Arn=role['Arn']
)
job_id = response['JobId']
# 等待作业完成
import time
while True:
details = self.iam.get_service_last_accessed_details(JobId=job_id)
if details['JobStatus'] == 'COMPLETED':
break
time.sleep(2)
# 检查最后访问时间
services = details['ServicesLastAccessed']
last_used = None
for service in services:
if 'LastAuthenticated' in service:
if not last_used or service['LastAuthenticated'] > last_used:
last_used = service['LastAuthenticated']
if not last_used or last_used.replace(tzinfo=None) < cutoff_date:
unused_roles.append(role_name)
except Exception as e:
print(f"Error checking role {role_name}: {e}")
if unused_roles:
print(f"Unused roles: {', '.join(unused_roles)}")
else:
print("No unused roles found")
def check_overprivileged_policies(self):
"""检查过度授权的策略"""
print("=== Overprivileged Policies Check ===")
dangerous_actions = ['*', 'iam:*', 'sts:AssumeRole']
overprivileged_policies = []
policies = self.iam.list_policies(Scope='Local')['Policies']
for policy in policies:
policy_arn = policy['Arn']
try:
policy_version = self.iam.get_policy_version(
PolicyArn=policy_arn,
VersionId=policy['DefaultVersionId']
)
policy_doc = policy_version['PolicyVersion']['Document']
statements = policy_doc.get('Statement', [])
for statement in statements:
if statement.get('Effect') == 'Allow':
actions = statement.get('Action', [])
if isinstance(actions, str):
actions = [actions]
for action in actions:
if action in dangerous_actions:
overprivileged_policies.append(policy['PolicyName'])
break
except Exception as e:
print(f"Error checking policy {policy['PolicyName']}: {e}")
if overprivileged_policies:
print(f"Overprivileged policies: {', '.join(set(overprivileged_policies))}")
else:
print("No overprivileged policies found")
if __name__ == "__main__":
checker = IAMComplianceChecker()
checker.check_mfa_compliance()
checker.check_old_access_keys()
checker.check_unused_roles()
checker.check_overprivileged_policies()
迁移验证清单
权限验证
- 所有用户都能正常访问所需资源
- 应用程序使用IAM角色正常工作
- 跨服务访问权限配置正确
- MFA设备正常工作
- 临时凭证可以正常获取
安全验证
# 1. 验证最小权限原则
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/alice.developer \
--action-names iam:CreateUser \
--resource-arns "*"
# 应该返回 "denied"
# 2. 验证MFA要求
aws iam get-account-summary | grep -i mfa
# 3. 验证密码策略
aws iam get-account-password-policy
审计验证
- CloudTrail记录IAM操作
- Access Analyzer正常工作
- 权限边界生效
- 合规检查脚本运行正常
最佳实践总结
用户管理
- 使用组管理权限:避免直接给用户附加策略
- 启用MFA:为所有用户启用多因素认证
- 定期轮换密钥:建立访问密钥轮换机制
- 最小权限原则:只授予必要的最小权限
角色设计
- 服务角色优先:应用程序使用IAM角色而非用户密钥
- 跨账户访问:使用角色实现安全的跨账户访问
- 临时凭证:优先使用临时凭证
- 信任关系限制:严格控制角色的信任关系
策略管理
- 使用托管策略:优先使用AWS托管策略
- 版本控制:为自定义策略启用版本控制
- 条件限制:使用条件限制策略的适用范围
- 定期审查:定期审查和清理不需要的策略
监控审计
- 启用CloudTrail:记录所有IAM操作
- 使用Access Analyzer:发现意外的外部访问
- 定期审计:建立定期权限审计机制
- 合规检查:自动化合规性检查
下一步学习方向
掌握了IAM基础后,你可以继续探索:
- CloudWatch监控:监控IAM相关的安全事件(下一篇文章重点)
- AWS Organizations:多账户权限管理
- AWS SSO:单点登录解决方案
- AWS Secrets Manager:密钥和凭证管理
- AWS Config:配置合规性监控
结语
通过配置IAM权限管理,我们为整个AWS架构构建了一道坚固的安全防线。IAM不仅保护了我们的资源安全,还提供了精细的访问控制和完整的审计追踪。
从无序的权限管理到结构化的身份安全体系,这是现代云架构的必备能力。我们学会了:
- 理解IAM的核心概念和工作原理
- 设计合理的用户、组、角色权限体系
- 编写精确的IAM策略
- 实施多因素认证和权限边界
- 建立权限审计和合规检查机制
现在我们的架构已经非常完整和安全:
- 计算层:EC2(动态内容)
- 数据层:RDS(数据库)
- 存储层:S3(静态资源)
- 加速层:CloudFront(全球CDN)
- 安全层:IAM(身份权限管理)
在最后一篇文章中,我们将学习CloudWatch监控服务,为整个架构建立全面的监控和告警体系,确保系统的稳定运行和及时的问题发现。
安全无小事,权限需精细!IAM让你的AWS资源拥有最专业的"身份安全卫士"!


3921

被折叠的 条评论
为什么被折叠?



