客户使用go语言开发,需要使用ssl方式连接达梦数据库,并且是双向加密,所以需要在连接串中配置ca证书所在路径,但达梦官方go文档中并没有配置ca证书路径的说明,因此需要检验一下达梦的go驱动能否支持双向加密的ssl连接方式,并写一个说明
| 内容 | 版本/类型 |
|---|---|
| 操作系统 | Kylin-Server-V10-SP3-2403 |
| CPU | x86_64bit |
| 达梦数据库 | 达梦9(达梦8也可用) |
| 编程语言 | go1.26.6 |
已经配置好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方式连接达梦数据库
把达梦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
通过查看达梦go驱动代码,得知其支持的连接串参数有:
更多连接串参数请查看文末参考(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",
)
}
经检验可以连接达梦数据库并进行增删查改操作
如果客户端想要使用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
SSL是一种网络安全协议,用于在客户端和服务器之间建立安全通信,能够实现数据加密、身份验证,以及保护数据完整性
在数据库领域,普通连接和SSL连接的主要区别是,普通连接在网络上明文传输SQL和账号密码;SSL连接会先建立加密通道,再传业务数据
当数据库切换到SSL/TLS认证模式后,disql和go程序都必须带证书相关参数,否则连不上
单向认证时,客户端主要校验服务端证书是否可信;双向认证时,客户端和服务端会互相校验身份。CA证书的作用就是提供这一层信任关系
在启用了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.
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
}
文章
阅读量
获赞
