跳到主要内容

AWS KMS 签名升级方案

版本: 1.0 | 状态: 待实施


概述

当前问题

问题风险影响
私钥明文存储在环境变量高危服务器泄露导致资金损失
无密钥轮换机制中危长期使用增加泄露风险
无访问审计中危无法追踪密钥使用情况
单点故障高危密钥丢失无法恢复

升级目标

  • 私钥永不离开 AWS KMS(硬件安全模块)
  • 完整的访问审计日志(CloudTrail)
  • 细粒度 IAM 权限控制
  • 自动密钥轮换支持
  • 跨区域灾难恢复

适用范围

服务当前方式升级后
WithdrawService环境变量私钥AWS KMS 签名
EarnService环境变量私钥AWS KMS 签名
ReferralService环境变量私钥AWS KMS 签名
AutoMarketMaker测试账户私钥保持不变(测试用途)

合约配置清单

Vault 合约(资金库)

配置项说明
功能存款/提款、持仓管理、抵押品管理
环境变量VAULT_ADDRESS
当前地址 (Sepolia)0xFDe43f8e6e082975d246844DEF4fE8E704403d43
使用服务WithdrawService, BlockchainService
签名用途EIP-712 提款签名、存款验证

Referral 合约(邀请码反佣)

Storage 合约 - 存储推荐关系

配置项说明
功能推荐码注册、推荐关系存储、用户绑定
环境变量REFERRAL_STORAGE_ADDRESS
当前地址 (Sepolia)0x984BC1C4Aa3995F9B78BA54372a10d3088C249D5

Rebate 合约 - 返佣发放

配置项说明
功能佣金计算、返佣发放、提成结算
环境变量REFERRAL_REBATE_ADDRESS
当前地址 (Sepolia)0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8

Earn 合约(理财服务)

配置项说明
功能定期理财产品、用户申购、到期结算、ERC-1155 NFT凭证
环境变量EARN_CONTRACT_ADDRESS
当前地址 (Sepolia)0xA40b4b726980C02F6558fcA5C0a52FaA2E5A0864
合约版本v3.1 (durationSeconds, dynamic APR, fixed interest)
签名用途EIP-712 申购签名、产品管理签名

Treasury 账户(资金中转)

配置项说明
类型EOA 账户(非智能合约)
功能理财产品利息支付、本金投资中转、收益存入
环境变量TREASURY_ADDRESS
当前地址 (Sepolia)0x6538469807e019E05c9ec4Bd158b12afB1DA50F3

架构设计

整体架构

┌─────────────────────────────────────────────────────────────────────────┐
│ AWS Cloud │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ VPC (Private) │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │
│ │ │ Backend │───▶│ KMS Client │───▶│ AWS KMS │ │ │
│ │ │ Service │ │ (SDK) │ │ ┌───────────────┐ │ │ │
│ │ └─────────────┘ └─────────────┘ │ │ secp256k1 │ │ │ │
│ │ │ │ │ Private Key │ │ │ │
│ │ │ │ │ (HSM 保护) │ │ │ │
│ │ ▼ │ └───────────────┘ │ │ │
│ │ ┌─────────────┐ └─────────────────────┘ │ │
│ │ │ CloudWatch │◀── 签名请求日志 │ │
│ │ │ Logs │ │ │
│ │ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ CloudTrail │ │
│ │ (所有 KMS 操作审计) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘


┌─────────────────┐
│ Blockchain │
│ (Arbitrum) │
└─────────────────┘

签名流程

┌──────────────┐     ┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│ Backend │ │ KMS Signer │ │ AWS KMS │ │ Blockchain │
│ Service │ │ Service │ │ │ │ │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │ │
│ 1. 签名请求 │ │ │
│ (message_hash) │ │ │
│───────────────────▶│ │ │
│ │ │ │
│ │ 2. Sign API │ │
│ │ (ECDSA_SHA_256) │ │
│ │───────────────────▶│ │
│ │ │ │
│ │ │ 3. HSM 内签名 │
│ │ │ (私钥不出 HSM) │
│ │ │ │
│ │ 4. 返回签名 │ │
│ │ (DER format) │ │
│ │◀───────────────────│ │
│ │ │ │
│ │ 5. 转换为 ETH │ │
│ │ 签名格式 │ │
│ │ (r, s, v) │ │
│ │ │ │
│ 6. 返回签名 │ │ │
│◀───────────────────│ │ │
│ │ │ │
│ 7. 提交交易 │
│─────────────────────────────────────────────────────────────▶│

密钥层次结构

AWS KMS
├── axblade-signer-prod (主签名密钥)
│ ├── 算法: ECC_SECG_P256K1 (secp256k1)
│ ├── 用途: 签名提款、Earn、Referral
│ └── 别名: alias/axblade-signer-prod

├── axblade-signer-staging (测试环境密钥)
│ ├── 算法: ECC_SECG_P256K1
│ └── 别名: alias/axblade-signer-staging

└── axblade-data-key (数据加密密钥 - 可选)
├── 算法: SYMMETRIC_DEFAULT (AES-256)
└── 用途: 敏感数据加密

AWS 资源配置

前置条件

# 1. 安装 AWS CLI
brew install awscli # macOS

# 2. 配置 AWS 凭证
aws configure
# AWS Access Key ID: YOUR_ACCESS_KEY
# AWS Secret Access Key: YOUR_SECRET_KEY
# Default region: ap-northeast-1
# Default output format: json

# 3. 验证配置
aws sts get-caller-identity

创建 KMS 密钥

# 创建 secp256k1 签名密钥 (生产环境)
aws kms create-key \
--key-spec ECC_SECG_P256K1 \
--key-usage SIGN_VERIFY \
--description "AXBlade Backend Signer - Production" \
--tags TagKey=Environment,TagValue=production TagKey=Service,TagValue=axblade \
--region ap-northeast-1

# 创建别名 (便于管理)
aws kms create-alias \
--alias-name alias/axblade-signer-prod \
--target-key-id <KEY_ID> \
--region ap-northeast-1

Terraform 配置 (推荐)

# terraform/kms.tf

resource "aws_kms_key" "axblade_signer_prod" {
description = "AXBlade Backend Signer - Production"
key_usage = "SIGN_VERIFY"
customer_master_key_spec = "ECC_SECG_P256K1"
deletion_window_in_days = 30
enable_key_rotation = false # 非对称密钥不支持自动轮换

tags = {
Environment = "production"
Service = "axblade"
ManagedBy = "terraform"
}
}

resource "aws_kms_alias" "axblade_signer_prod" {
name = "alias/axblade-signer-prod"
target_key_id = aws_kms_key.axblade_signer_prod.key_id
}

代码实现

添加依赖

# backend/Cargo.toml

[dependencies]
# AWS SDK
aws-config = "1.1"
aws-sdk-kms = "1.15"

# 签名处理
k256 = { version = "0.13", features = ["ecdsa"] }
elliptic-curve = "0.13"

KMS Signer 服务

// backend/src/services/kms_signer/mod.rs

use aws_sdk_kms::{Client as KmsClient, types::SigningAlgorithmSpec};
use ethers::types::{Address, Signature, H256, U256};

pub struct KmsSigner {
client: KmsClient,
key_id: String,
chain_id: u64,
public_key: Option<Vec<u8>>,
address: Option<Address>,
}

impl KmsSigner {
pub async fn new(config: KmsSignerConfig) -> anyhow::Result<Self> {
let aws_config = aws_config::defaults(aws_config::BehaviorVersion::latest())
.region(aws_config::Region::new(config.region))
.load()
.await;

let client = KmsClient::new(&aws_config);
// ... 初始化公钥和地址
}

pub async fn sign_hash(&self, hash: H256) -> anyhow::Result<Signature> {
let response = self.client
.sign()
.key_id(&self.key_id)
.message(aws_sdk_kms::primitives::Blob::new(hash.as_bytes()))
.message_type(aws_sdk_kms::types::MessageType::Digest)
.signing_algorithm(SigningAlgorithmSpec::EcdsaSha256)
.send()
.await?;

// 解析 DER 签名并转换为以太坊格式
// ...
}
}

部署指南

环境变量配置

# .env.production (生产环境)
ENVIRONMENT=production
SIGNER_TYPE=kms
KMS_KEY_ID=alias/axblade-signer-prod
AWS_REGION=ap-northeast-1

# .env.development (本地开发)
ENVIRONMENT=development
SIGNER_TYPE=local
BACKEND_SIGNER_PRIVATE_KEY=0xac0974bec... # Hardhat 测试私钥

迁移步骤

  1. 获取新 KMS 签名者地址
python scripts/get_eth_address.py alias/axblade-signer-prod
# 输出: Ethereum Address: 0x1234...
  1. 更新智能合约 SIGNER_ROLE
cast send $VAULT_CONTRACT \
"grantRole(bytes32,address)" \
$(cast keccak "SIGNER_ROLE") \
0x1234... \
--private-key $ADMIN_PRIVATE_KEY \
--rpc-url $RPC_URL
  1. 部署新后端
kubectl set env deployment/axblade-backend \
SIGNER_TYPE=kms \
KMS_KEY_ID=alias/axblade-signer-prod
  1. 验证签名
curl -X POST https://api.axblade.com/api/v1/withdraw \
-H "Authorization: Bearer $TOKEN" \
-d '{"token": "USDT", "amount": "1"}' \
| jq '.signature'
  1. 撤销旧签名者权限
cast send $VAULT_CONTRACT \
"revokeRole(bytes32,address)" \
$(cast keccak "SIGNER_ROLE") \
$OLD_SIGNER_ADDRESS \
--private-key $ADMIN_PRIVATE_KEY \
--rpc-url $RPC_URL

安全最佳实践

最小权限原则

# 只授予必要权限
Action = [
"kms:Sign", # 签名
"kms:GetPublicKey", # 获取公钥
"kms:DescribeKey" # 描述密钥
]

# 明确禁止危险操作
Action = [
"kms:Decrypt", # 解密
"kms:GenerateDataKey*", # 生成数据密钥
"kms:ScheduleKeyDeletion" # 删除密钥
]
Effect = "Deny"

密钥访问条件

# 限制只能从特定 VPC 访问
Condition = {
"StringEquals" = {
"aws:SourceVpc" = "vpc-12345678"
}
}

监控与审计

CloudWatch 指标

  • KMS signing errors
  • KMS signing latency
  • Request rate

CloudTrail 审计

所有 KMS 操作自动记录到 CloudTrail,包括:

  • 签名请求时间
  • 调用者身份
  • 请求参数

故障恢复

多区域备份

# 主区域密钥
resource "aws_kms_key" "signer_primary" {
provider = aws.primary # ap-northeast-1
}

# 备份区域副本
resource "aws_kms_replica_key" "signer_replica" {
provider = aws.backup # us-west-2
primary_key_arn = aws_kms_key.signer_primary.arn
}

故障切换流程

# 1. 检测主区域故障
# 2. 切换到备份区域
kubectl set env deployment/axblade-backend \
AWS_REGION=us-west-2 \
KMS_KEY_ID=alias/axblade-signer-replica

成本估算

KMS 定价 (ap-northeast-1)

项目价格预估用量月费用
密钥存储$1/密钥/月2 个密钥$2
签名请求$0.15/10000 次100,000 次$1.50
GetPublicKey$0.03/10000 次1,000 次$0.003
总计~$4/月

常见问题

Q: KMS 签名延迟是多少? A: 通常 50-200ms,取决于区域和网络条件。

Q: 是否支持密钥轮换? A: 非对称密钥 (secp256k1) 不支持自动轮换,需要手动创建新密钥并更新合约。

Q: 如果 AWS 服务不可用怎么办? A: 配置多区域副本,实现跨区域故障转移。


参考文档