意外に複雑なLinuxのパスワード生成事情とパスワード生成方法

# 1. 意外に複雑なパスワード生成事情

システムの構築や管理で強固なパスワードを生成したいことがある。しかし**TL;DR**に書いたように、Linuxでは意外に複雑な事情がある。そこで今回は主要なコマンドの特性と使い方を説明する。

### 1-1. TL;DR

* Linuxにはパスワードを生成するコマンドが複数ある
* コマンドによって特性が違い、標準リポジトリに「含まれている／含まれていない」などインストール方法も違う
* 一見ランダムでありながら、発音しやすい（＝覚えやすい）パスワード生成方法もある
* <font color="blue">パブリック・クラウドではOSにパスワード・ログインする機会は少ないが、VNCやxrdp、シリアルコンソール接続では必要になることがある</font>

### 1-2. 対象環境

* RHEL系Linux OS
* Ubuntu 

# 2. パスワード生成方法を考える

Linuxでパスワードを生成するには、大きく分けて以下の方法がある。

1. pwmakeやpwgen、mkpasswdなどのパスワード生成コマンドを使う
2. opensslや /dev/urandomなどを組み合わせて使う
3. Bitwardenや1Password、Lastpass、GoogleパスワードマネージャーなどのWebサイトパスワード管理ツールを使う

Webサイトのパスワードを管理するなら3を使うべきだろう。 **しかし今回は汎用的なパスワード生成を目指している。そのため1の方法を説明する。** 2の方法は以下のリンクを参照のこと。

* [10 Ways to Generate a Random Password from the Linux Command Line](https://www.howtogeek.com/howto/30184/10-ways-to-generate-a-random-password-from-the-command-line/)

### 2-1. 各コマンドの概要

それぞれのコマンドを簡単に紹介する。

**pwgen**
　汎用的なパスワード生成コマンド。オプションに指定した条件でパスワードを生成できる。
　http://sf.net/projects/pwgen

**pwmake**
　libpwqualityライブラリに含まれるパスワード生成コマンド。RHEL7系から採用されたpam_pwquality(libpwquality)に統合されているため、**オプションを指定しなくてもOSのパスワードポリシーに従ったパスワードを生成できる**。
　https://github.com/libpwquality/libpwquality/

**mkpasswd**
　expectに含まれるパスワード生成コマンド。機能はpwgenに似ているが、pwgenのほうが高機能。<font color="red">ただしRHEL系とUbuntuでは、コマンド名は同じだが別物。</font>

<font color="blue">**ヒント**</font>
<font color="blue">pwgenとpwmakeのmanを見ると「pronounceable passwords」と説明されている。つまり**発音しやすいパスワード**を生成できる。程度の問題なので、辞書に登録されている単語が含まれるわけではない。</font>

### 2-2. 各コマンドの入手方法

以下の表は、Linuxディストリビューションごとの入手方法だ。OSのインストールタイプに依存するが、デフォルトでイントールされるのは**<font color="blue">青字</font>**のパッケージだけで、それ以外は任意にインストールする必要がある。カッコ内は入手先リポジトリだ。

| ディストリビューション | pwmake | pwgen | mkpasswd |
|:-:|:-:|:-:|:-:|
| RHEL6系  | libpwquality（EPEL） | pwgen（EPEL）	| expect |
| RHEL7/8/9系  | <font color="blue">libpwquality</font> | pwgen（EPEL） | expect |
| Ubuntu18.04LTS  | libpwquality-tools | pwgen | whois |

### 2-3. 各コマンドの使い分け

これまで説明してきたことをまとめると次のようにいえる。次章ではpwmakeとpwgenの使い方を説明する。

* RHEL7系以降もしくはUbuntuで、OSのログイン・パスワードを生成するには**pwmake**が適している
* 利用方法を限定しないパスワードを生成するには**pwgen**が適している

# 3. pwgenを使う

汎用的なパスワード生成コマンドpwgenの使用方法を説明する。

### 3-1. pwgenをインストールする

pwgenはEPELリポジトリから提供されている。ただしパブリック・クラウドのOSイメージでは標準リポジトリに含まれていることもある。RHEL系とUbuntuのそれぞれについて説明する。

**RHEL系**

1. pwgenがインストールされているか確認する。

```shell-session
$ rpm -qa | grep pwgen
★インストールされていないときは何も表示されない。
```

2.インストールされていないときは、既存のリポジトリに含まれているか確認する。

```shell-session
$ sudo yum provides pwgen
★No matchesと表示されたときはリポジトリに含まれていない。
No matches found

★リポジトリに含まれているときはパッケージ名が表示される。
pwgen-2.08-1.el7.x86_64 : Automatic password generation
Repo        : epel
```

3.既存のリポジトリに含まれていないときには、先にEPELリポジトリをインストールする。EPELの詳細は「[あらためてEPELリポジトリの使い方をまとめてみた](https://qiita.com/yamada-hakase/items/fdf9c276b9cae51b3633)」を参照のこと。

```shell-session
# RHEL9系
sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm -y

# RHEL8系
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm -y

# RHEL7系
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm -y

# RHEL6系
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm -y

# Amazon Linux 2
sudo amazon-linux-extras install epel
```

4.pwgenをインストールする。

```shell-session
$ sudo yum install pwgen -y
```

**Ubuntu系**

```shell-session
$ sudo apt install pwgen
```

### 3-2. pwgenの実行方法

pwgenの文法は以下のとおり。オプションの後ろに、パスワード長と個数を指定する。下記以外のオプションはmanを参考のこと。

```:文法
pwgen [ OPTIONS ] [ pw_length ] [ num_pw ]
```

| オプション | 内容 |
|:--|:--|
| -c  | 最低一文字の大文字を含める  |
| -A  | 大文字を含めない  |
| -n  | 最低一文字の数値を含める  |
| -0  | 数値を含めない  |
| -y  | 最低一文字の記号を含める |
| -s | 完全にランダムなパスワードを生成する |
| -B  | 1（イチ）やl（エル）、O（オー）、0（ゼロ）など紛らわしい文字は含めない  |
| -1  | 1行あたり1パスワード表示する  |

**例1）** パスワード長は12文字で、最低1文字の大文字（-c）と数値（-n）を含める。個数指定しないときは、次のようにフルスクリーン分が表示される。この中から使いたいものを選べばよい。

```shell-session
$ pwgen -c -n 12
Eiv5roo5pha1 ahnie0Zeogh2 piedu8Vaijoo Foa2eghiiPho teiHosoh8ooF ohgh0Ohwaesh
pahph6Aiyu0M leiB2xahlah1 maePee7fonoe aeGo6xielaeM Veif1Iaj4Na7 beiB8IKungie
Ohlah2aithak Aelaelo2ieri bieRef8ceire cahxu7AF4Ung chah7Aht6vah edeva9Ooquie
gaeWo1Aijae7 ii1AeThuewei oohaeW0nahm5 ohmoot7Ia6Du pho0vooW4eet cu3eeThioKu9
★以下省略
```

**例2）** パスワード長は12文字で、最低1文字の大文字（-c）と数値（-n）、記号（-y）を含め、紛らわしい文字（-B）は含めない。1行1パスワード（-1）で5個生成する。

```shell-session
$ pwgen -c -n -y -B -1 12 5
ashoo3ga(M3W
goo7ke\o4aeL
beiHae4voeH.
AJ3ok3ahj{in
shoo7ExiJ"ir
```
	
# 4. pwmakeを使う

**pwmake**は、OSのパスワード認証と関係が深いコマンドで、オプションを指定しなくてもOSのパスワードポリシーに従ったパスワードを生成できる。

**pwgen**が単独のコマンドなのに対し、**pwmake**はRHEL7で採用されたpam_pwquality(libpwquality)モジュールに含まれている。そのためpwmakeの理解にはpam_pwqualityの理解も欠かせないので先に説明する。

### 4-1. pam_pwqualityとは

pam_pwqualityは「大文字小文字混在、○文字以上のパスワードが必須」といったパスワードポリシーを強制するPAMモジュールだ。passwdコマンドを実行すると、以下の順序でパスワードが評価され、満たしているときだけ設定できる。

* 辞書チェック
* 設定ファイル/etc/security/pwquality.confのルールチェック

pam_pwqualityの重要な2つのファイル`/etc/pam.d/system-auth`と`/etc/security/pwquality.conf`を説明する。

パスワードをチェックするPAMモジュールは、Linuxのバージョンや種類によって異なる。詳細は以下のリンクを参照のこと。

RHEL7以降：[pam_pwquality](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/security_guide/chap-hardening_your_system_with_tools_and_services#sec-Password_Security)
RHEL6：[pam_cracklib](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/security_guide/chap-security_guide-securing_your_network#sect-Security_Guide-Password_Security-Creating_Strong_Passwords)
Ubuntu：[pam_unix](https://help.ubuntu.com/lts/serverguide/user-management.html)。pam_pwqualityもオプションで使用可能
　　　→[Enforce Password Complexity Policy On Ubuntu 18.04](https://kifarunix.com/enforce-password-complexity-policy-on-ubuntu-18-04/)

#### 4-1-1. /etc/pam.d/system-auth

このファイルはPAMモジュールの定義ファイルで、pam_pwqualityを呼び出し元になっている。今回の説明と関係ない行もあるのでgrepしたものを紹介する。

メディアからインストールしたときのデフォルトは以下のとおり。クラウドではカスタマイズされていることもある。

```shell-session
# grep ^password /etc/pam.d/system-auth
password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password    required      pam_deny.so
```

次の例では、過去N回のパスワード再利用を防止するためpam_pwhistoryモジュールを併用している。

```shell-session:カスタマイズ例
password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= enforce_for_root
password    requisite     pam_pwhistory.so use_authtok enforce_for_root remember=4
password    sufficient    pam_unix.so sha512 shadow try_first_pass use_authtok enforce_for_root remember=4
password    required      pam_deny.so
```

**参考：RHEL6系の例**
RHEL6系ではpam_pwqualityの代わりにpam_cracklibを使用している。パスワードポリシーは後述する設定ファイルではなく、以下のように/etc/pam.d/system-authにインラインで指定する。

```shell-session:RHEL6系
password    requisite     pam_cracklib.so retry=3 minlen=8 difok=3 gecoscheck ocredit=-1 dcredit=-1 ucredit=-1 lcredit=-1 enforce_for_root
```

#### 4-1-2. /etc/security/pwquality.conf

`pwquality.conf`はパスワードのルールを定義する設定ファイルだ。ディストリビューションによっては`/etc/security/pwquality.conf.d/`ディレクトリ配下に配置した`*.conf`のときもある。

つまり次の順序で設定ファイルを読み込み、同じ値が複数のファイルにあるときは、最後に読み込んだものが有効になる。

1. /etc/security/pwquality.confを参照
2. /etc/security/pwquality.conf.d/*.confを参照（ASCII順）

```:pwquality.confのman
       pwquality.conf provides a way to configure the default password quality
       requirements for the system passwords. This file is read by the
       libpwquality library and utilities that use this library for checking
       and generating passwords.

       The file has a very simple name = value format with possible comments
       starting with "#" character. The whitespace at the beginning of line,
       end of line, and around the "=" sign is ignored.

       The libpwquality library also first reads all *.conf files from the
       /etc/security/pwquality.conf.d directory in ASCII sorted order. The
       values of the same settings are overriden in the order the files are
       parsed.
```

**参考：Oracle Cloud Infrastructureの場合**
インスタンスを作成した時期にもよるが、Oracle Linux 7/8では追加の定義ファイルがある。

```:shell-session
# ls /etc/security/pwquality.conf.d/
oci.conf
```

**設定ファイルの内容**

設定ファイルが長いのでgrepしたものを紹介する。

```
# 基本
grep -v -e '^\s*#' /etc/security/pwquality.conf
# 追加ファイルがあるときに備えて
grep -v -e '^\s*#' /etc/security/pwquality.conf.d/*.conf
```

メディアからインストールしたときは、すべてコメントアウトされているので、grepすると何も表示されない。

```shell-session:すべてコメントアウトされている例
# Number of characters in the new password that must not be present in the
# old password.
# difok = 5
#
# Minimum acceptable size for the new password (plus one if
# credits are not disabled which is the default). (See pam_cracklib manual.)
# Cannot be set to lower value than 6.
# minlen = 9
★以下省略
```

クラウドではデフォルト値が設定されていることがあり、Oracle Cloud Infrastructure Computeでは次のように設定されている。簡単に意味を書いたが、詳しくは設定ファイル内のコメントやmanを参考にしてほしい。

```shell-session
difok = 3       # 過去3回のパスワードは利用不可
minlen = 8      # パスワードが8文字以上
dcredit = -1    # 数字が1文字以上
ucredit = -1    # 大文字アルファベットが1文字以上
lcredit = -1    # 小文字アルファベットが1文字以上
ocredit = -1    # 記号が1文字以上
gecoscheck = 1  # /etc/passwdエントリのGECOSフィールドの単語が含まれていない
minclass=4      # 文字種別の数。4は数値、大文字、小文字、記号が必須
maxrepeat=3     # 連続した文字の最大数
```

### 4-2. pwmakeの実行方法

前置きが長くなったがpwmakeでパスワードを生成しよう。次のようにエントロピービット数を指定する。エントロピービット数を簡単に表すと解読の難易度だ。56以上の数値を指定でき、多くの場合64で十分だ。

```:文法
pwmake ＜エントロピービット数＞
```

pwmakeは「pam_pwqualityの設定値」と「エントロピービット数」の両方を考慮してパスワードを生成する。設定ファイルに値がないときは「エントロピービット数」だけを考慮する。次の例を見るとエントロピービット数が大きくなるほどパスワードも長くなっている。

```
$ pwmake 56
YKHUdiLIj$AH
$ pwmake 64
dEHimAf3PIwUgG
$ pwmake 80
iczaf0D4x@M-EhEGt
$ pwmake 128
Yc4kexIJiw5@sIDM3R6an(ijEDYM
```

次の例はOracle Cloud Infrastructure Computeで実行した例だ。定義ファイルの内容を反映し、大文字や数値、記号などが含まれている。気に入らないときは複数回実行すればよい。

```
$ pwmake 64
ErODFOROJ0w+YN
```

つまりパブリッククラウドのように設定ファイルに定義があるときには非常に便利なコマンドといえる。また定義がないときは大文字・小文字や数値などは運次第だが、強固なパスワードは生成できる。

* man pwmake
* man pam_pwquality
* man pwquality.conf

# 5. まとめ

* **pwgenは、広い用途で使用できるパスワード生成コマンド**
* **pwmakeは、RHEL7系以降でデフォルト・インストールされているパスワード生成コマンド。OSのパスワードポリシーに準じたパスワードを生成するときに便利**

今さらOSのログイン・パスワードと思うかも知れないが、一番のきっかけはVNCやxrdpである。これらを使用するときにはクラウドでもパスワードログインが必要だ。

またOracle Cloud InfrastructureやAzure VMのシリアルコンソール接続では、OSユーザーにパスワードを設定する必要がある。

自分で決めた強度の高いパスワードを使ってもよいが、あまり考えずに強度の高いパスワードを生成する方法として、これらのコマンドを活用してはどうだろう。