麒麟 v10 系统部署Angie与铜锁国密双栈验证

麒麟V10部署Angie与铜锁国密双栈验证

记录时间:2026-11-05
环境:Kylin V10 SP3 (Halberd) / aarch64(全新环境,离线)/ Angie 1.12.4 / Tongsuo 8.5.0(OpenSSL 3.5.4 基线)/ gcc 7.3.0

一、目标与背景

给 nginx 侧加国密能力:同一个入口既服务国密浏览器(TLCP 双证书),也保留 RSA 给国际浏览器,满足国密改造与等保要求。先在测试环境从零跑通整套流程,再谈生产切换。

Web 服务器选型为 Angie 1.12.4:sticky 会话保持和 NTLS 国密都是内置能力,不需要第三方模块;维护由 nginx 核心团队负责,GA 版本正常发布。

二、环境与准备

2.1 环境信息

节点 IP 系统 角色
localhost 192.168.120.79 Kylin V10 SP3 / aarch64 测试机,离线(ISO 挂载 /mnt)
组件 版本 说明
Angie 1.12.4 Web 服务器,内置 sticky 与 NTLS
Tongsuo 8.5.0 国密密码库,enable-ntls 编译
gcc 7.3.0 Kylin 自带
OpenSSL(系统) 1.1.1f(麒麟国密补丁版) 仅作客户端交叉验证,不能用于编译 Angie

2.2 本地 yum 源(离线环境)

ISO 挂载后配本地源。测试机若已有 kylin10-local-repo 可跳过本节。

mount /root/Kylin-Server-V10-SP3-2403-Release-20240426-arm64.iso /mnt
cat > /etc/yum.repos.d/kylin10-local.repo  <<'EOF'
[kylin10-local-repo]
name=Kylin Linux Advanced Server V10 Local Repo
baseurl=file:///mnt
enabled=1
gpgcheck=0
EOF
yum clean all && yum makecache
yum repolist

2.3 安装编译依赖

# yum install -y gcc gcc-c++ make perl perl-Text-Template pcre-devel zlib-devel tar
yum install -y gcc gcc-c++ make perl pcre-devel zlib-devel tar
rpm -q gcc make perl pcre-devel zlib-devel | sed 's/^/  /'

不要把 perl-Text-Template 写进这条命令。Kylin 本地源没有这个包,带上它会整条 yum install 报 No match 并中断,其他包也不会安装。它单独在 2.4 处理。

2.4 离线安装 Text::Template

Tongsuo 的 Configure 第 2109 行是 use Text::Template 1.46;,这是硬依赖,不是测试依赖。它也不是 Perl 核心模块,装了 perl 包也没有。

联网机器下载:

https://cpan.metacpan.org/modules/by-module/Text/Text-Template-1.61.tar.gz

传到测试机后:

cd /usr/local/src
tar xf Text-Template-1.61.tar.gz
cd Text-Template-1.61
perl Makefile.PL && make && make install
perl -MText::Template -e 'print $Text::Template::VERSION, "\n"'   # 输出 1.61

Makefile.PL 阶段提示的 Test::More::UTF8、Test::Warnings 只是测试依赖,忽略即可。装完后模块在 /usr/local/share/perl5,属于 @INC 路径。

2.5 获取源码包

两个项目 release 页都不提供源码 asset,用 tag 归档。在联网机器上下载:

# Tongsuo 8.5.0
curl -L -o Tongsuo-8.5.0.tar.gz \
  https://github.com/Tongsuo-Project/Tongsuo/archive/refs/tags/8.5.0.tar.gz

# Angie 1.12.4
curl -L -o angie-Angie-1.12.4.tar.gz \
  https://github.com/webserver-llc/angie/archive/refs/tags/Angie-1.12.4.tar.gz

传到测试机后解压:

cd /usr/local/src
tar xf Tongsuo-8.5.0.tar.gz
tar xf angie-Angie-1.12.4.tar.gz
ls -d Tongsuo-8.5.0 angie-Angie-1.12.4
ls Tongsuo-8.5.0/test/certs/sm2/ | head   # 只用其中的客户端双证书,第七节 ECDHE 握手要用

预期:两个源码目录就位。

三、编译 Tongsuo 8.5.0

cd /usr/local/src/Tongsuo-8.5.0
./config enable-ntls --prefix=/opt/tongsuo no-shared
make -j"$(nproc)"
make install

验证:

/opt/tongsuo/bin/openssl version
/opt/tongsuo/bin/openssl ciphers -v | grep -iE 'SM2|SM4'

预期输出:

  • 版本:Tongsuo: Tongsuo 8.5.0 加 OpenSSL 3.5.4(8.5.0 已改用 3.5.4 基线,不再是 1.1.1);
  • 套件:ECC-SM2-SM4-GCM-SM3、ECDHE-SM2-SM4-GCM-SM3、ECC-SM2-SM4-CBC-SM3、ECDHE-SM2-SM4-CBC-SM3,以及 TLS1.3 的 TLS_SM4_GCM_SM3、TLS_SM4_CCM_SM3。

Tongsuo 编译耗时几分钟属正常。如果 make 因告警中断,把最后 20 行贴出来再判断,不要自己改编译参数。

四、证书准备

国密证书必须用 CA 签发的标准编码证书,Tongsuo 源码树里那套自签测试证书浏览器不认(原因见 7.4),不写进配置示例。下面只准备两样:线上签发的国密双证书,和一张 RSA 自签证书。

4.1 RSA 自签证书

mkdir -p /AppHome/nginx/cert
openssl req -x509 -newkey rsa:2048 -nodes -days 30 \
  -subj "/CN=sm2-test.local" \
  -keyout /AppHome/nginx/cert/rsa.key -out /AppHome/nginx/cert/rsa.crt

4.2 线上签发国密双证书(gmcert.org)

浏览器验收和生产都用 CA 签发的证书。这里记录 https://www.gmcert.org/subForm# 的签发过程。

一共签两次,签名证书和加密证书各一次,除”密钥用途”外其余完全一致。

两次都相同的项:

表单项 填写 说明
设置证书算法 国密SM2算法
选择CA 签名证书选签名 CA,加密证书选加密 CA(下拉有区分就按类型选)
C / S / L / O / OU 按实际填写(如 CN、广东、广州、gzeport、yw)
主题名称/CN sm2-test.local 必须和浏览器访问的域名一致
基本约束 普通证书 CA 证书是给签发机构用的,不要选
主题备用名称 DNS=sm2-test.local,IP=192.168.120.79 域名必填,IP 加上方便直接用 IP 测
扩展密钥用途 服务器身份验证(TLS Web Server Authentication) 国密浏览器会检查
选择证书签名算法 SM3
证书有效天数 365 测试够用
证书链选项 有”包含完整链”就选它
输出格式 PEM证书+密钥 Angie 只认 PEM,PKCS12 不能直接用
是否发送到邮箱 仅下载 私钥不要走邮箱

两次不同的项:

证书 密钥用途(勾选) 下载后命名
第一次:签名证书 数字签名 + 不可否认(digitalSignature、nonRepudiation) sign.crt / sign.key
第二次:加密证书 密钥加密 + 数据加密(keyEncipherment、dataEncipherment) enc.crt / enc.key

不要选”兼顾签名加密”。TLCP 要求签名和加密是两套独立密钥,Angie 的 ssl_certificate 双参数就是按这个设计的。

下载后归档:

mkdir -p /opt/gmcert/sign /opt/gmcert/enc
cd /opt/gmcert/sign
cp sm2-test.local.cert.pem sign.crt
cp sm2-test.local.key.pem  sign.key
cd /opt/gmcert/enc
cp sm2-test.local.cert.pem enc.crt
cp sm2-test.local.key.pem  enc.key

本次签发结果:签名与加密两张证书签发者是 GMCert GM Root CA - 01,根直签没有中间证书;下载的证书里已经带了根,不需要再 cat 拼链。证书内容核对放在 7.1。

五、编译 Angie

5.1 用户与目录

id gzapps || useradd -r -s /sbin/nologin gzapps
mkdir -p /AppHome/nginx/logs
chown -R gzapps:gzapps /AppHome/nginx/logs

5.2 配置与编译

cd /usr/local/src/angie-Angie-1.12.4
./configure \
  --prefix=/AppHome/nginx --sbin-path=sbin/nginx \
  --user=gzapps --group=gzapps \
  --with-http_ssl_module --with-http_stub_status_module --with-pcre \
  --with-http_gzip_static_module --with-http_v2_module \
  --with-http_sub_module --with-http_realip_module \
  --with-stream --with-stream_ssl_module --with-stream_realip_module \
  --with-debug --with-ntls \
  --with-openssl=/usr/local/src/Tongsuo-8.5.0 \
  --with-openssl-opt="enable-ntls"
make -j"$(nproc)"
参数 作用 不加会怎样
--with-ntls 开启 NTLS 支持(USE_NTLS 默认 NO) ssl_ntls 报 unknown directive
--sbin-path=sbin/nginx 二进制装成 sbin/nginx(Angie 默认 sbin/angie) 启动脚本要改路径
--with-openssl=/usr/local/src/Tongsuo-8.5.0 用 Tongsuo 源码静态编译 TLS 库 用系统 OpenSSL,无国密
--with-openssl-opt="enable-ntls" Tongsuo 侧开启 NTLS TLCP 双证书握手失败
--prefix=/AppHome/nginx 与生产一致,相对 pid logs/... 按它解析 pid/日志路径错位
--user/--group=gzapps 运行用户按现网规范 默认用户不是 gzapps

5.3 安装与校验

make install
/AppHome/nginx/sbin/nginx -V
chown -R gzapps:gzapps /AppHome/nginx/logs

检查四点:Angie/1.12.4、nginx/1.31.2、built with OpenSSL 3.5.4、configure 参数里有 --with-ntls。

Angie 的安装目标默认把二进制命名成 sbin/angie,这里用 --sbin-path=sbin/nginx 保持原名。安装脚本会把同名旧文件改名为 .old,回滚时直接用。

5.4 关于 sticky 的编译参数

不需要任何参数。Angie 的 auto/options 里 HTTP_UPSTREAM_STICKY=YES 是默认值,只有加 --without-http_upstream_sticky_module 才会去掉,所以 configure 里没有、也不需要 --with-...sticky。stream 层的 sticky 同理(STREAM_UPSTREAM_STICKY=YES)。

六、双栈配置

/AppHome/nginx/conf/sm2-test.conf(浏览器验收通过的那一版):

worker_processes 1;
pid logs/angie-sm2-test.pid;
error_log logs/error.log info;
events { worker_connections 256; }
http {
    log_format sm2_probe '$remote_addr:$server_port $ssl_protocol $ssl_cipher $ssl_server_cert_type';

    server {
        listen 443 ssl;
        server_name sm2-test.local;
        ssl_ntls on;

        # 国密双证书:一条指令两个参数(签名证书 + 加密证书)
        ssl_certificate     /opt/gmcert/sign/sign.crt /opt/gmcert/enc/enc.crt;
        ssl_certificate_key /opt/gmcert/sign/sign.key /opt/gmcert/enc/enc.key;

        # 国际 RSA 证书,与国密证书并存
        ssl_certificate     /AppHome/nginx/cert/rsa.crt;
        ssl_certificate_key /AppHome/nginx/cert/rsa.key;

        access_log logs/sm2-access.log sm2_probe;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers "ECC-SM2-SM4-CBC-SM3:ECDHE-SM2-SM4-CBC-SM3:ECC-SM2-SM4-GCM-SM3:ECDHE-SM2-SM4-GCM-SM3:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256";

        location / { return 200 "proto=$ssl_protocol cipher=$ssl_cipher\n"; }
    }
}
指令 说明
ssl_ntls on 启用国密双证书,Angie 内置能力
ssl_certificate(两个参数) 顺序是签名证书在前、加密证书在后
第二组 ssl_certificate 国际 RSA 证书,与国密证书同 server 共存
ssl_ciphers ECC 与 ECDHE 两类国密套件都要列,部分国密客户端只支持 ECC 静态套件
ssl_protocols 只约束国际 TLS;国密走 NTLSv1.1,不受这里控制
log_format sm2_probe 四列分别记录客户端、端口、协议、套件、服务端证书类型,用来一眼区分两条路径
access_log ... sm2_probe 只在测试 server 上开,不能把自定义格式塞进生产 aka_logs
error_log ... debug 本次编译没加 --with-debug,debug 级别不产生调试行,等同 info;保留是为了以后重编时直接可用
/AppHome/nginx/sbin/nginx -t -c /AppHome/nginx/conf/sm2-test.conf
/AppHome/nginx/sbin/nginx -c /AppHome/nginx/conf/sm2-test.conf
ss -lntp | grep :443

国密那组证书固定用 /opt/gmcert 下线上签发的两张,不要换成 Tongsuo 源码树里的自签测试证书——那套浏览器不认。

七、握手验证

7.1 证书核对

握手前先确认两件事:证书内容符合要求、证书与私钥配对。

openssl x509 -in /opt/gmcert/sign/sign.crt -noout -subject -issuer -dates \
  -ext subjectAltName,keyUsage,extendedKeyUsage
openssl x509 -in /opt/gmcert/sign/sign.crt -noout -text | grep -A3 "Public Key Algorithm"
openssl x509 -in /opt/gmcert/sign/sign.crt -noout -text | grep -A1 "ASN1 OID"

cd /opt/gmcert
for p in sign/sign enc/enc; do
  echo "========== $p =========="
  openssl x509 -in $p.crt -noout -subject -issuer -dates \
    -ext subjectAltName,keyUsage,extendedKeyUsage
  openssl x509 -in $p.crt -noout -text | grep -A3 "Public Key Algorithm"
  echo -n "证书公钥指纹: "; openssl x509 -in $p.crt -noout -pubkey | openssl md5
  echo -n "私钥公钥指纹: "; openssl pkey -in $p.key -pubout 2>/dev/null | openssl md5
done

四项必须对:

检查项 期望
Public Key Algorithm id-ecPublicKey + ASN1 OID: SM2
签名证书 keyUsage digitalSignature、nonRepudiation
加密证书 keyUsage keyEncipherment、dataEncipherment(实测还带 Key Agreement)
SAN DNS:sm2-test.local、IP Address:192.168.120.79

第一项不对就别上服务,否则浏览器还是 alert 50(原因见 7.4)。本次签发结果:两张都是 id-ecPublicKey 加 ASN1 OID: SM2,签名证书 keyUsage 是 Digital Signature,加密证书是 Key Encipherment, Data Encipherment, Key Agreement,SAN 为 DNS:sm2-test.local, IP:192.168.120.79,证书与私钥的公钥指纹一致。

7.2 四格握手

客户端 预期协议 预期套件 结果
Tongsuo ECC(无客户端证书) NTLSv1.1 ECC-SM2-SM4-GCM-SM3 通过
Tongsuo ECDHE(带客户端双证书) NTLSv1.1 ECDHE-SM2-SM4-GCM-SM3 通过
360 国密浏览器 NTLSv1.1 ECC-SM2-SM4-GCM-SM3 通过
Chrome / Edge TLSv1.3 TLS_AES_128_GCM_SHA256 通过
Tongsuo TLS1.2 TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 通过
# 国密 ECC,客户端不需要证书
printf 'GET / HTTP/1.0\r\n\r\n' | /opt/tongsuo/bin/openssl s_client \
  -connect 127.0.0.1:443 -cipher ECC-SM2-SM4-GCM-SM3 \
  -enable_ntls -ntls

# 国密 ECDHE,必须带客户端双证书
printf 'GET / HTTP/1.0\r\n\r\n' | /opt/tongsuo/bin/openssl s_client \
  -connect 127.0.0.1:443 -cipher ECDHE-SM2-SM4-GCM-SM3 \
  -enable_ntls -ntls \
  -sign_cert /usr/local/src/Tongsuo-8.5.0/test/certs/sm2/client_sign.crt \
  -sign_key  /usr/local/src/Tongsuo-8.5.0/test/certs/sm2/client_sign.key \
  -enc_cert  /usr/local/src/Tongsuo-8.5.0/test/certs/sm2/client_enc.crt \
  -enc_key   /usr/local/src/Tongsuo-8.5.0/test/certs/sm2/client_enc.key

# 国际 TLS1.3
curl -k -s https://127.0.0.1:443/

# 国际 TLS1.2 精确套件
printf 'GET / HTTP/1.0\r\n\r\n' | /opt/tongsuo/bin/openssl s_client \
  -connect 127.0.0.1:443 -tls1_2 -cipher ECDHE-RSA-AES256-GCM-SHA384

判据:

  • 国密两条看 Protocol: NTLSv1.1,套件名里有没有 SM2 不作数;
  • 国际两条看 TLSv1.3 / TLSv1.2;
  • 客户端没导入 GMCert 根证书时会报 verify error:num=19 self-signed certificate in certificate chain,握手本身不受影响;
  • 自签 RSA 证书会报 verify error:num=18 self-signed certificate,测试环境属正常;
  • -cipher 只对 TLS1.2 及以下生效,不加 -tls1_2 时客户端会协商 TLS1.3、显示 TLS_AES_*,不是配置错误。

7.3 双栈同时生效(最终验证)

恢复双栈配置后,同一台客户端上两种浏览器分别访问,访问日志为:

tail -5 /AppHome/nginx/logs/sm2-access.log
192.168.122.109:443 TLSv1.3 TLS_AES_128_GCM_SHA256 RSA    ← Chrome / Edge
192.168.122.109:443 NTLSv1.1 ECC-SM2-SM4-GCM-SM3   SM2    ← 360 国密浏览器

error.log 无新增记录,说明没有握手失败、没有国际路径缺套件。四列分别是客户端、协议、套件、服务端证书类型。

image-20261105215514164

7.4 浏览器验收卡住的原因:证书公钥编码

这轮验证在浏览器侧耗时最多,先后出现过 alert 46(证书不受信)和 alert 50(decode error),最后定位到证书公钥编码:

证书来源 公钥算法编码 360 国密浏览器表现
Tongsuo openssl 自签 算法 OID 直接是 SM2(1.2.156.10197.1.301) 握手到 ServerKeyExchange 后发 alert 50
gmcert.org 签发 id-ecPublicKey + 曲线参数 SM2 握手成功,NTLSv1.1

结论:国密服务端证书不能只用 Tongsuo 自签,必须用标准编码的证书。向 CA 申请时明确四项要求:签名证书与加密证书两张、id-ecPublicKey + SM2 编码、SAN 含业务域名、PEM 私钥无口令。

八、内置 sticky 验证

在同一个 sm2-test.conf 的 http {} 内追加:

upstream demo_backend {
    server 127.0.0.1:19001;
    server 127.0.0.1:19002;
    sticky cookie route;
}
server {
    listen 18444;
    server_name sticky-test.local;
    location / { proxy_pass http://demo_backend; }
}

Angie 的 sticky 必须带模式参数。现网 nginx 的裸 sticky; 不能直接搬过来;要沿用现有 cookie 名,写 sticky cookie route;。cookie 值格式与 nginx-sticky-module 不同,切换时用户会一次性重新粘滞。

mkdir -p /tmp/b1 /tmp/b2
echo BACKEND-19001 > /tmp/b1/index.html
echo BACKEND-19002 > /tmp/b2/index.html
(cd /tmp/b1 && timeout 900 python3 -m http.server 19001 --bind 127.0.0.1 &)
(cd /tmp/b2 && timeout 900 python3 -m http.server 19002 --bind 127.0.0.1 &)

/AppHome/nginx/sbin/nginx -t -c /AppHome/nginx/conf/sm2-test.conf
/AppHome/nginx/sbin/nginx -s reload -c /AppHome/nginx/conf/sm2-test.conf

curl -sk -c /tmp/cookie.jar -o - http://127.0.0.1:18444/
for i in 1 2 3; do curl -sk -b /tmp/cookie.jar http://127.0.0.1:18444/; done

预期:首次响应带 Set-Cookie: route=<sid>,随后三次请求都落在同一个 BACKEND。

九、回滚与常见问题

现象 处理
ssl_ntls 报 unknown directive 编译时漏了 --with-ntls,重新 configure
ssl_certificate 报参数个数错误 双参数写法只在 ssl_ntls on 时成立,检查开关位置
sticky 报 unknown directive 检查是否误加了 --without-http_upstream_sticky_module
国密握手失败但 RSA 正常 先查签名/加密证书是否颠倒、私钥是否配对;浏览器报 alert 50 查证书公钥编码(7.4)
启动报 getpwnam("gzapps") failed 没有该用户,useradd -r -s /sbin/nologin gzapps
大响应或大上传报权限错误 logs、*_temp 目录属主不对,chown 给 gzapps
make 报 Can't locate Text/Template.pm 2.4 没装,或装完没在 @INC 路径

回滚:安装脚本留下的 sbin/nginx.old 是安装前的文件,覆盖回去后 -t 通过再 reload。

十、参考资料

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇