I have solved this problem by creating a custom driver that imports github.com/go-sql-driver/mysql and get registered in the sql package, so that when ever a new connection is required the custome driver can fetch password from vault and pass it down to mysql driver to open the connection. Refer the code sample below.
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{}})
}
This package is now imported in the daemon as below,
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.
}
This way whenever the vault rotates the password there won't be any connection failure since the vault driver will always fetch password from vault for every new connections.