权限管理
S3 提供多种访问控制机制,可以精细控制谁可以访问你的资源。
🔐 访问控制层级
访问控制层级(优先级从上到下):
├── 1. IAM 用户策略
├── 2. Bucket Policy (桶策略)
├── 3. ACL (访问控制列表)
└── 4. 预签名 URL (临时访问)👤 IAM 策略
IAM (Identity and Access Management) 策略附加到用户、组或角色,控制他们可以执行的操作。
IAM 策略示例
json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3FullAccess",
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
]
}常用 IAM 策略
只读访问
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
}
]
}上传权限
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::my-bucket/uploads/*"
}
]
}特定前缀访问
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket/user-${aws:username}/*"
]
}
]
}🪣 Bucket Policy
Bucket Policy 附加到 Bucket,控制对整个 Bucket 或特定对象的访问。
设置 Bucket Policy
javascript
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const setBucketPolicy = async (bucketName, policy) => {
const params = {
Bucket: bucketName,
Policy: JSON.stringify(policy)
};
try {
await s3.putBucketPolicy(params).promise();
console.log('Bucket policy set successfully');
} catch (err) {
console.error(err);
}
};
// 公开读取策略
const publicReadPolicy = {
Version: '2012-10-17',
Statement: [
{
Sid: 'PublicReadGetObject',
Effect: 'Allow',
Principal: '*',
Action: 's3:GetObject',
Resource: `arn:aws:s3:::my-bucket/*`
}
]
};
setBucketPolicy('my-bucket', publicReadPolicy);常用 Bucket Policy
1. 公开读取
json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}2. 限制 IP 地址
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"192.168.1.0/24",
"203.0.113.0/24"
]
}
}
}
]
}3. 限制 Referer(防盗链)
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"StringNotLike": {
"aws:Referer": [
"https://mywebsite.com/*",
"https://*.mywebsite.com/*"
]
}
}
}
]
}4. 要求 HTTPS
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}5. 限制上传文件类型
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"StringNotEquals": {
"s3:content-type": [
"image/jpeg",
"image/png",
"image/gif"
]
}
}
}
]
}6. 跨账户访问
json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}获取和删除 Bucket Policy
javascript
// 获取策略
const getBucketPolicy = async (bucketName) => {
try {
const result = await s3.getBucketPolicy({
Bucket: bucketName
}).promise();
const policy = JSON.parse(result.Policy);
console.log('Bucket Policy:', policy);
return policy;
} catch (err) {
if (err.code === 'NoSuchBucketPolicy') {
console.log('No bucket policy found');
} else {
console.error(err);
}
}
};
// 删除策略
const deleteBucketPolicy = async (bucketName) => {
await s3.deleteBucketPolicy({
Bucket: bucketName
}).promise();
console.log('Bucket policy deleted');
};📋 ACL (访问控制列表)
ACL 是传统的访问控制方式,AWS 推荐使用 Bucket Policy 和 IAM 策略代替。
Bucket ACL
javascript
// 设置 Bucket ACL
const setBucketACL = async (bucketName, acl) => {
await s3.putBucketAcl({
Bucket: bucketName,
ACL: acl // 'private' | 'public-read' | 'public-read-write' | 'authenticated-read'
}).promise();
};
// 私有
await setBucketACL('my-bucket', 'private');
// 公开读取
await setBucketACL('my-bucket', 'public-read');
// 获取 Bucket ACL
const getBucketACL = async (bucketName) => {
const result = await s3.getBucketAcl({
Bucket: bucketName
}).promise();
console.log('Owner:', result.Owner);
console.log('Grants:', result.Grants);
};对象 ACL
javascript
// 上传时设置 ACL
const uploadWithACL = async (bucketName, key, body) => {
await s3.putObject({
Bucket: bucketName,
Key: key,
Body: body,
ACL: 'public-read'
}).promise();
};
// 修改现有对象的 ACL
const setObjectACL = async (bucketName, key, acl) => {
await s3.putObjectAcl({
Bucket: bucketName,
Key: key,
ACL: acl
}).promise();
};
// 自定义 ACL
const setCustomACL = async (bucketName, key) => {
await s3.putObjectAcl({
Bucket: bucketName,
Key: key,
AccessControlPolicy: {
Owner: {
ID: 'owner-canonical-user-id'
},
Grants: [
{
Grantee: {
Type: 'CanonicalUser',
ID: 'user-canonical-user-id'
},
Permission: 'READ'
},
{
Grantee: {
Type: 'Group',
URI: 'http://acs.amazonaws.com/groups/global/AllUsers'
},
Permission: 'READ'
}
]
}
}).promise();
};ACL 权限
| 权限 | 对 Bucket 的含义 | 对对象的含义 |
|---|---|---|
| READ | 列出对象 | 读取对象内容 |
| WRITE | 创建、删除对象 | 不适用 |
| READ_ACP | 读取 Bucket ACL | 读取对象 ACL |
| WRITE_ACP | 修改 Bucket ACL | 修改对象 ACL |
| FULL_CONTROL | 完全控制 | 完全控制 |
🔑 预定义 ACL
| ACL | 含义 |
|---|---|
| private | 只有所有者有权限(默认) |
| public-read | 所有人可读 |
| public-read-write | 所有人可读写 |
| authenticated-read | 认证用户可读 |
| aws-exec-read | AWS 执行环境可读 |
| bucket-owner-read | Bucket 所有者可读 |
| bucket-owner-full-control | Bucket 所有者完全控制 |
🔒 阻止公共访问
S3 提供"阻止公共访问"设置,防止意外公开数据。
javascript
// 阻止所有公共访问
const blockPublicAccess = async (bucketName) => {
await s3.putPublicAccessBlock({
Bucket: bucketName,
PublicAccessBlockConfiguration: {
BlockPublicAcls: true, // 阻止公共 ACL
IgnorePublicAcls: true, // 忽略公共 ACL
BlockPublicPolicy: true, // 阻止公共 Bucket Policy
RestrictPublicBuckets: true // 限制公共 Bucket
}
}).promise();
console.log('Public access blocked');
};
// 获取公共访问设置
const getPublicAccessBlock = async (bucketName) => {
try {
const result = await s3.getPublicAccessBlock({
Bucket: bucketName
}).promise();
console.log('Public Access Configuration:', result.PublicAccessBlockConfiguration);
} catch (err) {
if (err.code === 'NoSuchPublicAccessBlockConfiguration') {
console.log('No public access block configuration');
} else {
console.error(err);
}
}
};
// 删除公共访问设置
const deletePublicAccessBlock = async (bucketName) => {
await s3.deletePublicAccessBlock({
Bucket: bucketName
}).promise();
};🌐 CORS 配置
跨域资源共享(CORS)允许浏览器访问不同域的 S3 资源。
javascript
const setCORS = async (bucketName) => {
const corsConfig = {
CORSRules: [
{
AllowedOrigins: ['https://example.com', 'https://*.example.com'],
AllowedMethods: ['GET', 'PUT', 'POST', 'DELETE'],
AllowedHeaders: ['*'],
ExposeHeaders: ['ETag', 'x-amz-meta-custom-header'],
MaxAgeSeconds: 3600
}
]
};
await s3.putBucketCors({
Bucket: bucketName,
CORSConfiguration: corsConfig
}).promise();
console.log('CORS configured');
};
// 获取 CORS 配置
const getCORS = async (bucketName) => {
try {
const result = await s3.getBucketCors({
Bucket: bucketName
}).promise();
console.log('CORS Rules:', result.CORSRules);
} catch (err) {
if (err.code === 'NoSuchCORSConfiguration') {
console.log('No CORS configuration');
} else {
console.error(err);
}
}
};
// 删除 CORS 配置
const deleteCORS = async (bucketName) => {
await s3.deleteBucketCors({
Bucket: bucketName
}).promise();
};💡 最佳实践
1. 最小权限原则
json
// ✅ 好:只授予必要权限
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-bucket/public/*"
}
// ❌ 坏:授予过多权限
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}2. 使用 IAM 角色
javascript
// EC2 或 Lambda 使用 IAM 角色,无需硬编码凭证
const s3 = new AWS.S3(); // 自动使用 IAM 角色3. 启用 MFA 删除
javascript
// 要求 MFA 才能删除对象版本
// 通过 AWS CLI 或控制台配置4. 审计访问
javascript
// 启用 CloudTrail 和 S3 访问日志
const enableLogging = async (bucketName, targetBucket) => {
await s3.putBucketLogging({
Bucket: bucketName,
BucketLoggingStatus: {
LoggingEnabled: {
TargetBucket: targetBucket,
TargetPrefix: `logs/${bucketName}/`
}
}
}).promise();
};5. 定期审查权限
javascript
// 定期检查并清理不必要的权限
// 使用 AWS Access Analyzer 发现公开的资源📖 相关资源
下一步:学习 预签名 URL 🔗