MySQLでクライアント証明書を使う
https://github.com/go-sql-driver/mysql/issues/884#issuecomment-437670408
クライアント証明書を使えないというコメントあり。クライアント証明書使ったこと無いぞ。
https://qiita.com/ngyuki/items/146252102315282e1f12
なるほど。この記事を見ながらやってみよう。
$ docker run -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -p 3306:3306 --rm --name mysqld mysql:8
code:shell
$ mysql -h127.0.0.1 -P3306 -uroot
mysql> SHOW VARIABLES LIKE 'ssl_%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| ssl_ca | ca.pem |
| ssl_capath | |
| ssl_cert | server-cert.pem |
| ssl_cipher | |
| ssl_crl | |
| ssl_crlpath | |
| ssl_fips_mode | OFF |
| ssl_key | server-key.pem |
+---------------+-----------------+
8 rows in set (0.00 sec)
クライアント証明書を作るためにca.pem を取り出す。ついでに公開鍵も。
code:shell
$ docker cp mysqld:/var/lib/mysql/public_key.pem .
$ docker cp mysqld:/var/lib/mysql/ca.pem .
証明書を使ってログインするためのユーザーを作る。
code:shell
$ mysql -h127.0.0.1 -P3306 -uroot
mysql> create user 'testu'@'%' identified by 'pass' REQUIRE X509;
Query OK, 0 rows affected (0.10 sec)
mysql> create database test;
Query OK, 1 row affected (0.03 sec)
mysql> grant all on test.* to 'testu'@'%';
Query OK, 0 rows affected (0.04 sec)
クライアント証明書を作ろう
code:shell
$ openssl req -new -out client.csr -keyout client.key -newkey rsa:2048 -nodes -subj "/C=JP/ST=Tokyo/L=SonoHen/O=OreOre/OU=Dev/CN=ore@example.jp"
Generating a 2048 bit RSA private key
.............+++
....................................+++
writing new private key to 'client.key'
-----
あれ?qiita記事の次のコマンドは openssl x509 -req -days 3650 -in /tmp/client.csr -out /tmp/client.crt -CA ca.crt -CAkey ca.key -CAcreateserial になっているけれども、MySQLが自動生成したCAは pem だぞ? ... docker の中を探したら ca-key.pem もあった。こっちが鍵だろ(適当)
code:shell
$ docker cp mysqld:/var/lib/mysql/ca-key.pem .
$ openssl x509 -req -days 3650 -in client.csr -out client.crt -CA ca.pem -CAkey ca-key.pem -CAcreateserial
Signature ok
subject=/C=JP/ST=Tokyo/L=SonoHen/O=OreOre/OU=Dev/CN=ore@example.jp
Getting CA Private Key
できた気がする。つないで見るぞ。
code:shell
$ mysql -h 127.0.0.1 -P3306 -u testu -ppass --ssl-cert=client.crt --ssl-key=client.key test;
mysql> select database();
+------------+
| database() |
+------------+
| test |
+------------+
1 row in set (0.00 sec)
mysql> select user(), database();
+------------------+------------+
| user() | database() |
+------------------+------------+
| testu@172.17.0.1 | test |
+------------------+------------+
1 row in set (0.00 sec)
やった!さて、これにGoからつないで見る。
code:go
package main
import (
"crypto/tls"
"database/sql"
"fmt"
"log"
"github.com/go-sql-driver/mysql"
)
func main() {
cert, err := tls.LoadX509KeyPair("./client.crt", "./client.key")
if err != nil {
log.Fatal(err)
}
clientCert := []tls.Certificate{cert}
mysql.RegisterTLSConfig("custom", &tls.Config{
Certificates: clientCert,
InsecureSkipVerify: true,
})
db, err := sql.Open("mysql", "testu:pass@tcp(127.0.0.1:3306)/test?tls=custom")
if err != nil {
log.Fatal(err)
}
err = db.Ping()
if err != nil {
log.Fatal(err)
}
var a, b string
err = db.QueryRow("SELECT user(), database()").Scan(&a, &b)
if err != nil {
log.Fatal(err)
}
fmt.Printf("user=%v, db=%v\n", a, b)
}
出力: user=testu@172.17.0.1, db=test
できた。さて、問題の issue はパスワードがない場合だ。
code:t
mysql> create user 'test2'@'%' require x509;
Query OK, 0 rows affected (0.05 sec)
mysql> grant all on test.* to 'test2'@'%';
Query OK, 0 rows affected (0.05 sec)
上の dsn を db, err := sql.Open("mysql", "test2@tcp(127.0.0.1:3306)/test?tls=custom") に。あれ、いけた?
master ブランチで行けたよ。なんだなんだ?
#MYSQL