如何为特定群组配置Amazon S3静态网站的私密访问权限?
给Amazon S3静态网站添加HTTP基础认证(类似.htaccess)
我明白你想要给S3静态网站加上像Apache .htaccess那样的用户名密码验证,而IP限制因为没法收集所有访问者的IP所以行不通——这确实是个很常见的需求。咱先明确一点:S3本身并不直接支持HTTP基础认证,所以得借助CloudFront来实现这个功能,下面给你两个实用的方案,你可以根据自己的场景选:
方案一:CloudFront + Lambda@Edge 实现灵活认证
这个方案适合需要稍微复杂逻辑的场景(比如从密钥管理服务拉取密码),步骤如下:
1. 创建Lambda@Edge函数
Lambda@Edge是运行在CloudFront边缘节点的Lambda函数,必须在us-east-1区域创建:
- 打开Lambda控制台,选择
us-east-1区域,创建新函数,选择Python 3.x运行时。 - 替换函数代码为以下内容(记得修改
USERNAME和PASSWORD为你自己的凭证):
import base64 USERNAME = "your-custom-username" PASSWORD = "your-custom-password" def lambda_handler(event, context): request = event['Records'][0]['cf']['request'] headers = request['headers'] # 检查是否携带Authorization头 if 'authorization' not in headers: return generate_unauthorized_response() # 解码认证信息 auth_header = headers['authorization'][0]['value'] encoded_creds = auth_header.split(' ')[1] decoded_creds = base64.b64decode(encoded_creds).decode('utf-8') username, password = decoded_creds.split(':') # 验证凭证 if username != USERNAME or password != PASSWORD: return generate_unauthorized_response() # 认证通过,放行请求 return request def generate_unauthorized_response(): return { 'status': '401', 'statusDescription': 'Unauthorized', 'headers': { 'www-authenticate': [{ 'key': 'WWW-Authenticate', 'value': 'Basic realm="Restricted S3 Site"' }] } }
- 发布函数版本(Lambda@Edge需要使用已发布的版本),然后在函数控制台的「Actions」里选择「Deploy to Lambda@Edge」,关联到你的CloudFront分发的Viewer Request事件(这个事件会在CloudFront收到用户请求后立刻触发)。
2. 配置S3桶的访问限制
为了防止用户绕开CloudFront直接访问S3,需要设置S3桶的权限:
- 创建CloudFront的Origin Access Identity(OAI),并在CloudFront分发的原点设置里关联这个OAI。
- 修改S3桶的桶策略,只允许这个OAI访问桶内的对象,同时关闭S3的公共访问设置。示例桶策略如下:
{ "Version": "2008-10-17", "Id": "PolicyForCloudFrontPrivateContent", "Statement": [ { "Sid": "1", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity YOUR-OAI-ID" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::your-bucket-name/*" } ] }
方案二:CloudFront Functions(轻量低成本)
如果你的认证逻辑很简单(只是固定用户名密码),CloudFront Functions是更优选择——它比Lambda@Edge更轻量、成本更低,且没有冷启动问题:
1. 创建CloudFront Function
- 打开CloudFront控制台,进入「Functions」页面,创建新函数,选择「Viewer Request」类型。
- 替换函数代码为以下内容(修改用户名密码):
function handler(event) { const request = event.request; const headers = request.headers; const USERNAME = 'your-custom-username'; const PASSWORD = 'your-custom-password'; // 检查Authorization头是否存在 if (!headers.authorization) { return { statusCode: 401, statusDescription: 'Unauthorized', headers: { 'www-authenticate': { value: 'Basic realm="Restricted S3 Site"' } } }; } // 解码并验证凭证 const authValue = headers.authorization.value; const encodedCreds = authValue.split(' ')[1]; const decodedCreds = atob(encodedCreds); const [username, password] = decodedCreds.split(':'); if (username !== USERNAME || password !== PASSWORD) { return { statusCode: 401, statusDescription: 'Unauthorized', headers: { 'www-authenticate': { value: 'Basic realm="Restricted S3 Site"' } } }; } // 认证通过,放行请求 return request; }
- 发布函数,然后在你的CloudFront分发的缓存行为里,将这个函数关联到Viewer Request事件。
2. 同样配置S3桶的OAI访问限制
和方案一的第二步一样,确保用户只能通过CloudFront访问S3内容。
重要注意事项
- 不要硬编码凭证! 如果用Lambda@Edge,建议把用户名密码存在AWS Secrets Manager里,让函数在运行时动态拉取,提升安全性;CloudFront Functions目前不支持访问其他AWS服务,如果你用这个方案,可以考虑定期轮换凭证。
- 测试时直接访问CloudFront的域名,浏览器会自动弹出用户名密码输入框,输入正确凭证即可访问,错误则返回401。
内容的提问来源于stack exchange,提问作者Sandeep Nair
相关产品推荐
相关产品推荐

