認証プラグイン

ldbcでは、デフォルトで提供されているMySQL認証プラグインと別でPure Scala3で実装されたAWS Aurora IAM認証などの認証プラグインが利用できます。

サポートされている認証方式

デフォルトでは3つの認証方式がサポートされています。

上記とは別でldbcには現在追加で2つの認証方式をサポートしています。

1. MySQL Clear Password認証

プレーンテキストパスワード認証を使用する場合:

import ldbc.connector.*
import ldbc.authentication.plugin.*

val datasource = MySQLDataSource
  .build[IO](
    host = "localhost",
    port = 3306,
    user = "cleartext-user"
  )
  .setPassword("plaintext-password")
  .setDatabase("mydb")
  .setSSL(SSL.Trusted)  // セキュリティのためSSL必須
  .setDefaultAuthenticationPlugin(MysqlClearPasswordPlugin)

注意: セキュリティ上の理由から、Clear Password認証使用時はSSL/TLS接続が必須です。

2. AWS Aurora IAM認証 {#aws-aurora-iam-authentication}

AWS Aurora でIAM認証を使用する場合:

import ldbc.amazon.plugin.AwsIamAuthenticationPlugin
import ldbc.connector.*

val hostname = "aurora-cluster.cluster-xxx.ap-northeast-1.rds.amazonaws.com"
val username = "iam-user"

val config = MySQLConfig.default
  .setHost(hostname)
  .setUser(username)
  .setDatabase("production")
  .setSSL(SSL.Trusted)  // IAM認証にはSSL必須

val awsPlugin = AwsIamAuthenticationPlugin.default[IO]("ap-northeast-1", hostname, username)

MySQLDataSource.pooling[IO](config, plugins = List(awsPlugin)).use { datasource =>
  val connector = Connector.fromDataSource(datasource)
  // クエリ実行
}

認証プラグインの設定

複数の認証プラグインを組み合わせる場合:

val plugins = List(
  MysqlClearPasswordPlugin,
  awsIamPlugin
)

val datasource = MySQLDataSource.pooling[IO](config, plugins = plugins)

必要な依存関係

各認証プラグインを使用する場合は、対応する依存関係を追加してください:

MySQL Clear Password認証:

libraryDependencies += "io.github.takapi327" %% "ldbc-authentication-plugin" % "0.5.2"

AWS Aurora IAM認証:

libraryDependencies += "io.github.takapi327" %% "ldbc-aws-authentication-plugin" % "0.5.2"

認証プラグインのカスタマイズ

ldbcでは独自の認証プラグインを組み込むことが可能となっています。 現在サポートされていない例えばAzure Database for MySQLなどで使用するためのプラグインを作成して使用することが可能となっています。

認証プラグインの作成にはAuthenticationPluginを使用することで実現可能です。

class CustomAuthenticationPlugin extends AuthenticationPlugin[IO]:
  override def name: PluginName = ???
  override def requiresConfidentiality: Boolean = ???
  override def hashPassword(password: String, scramble: Array[Byte]): IO[ByteVector] = ???

認証プラグインで設定しなければいけないものは以下3つのプロパティです。

プロパティ 詳細
name プラグインの名前
requiresConfidentiality SSLを必須かするかどうか
requiresConfidentiality パスワードの処理

nameは認証プラグインで使用するプラグイン名ですが、これはMySQLがサポートしているプラグイン名である必要があります。

現在設定可能なプラグインの種類は以下です。

プラグイン名 用途
mysql_clear_password クリアテキストパスワード送信(クライアント側)
mysql_native_password MySQL従来のパスワード認証(4.1以降)
sha256_password SHA-256パスワード認証
caching_sha2_password SHA-256ベースのキャッシュ付き認証(MySQL 8.0デフォルト)
mysql_old_password 旧式パスワード認証(MySQL 4.1以前、5.7.5で廃止)
authentication_windows Windows認証
authentication_pam PAM(Pluggable Authentication Modules)認証
authentication_ldap_simple LDAP簡易認証
authentication_ldap_sasl LDAP SASL認証
authentication_kerberos Kerberos認証
authentication_fido FIDO/WebAuthn認証(パスワードレス)
authentication_webauthn WebAuthn認証(FIDO2対応)
mysql_no_login ログイン不可アカウント用(プロキシ・ストアドプログラム用)
test_plugin_server テスト用認証プラグイン
auth_socket UNIXソケット経由のOS認証

AWS SDK for Java

認証プラグインのカスタマイズを利用することでAWS SDK for Javaを使用してAWS Aurora IAM認証を実現することも可能です。

lazy val project = project.in(file("."))
  .settings(
    libraryDependencies ++= Seq(
      "software.amazon.awssdk" % "rds" % "2.40.16",
      "software.amazon.awssdk" % "auth" % "2.40.16"
    ) 
  )
import cats.effect.IO
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.rds.RdsUtilities
import software.amazon.awssdk.services.rds.model.GenerateAuthenticationTokenRequest
import scodec.bits.ByteVector

import java.nio.charset.StandardCharsets

class AwsSdkIamAuthenticationPlugin(
  host: String,
  port: Int,
  user: String,
  region: Region
) extends AuthenticationPlugin[IO]:

  override def name: PluginName = MYSQL_CLEAR_PASSWORD

  override def requiresConfidentiality: Boolean = true

  override def hashPassword(password: String, scramble: Array[Byte]): IO[ByteVector] =
    IO.blocking {
      val credentialsProvider = DefaultCredentialsProvider.builder().build()

      val rdsUtilities = RdsUtilities.builder()
        .region(region)
        .credentialsProvider(credentialsProvider)
        .build()

      val request = GenerateAuthenticationTokenRequest.builder()
        .hostname(host)
        .port(port)
        .username(user)
        .build()

      val authToken = rdsUtilities.generateAuthenticationToken(request)

      ByteVector(authToken.getBytes(StandardCharsets.UTF_8)) :+ 0.toByte
    }