IAM 实战案例
通过真实场景案例,学习如何设计和实现安全、高效的 IAM 权限方案。
案例 1:开发环境资源隔离
业务需求
场景描述:
公司有 20 名开发人员:
├─ 每人需要独立的开发环境
├─ 可以创建 EC2、RDS、S3 等资源
├─ 只能管理自己的资源
├─ 不能查看或修改他人资源
└─ 防止误删生产环境资源
解决方案
方案设计:
核心思路:基于标签的访问控制(Tag-based Access Control)
标签规范:
├─ Owner: ${aws:username}
├─ Environment: development
└─ Project: 项目名称
权限模型:
├─ 只能操作带有 Owner=自己用户名 的资源
├─ 创建资源时强制添加 Owner 标签
└─ 限制在开发区域(如 us-east-1)
IAM 策略实现:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowReadAllResources",
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"rds:Describe*",
"s3:List*",
"s3:GetBucketLocation"
],
"Resource": "*"
},
{
"Sid": "AllowManageOwnResources",
"Effect": "Allow",
"Action": [
"ec2:*",
"rds:*",
"s3:*Object"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Owner": "${aws:username}",
"rds:db-tag/Owner": "${aws:username}",
"s3:ExistingObjectTag/Owner": "${aws:username}"
}
}
},
{
"Sid": "RequireOwnerTagOnCreation",
"Effect": "Allow",
"Action": [
"ec2:RunInstances",
"ec2:CreateVolume",
"rds:CreateDBInstance",
"s3:PutObject"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/Owner": "${aws:username}",
"aws:RequestTag/Environment": "development"
}
}
},
{
"Sid": "AllowTagging",
"Effect": "Allow",
"Action": [
"ec2:CreateTags",
"rds:AddTagsToResource"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestTag/Owner": "${aws:username}"
}
}
},
{
"Sid": "DenyTagModification",
"Effect": "Deny",
"Action": [
"ec2:DeleteTags",
"rds:RemoveTagsFromResource"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Owner": "${aws:username}"
},
"ForAnyValue:StringEquals": {
"aws:TagKeys": ["Owner", "Environment"]
}
}
},
{
"Sid": "RestrictToDevRegion",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": "us-east-1"
}
}
}
]
}
实施步骤
1. 创建IAM 组:
# 创建 Developers 组
aws iam create-group --group-name Developers
# 附加策略
aws iam put-group-policy \
--group-name Developers \
--policy-name DevEnvironmentPolicy \
--policy-document file://dev-policy.json
2. 添加用户到组:
# 为每个开发人员创建 IAM 用户
aws iam create-user --user-name alice
aws iam create-user --user-name bob
# 添加到 Developers 组
aws iam add-user-to-group --user-name alice --group-name Developers
aws iam add-user-to-group --user-name bob --group-name Developers
# 设置控制台密码
aws iam create-login-profile \
--user-name alice \
--password "TemporaryPassword123!" \
--password-reset-required
3. 用户使用示例:
# Alice 创建 EC2 实例(成功)
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t3.micro \
--tag-specifications \
'ResourceType=instance,Tags=[{Key=Owner,Value=alice},{Key=Environment,Value=development}]'
# Alice 尝试访问 Bob 的实例(失败)
aws ec2 stop-instances --instance-ids i-bob-instance-id
# Error: AccessDenied
# Alice 尝试删除 Owner 标签(失败)
aws ec2 delete-tags --resources i-alice-instance-id --tags Key=Owner
# Error: AccessDenied
效果验证
验证清单:
✓ 用户只能看到自己的资源
✓ 创建资源时必须打上正确的标签
✓ 不能修改或删除 Owner、Environment 标签
✓ 不能在开发区域外创建资源
✓ 不能操作他人的资源
✓ 可以查看所有资源列表(但不能操作)
案例 2:时间和网络访问控制
业务需求
安全要求:
合规部门要求:
├─ 仅允许工作时间(9:00-18:00)访问
├─ 必须来自公司网络(特定 IP 段)
├─ 敏感操作必须使用 MFA
├─ 生产环境操作需要额外审批
└─ 记录所有访问日志
解决方案
策略设计:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDuringBusinessHours",
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"DateGreaterThan": {
"aws:CurrentTime": "2024-01-01T01:00:00Z"
},
"DateLessThan": {
"aws:CurrentTime": "2024-12-31T10:00:00Z"
},
"IpAddress": {
"aws:SourceIp": [
"203.0.113.0/24",
"192.0.2.0/24"
]
}
}
},
{
"Sid": "DenyOutsideBusinessHours",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"DateLessThan": {
"aws:CurrentTime": "2024-01-01T01:00:00Z"
}
}
},
{
"Sid": "DenyOutsideBusinessHours2",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"DateGreaterThan": {
"aws:CurrentTime": "2024-12-31T10:00:00Z"
}
}
},
{
"Sid": "DenyFromUnauthorizedIP",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"203.0.113.0/24",
"192.0.2.0/24"
]
},
"Bool": {
"aws:ViaAWSService": "false"
}
}
},
{
"Sid": "RequireMFAForSensitiveOperations",
"Effect": "Deny",
"Action": [
"ec2:StopInstances",
"ec2:TerminateInstances",
"rds:DeleteDBInstance",
"rds:DeleteDBCluster",
"s3:DeleteBucket",
"s3:DeleteObject",
"iam:DeleteUser",
"iam:DeleteRole",
"iam:DetachUserPolicy",
"iam:DetachRolePolicy"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
},
{
"Sid": "DenyProductionAccessWithoutApproval",
"Effect": "Deny",
"Action": [
"ec2:*",
"rds:*",
"lambda:*"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Environment": "production",
"rds:db-tag/Environment": "production"
},
"StringNotEquals": {
"aws:PrincipalTag/ProductionAccess": "approved"
}
}
}
]
}
MFA 配置
启用 MFA:
# 1. 用户启用虚拟 MFA
aws iam create-virtual-mfa-device \
--virtual-mfa-device-name alice-mfa \
--outfile QRCode.png \
--bootstrap-method QRCodePNG
# 2. 绑定 MFA 设备到用户
aws iam enable-mfa-device \
--user-name alice \
--serial-number arn:aws:iam::123456789012:mfa/alice-mfa \
--authentication-code-1 123456 \
--authentication-code-2 789012
使用 MFA 获取临时凭证:
# 获取会话令牌
aws sts get-session-token \
--serial-number arn:aws:iam::123456789012:mfa/alice-mfa \
--token-code 123456 \
--duration-seconds 3600
# 输出包含临时凭证
{
"Credentials": {
"AccessKeyId": "ASIA...",
"SecretAccessKey": "...",
"SessionToken": "...",
"Expiration": "2024-01-11T12:00:00Z"
}
}
# 使用临时凭证
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
监控和告警
CloudWatch 告警:
# 监控非授权 IP 访问尝试
aws cloudwatch put-metric-alarm \
--alarm-name UnauthorizedIPAccess \
--alarm-description "Alert on access from unauthorized IP" \
--metric-name UnauthorizedIPCount \
--namespace Custom/IAM \
--statistic Sum \
--period 300 \
--evaluation-periods 1 \
--threshold 1 \
--comparison-operator GreaterThanThreshold \
--alarm-actions arn:aws:sns:us-east-1:123456789012:security-alerts
CloudTrail 日志查询:
-- 查询非工作时间的访问
SELECT
userIdentity.userName,
eventTime,
eventName,
sourceIPAddress
FROM cloudtrail_logs
WHERE eventTime NOT BETWEEN '09:00:00' AND '18:00:00'
AND errorCode IS NULL
ORDER BY eventTime DESC;
案例 3:多环境权限分离
业务需求
环境划分:
三个环境:
├─ Development(开发)
│ ├─ 开发人员:完全访问
│ └─ 成本优先,可随意实验
├─ Staging(预发布)
│ ├─ 开发人员:读写访问
│ ├─ QA:完全访问
│ └─ 接近生产配置
└─ Production(生产)
├─ DevOps:完全访问
├─ 开发人员:只读访问
└─ 严格变更控制
解决方案架构
多账户策略(推荐):
AWS Organizations
├─ Management Account(管理账户)
│ └─ 仅用于账单和组织管理
├─ Dev Account(开发账户)
│ ├─ 开发人员:AdministratorAccess
│ └─ SCP:限制昂贵服务
├─ Staging Account(预发布账户)
│ ├─ 开发人员:PowerUserAccess
│ ├─ QA:特定服务完全访问
│ └─ SCP:防止意外删除
└─ Production Account(生产账户)
├─ DevOps:管理员访问(有 MFA)
├─ 开发人员:ReadOnlyAccess
└─ SCP:强制加密、标签、CloudTrail
单账户策略(备选):
基于标签和命名约定:
├─ 资源标签:Environment=dev/staging/prod
├─ 命名前缀:dev-*, staging-*, prod-*
└─ IAM 策略根据标签控制访问
跨账户访问实现
1. 在 Production 账户创建角色:
{
"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"
},
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
2. 在 Dev 账户授权用户:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::222222222222:role/ProductionReadOnlyRole"
}
]
}
3. 用户切换角色:
# CLI 方式
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/ProductionReadOnlyRole \
--role-session-name alice-prod-session \
--external-id unique-external-id-12345 \
--serial-number arn:aws:iam::111111111111:mfa/alice \
--token-code 123456
# 使用 AWS CLI Profile
[profile prod-readonly]
role_arn = arn:aws:iam::222222222222:role/ProductionReadOnlyRole
source_profile = default
external_id = unique-external-id-12345
mfa_serial = arn:aws:iam::111111111111:mfa/alice
# 使用
aws s3 ls --profile prod-readonly
SCP 示例
开发账户 SCP(限制成本):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyExpensiveInstances",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotLike": {
"ec2:InstanceType": [
"t3.*",
"t4g.*"
]
}
}
},
{
"Sid": "DenyExpensiveServices",
"Effect": "Deny",
"Action": [
"redshift:*",
"sagemaker:CreateNotebookInstance"
],
"Resource": "*"
}
]
}
生产账户 SCP(强制安全):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyDisableCloudTrail",
"Effect": "Deny",
"Action": [
"cloudtrail:StopLogging",
"cloudtrail:DeleteTrail"
],
"Resource": "*"
},
{
"Sid": "RequireEncryption",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": [
"AES256",
"aws:kms"
]
}
}
},
{
"Sid": "RequireMandatoryTags",
"Effect": "Deny",
"Action": [
"ec2:RunInstances",
"rds:CreateDBInstance"
],
"Resource": "*",
"Condition": {
"Null": {
"aws:RequestTag/Owner": "true",
"aws:RequestTag/CostCenter": "true",
"aws:RequestTag/Environment": "true"
}
}
}
]
}
案例 4:第三方 SaaS 集成
业务需求
场景:
授权第三方监控服务(如 Datadog)访问 AWS:
├─ 需要读取 CloudWatch 指标
├─ 需要列出 EC2、RDS 实例
├─ 需要读取 S3 日志
├─ 不能修改任何资源
└─ 确保安全(防止混淆代理攻击)
解决方案
1. 创建第三方访问角色:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::464622532012:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "generated-by-third-party-12345"
}
}
}
]
}
External ID 重要性:
混淆代理攻击(Confused Deputy Problem):
没有 External ID 的风险:
1. 恶意用户 A 注册第三方服务
2. 第三方使用相同的 IAM 角色
3. 恶意用户 A 提供受害者的账户 ID
4. 第三方使用角色访问受害者账户
5. 恶意用户 A 获得受害者数据
使用 External ID 的保护:
1. 每个客户有唯一的 External ID
2. 第三方必须提供正确的 External ID
3. 角色信任策略验证 External ID
4. 防止跨客户访问
2. 权限策略(最小权限):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListResources",
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"rds:Describe*",
"elasticloadbalancing:Describe*",
"cloudwatch:ListMetrics",
"cloudwatch:GetMetricStatistics",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "*"
},
{
"Sid": "AllowReadLogs",
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-logs-bucket/*"
},
{
"Sid": "DenyWrite",
"Effect": "Deny",
"NotAction": [
"ec2:Describe*",
"rds:Describe*",
"s3:Get*",
"s3:List*",
"cloudwatch:Get*",
"cloudwatch:List*",
"logs:Describe*"
],
"Resource": "*"
}
]
}
3. 集成步骤:
# 第三方提供的集成脚本
aws cloudformation create-stack \
--stack-name datadog-integration \
--template-url https://datadog-cloudformation-template.s3.amazonaws.com/aws/main.yaml \
--parameters \
ParameterKey=ExternalId,ParameterValue=generated-by-datadog-12345 \
--capabilities CAPABILITY_IAM
# 验证角色创建
aws iam get-role --role-name DatadogIntegrationRole
# 测试角色承担
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/DatadogIntegrationRole \
--role-session-name test-session \
--external-id generated-by-datadog-12345
安全审计
定期审查:
# 查看第三方角色的使用情况
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=DatadogIntegrationRole \
--max-results 50
# 检查异常访问
SELECT
userIdentity.sessionContext.sessionIssuer.userName as role_name,
sourceIPAddress,
eventName,
eventTime,
COUNT(*) as request_count
FROM cloudtrail_logs
WHERE userIdentity.type = 'AssumedRole'
AND userIdentity.sessionContext.sessionIssuer.userName = 'DatadogIntegrationRole'
GROUP BY role_name, sourceIPAddress, eventName, eventTime
HAVING request_count > 100
ORDER BY eventTime DESC;
这些实战案例展示了 IAM 在真实场景中的应用,理解这些模式能够帮助你设计安全、高效的权限方案!