aws-samples/sample-cognito-apigateway-authorization
GitHub: aws-samples/sample-cognito-apigateway-authorization
演示如何通过 API Gateway 的 Lambda 授权方结合 Cognito JWT 验证,在边缘层实现严格的用户级数据隔离与防越权访问控制。
Stars: 0 | Forks: 0
# Cognito 授权演示
演示了如何使用 Amazon Cognito、API Gateway 和 Lambda 授权方来保护特定于用户的数据。核心安全规则:**用户只能访问自己的数据。** 任何 URL 中的 `userId` 与调用方 JWT 的 `sub` 声明不匹配的请求,都会在 API Gateway 层被拒绝——甚至在这些请求到达您的后端之前。
## 前置条件
在部署此示例之前,请确保您具备以下条件:
**AWS 账户和权限:**
- 一个拥有以下 IAM 权限的有效 AWS 账户:
- **Amazon Cognito**:`CreateUserPool`、`AdminCreateUser`、`DescribeUserPool`
- **API Gateway**:`CreateRestApi`、`CreateDeployment`、`CreateAuthorizer`
- **Lambda**:`CreateFunction`、`AddPermission`、`UpdateFunctionCode`
- **EKS**:`CreateCluster`、`DescribeCluster`、`UpdateKubeconfig`
- **IAM**:`CreateRole`、`AttachRolePolicy`、`CreatePolicy`
- **KMS**:`CreateKey`、`CreateAlias`、`Encrypt`、`Decrypt`
- **CloudFormation**:`CreateStack`、`DescribeStacks`、`DeleteStack`
- **VPC/EC2**:`CreateVpc`、`CreateSubnet`、`CreateSecurityGroup`
- 一个至少包含 2 个可用区的有效 VPC
**所需工具:**
- [AWS CLI v2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 并配置有默认区域
- [AWS CDK v2](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html) (`npm install -g aws-cdk`)
- [kubectl v1.24+](https://kubernetes.io/docs/tasks/tools/) 已安装并配置
- [Python 3.9+](https://www.python.org/downloads/)(用于演示脚本)
- [Docker](https://docs.docker.com/get-docker/)(如果适用,用于容器构建)
## 核心概念
如果您不熟悉本演示中使用的任何服务,这里有一个简短的介绍:
- **[Amazon Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html)** — 托管用户身份验证服务。可以将其视为用户登录后颁发 JWT 令牌的“登录系统”。
- **[API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html)** — 位于您的 API 前面的托管服务,负责处理路由、限流和授权。
- **[Lambda 授权方](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html)** — API Gateway 在转发请求之前调用的 Lambda 函数。它会检查 JWT 令牌并决定是允许还是拒绝。
- **[Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html)** — 托管的 Kubernetes 服务。在这里作为可选后端使用——该授权模式适用于任何后端。
- **JWT `sub` 声明** — JSON Web Token 中的 `sub`(主题)字段是已认证用户的唯一标识符。[了解更多关于 JWT 的信息](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html)。
## 工作原理
当用户调用 `GET /users/{userId}/orders` 时,Lambda 授权方会:
1. 从 `Authorization` 请求头中提取 `Bearer` 令牌
2. 根据 [Cognito JWKS 端点](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html)验证 JWT
3. 将令牌的 `sub` 声明(用户的唯一 ID)与请求路径中的 `{userId}` 进行比较
4. 如果它们匹配则返回 `Allow`,不匹配则返回 `Deny`
以下是 Lambda 函数中实际的执行逻辑:
```
# 来自 Lambda authorizer — 这是真实的代码,而不是 pseudocode
# 从 API Gateway method ARN 中提取 userId
# ARN format: arn:aws:execute-api:{region}:{account}:{api}/{stage}/{method}/users/{userId}/...
arn_parts = method_arn.split('/')
resource_path = '/'.join(arn_parts[3:])
path_segments = resource_path.split('/')
user_idx = path_segments.index('users')
user_id_from_path = path_segments[user_idx + 1]
# 解码 JWT 并提取 sub claim
payload = decode_jwt_payload(token) # base64-decodes the JWT payload
sub = payload.get('sub', '')
# 如果路径 userId 与 token 的 sub 不匹配,则拒绝
if user_id_from_path != sub:
return generate_policy(sub, 'Deny', method_arn)
return generate_policy(sub, 'Allow', method_arn)
```
**不匹配时发生的情况:**
```
GET /users/other-user-id/orders
Authorization: Bearer
→ Lambda authorizer returns Deny
→ API Gateway returns 403 Forbidden
→ Request never reaches backend
```
## 架构
```
┌──────────┐ ┌───────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Client │────▶│ API Gateway │────▶│ Lambda Authorizer│ │ EKS / Mock │
│ (Browser/ │ │ (Regional) │ │ (JWT Validation │ │ Backend │
│ SDK) │◀────│ │◀────│ + sub Match) │────▶│ │
└──────────┘ └───────────────┘ └──────────────────┘ └─────────────┘
│
▼
┌──────────────┐
│ Cognito User │
│ Pool (JWKS) │
└──────────────┘
```
**部署的内容:**
| 资源 | 用途 |
|----------|---------|
| 具有公有/私有子网的 VPC | 跨 2 个可用区的网络隔离 |
| NAT Gateway | 为私有子网提供出站互联网访问 |
| Cognito User Pool + App Client | 用户身份验证和 JWT 颁发 |
| Lambda 授权方 | JWT 验证和 `sub` 声明强制执行 |
| API Gateway(区域性) | 具有 3 个受保护端点的 REST API |
| EKS 集群 + 节点组 | 可选的 Kubernetes 后端 |
| KMS 密钥 | 用于 EKS 密钥、Lambda 环境变量和 CloudWatch Logs 的加密 |
| VPC Flow Logs | 网络流量审计日志 |
## 部署说明
### 第一步:克隆存储库
```
git clone https://github.com/aws-samples/sample-cognito-apigateway-authorization.git
cd sample-cognito-apigateway-authorization
```
### 第二步:验证前置条件
确保您的 AWS CLI 已配置并具有所需的权限:
```
aws sts get-caller-identity
```
您应该会看到您的账户 ID 和 IAM 主体。如果失败,请先运行 `aws configure`。
### 第三步:部署基础设施
**选项 A — 使用部署脚本(推荐):**
```
chmod +x deploy.sh
./deploy.sh
```
**选项 B — 使用 AWS CLI 手动部署:**
```
aws cloudformation deploy \
--template-file cloudformation/infrastructure.yaml \
--stack-name cognito-demo-authorizer-v2 \
--capabilities CAPABILITY_IAM \
--parameter-overrides EnvironmentName=cognito-demo
```
部署大约需要 15–20 分钟(EKS 集群创建是瓶颈)。
### 第四步:记录堆栈输出
部署完成后,检索测试所需的输出:
```
aws cloudformation describe-stacks \
--stack-name cognito-demo-authorizer-v2 \
--query 'Stacks[0].Outputs' \
--output table
```
您将看到:
| 输出 | 描述 |
|--------|-------------|
| `UserPoolId` | 用于身份验证的 Cognito User Pool ID |
| `UserPoolClientId` | 用于令牌请求的 App 客户端 ID |
| `ApiGatewayUrl` | 受保护 API 的基础 URL(例如,`https://{id}.execute-api.{region}.amazonaws.com/prod`) |
| `EKSClusterName` | EKS 集群名称(如果部署 K8s 工作负载) |
### 第五步:(可选)将 API 部署到 EKS
如果您想在 EKS 上运行后端 API 而不是使用 MOCK 集成:
```
chmod +x deploy-eks-apis.sh
./deploy-eks-apis.sh
```
这会更新您的 kubeconfig,并将三个经过强化的 Kubernetes 部署(user-info、orders、profile)部署到专用的 `cognito-demo` 命名空间中。
验证 Pod 是否正在运行:
```
kubectl get pods -n cognito-demo
```
### 第六步:运行演示测试
安装 Python 依赖并运行自动化测试:
```
pip install -r requirements.txt
python3 demo-scripts/test-demo.py
```
测试脚本将会:
1. 在 Cognito User Pool 中创建两个测试用户(`testuser1`、`testuser2`)
2. 对两个用户进行身份验证并获取 JWT 访问令牌
3. 测试每个用户是否可以访问自己的数据(期望 `200 OK`)
4. 测试每个用户访问对方数据时是否会被阻止(期望 `403 Forbidden`)
**预期输出:**
```
Starting User-Specific Data Protection Demo
Step 1: Creating test users...
✓ Created user: testuser1
✓ Created user: testuser2
Step 2: Getting access tokens...
✓ Got token for testuser1 (sub: a1b2c3d4...)
✓ Got token for testuser2 (sub: e5f6g7h8...)
Step 3: Testing API access scenarios...
--- Testing User Info API (GET /users/{userId}) ---
Test 1: User1 accessing their own data (Expected: ALLOW)
✓ SUCCESS: Access granted to info for user a1b2c3d4...
Test 2: User1 trying to access User2's data (Expected: DENY)
✓ SUCCESS: Access denied to info for user e5f6g7h8... (as expected)
...
Demo completed successfully!
```
### 第七步:使用 curl 手动测试
您也可以直接测试 API。首先,获取测试用户的令牌:
```
# 认证并获取 access token
TOKEN=$(aws cognito-idp admin-initiate-auth \
--user-pool-id \
--client-id \
--auth-flow ADMIN_NO_SRP_AUTH \
--auth-parameters USERNAME=testuser1,PASSWORD=TempPass123! \
--query 'AuthenticationResult.AccessToken' \
--output text)
```
然后调用 API — 将 `` 替换为令牌中的 `sub` 声明:
```
# 访问你自己的数据(应返回 200)
curl -H "Authorization: Bearer $TOKEN" \
/users//orders
# 尝试访问其他用户的数据(应返回 403)
curl -H "Authorization: Bearer $TOKEN" \
/users/some-other-user-id/orders
```
## 清理
删除所有已部署的资源:
```
chmod +x cleanup.sh
./cleanup.sh
```
这会删除 Kubernetes 部署(如果有)和 CloudFormation 堆栈,包括 Cognito User Pool、Lambda 函数、API Gateway、EKS 集群、VPC 以及所有相关资源。
要验证清理是否完成:
```
aws cloudformation describe-stacks --stack-name cognito-demo-authorizer-v2
# 应返回 "Stack does not exist"
```
## 安全注意事项
### 身份验证与授权
- **令牌过期**:Cognito User Pool 令牌具有可配置的过期时间。请设置短期访问令牌(1 小时或更短)并定期轮换刷新令牌。
- **授权方缓存**:Lambda 授权方会缓存策略结果(默认 300 秒 TTL)。请根据您的安全要求调整缓存 TTL——TTL 越短意味着被撤销的令牌会被越快拒绝,但这会增加 Lambda 调用次数。
- **受众验证**:将 JWT 验证范围限制为特定的 Cognito User Pool ARN。避免使用通配符受众验证。
### IAM 最小权限
- **演示 IAM 策略**:为了简单起见,此演示使用了宽泛的 IAM 策略。在生产环境之前,请将通配符(`*`)资源替换为每个 API 和函数的特定 ARN。
- **EKS Pod 身份**:为 EKS Pod 使用 [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html),而不是节点级别的实例配置文件。
### 网络安全
- **VPC Flow Logs**:此模板启用 VPC Flow Logs 以进行审计日志记录和异常检测。
- **Security Groups**:使用 Security Groups 限制 API Gateway、Lambda 和 EKS 命名空间之间的流量。
- **WAF**:考虑在 API Gateway 上使用 [AWS WAF](https://docs.aws.amazon.com/waf/latest/developerguide/what-is-aws-waf.html),以提供针对常见 Web 攻击的额外保护。
### 生产环境强化
- 在生产部署之前,请根据组织的安全策略进行渗透测试。
- 为所有 API 调用和 Lambda 调用启用 [CloudTrail](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html) 和 CloudWatch Logs。
- 使用 [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) 管理任何密钥,而不是使用环境变量。
- 实施适合您流量模式的速率限制和节流。
- 根据组织的 Pod 安全标准审查并强化 Kubernetes 清单。
## 许可证
本项目基于 MIT-0 许可证授权。详情请参见 [LICENSE](LICENSE) 文件。
标签:Amazon Cognito, API Gateway, AWS, AWS CDK, AWS Lambda, CISA项目, CloudFormation, Docker, DPI, EKS, IAM, JSONLines, JWT, KMS, Lambda授权器, ProjectDiscovery, Python, Serverless, Streamlit, Token验证, VPC, 安全演示, 安全防御评估, 微服务安全, 授权, 数据保护, 无后门, 用户数据隔离, 访问控制, 逆向工具, 零信任