はじめに
他のパターンで書くケースがあるかどうかわからないが、「パスワード生成」に関してTPOに応じたルールというかポリシーについて、常々思っていたことをメモしておく。
今回はMySQLということで、想定バージョンは8系以降とする。より古いバージョンについては見なかったこととするとして、もう5系については考慮しなくていいよね。
参考文献として本家ドキュメントのリンクを用意したので、合わせて参照してください。本ドキュメントが怪しくなっても本家ドキュメントなら安心できること請け合いです:-)。
パスワードに使用できる文字種について
本章ではパスワードに使用できる文字種について述べる。
広くパスワードの話をするなら、絵文字の使用もありうるわけで、ここではMySQLと銘打って、いわゆるアスキー文字のみを前提としてとりまとめる。
使用できる文字について
この手のは原則として英数字1および記号類、いわゆる「アスキー印字可能文字」が使用できる。が、この記号類というものがくせ者で、後述の記号については除外する。
もちろん 0
と O
、1
と l
といった字形が似ている文字を除外するケースもあるが、本ユースケースではそこまでの対応は不要であろうと思われる。
この辺りがTPOに応じてポリシーを考える必要がでてくる次第。
使用できない文字について
MySQL自身が設定できないと謳ってる文字もあるかもしれないが、下記の理由で使えない文字について具体的に明記する。
- プログラミング言語(SQLを含む)ユースで使えない/使いたくない
- シェルユースでの利用で使えない(上記ユースケースに対して追加の制限)
- ヒヤリハットが発生するので使わない方がよい
記号 | 記号名 | 使わない方がいい理由 |
---|---|---|
|
空白 | 目視的にも文法的にも除外される危険がある |
" |
ダブルクォート | 文字列を明示する文法に引っかかる |
# |
シャープ | mysqlコマンドの入力で問題になる(後述) |
$ |
ダラー | 変数展開されてしまう可能性が多々ある |
' |
シングルクォート | 文字列を明示する文法に引っかかる |
/ |
スラッシュ | 区切り記号としてパースされてしまうケースがある |
@ |
アット | 変数展開されてしまう可能性が希にある |
= |
イコール | コピペ時に見逃されやすい(特に最初と最後) |
\ |
バックスラッシュ | エスケープ文字として利用されているケースが多々ある |
` |
バッククォート | 文字列を明示する文法に引っかかる |
#
に関してだが、バグレポートを見ると、一部文字(#
等2)は使えるようになったとあるが、バージョン依存であるため使用しているMySQLバージョンを確認すること。
詳しくはリリースノート(8.0.24の変更点)参照のこと(To enable use of spaces and ... の下り)。
パスワード入力方法の簡略化
各種MySQLクライアント(mysql
コマンドや mysqldump
コマンド等)では --login-path
オプションを指定することで、事前に設定されたパスワード(および接続情報)に基づき、データベースに接続できる。
ここでは設定、参照、利用について解説する。設定一覧・削除・変更については参考文献を参照のこと。
パスワード設定
mysql_config_editor コマンド3を使用することで --login-path
で指定されたキーワードに基づき、ユーザー名とパスワードを設定(保存)できる。
下記の通りコマンドを実行すると、パスワード入力を求められるプロンプトが表示されるので、パスワードを入力してリターンキーを押す。
mysql_config_editor set --login-path=admin --user=admin --password
この指定では更に --host
(ホスト名)や --port
(ポート番号)を指定することで、接続先データベースについても設定できる。
mysql_config_editor set --login-path=admin --host=mysql.example.jp --port=3306 --user=admin --password
この時設定される情報は ~/.mylogin.cnf
ファイルに保存される。本ファイルの内容はカジュアルには読めない形式4となっているが、my_print_defaults
コマンド等で、パスワード入力を求められたりせず、容易に表示することができるので、そういう向きに期待してはいけない。
パスワード設定状況の確認
パスワードや接続先データベース等の設定状況を確認することができる。
my_print_defaults --login-path=admin --show client
この時下記のように情報が出力される。
$ my_print_defaults --login-path=admin --show client
--user=admin
--password=^nV3u-Uj620vP+eC
--host=mysql.example.jp
他のメンバーに直接、ID/パスワードを伝えるくらいなら、このコマンドを実行させることで、ID/パスワードを取得させた方が、外部に暴露せずに共有できる。
なおパスワードの先頭に =
があるとコピペしにくい(--password==...
)のがわかると思う。記号類は基本、コピペしにくいものであるが、よく見定めてコピペすること。
実際の利用方法
極シンプルに下記の通りで動く。
mysql --login-path=admin mysql
AWSのテンプレートでの指定例
AWSTemplateFormatVersion: '2010-09-09'
Resources:
RDSMySQLDataBaseInstance:
Type: AWS::RDS::DBInstance
Properties:
Engine: MySQL
MasterUsername: !Sub '{{resolve:secretsmanager:${RDSMySQLDataBaseInstanceAdminAccount}:SecretString:username}}'
MasterUserPassword: !Sub '{{resolve:secretsmanager:${RDSMySQLDataBaseInstanceAdminAccount}:SecretString:password}}'
:
RDSMySQLDataBaseInstanceAdminAccount:
Type: AWS::SecretsManager::Secret
Properties:
Name: RDSMySQLDataBaseAdminAccount
GenerateSecretString:
SecretStringTemplate: '{"username":"admin"}'
GenerateStringKey: password
PasswordLength: 16
ExcludeCharacters: !Join [ '', [ ' ', '"', '#', '$', "'", '/', '@', '=', '\\', '`' ] ]
RDSMySQLDataBaseInstanceAdminAccountAttachment:
Type: AWS::SecretsManager::SecretTargetAttachment
Properties:
TargetType: AWS::RDS::DBInstance
TargetId: !Ref RDSMySQLDataBaseInstance
SecretId: !Ref RDSMySQLDataBaseInstanceAdminAccount
上記クラウドフォーメーションのテンプレート(YAML形式)をデプロイすると、MySQLインスタンスが作成され、自動的にパスワードが設定される。
自動的に設定されたパスワードはシークレットマネージャーの管理下で保存されるため、下記のように5実行6してリソース名を取得できる。
$ aws cloudformation list-stack-resources --stack-name 上記テンプレートのスタック名 --output text --query "StackResourceSummaries[?LogicalResourceId == 'RDSMySQLDataBaseInstanceAdminAccount'][].PhysicalResourceId | [0]"
arn:aws:secretsmanager:リージョン名:アカウントID:secret:RDSMySQLDataBaseInstanceAdminAccount-XXXXXX
このリソース名から下記のようにコマンドを実行6すると、JSON形式で設定されたせつぞくじょうほうが引き出せる。
$ aws secretsmanager get-secret-value --secret-id arn:aws:secretsmanager:リージョン名:アカウントID:secret:RDSMySQLDataBaseInstanceAdminAccount-XXXXXX --output text --query 'SecretString'
{"password":"ランダムなパスワード","engine":"mysql","port":3306,"dbInstanceIdentifier":"DBネーム","host":"DBホスト名","username":"admin"}
よくある質問とその答え
Q.!
は対象にならないのですか?
A.!
でおかしくなるケースは確かにあります。シェルとそれ以外のプログラミング言語とは分けて考えた方がいいのですが、一般的なプログラミング言語では !
にさほど意味はありません。
確かにシェルでは !
が多大な影響を受けるケースがあります。しかしシェルで使いたいケースでは --login-path
オプションを付けてコマンドを実行すればいいだけなので、!
を明示的に拒否するほどの問題を感じません。
もちろん !
を除外対象にすることは問題はありません。ここでは絶対的なポリシーというよりも、痛い目にあったので、こういうポリシーを提案してみました、という話でしかないためです。
シェルの話で言うと &
にも捨てがたい(除外したい)魅力はあります。さらには ?
や *
等も除外したくなるでしょう。いずれも上記理由より、除外する意味はありません。
Q.パスワードの長さは?
A.てきと~に決めればいいと思います。長すぎるのは問題ですが、短すぎるのも問題なので、基本的に12~24文字程度にしておくのが良いかと。
ユースケース的には何度もパスワード入力することは無いはずなので、極端に安全に倒したところ(100文字等)で運用負荷はたかが知れてるでしょう。
長すぎた(1メガ文字等)場合のケースについては未検証なので、それについてはノーコメントで。
Q.パスワードのローテーションは?
A.あー自分、その手の運用は事故しか起きてないので、個人的にオススメしてません。こういうのはより上位からのポリシー強制によるものなので、ここで考える範疇を超えます。
また自動ローテーションする仕組みが提供されているケースもありますが、影響範囲を十分に考慮の上、十分にテストしてから実践することをオススメします。
ていうか、記号を含む十分に長いランダムなパスワード使用してるなら、通常の運用では十分でしょ。パスワードを漏らさないような仕組みや枠組み考える方が先かと。
参考文献
- mysql_config_editor — MySQL Configuration Utility / 日本語版(機械翻訳)
- my_print_defaults — Display Options from Option Files / 日本語版(機械翻訳)
- Assigning Account Passwords / 日本語版(機械翻訳)
- End-User Guidelines for Password Security / 日本語版(機械翻訳)
- Bug#74691: mysql_config_editor does not escape strings
- Changes in MySQL 8.0.24 (2021-04-20, General Availability)
- mysql_config_editor は シャープを含むパスワードをうまく扱えない
- mysqlのパスワードにビックリマーク!入れたらいろいろハマった話
-
大文字・小文字含み、それらは別の文字として区別する。 ↩
-
リリースノートを読むと有効になった記号類として「spaces」という表現が気になる。
\t
(タブ)や\r
(CR)、\n
(LF)も含んでいるのだろうか。mysql_config_editor
のマニュアルには記載が無いので詳細は不明。 ↩ -
MySQLクライアントとしてではなく、MySQLサーバーとしてインストールされるケースがある。一例としてRHEL系では
dnf -y install mysql-community-server
すると本コマンドがインストールされる。 ↩ -
本機能を暗号化(ソースを読むと確かにAESで暗号化してるが)と称するケースもあるが、同ファイル中に暗号キーを含んでいるので、難読化が正しい。 ↩
-
JMESPathは文字列として
'
または`
でくくることを要求しているので留意すること。 ↩