使用Stunnel作为网关实现PSK认证

一、背景

在某业务场景下,需要使用PSK(Pre-Shared Key)认证方式,且对TLS版本有要求。Pre-Shared Key是预定义的密码认证方式,在客户端和服务器端通过预先定义好的密码进行校验,校验成功则建立TLS连接,全过程不依赖SSL证书。PSK是一种轻量级的认证方式,通常适合客户端设备不方便使用证书、或者客户端加密算力不足的场景。

为满足此类需求,通常可以考虑的方案包括基于常见的网关服务如Nginx、HAproxy上进行相应的配置,并转发流量。虽然如此,主流操作系统如Ubuntu默认的Nginx/HAproxy安装包里的二进制文件启动的服务是不支持PSK认证的,需要从源代码重新编译Nginx和HAproxy,由此需要配置OpenSSL等软件开发包,过程相当麻烦。

为解决这个问题,可使用Stunnel。Stunnel是一个开源的TLS服务代理,可以负责接收客户端请求作为TLS网关,并转发流量到后端真正的应用服务器上。本文介绍如何配置Stunnel实现PSK认证。

二、部署模拟后端应用程序的WEB服务器

本文部署一个WEB服务器,提供一个静态网页输出,最终能请求到这个网页表示系统工作正常。

sudo apt install apache2
sudo systemctl start apache2
sudo systemctl enable apache2

编辑/var/www/html/index.html文件,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PSK Authentication Success</title>
</head>
<body>
    <h1>Hello World!</h1>
    <p>Welcome to the PSK-authenticated website.</p>
    <p>If you can see this page, your TLS PSK authentication is working correctly.</p>
</body>
</html>

现在使用curl在本机测试下访问WEB服务器。

curl http://localhost:80/index.html

可看到访问成功。

三、部署Stunnel以支持TLS-PSK

1、从Ubuntu自带软件源安装

为了简化测试过程,安装Stunnel的PSK网关和模拟后端应用的WEB服务器部署在同一个EC2虚拟机上,以简化测试过程。实际使用中,可将它们分别部署在不同的EC2实例上。

创建一台EC2,配置如下:

  • AMI机型选择Ubuntu 24.04LTS
  • 规格选择 c7i-flex.large (2vCPU/4GB)
  • 系统架构选择 x86_64
  • 存储选择gp3类型容量10GB
  • 安全组选择放行443入站流量
  • VPC和子网选择能有外部网络的子网,Public IP选择启动

其他选项使用默认即可。

创建完毕后登录到系统,执行如下命令:

sudo apt update
sudo apt upgrade -y
sudo apt install stunnel4
sudo reboot

由于安装升级了较多软件包,最后执行重启。

2、创建配置文件

执行如下命令创建Stunnel配置文件:

sudo mkdir -p /var/run/stunnel4
sudo chown stunnel4:stunnel4 /var/run/stunnel4

sudo tee /etc/stunnel/psk.conf << 'EOF'
pid = /var/run/stunnel4/psk.pid
foreground = no

[psk-web]
accept = 443
connect = 127.0.0.1:80
PSKsecrets = /etc/psk/psk.txt
EOF

执行如下命令创建PSK密钥配置文件并设置权限,这里预设了几个账号的PSK密码例子(注意Stunnel要求密钥长度大于16位)。

sudo tee /etc/psk/psk.txt << 'EOF'
client1:deadbeefcafebabedeadbeefcafebabe
client2:1234567890abcdef1234567890abcdef
iot_device_001:abcdef1234567890abcdef1234567890
EOF
sudo chmod 600 /etc/psk/psk.txt
sudo chown stunnel4:stunnel4 /etc/psk/psk.txt

3、启动服务

sudo systemctl start stunnel4
sudo systemctl enable stunnel4

四、客户端访问测试

1、OpenSSL客户端测试

在安装Stunnel的本机使用openssl客户端发起连接:

openssl s_client -connect localhost:443 -servername localhost -psk_identity client1 -psk deadbeefcafebabedeadbeefcafebabe

测试结果如下表示握手成功。

CONNECTED(00000003)
---
no peer certificate available
---
No client certificate CA names sent
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 229 bytes and written 481 bytes
Verification: OK
---
Reused, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_CHACHA20_POLY1305_SHA256
    Session-ID: 335F08FEC9785156B7CAE3EF7FE5BF17F38481A4CA50189E52430543259090F0
    Session-ID-ctx:
    Resumption PSK: E377C1BD69AB537230F3BC2F36DBF62E24CC081BD3B20337A3995DF5BCB43BBD
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 304 (seconds)
    TLS session ticket:
    0000 - c8 65 62 3a 92 23 cb 38-17 79 15 d8 3e cf 7e ae   .eb:.#.8.y..>.~.
    0010 - 1f 90 81 94 8b f4 9e 0d-18 45 d4 d6 7b 41 a3 8a   .........E..{A..
    0020 - 27 db ae a9 cf e7 d7 08-64 03 85 3f 65 6d 7d 58   '.......d..?em}X
    0030 - 80 50 4e 9e c9 e9 b4 d5-74 7e a3 33 3b 4f 4c fa   .PN.....t~.3;OL.
    0040 - e8 4d 91 a0 99 93 86 ba-6b d0 d6 f5 fa 8d 70 5f   .M......k.....p_
    0050 - c1 ea 06 5e a8 b5 5b 9a-5d 27 86 73 14 a5 c1 da   ...^..[.]'.s....
    0060 - ac fd 75 19 a0 71 3c 09-5c be 34 07 9a 6c c3 0e   ..u..q<.\.4..l..
    0070 - 05 3a b6 3b ad 4e 3a 8c-d9 dc a2 17 27 dd 20 a6   .:.;.N:.....'. .
    0080 - 83 ae 0e 7c 0f 20 31 fc-ae 25 a0 ed fa 46 11 8d   ...|. 1..%...F..
    0090 - 9f 46 07 c2 cf af 41 32-85 b3 2f c9 78 0a 14 a5   .F....A2../.x...
    00a0 - 53 de 95 7f f0 9b 36 1d-1f 3b 87 53 bb dd c9 60   S.....6..;.S...`
    00b0 - a3 75 54 90 77 1d 53 b1-5c a7 59 8f 6f f9 89 c9   .uT.w.S.\.Y.o...
    00c0 - 3c ab 4c 27 05 93 30 8e-68 81 93 38 46 2d a8 2e   <.L'..0.h..8F-..

    Start Time: 1765526300
    Timeout   : 304 (sec)
    Verify return code: 1 (unspecified certificate verification error)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK

2、HTTP请求测试

现在换成HTTP方式的请求,并且可以在远程的其他服务器上测试请求,注意请求Header里边包含PSK密钥。命令如下:

echo -e "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n" | openssl s_client -connect localhost:443 -servername localhost -psk_identity client1 -psk deadbeefcafebabedeadbeefcafebabe -quiet

返回结果如下:

HTTP/1.1 200 OK
Date: Fri, 12 Dec 2025 08:09:35 GMT
Server: Apache/2.4.58 (Ubuntu)
Last-Modified: Fri, 12 Dec 2025 07:53:16 GMT
ETag: "181-645bc8ddd33cb"
Accept-Ranges: bytes
Content-Length: 385
Vary: Accept-Encoding
Content-Type: text/html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PSK Authentication Success</title>
</head>
<body>
    <h1>Hello World!</h1>
    <p>Welcome to the PSK-authenticated website.</p>
    <p>If you can see this page, your TLS PSK authentication is working correctly.</p>
</body>
</html>

由此可以看到Stunnel服务实现了PSK认证、以及后续的流量转发。

五、其他使用操作

1、修改PSK密码文件

执行如下命令修改密码文件:

sudo vim /etc/psk/psk.txt

改动完毕后,需要重启服务才能生效,执行如下命令:

sudo systemctl stop stunnel4
sudo systemctl start stunnel4

如果您需要高频修改密码,建议将Stunnel网关上的PSK认证文件/etc/psk/psk.txt部署到共享存储服务上,或者放在S3存储桶内,这样配置文件更新后,所有的EC2都可以读取到最新的PSK密码配置文件。

2、指定特定TLS算法

安装Stunnel最新版后,默认使用最新的TLS 1.3算法。查看算法的方法是运行如下命令:

openssl s_client -connect localhost:443 -psk_identity client1 -psk deadbeefcafebabedeadbeefcafebabe | grep -E "Protocol|Cipher"

例如返回结果如下:

Reused, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256
    Protocol  : TLSv1.3
    Cipher    : TLS_CHACHA20_POLY1305_SHA256

可以看到这是默认的算法。如果要修改算法,例如使用TLSv1.2,那么需要修改Stunnel的配置文件。

执行如下命令编辑配置文件:

sudo vim /etc/stunnel/psk.conf

在配置文件末尾加入如下两行:

slVersion = TLSv1.2
ciphers = PSK-AES128-GCM-SHA256:PSK-AES256-GCM-SHA384

保存配置文件,退出编辑模式,然后重启服务。

sudo systemctl stop stunnel4
sudo systemctl start stunnel4

再次运行刚才的命令查看建立连接的协议,即可看到:

New, TLSv1.2, Cipher is PSK-AES256-GCM-SHA384
    Protocol  : TLSv1.2
    Cipher    : PSK-AES256-GCM-SHA384

修改配置成功。

六、小结

根据本文测试可以看出,Stunnel可以实现PSK认证并实现对后端应用服务器的转发。如果需要在生产环境部署,那么可使用如下方式:

  • 在最前端部署NLB四层负载均衡,使用唯一的域名作为入口,转发流量到至少2台EC2
  • EC2上部署Stunnel作为网关,提供PSK认证服务,在配置文件中指定后端应用的入口地址(可以用域名)

全文完。


最后修改于 2025-12-12