pwgenで開発時に必要なパスワード類をいい感じに生成する

システム開発時にはDBなどのミドルウェアや連携する何らかのサーバー、Ansible Vaultのパスワードファイルなど、何かとたくさんのパスワード（やキーなどのランダムな文字列）が必要になることがありますよね。

みなさんは、これらのパスワードをどのように用意していますか？　毎回その場で適当に考えている？　ツールを使って生成している？

今回は`pwgen`というコマンドライン上でパスワードの生成が行えるツールと、開発時における活用方法を紹介したいと思います。

## 本記事で扱うこと、扱わないこと

システム開発時に何かと必要となる様々な（DBなどの）パスワードやAPIキーのようなシークレットトークンの扱いを主なターゲットとします（人間が普段あまり意識する必要のないやつ）。
主に設定ファイルなどに書いておくやつです。

もちろん、みなさんが普段利用しているサービスのパスワード生成などにも利用できますが、そういうのはどちらかというとブラウザのパスワード管理機能やパスワードマネージャー（1Passwordなど）を利用したほうがよいかと思います。

また、本記事ではパスワードの強度について詳しく取り扱うつもりはありません。
文字種や文字数については、各自の環境におけるポリシー等に照らし合わせて調整してください。

## `pwgen`の導入

`pwgen`はWindowsを除く多くの環境で、標準的なパッケージとしてインストールできます。
いちおう公式なページは下記のものだと思われます（各種パッケージマネージャーのinfo等に記載されているURLがコレ）。

https://sourceforge.net/projects/pwgen/

Windowsに関しては、`PWGen`のような（ほぼ）同一の名前ながら、上記とは**異なる別アプリ**しか見当たりませんでした。
Windows環境の場合はWSL等で使うのがよいでしょう。

### インストール例

```sh
# macOS
brew install pwgen

# Debian/Ubuntu
apt install pwgen
```

## `pwgen`の使い方

実行してみると次のような感じでパスワードがたくさん出力されるので、
この中から気に入ったものをピックアップします。

```console
$ pwgen
Veichae0 ohwu6aeJ sieGhu2O udeiY7ei au2Ux8me taaM9Oon hoVoa0ah iorahPu9
AX0eviy4 xaekee1U Ieth8ahH ieliC0ea goh2uSee Gae9cohf BeThaex9 ohFiey4u
ye5Eeloo aujae9Ba Ael9Uyoh aefoN1qu Iaroog8z Eiri7kah ceaCha1x pu4wohBa
Eifua0ee gohRouy8 Iepuu1ae zaiTh4wi ra9Pohvo Tah3ahta auKoo0en iiW1bieb
moo9feiK aB7uzogh wiiGhez6 Onigo2gi kohn3Iek Taik4aht ro9ooXoF ooPhoh1n
                                :
```

この沢山表示される挙動は標準出力が`tty`（対話型のシェルなど）の場合だけで、それ以外の場合（リダイレクトなど）は1つだけ出力されるので、スクリプトなどに組み込んで使うことも可能です。

```console
$ pwgen >password.txt
$ cat password.txt
Iehu5epu

$ echo "パスワードは $(pwgen) です"
パスワードは ohW0vu6l です
```

### オプションによる調整

オプションを指定することで、使用する文字種や長さを制御することができます。

ここではよく使うオプションに絞って紹介したいと思います。全てのオプションを知りたい方は`man pwgen`か`pwgen --help`を見てください。

| オプション           | 意味                                               |
| -------------------- | -------------------------------------------------- |
| `-c`, `--capitalize` | 少なくとも1つの大文字を含める                      |
| `-n`, `--numerals`   | 少なくとも1つの数字を含める                        |
| `-y`, `--symbols`    | 少なくとも1つの記号を含める                        |
| `-s`, `--secure`     | 完全にランダムなパスワードを生成する               |
| `-B`, `--ambiguous`  | 紛らわしい文字を除外する（ゼロと大文字のオーなど） |

`-s`を指定しない場合、生成されるパスワードは覚えやすい母音と子音の組み合わせで構成されたパスワードが生成されます（なんとなく読めそう＝覚えやすいパスワードになる）。
`pwgen`と`pwgen -s`で比べてみてください。

また、引数でパスワードの長さと生成する個数を指定することができます。

```sh
pwgen [パスワードの長さ] [生成する個数]
```

#### 実行例

```console
# 大文字(-c)、数字(-n)、記号(-y)を含める
# 曖昧な文字は含めない(-B)
# 20文字のパスワード
# 5個出力する

$ pwgen -cnyB 20 5
aaf7Aqu3ceixah:ph}oa heiko4eiNg{o=fe7chee xeaso-a9Hamah%t?oa3U
ahn4eid3quae:T9eivee Phoo?d9tae+seexee'ja
```

## 活用方法

`pwgen`の使い方がわかったところで、システム開発時における活用例を紹介したいと思います。

例えば開発用にDockerなどを使ってDBを起動したいとします。
そのような場合に、例えば次のようなオプションでパスワードを生成して使います。

```console
# 大文字(-c)、数字(-n)を含める
# 完全にランダムなパスワードにする(-s)
# 曖昧な文字は含めない(-B)
# 32文字のパスワード

$ pwgen -cnsB 32
yP7rt4VWuEdmxxcNkkwtzWyqFCHsr7sc pPaKexJzys9hoJUemdmjTY4KfuTP7oMJ
dwnaxe4KYJmfNvF4jvcFqdKpKveRNwMd oFYpJKLRHvMyjXpp3MKxXif7u9Pnbf7P
p3d77fcdVvzynNiiYU77mUkUFKsKRcbt V7YNozEEt9bPHrmzaRFYqzrtWvke4juP
                                :
```

ポイントは設定ファイルやソースコードに書くことを目的としてオプションを指定していることです。

- 十分に長いパスワードにする
  - 人が手で入力することは想定していない
- 完全にランダムなパスワードにする
  - 人間にとって覚えやすい必要はない
- 記号を含めない
  - YAMLなどの設定ファイルやコード内に記述する際に、記号のエスケープなどでトラブルを起こしたくない
    - 特にURL形式で記述する際は、記号をパーセントエンコードしないといけなかったりして大変
  - コピペするときに簡単に選択できる（記号が含まれていると、単語選択するときにそこで途切れたりしますよね？）
- `-B`（あいまいな文字を除外）は意見がわかれるところ
  - 人が入力しないのであれば紛らわしい文字は関係ない
  - とはいえ、何かの事情で目視で確認したいときなどに、紛らわしい文字で混乱したくない

余談ですが、先日私はDaaS環境でコピペも出来ないという状況で、このような長いパスワードを手入力する羽目になり、とても苦労しました😭

### その他の例

Ansible Vault用のパスワードファイルを生成したり、開発時に何かの固定のキーを作って払い出したい時などにも、同じような感じでランダムな文字列を生成し放題です。

```sh
# Ansible Vaultのパスワードファイルを生成する
pwgen -cns 64 >.my_vault_pass

# 何か開発用に固定のAPIキー（のようなもの）を発行する
pwgen -cns 64
```

まぁ、だいたい`-cns`か`-cnsB`で、あとは文字数を指定して使う感じですね。

人が入力するパスワードで、ちょっと短めだけど記号は含めたいみたいな場合だとこんな感じでしょうか。

```sh
# -c: 大文字を含める
# -n: 数字を含める
# -y: 記号を含める
# -B: あいまいな文字は除く
pwgen -cnyB 12
```

## おわりに

これからは、その場で適当に考えたような安易なパスワードを使用するのはやめて、（`pwgen`でなくてもよいので）ツールで生成したパスワードを使うようにしましょう。