SMN Service 部署
SMN Service 为部署在服务端的 MPC 可信计算节点,提供 Restful API 供开发者使用,内部集成了一系列 MPC-TSS 密码学算法以及基于 Intel SGX 保护敏感私钥分片数据和 MPC 协议的执行。SMN Service 集群通过使用一套数据库实例维护 SMN Service 集群状态,因此在部署 SMN Service 之前开发者需要准备好 MySQL 数据库。
交付物
| 交付物 | 说明 |
smn-service:X.Y.Z | SMN Service docker 镜像 |
| mpc_node_config.toml | SMN Service 配置文件模版 |
运行环境和依赖
| 类型 | 规格 | 说明 |
| Docker 运行环境 | 最小规格要求:2 CPU、4 G内存、20 G 存储,操作系统使用 Ubuntu 20.04 | 用于运行 SMN Service docker 镜像,宿主机必须支持 Intel SGX 指令集 |
| MySQL 数据库 | 版本 ≥ 8.0 | 用于 SMN Service 集群间通信以及持久化数据,需要创建好数据库,准备好连接地址、账户和密码 |
| SMN Relayer | 用于集群间通信的中间件,需要用到连接地址 | |
| SMN CA | 用于管理和授权 TEE 中相关密钥 |
Docker 宿主机环境
运行 SMN Service 的物理机器需要支持 Intel SGX 指令集,推荐使用阿里云安全增强通用型实例规格族 g7t 运行 SMN Service,操作系统使用 Ubuntu 20.04。创建完成机器后需要安装 Intel SGX 驱动:
apt update && apt install dkms -y
wget https://download.01.org/intel-sgx/sgx-linux/2.22/distro/ubuntu20.04-server/sgx_linux_x64_driver_1.41.bin
chmod +x sgx_linux_x64_driver_1.41.bin
./sgx_linux_x64_driver_1.41.bin检查驱动是否安装成功:
ls /dev | grep sgx
# 如果看到以下设备即安装成功
# sgx
# sgx_enclave
# sgx_provision远程认证配置文件
在阿里云服务器中生成 Intel SGX 可信应用远程认证时依赖的配置文件:
token=$(curl -s -X PUT -H "X-aliyun-ecs-metadata-token-ttl-seconds: 60" "http://100.100.100.200/latest/api/token")
region_id=$(curl -s -H "X-aliyun-ecs-metadata-token: $token" http://100.100.100.200/latest/meta-data/region-id)
PCCS_URL=https://sgx-dcap-server-vpc.${region_id}.aliyuncs.com/sgx/certification/v3/
cat > /etc/sgx_default_qcnl.conf << EOF
PCCS_URL=${PCCS_URL}
USE_SECURE_CERT=TRUE
EOF创建数据库
数据库的字符集 CHARSET 使用 utf8mb4,排序和比较规则 COLLATE 使用 utf8mb4_general_ci;开发者也可以使用以下 SQL 命令创建数据库:
CREATE DATABASE safeheron_mpc_node_service CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;首次启动 SMN Service 时会自动检测是否存在相关的数据表结构,如果不存在将会自动创建表结构,无需手动创建。
创建配置文件
我们在用户目录下准备一个文件夹 node,在 node 文件夹内创建 mpc_node_config.toml:
cd ~
mkdir node && cd node
touch mpc_node_config.tomlmpc_node_config.toml 配置文件内容如下,开发者需要修改其中的 relayer 地址和数据库相关配置:
[MPC]
# 默认 10s,建立 MPC 节点之间连接的等待时间
# 如一个 MPC Session 需要 Party 1,Party 2,Party 3 参与,当前节点为 Party 1,
# 则需要在 10s 内完成收到 Party 2 和 Party 3 的 ReadyMessage,否则响应 ReadyTimeout 错误
ReadyTimeout = '10s'
# 默认 2m,当启动一个计算 Session 后,这个 Session 需要在 2m 内完成,
# 否则响应 SessionTimeout 错误
SessionTimeout = '2m'
# 配置本地 Party
[Party]
# 必填,每一个 Party 必须指定一个 ID,所有参与方的 Party 的 ID 在全局上必须是连续的,
# 并且从 1 开始,比如 SMN Service ID 是 1,Embeded MPC Node 的 Party ID 分别是 2 和 3
# 建议 MPC Node Service 使用 ID 1
ID = 1
# 租户公私钥,用于 MPC Node 之间通信加解密;用于连接通信 Relayer 鉴权
# 开发者可以使用 openssl 命令行工具生成 PrivateKey 和 PublicKey,具体的生成方式见后文
PrivateKey = '7c6567273b75068b53e09ac07334d0bd8ffa00ae006635d99c266512e3008644'
PublicKey = '040ad492d08ba2f34e8bdf44a079694b47374f89c74265700a57888ea2437ee1f4167f98fa232d33daf24440726b03a08476cd1ef697d4b0a6a145dccbea732202'
# 配置通信 Relayer 信息
[Relayer]
# 必填,通信 Relayer 的地址
# 必须是 ws:// 和 wss:// 开头,后面是一个标准的可访问的 URL 路径,可以是 IP 或者域名
Address = 'ws://url:8070'
[Database]
# Url 中 safeheron_mpc_node_service 为数据库名称,需要根据实际情况修改
Url = 'jdbc:mysql://url:3306/safeheron_mpc_node_service?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B0'
# 用户授权说明:
# GRANT SELECT ON `performance_schema`.user_variables_by_thread TO username@'%';
# GRANT ALL PRIVILEGES ON database_name.* TO 'username'@'%';
# FLUSH PRIVILEGES;
Username = 'username'
Password = 'password'
# 提供 Restful API 的 Server 相关配置
[APIServer]
Port = 8080
# CMP 算法相关配置
[CMP]
# CMP 算法在分布式私钥分片生成时会在本地生成同态加密密钥,生成同态加密密钥比较耗时
# 同态加密密钥在可信环境中生成,仅存储在加密内存中,通过以下两个参数控制预生成数据的数量
# 最小预生成数量,必须小于等于 MaxPrekeyGenCacheSize,大于等于 0
MinPrekeyGenCacheSize = 50
# 最大预生成数量
MaxPrekeyGenCacheSize = 100
# Log 配置
[Log]
# 日志级别,支持 Debug、Info、Warning、Error、Off 等级,其中 Off 为不输出日志
Level = 'Info'
# 日志存放位置
Filepath = '/opt/logs'
[TEE]
# 通过完成授权的 CA 进行授权
CAAddress = 'http://ip_or_cluster_url:port'
# 配置 License 信息
[License]
# 配置 License 数据,例如:key/ewog****
Key = 'key/ewog****'生成 Party 公私钥
在上述配置文件中,[Party] 配置项需要配置本地租户的通信和鉴权公私钥,同时公钥也需要配置到 Relayer 的配置文件以及 Embedded MPC Node 的配置文件中,使用 openssl 生成的命令如下:
# 生成 secp256r1 私钥文件
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
# 根据私钥文件生成公钥
openssl ec -in private_key.pem -pubout -out public_key.pem
# 以 16 进制字符串形式输出 MPC Node Service 需要的私钥格式
# 预期的输出结果类似 23201708d099c8a1751aedd303135cd75533dd4912086c27c3c39b09e05fa282
openssl ec -in private_key.pem -text -noout | grep -A 3 "priv:" | grep -v "priv:" | tr -d ' \n:' && echo
# 以 16 进制字符串形式输出 MPC Node Service 需要的公钥格式
# 预期的输出结果类似 04b398578127089d06deea4004820ff867c50c22972568f6da00c602af26c19e96339d609f90c236b9d97744a62723c1933a94f8935657c6a35f04701642192aaf
openssl ec -in public_key.pem -pubin -text -noout | grep -A 5 "pub:" | grep -v "pub:" | tr -d ' \n:' && echo生成接口 JWT 鉴权公私钥
在调用 SMN Service 接口时,需要使用私钥对发起的交易数据进行签名。您可以通过以下命令生成鉴权公私钥:
# 生成 Secp256r1 私钥
openssl ecparam -genkey -name prime256v1 -noout -out mpcnode_secret.pem
# 生成对应的公钥
openssl ec -in mpcnode_secret.pem -pubout -out mpcnode.pem如果在调用方程序中需要使用 pkcs8 格式的私钥,您可以通过以下命令转换密钥:
openssl pkcs8 -topk8 -in mpcnode_secret.pem -out mpcnode_secret_pkcs8.pem -nocrypt在部署 SMN Service 时,您需要将公钥 mpcnode.pem 存放至和配置文件相同的目录内。
使用 docker 启动
假设 mpc_node_config.toml 配置文件以及 在当前目录,在当前目录内使用以下命令启动 SMN Service,日志存储在当前目录 logs 文件夹下:
cd ~/node
docker run \
-d \
--rm \
--device /dev/sgx_enclave:/dev/sgx_enclave \
--device /dev/sgx_provision:/dev/sgx_provision \
-p 8080:8080 \
-v $(pwd)/mpc_node_config.toml:/opt/safeheron/mpc_node_config.toml \
-v $(pwd)/mpcnode.pem:/opt/safeheron/mpcnode.pem \
-v $(pwd)/logs:/opt/logs \
-v $(pwd)/smn_tee_engine:/root/.smn_tee_engine \
-v $(pwd)/preStop:/opt/safeheron/preStop \
-v /etc/localtime:/etc/localtime:ro \
-v /etc/sgx_default_qcnl.conf:/etc/sgx_default_qcnl.conf \
--name mpcnode \
smn-service:X.Y.Z使用以下命令查看 SMN Service 日志输出:
# service layer log
tail -f logs/web_info.log
# tee engine log
tail -f logs/tee_engine.log使用以下命令查看 SMN Service 是否正常启动,如果返回 HTTP 状态码 200,即正常启动:
curl 127.0.0.1:8080/check -v使用以下命令停止容器:
docker stop mpcnode至此,已经部署完成 SMN Service,后续我们将提供高可用集群部署方式以及横向扩容方式。开发者需要记录 SMN Service 所在服务器 IP、Party ID 和 TPK(租户公钥),供后续使用。
更新 SMN Service
在更新 SMN Service 前准备好需要更新的 smn-service 镜像,更新流程为停止当前正在运行的 docker 容器,使用新景象启动即可。停止当前运行的容器:
docker stop mpcnode在包含配置文件 mpc-node-config.toml 的文件夹中启动容器,注意,镜像 tag 使用需要更新的新镜像:
cd ~/node
docker run \
-d \
--rm \
--device /dev/sgx_enclave:/dev/sgx_enclave \
--device /dev/sgx_provision:/dev/sgx_provision \
-p 8080:8080 \
-v $(pwd)/mpcnode.pem:/opt/safeheron/mpcnode.pem \
-v $(pwd)/mpc_node_config.toml:/opt/safeheron/mpc_node_config.toml \
-v $(pwd)/logs:/opt/logs \
-v $(pwd)/smn_tee_engine:/root/.smn_tee_engine \
-v $(pwd)/preStop:/opt/safeheron/preStop \
-v /etc/localtime:/etc/localtime:ro \
-v /etc/sgx_default_qcnl.conf:/etc/sgx_default_qcnl.conf \
--name mpcnode \
smn-service:X.Y.Z使用以下命令查看 SMN Service 日志输出:
# service layer log
tail -f logs/web_info.log
# tee engine log
tail -f logs/tee_engine.log使用以下命令查看 SMN Service 是否正常启动,如果返回 HTTP 状态码 200,即正常启动:
curl 127.0.0.1:8080/check -v高可用和扩容

SMN Service 的集群部署模式如上图所示,同一个 SMN Service 集群通过同一个 MySQL 维护 SMN Service 自身集群状态,因此只需要使用相同的配置启动多个 SMN Service,通过负载均衡器代理 SMN Service 服务即可。
SMN Service 通过部署多实例的方式提供高可用服务以及通过横向增加实例的方式进行扩容。在部署多个 SMN Service 实例时,这些实例必须都连接相同的 MySQL ,并且使用相同的配置项,如保持门限、超时时间等相同以避免预料之外的错误。
Load Balance 本身的高可用和扩容一般由云厂商 Load Balance 类产品或者成熟的负载均衡产品提供。MySQL 通过主从复制方式实现高可用,通过自身垂直扩容的方式实现扩容。
文档变更记录
2024-03-22 1.1.0 版本更新
- Docker 启动命令增加 preStop 目录挂载
- 更新高可用和扩容章节中的图示
2024-06-26 1.2.0 版本更新
- 增加 License 配置