当新连接失败时,使用数据库/ SQL库并从保管库获取密码

时间:2019-05-29 07:52:56

标签: go

我有一个用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.
}

2 个答案:

答案 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.
}

这样,每当保管库旋转密码时,就不会出现任何连接失败,因为保管库驱动程序将始终为每个新连接从保管库获取密码。