Skip to content

权限管理

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-readAWS 执行环境可读
bucket-owner-readBucket 所有者可读
bucket-owner-full-controlBucket 所有者完全控制

🔒 阻止公共访问

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 🔗