惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
P
Privacy International News Feed
T
Tenable Blog
L
Lohrmann on Cybersecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
S
Securelist
C
CXSECURITY Database RSS Feed - CXSecurity.com
Cisco Talos Blog
Cisco Talos Blog
T
The Exploit Database - CXSecurity.com
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
Vercel News
Vercel News
Cyberwarzone
Cyberwarzone
月光博客
月光博客
T
The Blog of Author Tim Ferriss
Scott Helme
Scott Helme
爱范儿
爱范儿
Stack Overflow Blog
Stack Overflow Blog
C
Cisco Blogs
aimingoo的专栏
aimingoo的专栏
博客园 - 司徒正美
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Proofpoint News Feed
A
Arctic Wolf
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LangChain Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
阮一峰的网络日志
阮一峰的网络日志
Simon Willison's Weblog
Simon Willison's Weblog
T
Tor Project blog
Security Latest
Security Latest
Blog — PlanetScale
Blog — PlanetScale
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
博客园 - 三生石上(FineUI控件)
I
InfoQ
Spread Privacy
Spread Privacy
B
Blog RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
S
SegmentFault 最新的问题
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
MongoDB | Blog
MongoDB | Blog
C
CERT Recently Published Vulnerability Notes
A
About on SuperTechFans
博客园_首页
Engineering at Meta
Engineering at Meta
Project Zero
Project Zero
Latest news
Latest news

Alliot's blog

域名切换到blog.alliot.tech Docker 代理配置机制与作用域 Docker 代理配置机制与作用域 2025年底的安卓搞机备忘录 2025年底的安卓搞机备忘录 ArgoCD部署应用出现metadata.annotations过大问题 ArgoCD部署应用出现metadata.annotations过大问题 APC UPS更换电池校准容量 APC UPS更换电池校准容量 M1 Mac安装低版本Node.js M1 Mac安装低版本Node.js Ansible使用Bitwarden存储Vault密码 Ansible使用Bitwarden存储Vault密码 Cloudflare Tunnel前置代理支持 Cloudflare Tunnel前置代理支持 CDN场景下配置Vaultwarden启用fail2ban CDN场景下配置Vaultwarden启用fail2ban 中银香港丝滑开户总结 中银香港丝滑开户总结 从指定路径更新雷池WAF证书 AWS ECS使用EBS作为Volume AWS ECS使用EBS作为Volume 浅浅的调教一下国产智障电视 浅浅的调教一下国产智障电视 Nginx proxy_pass到AWS ALB的504问题 Nginx proxy_pass到AWS ALB的504问题 OpenV**手动指定路由规则 OpenV**手动指定路由规则 本地模拟CNAME解析 本地模拟CNAME解析 Nginx搭建WebDAV服务 Nginx搭建WebDAV服务 迎来船新版本的Hexo+NexT 迎来船新版本的Hexo+NexT 优雅的处理Git多帐号与代理问题 优雅的处理Git多帐号与代理问题 验光配镜扫盲 验光配镜扫盲 Prometheus relabel实现动态metrics path Prometheus relabel实现动态metrics path
从指定路径更新雷池WAF证书
Alliot · 2024-04-02 · via Alliot's blog

  雷池(SafeLine) 是长亭科技部分开源的一款 Web 防火墙,社区版本已经有较为完善的 WAF 功能,可以满足个人项目的基本 Web 防护需求。 不过目前(v5.2.0)雷池对于证书的操作,仅支持从 UI 导入或使用 Let’s Encrypt 的 HTTP-01 验证方法 来配置证书, 这对于使用 DNS 验证的短期证书用户来说非常不方便,可以看到社区有这样的需求的小伙伴还是挺多的: [建议] 证书增加使用路径导入方式 | Github issue, 因此便写了个小脚本来实现这个需求。

调研

雷池本身也是基于 Tengine 来做网关的, 证书配置也在 Tengine 来实现, 因此 Alliot 一开始准备直接操作容器中 Tengine 的证书文件来实现, 不过看样子社区中有小伙伴已经尝试过了: [Bug] 手动更新证书文件并重启容器后,【证书管理】界面的有效期时间没有同步更新, 从底下的评论可以知道目前雷池的证书还是以数据库为准,直接操作文件并不能达到更新证书的目的。
这里打算通过操作雷池 API 来达到目的。

动手

官方并没有提供 API 文档,也没有提供生成 API key 的操作,只能通过模拟登录来实现。
雷池登录流程为: 密码登录 -> 校验通过后得到中间 JWT -> 校验 OTP -> 校验通过后得到最终的 JWT, 并且前面过程中都需要携带 CSRF token, 由于逻辑并不复杂,并且也是简单的构建一下请求,这里就直接贴代码吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import requests
import time
import pyotp
import urllib3

BASE_URL = "https://www.iots.vip" # 登录地址
USERNAME = "admin"
PASSWORD = "123123123"

OTP_SECRET = "ADXXXXXXWB5S3UIWZCDX" # 动态验证码的密钥
CERT_ID = "1" # 证书ID, 一般如果仅有一个证书,ID为1, 多个证书也可以调用下面的list_all_certs来获取ID
CERT_FILE_PATH = "www.iots.vip.crt" # 证书路径
CERT_KEY_PATH = "www.iots.vip.key" # 证书路径


def get_passcode(secret):
totp = pyotp.TOTP(secret)
return totp.now()

class SafeLine:
def __init__(self, base_url):
urllib3.disable_warnings()
self.base_url = base_url
self.csrf_token = None
self.jwt = None
self.session = requests.Session()
self.session.verify = False

def get_csrf_token(self):
response = self.session.get(f"{self.base_url}/api/open/auth/csrf")
data = response.json()
self.csrf_token = data['data']['csrf_token']
return self.csrf_token

def login(self, username, password):
self.get_csrf_token()
payload = {
"username": username,
"password": password,
"csrf_token": self.csrf_token
}
response = self.session.post(f"{self.base_url}/api/open/auth/login", json=payload)
data = response.json()
self.jwt = data['data']['jwt']
return self.jwt

def validate_mfa(self, code):
self.get_csrf_token()
headers = {'authorization': 'Bearer ' + self.jwt}
payload = {
"code": code,
"timestamp": int(time.time() * 1000),
"csrf_token": self.csrf_token
}
response = self.session.post(f"{self.base_url}/api/open/auth/tfa", headers=headers, json=payload)
data = response.json()
if data['err'] is None:
self.jwt = data['data']['jwt']
print("login success")
else:
self.jwt = None
return data['data']['jwt']

def list_all_certs(self):
headers = {'authorization': 'Bearer ' + self.jwt}
response = self.session.get(f"{self.base_url}/api/open/cert", headers=headers)
data = response.json()
return data['data']['nodes']

def update_cert(self, cert_id, crt, key):
headers = {'authorization': 'Bearer ' + self.jwt}
payload = {
"manual": {
"crt": crt,
"key": key
},
"type": 2
}
response = self.session.put(f"{self.base_url}/api/open/cert/{cert_id}", headers=headers, json=payload)
data = response.json()
if data['err'] is None:
print("update success")


if __name__ == '__main__':
safeline = SafeLine(base_url=BASE_URL)
safeline.login(USERNAME, PASSWORD)
safeline.validate_mfa(get_passcode(OTP_SECRET))

with open(CERT_FILE_PATH, 'r') as cert_file:
cert_str = cert_file.read()
with open(CERT_KEY_PATH, 'r') as key_file:
cert_key = key_file.read()
safeline.update_cert(CERT_ID, cert_str, cert_key)

安装依赖:

1
pip install requests pyotp

填好参数后 python main.py 运行,去到控制台便可以看到完成了证书更新。

部署到Certbot

Alliot 是使用 Certbot 自动申请的泛域名证书,配合对应 DNS 提供商的插件,可以实现自动颁发、续签证书。 这里使用 certbot-dns-aliyun 来实现阿里云托管域名的 Let’s Encrypt 证书自动申请。

安装部署Certbot && 阿里云DNS插件

已经有自己的证书的可以跳到下一小节。

1
2
# 确保已经安装Python3运行环境后执行 
pip install certbot certbot-nginx certbot-dns-aliyun

创建配置文件,填入阿里云 AccessKey(申请方式: 获取AccessKey|Aliyun):

1
2
3
4
mkdir /etc/certbot

touch ali_credentials.ini
chmod 600 ali_credentials.ini

ali_credentials.ini 格式如下:

1
2
dns_aliyun_access_key = xxxx
dns_aliyun_access_key_secret = xxxx

之后我们尝试申请一下证书:

1
2
3
4
certbot certonly \
--authenticator=dns-aliyun \
--dns-aliyun-credentials='/etc/certbot/ali_credentials.ini' \
-d "*.example.com,example.com"

添加一个定时任务到 crontab

1
(crontab -l 2>/dev/null; echo "0 0 * * * certbot renew -q") | crontab -

配置自动更新雷池里的证书

现在 Certbot 已经可以为我们自动申请 SSL 证书了,我们可以利用 Certbot 的 renewal-hooks 来达到证书续期后自动更新到雷池:

1
2
3
4
5
6
7
8
9
10
# 复制上面的代码,填入自己的配置
vim /etc/certbot/renew_safeline_cert.py

# 创建一个hook
cd /etc/letsencrypt/renewal-hooks/deploy

cat > update_safeline_ssl.sh << EOF
#!/bin/bash
python /etc/certbot/safeline_renew_cert/main.py
EOF

现在来测试一下 renewal-hooks:

1
2
3
4
5
6
7
8
9
10
11
certbot renew 
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/www.iots.vip.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simulating renewal of an existing certificate for www.iots.vip
Waiting 30 seconds for DNS changes to propagate
Hook 'deploy-hook' ran with output:
login success
update success

可以看到 deploy-hook 成功执行,大工告成! 之后每次 Certbot 在更新完证书后都会同步更新雷池里托管的 SSL 证书。

更新

date: 2024-12
为了更方便大家调用,Alliot 封装了一个 Safeline 雷池的 Pypi 包,你可以直接通过如下方式来调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from safeline import SafeLine
CERT_ID = 1
CERT_FILE_PATH = "mycert.pem"
CERT_KEY_PATH = "mykey.pem"

if __name__ == '__main__':
BASE_URL = "https://xxxx"
USERNAME = "admin"
PASSWORD = "xxxxxx"

OTP_SECRET = "x"

waf = SafeLine(BASE_URL,
USERNAME,
PASSWORD,
OTP_SECRET
)


with open(CERT_FILE_PATH, 'r') as cert_file:
cert_str = cert_file.read()
with open(CERT_KEY_PATH, 'r') as key_file:
cert_key = key_file.read()

waf.certification.update(CERT_ID, cert_str, cert_key)