frp 自定义tls协议加密
之前讲了通过frp实现内网穿透来实现ssh访问局域网内主机的功能. 事实上frp还可以用来将部署在本地电脑上的服务暴露在公网上, 让用户可以自由地访问. 这让很多老电脑有了变废为宝的机会, 比如我在上面部署了个聊天室. 然而, 有一个问题是如果走tcp或者http协议的话, 配置起来很方便但本地主机到服务器之间的流量是明文的, 会有一些安全隐患. 这篇文章记录一下我配置服务端和客户端之间通信走tls加密的过程.
客户端配置
本文的内容是基于已经配置好了基本的frp的情况的, 所以如果还没开始, 可以先参考这篇[文章].
首先, 官方文档里提供了http和https的传输方式, 可以通过域名来提供不同的服务. 但是我折腾了半天, HTTPS那个一直失败, 所以就选择了官方文档里的另一个方案: 通过tls进行全局加密. 这也是官方推荐的安全配置方式 [Ref].
本文内容是基于官方文档的, 只是官方文档和github主页的简单说明里有些内容有重复和命名混淆, 让我这个小白在里面绕了很多圈子, 这里的讲解会区分它们.
首先, 把openssl的配置文件拷贝过来, 文件路径会有不同, 可以用openssl version -d
命令查看.
# 查看配置文件路径
$ openssl version -d
OPENSSLDIR: "/usr/lib/ssl"
# 拷贝到frpc本地
cp /usr/lib/ssl/openssl.cnf ./my-openssl.cnf
然后, 在客户端生成ca和给服务端的证书. 记得把IPADDRESS
改成服务端的IP.
# 生成ca证书
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=example.ca.com" -days 5000 -out ca.crt
# 生成给服务端的证书
openssl genrsa -out server.key 2048
openssl req -new -sha256 -key server.key \
-subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=server.com" \
-reqexts SAN \
-config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP:[IPADDRESS],DNS:example.server.com")) \
-out server.csr
openssl x509 -req -days 3650 -sha256 \
-in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(printf "subjectAltName=DNS:localhost,IP:[IPADDRESS],DNS:example.server.com") \
-out server.crt
然后把server.key
和server.crt
拷贝到服务端, 可以用scp
命令实现.
服务端配置
同样的, 根据openssl配置文件生成ca证书并给客户端的证书. 这里证书申请里是不用配置IP的, 所以直接复制粘贴运行就好了.
# 查看配置文件路径
$ openssl version -d
OPENSSLDIR: "/usr/lib/ssl"
# 拷贝到frps本地
cp /usr/lib/ssl/openssl.cnf ./my-openssl.cnf
# 生成ca证书
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=example.ca.com" -days 5000 -out ca.crt
# 生成给客户端的证书
openssl genrsa -out client.key 2048
openssl req -new -sha256 -key client.key \
-subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=client.com" \
-reqexts SAN \
-config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:client.com,DNS:example.client.com")) \
-out client.csr
openssl x509 -req -days 3650 -sha256 \
-in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(printf "subjectAltName=DNS:client.com,DNS:example.client.com") \
-out client.crt
然后把client.key
和client.crt
拷贝到客户端, 可以用scp
命令实现.
配置文件修改
注意配置文件中关于tls协议的配置比如在[common]
section下面.
首先修改客户端的配置文件 frpc.ini
.
# 开启tls
tls_enable = true
# 指定ca证书和服务端复制来的client公私钥目录
tls_trusted_ca_file = path/ca.crt
tls_cert_file = path/client.crt
tls_key_file = path/client.key
然后修改服务端的配置文件 frps.ini
.
# 强制开启tls, 只接受tls连接的客户端
tls_only = true
# 开启tls
tls_enable = true
# 指定ca证书和客户端来的server公私钥目录
tls_cert_file = path/server.crt
tls_key_file = path/server.key
tls_trusted_ca_file = path/ca.crt
最后, 在客户端上运行./frpc -c frpc.ini
, 在服务端上运行./frps -c frps.ini
, 查看是否正常运行.
没有问题的话, 就可以systemctl restart
它们了. 这样下来, 本地端到服务端之间的通信是全局加密的了.
将本地服务端口暴露给服务端
配置了服务端和客户端之间的流量走tls协议加密之后, 就可以很快地用tcp为本地的服务进行配置. 比如我把本地的rocket chat端口暴露给服务端, 这样服务端通过nginx方向代理就可以像访问服务端的服务一样访问本地的服务了.
[rocketchat_tcp]
type = tcp
local_ip = 127.0.0.1
local_port = 3000
remote_port = 3000
use_compression = true
作者以非凡的视角解读平凡,让文字焕发出别样的光彩。
这是一篇佳作,无论是从内容、语言还是结构上,都堪称完美。
语言通俗易懂,适合目标读者群体。