Amazon Cognito 多区域复制实战:跨 Region 用户认证不中断的正确姿势

Amazon Cognito 多区域复制实战:跨 Region 用户认证不中断的正确姿势

上个月隔壁组的登录服务挂了 15 分钟。事后复盘的时候老板问了一句:如果整个区域不可用怎么办?全场沉默。

说实话,之前做认证服务的容灾,我们的方案是自己写数据同步脚本。每次切换都得强制让用户重新登录,体验极差。

现在亚马逊云科技的 Cognito 原生支持多区域复制了。用户数据、凭证、池配置自动同步到备用区域,故障切换时用户无感知——不需要重置密码,不需要重新登录。我实际配了一把,记录一下。

这个功能解决什么问题

之前用 Amazon Cognito 做多区域容灾有三个痛点:

  1. 自己写同步逻辑 — 用户池配置、用户数据要自己导出导入,容易出不一致
  2. 切换时用户体验差 — token 换了签发方,客户端得强制重新认证
  3. M2M 认证更麻烦 — 机器间通信的 client_id/secret 要在备用区域重新创建

现在 Cognito 的 multi-Region replication 把这些全包了:

  • 单向复制:主区域 → 备用区域(备用区域只读)
  • 用户数据、凭证、池配置自动同步
  • 两个区域发的 access token 互相认可
  • 支持所有认证方式:社交登录、SAML、OIDC、API 授权流

限制先说清楚

在动手之前,有几个限制得知道:

  • 故障切换期间不支持新用户注册配置更新
  • 备用区域是只读的,只负责认证
  • Lambda 触发器、WAF 配置需要在备用区域手动部署
  • 需要 Essentials 或 Plus 层级

配置步骤:三步搞定

第一步:创建多区域 KMS 密钥

Cognito 多区域复制的前提是用自定义 KMS 密钥加密。这个密钥必须是多区域密钥(Multi-Region Key)。

# 在主区域创建多区域主密钥
aws kms create-key \
  --description "Cognito multi-region encryption key" \
  --multi-region \
  --region us-west-2

# 记下返回的 KeyId,格式类似 mrk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

拿到 Key ARN 后,在目标区域创建副本:

# 在备用区域创建副本密钥
aws kms replicate-key \
  --key-id arn:aws:kms:us-west-2:123456789012:key/mrk-xxxxxxxx \
  --replica-region us-east-1

然后更新密钥策略,允许 Cognito 服务使用这个密钥:

{
  "Sid": "AllowCognitoAccess",
  "Effect": "Allow",
  "Principal": {
    "Service": "cognito-idp.amazonaws.com"
  },
  "Action": [
    "kms:Encrypt",
    "kms:Decrypt",
    "kms:GenerateDataKey",
    "kms:DescribeKey",
    "kms:CreateGrant"
  ],
  "Resource": "*"
}

第二步:配置多区域 OIDC Endpoint

这一步是让你的应用使用新的、支持多区域路由的 OIDC endpoint。

在 Cognito 控制台,进入 User Pool → Multi-Region → Step 2,切换 OIDC issuer 类型。

切换后会生成新的 endpoint URL。重要:你的客户端应用必须更新到新 endpoint。如果不更新,切换区域后旧 endpoint 会失效。

对于服务端应用,改配置重新部署。对于移动端 App,需要提交新版本到应用商店。这一步建议提前规划。

第三步:启用复制

# 在控制台选择目标区域后启用
# 目前 CLI/SDK 配置方式参考官方文档
# 控制台操作:User Pool → Multi-Region → Step 3 → 选择目标区域 → Create

复制准备时间取决于用户池的数据量。准备好后手动激活(Activate),状态变为 Active 即可。

故障切换策略

Cognito 不会帮你自动切换流量——这是有意为之的。你需要自己设计检测和切换机制。

方案一:Route 53 健康检查

如果用自定义域名做 Cognito 的 Hosted UI,可以配置 Route 53 健康检查:

# 创建健康检查
aws route53 create-health-check \
  --caller-reference "cognito-health-$(date +%s)" \
  --health-check-config '{
    "Type": "HTTPS",
    "FullyQualifiedDomainName": "auth.example.com",
    "Port": 443,
    "ResourcePath": "/.well-known/openid-configuration",
    "RequestInterval": 10,
    "FailureThreshold": 3
  }'

方案二:自定义监控 + DNS 切换

import boto3
import time

def check_cognito_health(region, user_pool_id):
    """检查 Cognito 服务健康状态"""
    client = boto3.client('cognito-idp', region_name=region)
    try:
        response = client.describe_user_pool(UserPoolId=user_pool_id)
        return response['UserPool']['Status'] == 'Active'
    except Exception as e:
        print(f"Health check failed in {region}: {e}")
        return False

def failover_dns(primary_region, secondary_region):
    """切换 DNS 到备用区域"""
    route53 = boto3.client('route53')
    # 更新 DNS 记录指向备用区域的 Cognito endpoint
    # 具体实现根据你的 DNS 架构
    print(f"Failover: {primary_region} → {secondary_region}")

# 主循环
primary = 'us-west-2'
secondary = 'us-east-1'
pool_id = 'us-west-2_xxxxx'

while True:
    if not check_cognito_health(primary, pool_id):
        failover_dns(primary, secondary)
        break
    time.sleep(30)

定价

多区域复制是附加功能,按月活用户数计费:

层级 每 MAU 每副本区域
Essentials $0.0045
Plus $0.006

M2M(机器间认证)在标准价格基础上加 30%。

举个例子:10 万 MAU 的 Essentials 层应用,加一个副本区域,每月多花 $450。对于核心业务来说这个成本可以接受。

可用区域

主区域和备用区域都必须在支持列表内:

  • 美东:Ohio、N. Virginia
  • 美西:N. California、Oregon
  • 亚太:Mumbai、Seoul、Singapore、Sydney、Tokyo
  • 加拿大:Central
  • 欧洲:Frankfurt、Ireland、London、Paris、Stockholm
  • 南美:São Paulo

东京可用——对亚太业务来说够用了。

我的建议

  1. 先做 OIDC endpoint 迁移 — 这一步对客户端有影响,提前做
  2. 选相同大洲的备用区域 — 延迟更低,比如东京主→首尔备
  3. Lambda 触发器别忘了 — 自定义认证流程的 Lambda 要在备用区域也部署一份
  4. 定期演练 — 配好不测试等于没配,每季度做一次切换演练

参考链接

posted @ 2026-06-08 11:06  亚马逊云开发者  阅读(3)  评论(0)    收藏  举报