Docker 部署 MongoDB / MySQL / PostgreSQL 安全加固实录:TLS 双向认证、双因素鉴别与审计

环境:Linux 宿主机 + Docker Compose、fastgpt_shared_network(典型网段 172.18.0.0/16

场景:等保 / 行业安全检查中的数据库整改项(传输加密、身份鉴别、审计)

版本:MongoDB 5.0.18、MySQL 8.2.0、PostgreSQL(官方镜像)


一、写在前面:检查项与社区版能力

近期连续做了三套库的加固,检查方常见要求可归纳为:

类别 典型表述 社区版能否做
传输加密 启用 TLS/SSL,requireSSL / 双向证书 (OpenSSL,国际算法)
国密 SM2/SM4 传输/存储使用国密算法 库本身不原生支持 TLCP;需网关/VPN/应用层 SM4
双因素鉴别 口令 + 证书 / 动态口令 / 堡垒机 (证书+口令;OTP 在堡垒机)
安全审计 logging_collector、登录与 DDL 等 (PG 推荐 pgAudit)

结论 :不必迷信「SSL 版」「企业版才有 TLS」------官方 Docker 镜像已带 OpenSSL;企业版主要多 TDE、LDAP 等,不等于国密 TLCP。


二、整体架构(与 FastGPT 类项目一致)

text 复制代码
                    ┌─────────────────────────────────────────┐
  运维 Navicat       │  Docker: fastgpt_shared_network         │
  (证书+口令)  ────► │  fastmongo:27017  (映射宿主机 27018)    │
                    │  mysql:3306      (通常不映射公网)       │
                    │  postgres:5432   (通常不映射公网)       │
                    │  fastapi / One-API / 业务容器 ──► 各库   │
                    └─────────────────────────────────────────┘
                              ▲
                    堡垒机 SSH + OTP(可选第三层)

统一原则

  1. 管理账号dba_admin / 带 REQUIRE X509 或 mTLS):证书 + 强口令。
  2. 应用账号fastgpt / oneapi):仅传输加密 + 口令,不配客户端证书。
  3. 端口:能内网就不映射;必须映射时防火墙收窄源 IP。
  4. 口令 :不要写在 compose 明文里,用 .env / secrets,整改后轮换。

三、MongoDB 5.0:TLS 双向认证 + 双因素

3.1 现状诊断

bash 复制代码
docker exec fastmongo mongo -u ... --eval 'printjson(db.adminCommand({getParameter:1,tlsMode:1}))'
# 整改前: "tlsMode" : "disabled"

docker exec fastmongo mongo --ssl --host localhost:27017 --eval "db.version()"
# 报错: stream truncated  → 客户端要 TLS,服务端仍是明文

说明:--keyFile 是副本集成员认证,不能代替 TLS。

3.2 证书目录与 mongod.conf

宿主机:

text 复制代码
/data/project/config/mongo-tls/
  ca.pem
  server.pem          # server.crt + server.key
  client-app.pem      # 给应用/运维客户端

mongod.conf 片段:

yaml 复制代码
net:
  port: 27017
  bindIp: 0.0.0.0
  tls:
    mode: requireTLS
    certificateKeyFile: /data/mongo-tls/server.pem
    CAFile: /data/mongo-tls/ca.pem
    allowConnectionsWithoutCertificates: false   # 强制客户端证书
    allowInvalidCertificates: false

db-compose.yml 挂载:

yaml 复制代码
volumes:
  - /data/project/config/mongod.conf:/data/mongod.conf:ro
  - /data/project/config/mongo-tls:/data/mongo-tls:ro

关键坑 :改 compose 后必须 docker compose up -d --force-recreate fastmongo,仅 restart 不会 挂上 mongo-tls 卷。入口脚本里 until mongo ... 也要加 --tls 和证书参数,否则容器永远 Waiting。

3.3 双因素(整改表述)

因子 实现
持有 mTLS 客户端证书
知晓 SCRAM 用户口令,authSource=admin

应用 URI 示例:

text 复制代码
mongodb://fastgpt:***@fastmongo:27017/fastgpt?authSource=admin&tls=true&tlsCAFile=...&tlsCertificateKeyFile=...
CA ca.pem
客户端密钥 client-app.pem(或 cert+key)
验证数据库 admin(必填)
允许无效主机名 用 IP 连时建议勾选
  • 国际 TLS(RSA) :Navicat 可以直连。
  • 端到端 TLCP/SM2 :普通 Navicat 不能直连;需国密网关/VPN,或内网仍用国际 TLS、国密放在网段入口。

四、MySQL 8.2:自动证书 + require_secure_transport

4.1 自动生成证书

数据目录 /data/project/data/mysql 下已有(首次初始化自动创建):

text 复制代码
ca.pem  server-cert.pem  server-key.pem  client-cert.pem  client-key.pem

Issuer 为 MySQL_Server_8.2.0_Auto_Generated_CA_Certificate2035 年前有效,整改演示可直接用。

bash 复制代码
docker exec mysql mysql -uroot -p -e "SHOW VARIABLES LIKE '%ssl%';"
# have_ssl=YES, ssl_ca=ca.pem, ssl_cert=server-cert.pem

4.2 强制 SSL

/data/project/config/mysql/conf.d/ssl.cnf

ini 复制代码
[mysqld]
require_secure_transport=ON
ssl_ca=/var/lib/mysql/ca.pem
ssl_cert=/var/lib/mysql/server-cert.pem
ssl_key=/var/lib/mysql/server-key.pem

挂载:./config/mysql/conf.d:/etc/mysql/conf.d:ro,然后 force-recreate

4.3 用户与双因素

sql 复制代码
CREATE USER 'dba_admin'@'%' IDENTIFIED BY '强密码' REQUIRE X509;
-- 管理:证书 + 口令

ALTER USER 'oneapi'@'%' REQUIRE SSL;
-- 应用:仅加密通道

4.4 踩坑:VERIFY_IDENTITY 与 One-API

bash 复制代码
# 错误:证书 CN 不是 mysql/127.0.0.1
mysql ... --ssl-mode=VERIFY_IDENTITY ...
# SSL connection error: certificate verify failed

# 管理端测试用
--ssl-mode=VERIFY_CA

# 无客户端证 + dba_admin → 1045(预期,说明 X509 生效)

One-API SQL_DSN (容器内连 mysql:3306):

text 复制代码
# 错误
oneapi:***@tcp(mysql:3306)/one-api?tls=true

# 正确(内网自签)
oneapi:***@tcp(mysql:3306)/one-api?tls=skip-verify&parseTime=true

日志:

text 复制代码
tls: certificate is not valid for any names, but wanted to match mysql

只改应用连接串这一处 (grep 仅 db-compose.ymlSQL_DSN),MySQL 侧 SSL + 用户权限需已配好。

  • CA:ca.pem
  • 客户端证书/私钥:client-cert.pemclient-key.pem
  • 不要server-cert 当客户端证

五、PostgreSQL:pg_hba + SSL + 审计

5.1 改掉 trust 和明文 host

整改前(不合格)

text 复制代码
local   all   all                 trust
host    all   all   127.0.0.1/32  trust
host    all   all   all           scram-sha-256   # 明文 TCP 即可连

整改后(示例)

text 复制代码
local   all             postgres                                peer
local   all             all                                     scram-sha-256

hostssl all             fastgpt          172.18.0.0/16           scram-sha-256
hostssl all             dba_admin       172.18.0.0/16           scram-sha-256 clientcert=verify-ca

hostssl all             fastgpt          127.0.0.1/32            scram-sha-256
hostssl all             dba_admin       127.0.0.1/32            scram-sha-256 clientcert=verify-ca

hostnossl all           all             all                     reject
  • fastgpt :业务账号(不是示例里的 app_user)。
  • 172.18.0.0/16 :以 docker network inspect fastgpt_shared_networkSubnet 为准,不是 Navicat 里填的 10.102.53.251
  • 从宿主机连映射端口时,先 SELECT inet_client_addr();,常见为 172.18.0.1 ,需单独加一条 hostssl

postgresql.conf

ini 复制代码
ssl = on
ssl_cert_file = '/etc/postgresql/ssl/server.crt'
ssl_key_file = '/etc/postgresql/ssl/server.key'
ssl_ca_file = '/etc/postgresql/ssl/ca.crt'
password_encryption = scram-sha-256

5.2 双因素

dba_adminscram-sha-256 + clientcert=verify-ca + Navicat 填 客户端证书 + 客户端密钥 + 根证书 + 密码

常见遗漏 :只填了 client-admin.crt未填 client-admin.key → 锁图标报红。

应用 JDBC:

text 复制代码
jdbc:postgresql://postgres:5432/your_db?sslmode=require

5.3 安全审计

conf.d/audit.conf

ini 复制代码
logging_collector = on
log_destination = 'csvlog'
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age = 1d
log_connections = on
log_disconnections = on
log_failed_login_attempts = on    # PG14+
log_line_prefix = '%m [%p] %u@%d %h %a '
log_statement = 'ddl'

加强(需重启):

ini 复制代码
shared_preload_libraries = 'pgaudit'
pgaudit.log = 'ddl, role, write'
pgaudit.log_parameter = on
sql 复制代码
CREATE EXTENSION pgaudit;

日志目录挂宿主机:/data/project/logs/postgres,保留 ≥6 个月。


六、三套库对照表(写报告用)

项目 MongoDB MySQL PostgreSQL
强制加密传输 tls.mode: requireTLS require_secure_transport=ON ssl=on + hostssl
管理双因素 mTLS + SCRAM REQUIRE X509 + 口令 clientcert=verify-ca + SCRAM
应用账号 fastgpt + TLS oneapi + REQUIRE SSL fastgpt + hostssl scram
应用改连接 MONGODB_URI tls 参数 SQL_DSN?tls=skip-verify JDBC sslmode=require
管理客户端 Navicat:CA+客户端证+口令 同上 + client-key 同上,key 必填
主机名校验 允许无效主机名 / SAN skip-verify 内网 verify-ca 或 allow invalid hostname
审计 auditLog(企业)/ 应用日志 general/audit plugin logging_collector + pgAudit

七、高频踩坑汇总

现象 原因 处理
stream truncated 服务端未开 TLS,客户端 --ssl requireTLS / require_secure_transport
No such file ... mongo-tls/client-app.pem compose 未挂卷或未 recreate force-recreate + ls /data/mongo-tls
MySQL certificate verify failed VERIFY_IDENTITY 与自动证书 CN 不符 改用 VERIFY_CAtls=skip-verify(应用)
MySQL 1045 无客户端证 REQUIRE X509 正常拒绝 带 client-cert/key 再连
One-API wanted to match mysql tls=true 校验主机名 tls=skip-verify
PG Navicat 红锁 client-admin.key 补私钥,与 crt 成对
PG 连不上 hba 客户端 IP 不是 10.102.53.251 inet_client_addr() 后改 pg_hba
restart 不 recreate 卷/环境变量未更新 docker compose up -d --force-recreate

八、整改报告可粘贴段落(示例)

已对 MongoDB、MySQL、PostgreSQL 实施传输层加密与身份鉴别加固。三套数据库均启用 TLS/SSL 强制加密(MongoDB requireTLS、MySQL require_secure_transport、PostgreSQL ssl+hostssl)。管理用户使用 数字证书与强口令 双因素鉴别(MongoDB mTLS、MySQL REQUIRE X509、PostgreSQL scram-sha-256 clientcert=verify-ca);应用使用独立账号与加密通道。数据库端口不对公网开放,运维经内网/堡垒机访问。PostgreSQL 已启用 logging_collector 及 pgAudit(或 log_statement=ddl)记录登录、权限变更与 DDL 操作,日志集中存储并定期归档。

国密专项(若检查明确要求 SM2/SM4)可补充:

数据库引擎采用国际标准 TLS 保障传输机密性与完整性;跨网访问通过国密 VPN/SSL 网关实现国密算法保护;敏感字段采用 SM4 应用层加密存储。


九、验收命令清单(收藏)

bash 复制代码
# MongoDB
docker exec fastmongo mongo ... --tls --tlsCAFile /data/mongo-tls/ca.pem \
  --tlsCertificateKeyFile /data/mongo-tls/client-app.pem \
  --eval 'printjson(db.adminCommand({getParameter:1,tlsMode:1}))'

# MySQL
docker exec mysql mysql ... --ssl-mode=VERIFY_CA \
  --ssl-ca=/var/lib/mysql/ca.pem --ssl-cert=/var/lib/mysql/client-cert.pem \
  --ssl-key=/var/lib/mysql/client-key.pem -e "SELECT 1"

# PostgreSQL
docker exec postgres psql "host=127.0.0.1 sslmode=verify-ca user=dba_admin sslrootcert=... sslcert=... sslkey=..." -c "SELECT current_user;"
docker network inspect fastgpt_shared_network --format '{{(index .IPAM.Config 0).Subnet}}'

十、结语

这套加固的核心不是「买企业版」,而是:

  1. 把 TLS 真正开起来(配置 + 挂卷 + recreate);
  2. 管理与应用账号分离 ,管理上 证书+口令
  3. 应用连接串补上 tls/sslmode ,并处理 Docker 内网主机名与自签证书 的校验问题;
  4. PostgreSQL 改掉 trust ,补上 审计日志

按本文逐项落地后,再配合截图与日志样本,一般可满足「传输加密」「双因素鉴别」「审计」类检查项;若检查卡「国密算法」字样,再在入口加国密网关,而不是强求 Navicat 直连 SM2。

相关推荐
AI服务老曹1 小时前
源码交付与低代码解耦:基于 Docker 的边缘计算 AI 视频管理平台二次开发深度实战(兼容 GB28181/RTSP)
人工智能·docker·媒体
IT策士2 小时前
Docker 从 0 到 1 再到 Kubernetes 实战:第1篇 为什么要从 Docker 学到 Kubernetes?系列导读与环境准备
docker·容器·kubernetes
tongyiixiaohuang2 小时前
MySQL与钉钉数据同步的灵活高效方案详解
android·mysql·钉钉
程序猿乐锅2 小时前
【MySQL | 第二篇】: 函数、约束、多表查询和事务
android·数据库·mysql
NiceCloud喜云2 小时前
Anthropic 发布 Project Glasswing:未公开模型 Mythos 已挖出 10000+ 漏洞,含 OpenBSD 27 年老 bug
android·java·数据库·c++·python·docker·bug
ai产品老杨2 小时前
基于 Docker 与 GB28181/RTSP 的边缘计算 AI 视频管理平台:高并发流媒体解耦与源码交付架构深析
人工智能·docker·边缘计算
内蒙深海大鲨鱼2 小时前
mysql学习
学习·mysql·oracle
handler012 小时前
【MySQL】常用约束语法总结
linux·运维·数据库·笔记·mysql
一条泥憨鱼3 小时前
详解MyBatis 动态 SQL
java·数据库·sql·mysql·mybatis·动态sql