Shogo's Blog

Mar 11, 2024 - 2 minute read - aws mysql go golang

GoのMySQLドライバーにBeforeConnectが追加されました

先日 go-sql-driver/mysql v1.8.0 がリリースされ、 いくつかのオプションが追加されました。 その中からひとつ BeforeConnect を紹介したいと思います。

何が嬉しいの?

パスワード以外の方法で MySQL にログインするのが簡単になります。

BeforeConnect を使わない従来の方法

たとえば、AWS では IAM 認証を使ってログインする方法を提供しています。 IAM の情報を使って短期間だけ有効なトークンを発行し、そのトークンを使ってログインします。

トークンの有効期限は短いので、接続を開始する直前にトークンを発行し接続設定を書き換えなければいけません。 しかし、Go はコネクションプールを採用しているため、実際に接続を開始するタイミングを知るのは意外と難しいです。

頑張ってそれを実現するためにわざわざドライバーを書いたこともありました。

BeforeConnect を使った方法

BeforeConnect は、接続を開始する直前に接続設定を書き換える機能です。 shogo82148/rdsmysql を使用せずとも、簡単に IAM 認証を実現できます。

package main

import (
  "context"

  "github.com/aws/aws-sdk-go-v2/config"
  "github.com/aws/aws-sdk-go-v2/feature/rds/auth"
  "github.com/go-sql-driver/mysql"
)

func main() {
  mycnf := mysql.NewConfig()
  mycnf.TLSConfig = "true"
  mycnf.AllowCleartextPasswords = true
  mycnf.DBName = "DatabaseName"
  mycnf.User = "DatabaseUser"
  mycnf.Addr = "mysqldb.123456789012.us-east-1.rds.amazonaws.com:3306"
  var region = "us-east-1"

  cfg, err := config.LoadDefaultConfig(context.TODO())
  if err != nil {
    panic(err)
  }

  beforeConnect := func(ctx context.Context, config *mysql.Config) error {
    // 実際に接続する直前になると呼び出される
    // このタイミングでトークンを発行する
    token, err := auth.BuildAuthToken(ctx, config.Addr, region, config.User, cfg.Credentials)
    if err != nil {
      return err
    }

    // 接続設定を書き換える
    config.Passwd = token
    return nil
  }
  if err := mycnf.Apply(mysql.BeforeConnect(beforeConnect)); err != nil {
    panic(err)
  }

  // 新規コネクションプール作成
  conn, err := mysql.NewConnector(mycnf)
  if err != nil {
    panic(err)
  }
  db := sql.OpenDB(conn)
  defer db.Close()
}

shogo82148/rdsmysql の宣伝

shogo82148/rdsmysql を使うともう少し短くかけます。

package main

import (
  "context"

  "github.com/aws/aws-sdk-go-v2/config"
  "github.com/aws/aws-sdk-go-v2/feature/rds/auth"
  "github.com/go-sql-driver/mysql"
  "github.com/shogo82148/rdsmysql/v2"
)

func main() {
  mycnf := mysql.NewConfig()
  mycnf.DBName = "DatabaseName"
  mycnf.User = "DatabaseUser"
  mycnf.Addr = "mysqldb.123456789012.us-east-1.rds.amazonaws.com:3306"
  var region = "us-east-1"

  cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region))
  if err != nil {
    panic(err)
  }

  // BeforeConnect, TLS, AllowCleartextPasswords
  // の設定を全部やってくれる!便利!
  if err := rdsmysql.Apply(mycnf, cfg); err != nil {
    panic(err)
  }

  // 新規コネクションプール作成
  conn, err := mysql.NewConnector(mycnf)
  if err != nil {
    panic(err)
  }
  db := sql.OpenDB(conn)
  defer db.Close()
}

Amazon RDS 証明書もダウンロードして、ライブラリに組み込んであります。

まとめ

参考