第 7 章 · 安全与合规
7.1 安全设计原则
ADAP 的安全设计遵循以下核心原则:
- 最小权限原则:每个组件(Lambda、Glue Job、EMR、Agent)使用独立 IAM Role,仅授予完成本职工作所需的最小权限
- 纵深防御:认证、鉴权、网络隔离、数据加密多层防护,任一层失效不导致整体沦陷
- 密钥零暴露:数据库密码等敏感信息全程不出现在代码、日志或前端请求中
- 用户数据隔离:所有数据按用户 ID(Cognito sub)严格隔离,跨用户无法访问
7.2 用户认证
7.2.1 Amazon Cognito User Pool
ADAP 使用 Amazon Cognito User Pool(adap-users) 管理用户身份:
| 配置项 | 值 |
|---|---|
| 登录方式 | 邮箱 + 密码(不支持用户名登录) |
| 邮箱验证 | 注册后自动发送验证邮件,强制验证 |
| 密码策略 | 最少 8 位,含大写字母 + 小写字母 + 数字 |
| 认证协议 | SRP(Secure Remote Password),不传递明文密码 |
| MFA | 当前关闭(原型阶段),可后续启用 TOTP |
| 账号恢复 | 仅邮箱方式找回 |
| 自注册 | 允许用户自主注册 |
| 数据保护 | CDK destroy 时保留用户数据(RemovalPolicy=RETAIN) |
7.2.2 Token 配置
| Token 类型 | 有效期 | 说明 |
|---|---|---|
| Access Token | 1 小时 | 用于 API 调用鉴权 |
| ID Token | 1 小时 | 含用户属性(email、sub 等),前端使用 |
| Refresh Token | 30 天 | 用于无感刷新 Access/ID Token |
7.2.3 前端认证流程
用户输入邮箱 + 密码
↓
前端调用 Cognito SRP 认证(AWS Amplify SDK)
↓
Cognito 返回 Access Token + ID Token + Refresh Token
↓
Token 存储在内存(不存 localStorage,防 XSS)
↓
每次 API 请求携带 Authorization: Bearer <AccessToken>
↓
Token 过期 → 用 Refresh Token 静默刷新 → 失败则跳转登录页7.3 API 鉴权
7.3.1 REST API:Cognito Authorizer
REST API Gateway 使用 Cognito Authorizer 验证每个请求的 JWT Token:
HTTP 请求
Header: Authorization: Bearer <AccessToken>
↓
API Gateway Cognito Authorizer
↓
验证 Token 签名(Cognito JWKS 公钥)
验证 Token 未过期
验证 aud(Client ID 匹配)
↓
通过 → 将 claims 注入 requestContext.authorizer.claims
失败 → 返回 401 Unauthorized后端 Lambda 从 claims.sub 获取用户唯一标识(owner_id),用于数据隔离:
owner_id = event["requestContext"]["authorizer"]["claims"]["sub"]
# 查询时仅返回该 owner_id 的数据7.3.2 WebSocket API:Lambda 自定义鉴权
WebSocket $connect 时使用 Lambda 自定义鉴权器(adap-ws-authorizer) 验证 Token:
鉴权流程:
WebSocket 连接请求
URL: wss://xxx.execute-api.../prod?token=<IDToken>
↓
Lambda 鉴权器(adap-ws-authorizer)
↓
1. 从 queryStringParameters.token 提取 JWT
2. 从 Cognito JWKS 端点获取公钥(缓存 1 小时)
3. 用 PyJWT 验证签名、过期时间、aud(Client ID)
↓
通过 → 返回 Allow IAM Policy + principalId
失败 → 返回 Deny IAM Policy → 连接被拒绝JWKS 缓存机制:Lambda 容器级别缓存 Cognito 公钥(TTL=1 小时),避免每次连接都请求 JWKS 端点,减少延迟。
7.4 用户数据隔离
7.4.1 项目级隔离
adap-projects DynamoDB 表使用 GSI(owner_id-created_at-index)实现用户隔离:
- 每个项目写入时携带
owner_id(来自 Cognito sub) - 查询时强制带上
owner_id过滤,用户只能看到自己的项目 - 即使猜到其他用户的
project_id,API 也会返回 403(owner_id 不匹配)
7.4.2 数据源隔离
数据源(数据库连接信息)同样与 owner_id 绑定:
- 下拉框只显示当前用户保存的数据源
- 跨用户无法复用数据源配置
7.5 密钥与敏感信息管理
7.5.1 数据库密码:SSM Parameter Store
ADAP 全程不传递明文数据库密码,统一通过 AWS SSM Parameter Store(SecureString 类型) 管理:
存储格式:
参数路径: /adap/datasource/{datasource_id}/password
类型: SecureString(KMS 加密)前端交互:
- 新建数据源时,前端只填写 SSM Key 路径(如
/adap/mysql/password) - 密码在前端环境中不存在,不会出现在网络请求、日志、浏览器缓存中
运行时取用:
# Agent 运行时通过 IAM Role 权限动态获取
ssm = boto3.client("ssm", region_name=config.AWS_REGION)
password = ssm.get_parameter(
Name=password_ssm_key,
WithDecryption=True # KMS 自动解密
)["Parameter"]["Value"]IAM 限制:
# 所有 Lambda/Agent/Glue Job 的 SSM 权限仅限 /adap/* 路径
Resource: arn:aws:ssm:{region}:{account}:parameter/adap/*
Action: ssm:GetParameter, ssm:GetParameters7.5.2 其他敏感配置
| 配置项 | 存储位置 | 说明 |
|---|---|---|
| AgentCore Memory ID | SSM /adap/memory_id | Chief Architect 跨会话记忆标识 |
| Step Functions ARN | SSM /adap/sfn/arn | 优先从环境变量读取,降级到 SSM |
| QuickSight 用户名 | 环境变量 QS_USER | 注入到 AgentCore 容器 |
| EMR Application ID | DynamoDB adap-settings | 由用户在 SettingsPage 配置,加密存储 |
7.6 IAM 最小权限
7.6.1 ADAP-LambdaAgentRole(Lambda 执行角色)
| 权限 | 资源范围 | 用途 |
|---|---|---|
| S3 读写 | arn:aws:s3:::adap-* | 读写数据湖和 Agent 状态 |
| DynamoDB 读写 | arn:aws:dynamodb:...:table/adap-* | 项目、事件、WS 连接、HitL 表 |
| DynamoDB Stream | arn:aws:dynamodb:...:table/adap-*/stream/* | ws-sender 读取变更流 |
| SSM 读写 | arn:aws:ssm:...:parameter/adap/* | 读取/写入数据库密码 |
| Bedrock 调用 | 指定模型 ARN | 调用 Claude 系列模型 |
| AgentCore 调用 | arn:aws:bedrock-agentcore:...:runtime/* | 调用 Agent Runtime |
| Step Functions | arn:aws:states:...:stateMachine:adap-* | 启动 / 查询 SFN 执行 |
| CloudWatch Logs | 所有 | Lambda 基础执行权限 |
| Glue(部分) | arn:aws:glue:...:*/adap-* | 查询 Glue 表、Job 状态 |
7.6.2 ADAP-GlueServiceRole(Glue ETL 执行角色)
| 权限 | 资源范围 | 说明 |
|---|---|---|
| S3 读写 | arn:aws:s3:::adap-prototype-* | 仅限数据湖 Bucket |
| SSM 读取 | arn:aws:ssm:...:parameter/adap/* | 读取数据库密码 |
| Glue 基础权限 | AWSGlueServiceRole 托管策略 | CloudWatch Logs 等 |
⚠️ 不挂载
AmazonS3FullAccess或AmazonAthenaFullAccess,避免权限过宽。
7.6.3 ADAP-AgentCore-Role(Bedrock Agent 执行角色)
| 权限 | 资源范围 | 说明 |
|---|---|---|
| Bedrock 模型调用 | Claude Sonnet 4.6 / Opus 4 | 仅授权指定模型 |
| S3 读写 | 数据湖 Bucket | 读写 Agent 状态、PRD、中间结果 |
| Knowledge Base | Bedrock KB ARN | RAG 检索行业知识库 |
| Step Functions | adap-* 状态机 | Agent 触发后续阶段 |
7.6.4 ADAP-EMR-JobRole(EMR Serverless 执行角色)
| 权限 | 资源范围 | 说明 |
|---|---|---|
| S3 读写 | 数据湖 Bucket | PySpark 读写 ODS/DWD/DWS/ADS |
| Glue Catalog | 所有 adap 数据库 | 读取表 Schema,写入 Iceberg 元数据 |
| CloudWatch Logs | 指定日志组 | EMR 作业日志 |
7.7 网络与传输安全
7.7.1 HTTPS 强制
- REST API Gateway:默认 TLS 1.2+,不支持 HTTP 降级
- WebSocket API:
wss://(WebSocket Secure),不允许ws:// - CloudFront → S3:Origin Access Identity(OAI),S3 禁止直接公开访问
7.7.2 S3 数据湖安全配置
s3.Bucket(
self, "DataLakeBucket",
block_public_access=s3.BlockPublicAccess.BLOCK_ALL, # 完全屏蔽公开访问
encryption=s3.BucketEncryption.S3_MANAGED, # SSE-S3 服务端加密
enforce_ssl=True, # 强制 HTTPS 访问
)7.7.3 VPC 网络隔离(生产建议)
Glue ETL Job 在私有 VPC 内运行,通过 Glue Connection(VPC 模式)访问 MySQL/RDS:
- Glue Worker 启动在与 RDS 同安全组的子网内
ensure_glue_connectionTool 自动创建 Glue VPC Connection(仅读取 VPC 配置,不修改安全组规则)- Agent Runtime(AgentCore)部署在 VPC 私有子网,可访问 RDS
7.8 数据合规
7.8.1 PII 数据治理
详见第 5 章 5.4 节,此处补充合规流程:
ODS 数据接入完成
↓
Data Governance Agent 自动触发 PII 扫描
↓
识别敏感字段(双重策略:字段名匹配 + 采样值正则验证)
↓
HIGH / MEDIUM / LOW 三级分类
↓
申请 Lake Formation 列级标签(SENSITIVITY 维度)
↓
生成 GovernanceReport(保存 DynamoDB + S3)
↓
结果在前端"合规报告" Tab 展示给用户7.8.2 数据生命周期管理
S3 数据湖配置了生命周期规则(CDK 定义):
| 数据前缀 | 保留周期 | 说明 |
|---|---|---|
ods/ | 90 天 | ODS 原始数据,超期自动删除 |
athena-results/ | 30 天 | Athena 查询结果缓存 |
dwd/ dws/ ads/ | 无限制(默认) | 分析层数据,手动管理 |
7.8.3 项目删除与数据清理
ADAP 提供两种项目删除模式,满足数据清理合规需求:
模式 A(仅删除元数据):
- 删除 DynamoDB 中的项目记录和事件记录
- AWS 资源(Glue Tables、S3 数据、Athena 历史)保留
- 适合:快速删除,保留底层数据用于审计
模式 B(级联删除):
- 删除 DynamoDB 记录
- 删除 Glue Tables(四层数据库中的所有表)
- 删除 S3 对应前缀下的所有数据文件
- 适合:满足数据删除合规要求(如用户注销、GDPR 数据删除请求)
7.9 安全最佳实践建议
以下为生产环境部署建议(当前原型阶段部分未实施):
| 建议项 | 优先级 | 说明 |
|---|---|---|
| 启用 MFA | P1 | Cognito TOTP 二次验证,保护管理员账号 |
| 限制自注册 | P1 | 生产环境关闭 self_sign_up,改为管理员邀请制 |
| WAF 接入 | P1 | 在 CloudFront + API Gateway 前挂载 AWS WAF,防 SQL 注入 / DDoS |
| 启用 CloudTrail | P1 | 记录所有 AWS API 调用,满足审计要求 |
| KMS 自定义密钥 | P2 | 将 S3 加密从 SSE-S3 升级为 SSE-KMS(自管密钥) |
| VPC Endpoint | P2 | S3/DynamoDB/SSM 走 VPC Endpoint,避免流量出公网 |
| PII 字段脱敏 | P2 | DWD 层对 HIGH 级 PII 字段做哈希或掩码处理 |
| Lake Formation 细粒度权限 | P3 | 实施列级访问控制,限制不同角色对 PII 字段的查询权限(v3.0 规划) |
| 定期轮换 SSM 密码 | P2 | 配合 AWS Secrets Manager 实现自动轮换 |
本章参考来源:infra/cdk/auth_stack.py、iam_stack.py、api_stack.py、lambda_authorizer.py、s3_stack.py、agentcore_stack.py、agents/data_governance.py