注册
go语言使用SSL方式连接达梦数据库
专栏/技术分享/ 文章详情 /

go语言使用SSL方式连接达梦数据库

青空 2026/08/28 98 0 1
摘要

1. 背景介绍

客户使用go语言开发,需要使用ssl方式连接达梦数据库,并且是双向加密,所以需要在连接串中配置ca证书所在路径,但达梦官方go文档中并没有配置ca证书路径的说明,因此需要检验一下达梦的go驱动能否支持双向加密的ssl连接方式,并写一个说明

2. 环境

内容 版本/类型
操作系统 Kylin-Server-V10-SP3-2403
CPU x86_64bit
达梦数据库 达梦9(达梦8也可用)
编程语言 go1.26.6

3. 配置过程

3.1. 配置ssl证书,并查看其目录结构

已经配置好ssl证书(可以参考文末附录参考内容1和2进行配置)之后,查看目录结果

这里的ca目录是/opt/ca,该目录包含以下文件

[root@localhost ca]# tree
. # 根CA
├── ca-cert.pem # 根CA的公钥
├── ca-cert.srl
├── ca-key.pem # 私钥
├── certs
├── client_ssl # 客户端的身份凭证,对应disql以及go程序等调用数据库的其他程序
│ └── SYSDBA
│   ├── ca-cert.pem
│   ├── client-cert.pem
│   ├── client.csr
│   └── client-key.pem
├── crl
├── index.txt
├── newcerts
├── serial
└── server_ssl # 服务端的身份凭证,对应数据库
  ├── ca-cert.pem
  ├── server-cert.pem
  ├── server.csr
  └── server-key.pem

6 directories, 14 files

服务端的server-key.pem、server-cert.pem分别是服务端的私钥和公钥,server.csr是证书签名请求文件,用于向根CA请求server-cert.pem,ca-cert.pem是根CA公钥证书的副本,用来验证请求连接的客户端证书和自己是不是由同一个根CA签发

同理,客户端的client-key.pem、client-cert.pem分别是它的私钥和公钥,client.csr是它的证书签名请求文件,用于向根CA请求client-cert.pem,ca-cert.pem是根CA公钥证书的副本,用来验证连接的服务端证书和自己是不是由同一个根CA签发

需要注意,这里因为根CA、服务端、客户端都是本机,所以同时有这三类的证书,实际情况可能只有客户端是本机,使得本机只有client_ssl(客户端的ssl证书)相关文件

之后开始写代码使用ssl方式连接达梦数据库

3.2. 安装go相关依赖

把达梦go驱动复制到GOPATH的src目录下,并安装依赖

# 查看GOPATH位置 [root@localhost ~]# go env GOPATH /root/go # 复制到该位置

安装依赖包

go get golang.org/x/text go get github.com/golang/snappy go get github.com/gaoyuan98/dm

3.3. 双向认证连接串写法

通过查看达梦go驱动代码,得知其支持的连接串参数有:

  • sslFilesPath:SSL证书文件所在目录,该目录需要包含ca-cert.pem、client-cert.pem和client-key.pem三个文件
  • sslCertPath:客户端证书文件路径
  • sslKeyPath:客户端私钥文件路径

更多连接串参数请查看文末参考(DM Go 编程指南 | 达梦技术文档)

因此使用go双向认证连接达梦数据库,需要显式传证书目录和具体证书文件路径,在编写程序的时候使用的是客户端的证书,比如go程序里应该这样填写连接串:

func sslTwoWayDSN() string { host := env("DM_HOST", "127.0.0.1") port := env("DM_PORT", "5236") user := env("DM_USER", "SYSDBA") password := env("DM_PASSWORD", "Dameng123") sslPath := env("DM_SSL_FILES_PATH", "/opt/ca/client_ssl/SYSDBA") return fmt.Sprintf( "dm://%s:%s@%s:%s?sslFilesPath=%s&sslCertPath=%s&sslKeyPath=%s", // sslFilesPath是客户端SSL证书文件所在目录,该目录需要包含ca-cert.pem、client-cert.pem和client-key.pem三个文件 // sslCertPath和sslKeyPath用具体文件路径,具体到某个文件 user, password, host, port, sslPath, sslPath+"/client-cert.pem", sslPath+"/client-key.pem", ) }

经检验可以连接达梦数据库并进行增删查改操作

4. 结论

如果客户端想要使用ssl双向认证连接达梦数据库,需要在连接串中使用sslFilesPath=来指定ssl相关文件的路径,

sslFilesPath对应的路径下应该包括三个文件,分别是客户端的ca-cert.pem(根证书副本)、client-cert.pem(公钥)和client-key.pem(私钥)

并使用sslCertPath=sslKeyPath=分别指定客户端公钥client-cert.pem和客户端私钥client-key.pem的完整路径

格式是:

dm://SYSDBA:Dameng123@localhost:5236?sslFilesPath=客户端ssl文件目录&sslCertPath=客户端ssl文件目录/公钥文件名&sslKeyPath=客户端ssl文件目录/私钥文件名

对于该例子是:

dm://SYSDBA:Dameng123@127.0.0.1:5236?sslFilesPath=/opt/ca/client_ssl/SYSDBA&sslCertPath=/opt/ca/client_ssl/SYSDBA/client-cert.pem&sslKeyPath=/opt/ca/client_ssl/SYSDBA/client-key.pem

5. 附录:

5.1. 参考

  1. 达梦数据库配置SSL通信加密 | 达梦技术社区
  2. 达梦数据库配置SSL通信加密 | CSDN
  3. DM Go 编程指南 | 达梦技术文档

5.2. 背景知识

5.2.1. SSL是什么

SSL是一种网络安全协议,用于在客户端和服务器之间建立安全通信,能够实现数据加密、身份验证,以及保护数据完整性

在数据库领域,普通连接和SSL连接的主要区别是,普通连接在网络上明文传输SQL和账号密码;SSL连接会先建立加密通道,再传业务数据

当数据库切换到SSL/TLS认证模式后,disql和go程序都必须带证书相关参数,否则连不上

5.2.2. CA证书是什么

单向认证时,客户端主要校验服务端证书是否可信;双向认证时,客户端和服务端会互相校验身份。CA证书的作用就是提供这一层信任关系

5.3. 问题说明

5.3.1. 数据库设置SSL后明文连接失败

在启用了SSL之后就不再能直接明文使用密码在终端登录(账号/密码@ip:端口)了,这是正常现象,只需在disql连接时加上SSL路径即可,格式如下:

./disql 账号/密码@ip:端口#"{SSL_PATH=路径}"

比如这样:

[root@localhost gotest]# cd /home/dmdba/dmdbms/bin
[root@localhost bin]# ./disql SYSDBA/Dameng123@localhost:5236#"{SSL_PATH=/opt/ca/client_ssl/SYSDBA}"

服务器[localhost:5236]:处于普通打开状态
登录使用时间 : 16.827(ms)
disql V8
SQL> select name, value
from v$parameter
where name in ('ENABLE_ENCRYPT','COMM_ENCRYPT_NAME');

行号     NAME              VALUE
---------- ----------------- -----
1          ENABLE_ENCRYPT    2
2          COMM_ENCRYPT_NAME RC4

已用时间: 20.220(毫秒). 执行号:1001.

5.4. 资源下载

demo程序:main.go

package main import ( "database/sql" "fmt" "log" "os" _ "github.com/gaoyuan98/dm" ) func main() { dsn := buildDSN() fmt.Println("==> DSN:", dsn) db, err := sql.Open("dm", dsn) if err != nil { log.Fatalf("sql.Open failed: %v", err) } defer db.Close() if err := db.Ping(); err != nil { log.Fatalf("db.Ping failed: %v", err) } fmt.Println("connect succeed.") } func buildDSN() string { host := getEnv("DM_HOST", "127.0.0.1") port := getEnv("DM_PORT", "5236") user := getEnv("DM_USER", "SYSDBA") password := getEnv("DM_PASSWORD", "Dameng123") sslPath := getEnv("DM_SSL_FILES_PATH", "/opt/ca/client_ssl/SYSDBA") return fmt.Sprintf( "dm://%s:%s@%s:%s?sslFilesPath=%s&sslCertPath=%s&sslKeyPath=%s", user, password, host, port, sslPath, sslPath+"/client-cert.pem", sslPath+"/client-key.pem", ) } func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback }
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服