我有一个用Go编写的运行时间长的守护程序,该守护程序侦听端口并为每个新连接启动多个go例程以处理数据。在脚本的func main()中,有一个全局变量db
被分配了database/sql
库的open()
函数返回的连接上下文。
出于安全原因,我们将db密码存储在Vault中,该密码每两天轮换一次。我可以在首次创建连接上下文时从Vault中获取密码,并且在所有go例程中都使用相同的上下文来创建新的数据库连接。 但是,当Vault旋转密码时,所有新的数据库连接都会失败。我想知道什么是处理此问题的最佳方法,以便在发生故障时从库中获取密码并重新连接。如果这是一种oop语言,我可以扩展db库并覆盖连接功能以捕获错误并在连接失败时从Vault中获取密码。 Go中是否可以使用类似的方法,或者还有其他方法可以处理此问题?我是Go的新手,如果我没有提出正确的问题,我深表歉意。
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"net"
)
var db *sql.DB
const port = "port number"
func main() {
db, err = sql.Open("mysql","!!Connection string that contains the password fetched from vault!!")
db.SetMaxOpenConns(100)
listener, err := net.Listen("tcp", ":"+port)
for {
conn, err := listener.Accept()
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
// Uses db variable to connect to db.
}
答案 0 :(得分:0)
为什么必须在main上创建上下文? 为什么不创建一个单独的包/命名空间并在其中执行数据库连接。 使用方法创建新的名称空间... createDBClient()通过从Vault中获取密码来创建新的数据库上下文,并将其存储在全局var db中 GetDBClient()会检查全局var db中是否包含某些内容,如果有,则检查它是否可以连接到db(https://golang.org/pkg/database/sql/#DB.Ping) 如果没有调用createDBClient(),则在没有连接时死机并烧毁,使它在睡眠中循环几次 如果连接,则返回上下文
现在在您的handleConnection()中调用db:= newnamespace.GetDBClient()
答案 1 :(得分:0)
我已经通过创建一个自定义驱动程序解决了这个问题,该自定义驱动程序导入github.com/go-sql-driver/mysql并在sql程序包中注册,以便在需要任何新连接时,该自定义驱动程序都可以从中获取密码。 Vault并将其传递给mysql驱动程序以打开连接。请参考下面的代码示例。
package vault-mysql-driver
import (
"database/sql"
"github.com/go-sql-driver/mysql"
)
type VaultMysqlDriver struct {
*mysql.MySQLDriver
}
func updateDsn(dsn string) (string, err) {
// logic to fetch password from vault and update dsn with the password
}
func (d VaultMysqlDriver) Open(dsn string) (driver.Conn, error) {
updateddsn, err := updateDsn(dsn)
// Pass down the dsn with password to mysql driver's open function
return d.MySQLDriver.Open(updateddsn)
}
// When initialised will register the driver in sql package
func init() {
sql.Register(vault-driver, &CyberarkMysqlDriver{&mysql.MySQLDriver{}})
}
此软件包现在如下所示导入到守护程序中,
import (
"database/sql"
_ "vault-mysql-driver"// init is invoked and it will get registered in sql package
"net"
)
var db *sql.DB
const port = "port number"
func main() {
// vault-driver is used instead of mysql so that the sql package knows to use the custom driver for new connections.
db, err = sql.Open("vault-driver","<Connection string that contains the password fetched from vault>")
db.SetMaxOpenConns(100)
listener, err := net.Listen("tcp", ":"+port)
for {
conn, err := listener.Accept()
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
// Uses db variable to connect to db.
}
这样,每当保管库旋转密码时,就不会出现任何连接失败,因为保管库驱动程序将始终为每个新连接从保管库获取密码。