2020年はsystemd-homedの登場でLinuxのユーザー管理が大きく変わるぞ

これまでのLinuxでは、ユーザーの追加は`useradd`で行われ、ホームディレクトリは`/home`以下にディレクトリとして作られ、ユーザーのアカウントは`/etc/passwd`、`/etc/group`、`/etc/shadow`で管理されていました。

これからは、`systemd-homed`がその全ての仕事を置換することになります。

※タイトル詐欺感がありますが、従来の方式も並行して使えます。安心してください。

# systemd-homedとは？

systemd バージョン245で追加された、ユーザー管理デーモン。実体はsystemdのサービスユニットファイルで、`systemd-homed.service`として起動されます。

~~今後、ユーザーの管理や認証はsystemd-homed（以下、 homed ）によって行われることになるようですね。~~ 出典が無く間違いだったため、訂正しました。systemd-homedを使うかはユーザーの選択であるため、無理に移行する必要はありません。
homed自体は、最新のsystemdをインストールしてある環境であれば自動的に有効化されます。（ただ、使うためには要設定です。後述します。）

# homedができること

- ユーザーの作成、削除、編集
- `/etc/passwd`、`/etc/group`、`/etc/shadow`に変わる、ユーザーごとのJSONファイルによるユーザー情報の管理
- ホームディレクトリの暗号化・復号
- ホームディレクトリへのnosuid,nodev,noexecの付与
- ユーザーの使用リソースの制限

上3つのみ一つずつ説明していきます。

# ユーザーの作成、削除、編集

homedでユーザーを管理する場合、`useradd`等のコマンドではなく`homectl`コマンドを使うことになります。
**もちろん、homedが導入されたLinuxで今後も`useradd`と`/etc/passwd`を使ったユーザー管理は継続できるので安心してください。**ただ、片方で作成したアカウントはもう片方で管理できません。（互換性がない）
また、homedはNSSに対応しているため(nsswitch.confにsystemdが追記されています)`getent`コマンドやglibcを使った従来のソフトウェアでも正しくLinuxユーザーが認識されます。

新しい`homectl`コマンドを簡単に説明します。

- `homectl create <user>` ユーザー追加
- `homectl remove <user>` ユーザー削除
- `homectl update <user>` ユーザー更新
- `homectl passwd <user>` ユーザーのパスワードを変更

createとupdateで指定・変更できるオプションは以下です。※より沢山あるのですが、長いため割愛しています。詳しくは`homectl -h`へ。

```
General User Record Properties:
  -c --real-name=REALNAME     Real name for user
     --realm=REALM            Realm to create user in
     --email-address=EMAIL    Email address for user
     --location=LOCATION      Set location of user on earth
     --icon-name=NAME         Icon name for user
  -d --home-dir=PATH          Home directory
     --uid=UID                Numeric UID for user
  -G --member-of=GROUP        Add user to group
     --skel=PATH              Skeleton directory to use
     --shell=PATH             Shell for account
     --setenv=VARIABLE=VALUE  Set an environment variable at log-in
     --timezone=TIMEZONE      Set a time-zone
     --language=LOCALE        Set preferred language
     --ssh-authorized-keys=KEYS
                              Specify SSH public keys
     --pkcs11-token-uri=URI   URI to PKCS#11 security token containing
                              private key and matching X.509 certificate
```
```
Account Management User Record Properties:
     --locked=BOOL            Set locked account state
     --not-before=TIMESTAMP   Do not allow logins before
     --not-after=TIMESTAMP    Do not allow logins after
     --rate-limit-interval=SECS
                              Login rate-limit interval in seconds
     --rate-limit-burst=NUMBER
                              Login rate-limit attempts per interval

```
```
Password Policy User Record Properties:
     --password-hint=HINT     Set Password hint
     --enforce-password-policy=BOOL
                              Control whether to enforce system's password
                              policy for this user
  -P                          Equivalent to --enforce-password-password=no
     --password-change-now=BOOL
                              Require the password to be changed on next login
     --password-change-min=TIME
                              Require minimum time between password changes
     --password-change-max=TIME
                              Require maximum time between password changes
     --password-change-warn=TIME
                              How much time to warn before password expiry
     --password-change-inactive=TIME
                              How much time to block password after expiry
```
```
Resource Management User Record Properties:
     --disk-size=BYTES        Size to assign the user on disk
     --access-mode=MODE       User home directory access mode
     --umask=MODE             Umask for user when logging in
     --nice=NICE              Nice level for user
     --rlimit=LIMIT=VALUE[:VALUE]
                              Set resource limits
     --tasks-max=MAX          Set maximum number of per-user tasks
     --memory-high=BYTES      Set high memory threshold in bytes
     --memory-max=BYTES       Set maximum memory limit
     --cpu-weight=WEIGHT      Set CPU weight
     --io-weight=WEIGHT       Set IO weight
```

今までuseraddで指定できたオプションとは別に、追加で色々なリソース制限がかけられるようになっているのがわかります。

※余談ですが、リソース制限を試してみたところ、cgroupがプロセスに適用されていました。だろうね。

また、パスワードの有効期限がユーザーごとに設定可能になった点や、一定時間あたりのログイン試行回数がここで制限できるようになった点もポイントが高いです。

# ユーザー情報の管理

homedは、ユーザー情報も管理します。homectlによって作成されたユーザーは、`/etc/passwd`、`/etc/group`、`/etc/shadow`へ記載されません。

そのかわり、

- ユーザー情報はhomedのデーモンが管理し、APIによって情報を提供します。（おそらく`/run/systemd/userdb/io.systemd.Home`ソケット）
- また、各ホームディレクトリへ`~/.identity`というファイルが作成され、JSON形式でユーザー情報を確認できます。

`~/.identity`は、例えばこんな内容です。

```json
{
        "cpuWeight" : 10,
        "disposition" : "regular",
        "lastChangeUSec" : 1584387192577240,
        "lastPasswordChangeUSec" : 1584382416144118,
        "memberOf" : [
                "testgroup"
        ],
        "perMachine" : [
                {
                        "diskSize" : 10737418240,
                        "matchMachineId" : [
                                "48801054a2af8b2c0104ff82c482fe2d"
                        ]
                }
        ],
        "privileged" : {
                "hashedPassword" : [
                        "$6$h9kNT.dmjmHXt/i1$ATJy/KnBCXMlmIjBziemYqRa8XUtiVDMCnC.m/iSNNh8zdXfX5V7jJwwsZCJo3PJIv3.C0p/6OXTxN8CXCIcS1"
                ]
        },
        "signature" : [
                {
                        "data" : "hoge",
                        "key" : "-----BEGIN PUBLIC KEY-----\fuga=\n-----END PUBLIC KEY-----\n"
                }
        ],
        "userName" : "test"
}
```

このファイルはrootでなくても読み書きできるので、おそらく本体は別の場所にあるか、もしくは`signature`項目でhomedがこのファイルに署名している気がします。が、両方共私の憶測なのでどうかはわかりません。

## userdbctl

ユーザーの作成・更新以外に、ユーザーの情報やグループの情報を確認したい場合は`userdbctl`コマンドを使用します。

```:サブコマンド
  user [USER…]                Inspect user
  group [GROUP…]              Inspect group
  users-in-group [GROUP…]     Show users that are members of specified group(s)
  groups-of-user [USER…]      Show groups the specified user(s) is a member of
```

例えば`userdbctl user <ユーザー名>`でそのユーザーの所属グループやホームディレクトリの暗号化状況、リソース制限が確認できます。

## ユーザーの認証について

Linuxのユーザーの管理をしているのは、PAM(Pluggable Authentication Modules)です。
pam小話をしましょう。

- PAMの実体はただの設定ファイルと共有ライブラリ(PAMモジュール)です。
- PAMの役割は、ログイン時にログインプロンプトやsshdがユーザーの情報を取得する場合にユーザーの認証情報を確認することです
  - 具体的には、TTYからパスワードを取ってきて正しければ成功を返すような共有ライブラリ(PAMモジュール)を、各ログインソフトウェアが実行します。
  - 各ソフトウェアは、成功が帰ってきたらデフォルトシェルをそのユーザーで動作させます。

homedのない従来の環境では、「`/etc/passwd`と`/etc/shadow`を読みに行きパスワードが正しければ成功をソフトウェアへ返すPAMモジュール」が存在し、またデフォルトでそれを使うような設定ファイルになっていました。(細かい話は省略)

homed時代では、このpamに「homedを呼び出しユーザーの認証情報の確認をさせるようなPAMモジュール」を**追加します。**追加なので、今までのユーザー管理も適用されるというわけです。

ちなみに余談ですが、LDAP認証やNIS認証など、Linuxユーザーのネットワーク管理を行う際にもこのPAMにモジュールを追加しています。

## homedのpamを有効にする

**※この設定をしない場合、`homectl`でユーザーを追加してもログインができません。**

homedを使うためには、一応準備が必要です。pamの設定ファイルを更新する必要があります。
おそらく、最新のsystemdが入ったOSをインストールすればデフォルトで更新された設定ファイルが入るのでしょうが、途中でアップデートする我々は設定ファイルを手動で書き換える必要があります。
これは推測ですが、pam設定ファイルは環境によってインストール後に結構編集されるため（LDAP認証のため等）でしょう。

特にpamの設定を弄っていない場合は、pam設定を上書きすれば更新は完了です。

```console
$ sudo cp /usr/share/factory/etc/pam.d/system-auth /etc/pam.d/system-auth
```

設定を弄っている場合は、diffを見てよしなに設定してください。`man pam_systemd_home`を実行すると詳しい設定の方法が確認できます。



# ホームディレクトリの暗号化

おそらく、homedでの一番大きな特徴が、ホームディレクトリの暗号化に対応したことです。今まではecryptfs等で一々設定する必要がありました。

homedでは、ユーザー作成時にホームディレクトリの種類を選べます。(`--storage=`)
**何も指定しない場合、homedはデフォルトで`luks`を使用します。**

  - `directory` … 従来どおり、`/home`以下にユーザー名のディレクトリを作成する
  - `subvolume` … `/home`以下に、ユーザー名のbtrfs subvolumeを作成する
  - `luks` … `/home`以下に、LUKS暗号化を使ったホームディレクトリを作成する
  - `fscrypt` … `/home`以下に、FSCryptを使った（略
  - `cifs` … `/home`以下に、cifs(いわゆるSamba/ネットワーク共有)を使った(略

この内、`luks`か`fscrypt`を使うと暗号化されます。まあLUKSとFSCrpytを使うので当たり前ですね。特に理由がなければ、`fscrypt`より`luks`を使うことをsystemdは推奨しています。

また、このhomedによるluks暗号化は、ユーザーログイン時・ログアウト時の自動復号・自動再暗号化に対応しています。便利ですね。

## homedで`luks`を使った場合の動作について（おまけ）

homedでluksを使用した場合、`/home/`以下に`ユーザー名.home`と呼ばれる数十GBのサイズのファイルが生成されます。これがどうやらホームディレクトリの本体です。
このファイルは`ext4`や`btrfs`のイメージファイルになっていて（luks内部をどのファイルシステムにするかは選べます）、これがluks(dm-verity)でブロックストレージごと暗号化されています。
homedはログイン時にこのイメージファイルを復号化しつつ`/home/ユーザー名`にマウントするようです。

ユーザーがログインしていないときにホームディレクトリを復号（マウント）するのには、`homectl`コマンドを使用します。もちろん復号には復号パスフレーズ（ユーザーのログインパスワードと同じっぽい）が必要です。

- `homectl activate <user>` 復号
- `homectl deactivate <user>` 暗号化

どうやら復号化された状態を「アクティブ」って呼んでいるみたいですね。ちなみに今どのユーザーがアクティブかどうかは`homectl list`で確認できます。

ここで気づくのが、ユーザーのホームディレクトリへアクセスする場合に復号パスフレーズが必要という点です。root権限を持っていても、ユーザーがログインしていなければ（ユーザーが復号化していなければ）他人のホームディレクトリへアクセスできないのは、セキュリティやプライバシーの観点から大変有利です。

## ホームディレクトリのサイズ制限について

homectlで作成したユーザーは、デフォルトでホームディレクトリのサイズが制限されるようです。luksの場合はイメージファイルのサイズが制限されます。

サイズ制限を変更するには`homectl resize`コマンドが使用できます。

例:

```console
$ homectl resize user1 10G
```

luksモード時のイメージファイルは、固定イメージファイル（予め容量を確保する方式）のため、最初から空のイメージファイルが数十GB作成されます。非効率だしそこまで使わないので、resizeコマンドで10GB程度に抑えておくのがいいと思います。

# まとめ

systemd-homedを紹介しました。これからも従来の方法でユーザー管理は行えます。そのため、現状で問題がない場合は徐々にhomedが浸透するまで長い時間がかかると思います。ただ、Linuxデスクトップユーザーにとっては大変便利なため、興味がある方はぜひ使用してみてください。

長文失礼いたしました&ここまで読んでくれてありがとうございます。

# 参考

- https://wiki.archlinux.org/index.php/Systemd-homed
- https://systemd.io/HOME_DIRECTORY/