Использование базы данных / библиотеки sql и выбор пароля из хранилища при сбое нового соединения - PullRequest
0 голосов
/ 29 мая 2019

У меня есть долго работающий демон, написанный на Go, который слушает порт и запускает несколько процедур go для каждого нового соединения для обработки данных.Существует глобальная переменная db, которой назначен контекст соединения, возвращаемый функцией open() библиотеки *1003* в функции func main () моего сценария.

Мы храним пароль БД в хранилище, которое вращается каждые несколько дней из соображений безопасности.Я могу получить пароль из хранилища при первом создании контекста соединения, и этот же контекст используется во всех подпрограммах go для создания новых соединений базы данных.Тем не менее, когда пароль поворачивается в хранилище, все новые соединения БД терпят неудачу.Я хотел бы знать, каков наилучший способ справиться с этим, чтобы при сбое он получал пароль из хранилища и переподключался.Если бы это был oop-язык, я мог бы расширить библиотеку db и переопределить функцию соединения, чтобы перехватить ошибку и получить пароль из хранилища при сбое соединения.Есть ли подобный подход, который можно использовать в 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 голосов
/ 12 июня 2019

Я решил эту проблему, создав собственный драйвер, который импортирует github.com/go-sql-driver/mysql и регистрируется в пакете sql, так что, когда требуется новое соединение, драйвер пользователя может получить пароль из хранилище и передать его драйверу 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.
}

Таким образом, всякий раз, когда хранилище поворачивает пароль, не будет никакого сбоя соединения, так как драйвер хранилища всегда будет извлекать пароль из хранилища для каждого нового соединения.

0 голосов
/ 04 июня 2019

Почему вы должны создать контекст на главном?почему бы не создать отдельный пакет / пространство имен и выполнить там соединения с БД.создать новое пространство имен с методами ... createDBClient () это создает новые контексты БД, выбирая пароль из хранилища и сохраняя его в глобальном var db GetDBClient () это проверяет, есть ли в глобальном var db что-либо, если это так, проверьте, может ли оноconnect to db (https://golang.org/pkg/database/sql/#DB.Ping), если не вызывать createDBClient (), зациклите это несколько раз с помощью sleep, если не происходит аварийное завершение соединения и прожиг, если он соединяется, верните контекст

теперь в вашем handleConnection () вызове db:= newnamespace.GetDBClient ()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...