Linux ユーザ管理

# ユーザの種類

- `root` ユーザ
- システムユーザ
- 一般ユーザ

## `root` ユーザ

- システム管理者専用
- UID：`0`
- すべてのコマンドを実行できる

## システムユーザ

- サービス、デーモンの実行専用
- UID：`1` ~ `999`（ディストリビューションによって異なる場合あり）
- `nobody`、`daemon`、`www-data`、`mysql` など

## 一般ユーザ

- UID：`1000` 以上
- それぞれのホームディレクトリ内のファイルや設定を管理できる
- `$ sudo` コマンドによって一部の管理権限を取得可能（`sudo` グループに所属する場合）


## `/etc/passwd`

:::note alert
`/etc/passwd` の書式を間違えるとシステムが正常に動作しなくなるため、編集には `$ vipw` や `$ usermod`、`$ passwd` を利用する
:::

ユーザアカウント情報が保存されたファイル。

`/etc/passwd` は 1 ユーザあたりの情報が 1 行のテキストファイルになっていて、各項目は `:` で区切られている。

[パーミッション](https://qiita.com/AsahinaKei/items/2fbc4e079b1c4b847240) は通常、 `-rw-r--r--` となっている。

```plaintext:/etc/passwd
ユーザ名:パスワード:UID:GID:コメント:ホームディレクトリ:ログインシェル
```

| フィールド | 説明 |
|:-:|:-|
| ユーザ名 | 最大 32 文字 |
| パスワード | ユーザのパスワード。通常は `x` と表示される。<br>実際のパスワードはシャドウパスワードとして [`/etc/shadow`](#etcshadow) に保存される。<br>`*`：ログイン不可<br> `!`：ログイン不可 |
| コメント | ユーザの説明（フルネームなど） |
| UID | ユーザID |
| GID | ユーザが所属する [プライマリグループ](#プライマリグループ) の GID |
| ホームディレクトリ | `/root`、`/home/ユーザ名` など（※ [`/home/`](https://qiita.com/AsahinaKei/items/09ee7ce55b1a0be01ff0#fhs)） |
| [ログインシェル](https://qiita.com/AsahinaKei/items/22d9fae93cabfbf137ee#%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%B7%E3%82%A7%E3%83%AB) | ログイン時に自動で起動するシェル<br>`/bin/bash`、[`/usr/sbin/nologin`](#sbinnologin--usrsbinnologin) など |

```plaintext:root ユーザの例
root:x:0:0:root:/root:/bin/bash
```

```plaintext:システムユーザの例
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
```

```plaintext:一般ユーザの例
user1:x:1000:1000:User One:/home/user1:/bin/bash
```

## `/etc/shadow`

ユーザパスワード情報を安全に格納するためのファイル。暗号化されたパスワードなどが格納される。

[パーミッション](https://qiita.com/AsahinaKei/items/2fbc4e079b1c4b847240) は `-rw------` で `root` ユーザのみが読み書きできる。

```plaintext:/etc/shadow
ユーザ名:パスワード:最終変更日:最小日数:最大日数:警告日数:無効日数:有効期限:予約
```

昔は `/etc/passwd` に `x` ではなく直接パスワードが格納されていた。暗号化されて保存されていた場合も解読される恐れがあるため、今では `/etc/shadow` が使用される。

| フィールド | 説明 |
|:-|:-|
| ユーザ名 | `/etc/passwd` に対応するユーザ名 |
| パスワード | 暗号化されたパスワード<br>`*`：ログイン不可<br> `!`：ログイン不可<br>`!!`：パスワード未設定 |
| 最終変更日 | UNIX時代（`1970/1/1`）からの日数として格納されている。<br>`$ chage -l ユーザ名` で確認可能。 |
| 最小日数 | パスワード変更を強制するための最低間隔（日数）<br>`0`：制限なし |
| 最大日数 | パスワードの有効期間（日数）<br>`99999`：無期限 |
| 警告日数 | 有効期限前に警告を表示する日数<br>`7`：7日前から警告 |
| 無効日数 | 期限切れ後、アカウントを無効にするまでの日数<br>`14`：14日後に無効 |
| 有効期限 | アカウントの有効期限 |
| 予約 | 予約フィールド |

## `/etc/nologin`

`/etc/nologin` ファイルを作成することで、一時的に `root` ユーザ以外のすべてのユーザのログインを拒否することができる。

```console:/etc/nologin ファイルを作成する
$ touch /etc/nologin
```

`/ets/nologin` は、**ファイルの存在有無によって動作を制御するフラグファイル** と呼ばれるテキストファイルであるため、ファイルの中身は特に必要ない。

システムメンテナンスなどで一時的に通常ユーザのログインを禁止する場合に利用される。

## `/sbin/nologin` / `/usr/sbin/nologin`

システムユーザや特定のユーザのシステムへのログインを制限するための **実行可能ファイル**。実体は何もしないで即座に [終了ステータス](https://qiita.com/AsahinaKei/items/22d9fae93cabfbf137ee#%E7%B5%82%E4%BA%86%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9--) `1` を返すプログラム。

[`/etc/passwd`](#etcpasswd) のログインシェルとして設定される。

ログインシェルとして `/sbin/nologin` または `/usr/sbin/nologin` が設定されたユーザがログインを試みた場合、以下のようなメッセージが表示される。

```console:
This account is currently not available.
```

`/usr/sbin/nologin` の代わりに `/bin/false` を使用することもできる。

Linux ディストリビューションの種類によって `/sbin/nologin` または `/usr/sbin/nologin` のどちらが使用されるかが異なり、どちらが使用されているかは [`$ which`](https://qiita.com/AsahinaKei/items/22d9fae93cabfbf137ee#-which) で確認することができる。

```console:ログイン制限用の実行可能ファイルのパスを確認する
$ which nologin
```

## `/bin/false`

[`/usr/sbin/nologin`](#usrsbinnologin) と同様の目的で使用される実行可能ファイル。

`/usr/sbin/nologin` とは異なり、誤ってログインした場合にメッセージが表示されない（無言で失敗する）。

## `/etc/skel/`
skeleton=骨格、骨組み、基盤

新しいユーザを作成する際に、そのホームディレクトリに自動的にコピーされるテンプレートファイルを格納するディレクトリ。

デフォルトで以下のファイルが既に作成されている。

```console:/etc/skel/ の中身を確認する
$ ls -la /etc/skel/
total 20
drwxr-xr-x   2 root root 4096 Aug 27  2024 .
drwxr-xr-x 108 root root 4096 Feb 26 20:45 ..
-rw-r--r--   1 root root  220 Mar 31  2024 .bash_logout
-rw-r--r--   1 root root 3771 Mar 31  2024 .bashrc
-rw-r--r--   1 root root  807 Mar 31  2024 .profile
```

以下は Bash の [設定ファイル](https://qiita.com/AsahinaKei/items/22d9fae93cabfbf137ee#%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB)。

- `.bash_logout`
- `.bashrc`
- `.profile`

`/etc/skel/` 内のファイルを追加、または削除したとしても、既存のユーザのホームディレクトリは影響を受けない。

## `$ id`

```console:ログインしているユーザの UID、GID を表示する
$ id
```

```console:指定したユーザの UID、GID を表示する
$ id ユーザ名
```

## `$ useradd` / `$ adduser`

```console:新しいユーザアカウントを作る
$ useradd ユーザ名
$ useradd オプション ユーザ名
```

オプションを省略した場合、`/etc/default/useradd` の設定がデフォルトとして利用される。

| オプション | 説明 |
|:-|:-|
| `-u ユーザID`<br>`--uid ユーザID` | UID を指定する |
| `-g グループID`<br>`--gid グループI` | 所属する [プライマリグループ](#プライマリグループ) を指定する |
| `-G グループ名`<br>`--groups` | 所属する [サブグループ](#サブグループ) を指定する（`,` で複数指定可） |
| `-d パス`<br>`--home パス` | ホームディレクトリのパスを指定する |
| `-c "コメント"`<br>`--comment "コメント"` | コメントを追加する |
| `-m`<br>`--create-home` | ホームディレクトリを作成する |
| `-s シェルのパス`<br>`--shell シェルのパス` | [ログインシェル](https://qiita.com/AsahinaKei/items/22d9fae93cabfbf137ee#%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%B7%E3%82%A7%E3%83%AB) を指定する |
| `-p パスワード`<br>`--password パスワード` | パスワードを設定する<br>通常は `$ passwd` コマンドを [コマンド置換](https://qiita.com/AsahinaKei/items/22d9fae93cabfbf137ee#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E7%BD%AE%E6%8F%9B) によって使用し、暗号化したパスワードを指定する |
| `-r システムユーザ名`<br>`--system システムユーザ名` | [システムユーザ](#システムユーザ) を作成する |

ユーザを作成することにより、以下のファイルにエントリが追加される。

- [`/etc/passwd`](#etcpasswd)
- [`/etc/shadow`](#etcshadow)
- [`/etc/group`](#etcgroup)
- [`/etc/gshadow`](#etcgshadow)

## `$ userdel`

```console:ユーザを削除する（ホームディレクトリは残る）
$ sudo userdel ユーザ名
```

```console:ユーザを削除する（ホームディレクトリも削除される）
$ sudo userdel -r ユーザ名
$ sudo userdel --remove ユーザ名
```

```console:ユーザを削除する（削除対象ユーザがログインしていても、強制的に削除する）
$ sudo userdel -f ユーザ名
$ sudo userdel --force ユーザ名
```

強制削除する場合、ユーザが起動したプロセスについても停止させておく必要がある。

```console:指定したユーザが起動したプロセスを停止する
$ sudo killall -u ユーザ名
$ sudo pkill -KILL -u ユーザ名
```

※ [`$ killall`](https://qiita.com/AsahinaKei/items/e354a3814639aeac4138#-killall)、[`$ pkill`](https://qiita.com/AsahinaKei/items/e354a3814639aeac4138#-pkill)

## `$ usermod`

ユーザ情報を変更する。

```console:基本構文
$ usermod [-option] ユーザ名
```
手動で [`/etc/passwd`](#etcpasswd) ファイルを編集する方法もある。

```console:ユーザ名を変更する（login）
$ usermod -l 新ユーザ名 旧ユーザ名
```

`-d` を付与すると、`/etc/passwd` のエントリが書き換えられ、`-m` を付与すると、ユーザのホームディレクトリ内のファイルが新しいホームディレクトリに移動される、

```console:ホームディレクトリを変更し、中身を移動する（directory、move）
$ usermod -d 新しいパス -m ユーザ名
```

```console:ログインシェルを変更する（shell）
$ usermod -s シェルのパス ユーザ名
```

```console:所属するプライマリグループを変更する（group）
$ usermod -g グループ名 ユーザ名
```

```console:所属するサブグループを変更する（groups）
$ usermod -G グループ名 ユーザ名
```

```console:所属するサブグループを追加する（append groups）
$ usermod -aG グループ名 ユーザ名
```

```console:ログインにロックをかける（lock）
$ usermod -L ユーザ名
```

```console:ロックを解除する（unlock）
$ usermod -U ユーザ名
```

```console:アカウントの有効期限を設定する（expire）
$ usermod -e YYYY-MM-DD ユーザ名 # 指定した日を過ぎるとログインできない
$ usermod -e "" ユーザ名 # 有効期限を無期限（制限なし）にする
```

```console:パスワード期限切れ後の猶予日数を設定（inactive）
$ uusermod -f 日数 ユーザ名   # 猶予期間中にパスワードの変更をしないとアカウントがロックされる
```

## `$ passwd`

```console:パスワードを変更する
$ passwd # 自分のパスワードを変更する
$ sudo passwd 他人のユーザ名
```

パスワードは `!` に変更することで、ログインにロックをかけることができる。

```console:ログイン不可にする（lock）
$ sudo passwd -l ユーザ名 # /etc/shadow のパスワードが ! に変更される
```

```console:ログイン不可を解除する（unlock）
$ sudo passwd -u ユーザ名
```

`$ passwd` コマンドの実体である `/usr/bin/passwd` には [SUID](https://qiita.com/AsahinaKei/items/2fbc4e079b1c4b847240#suid--sgid) パーミッションが設定されている。SUID が設定された実行可能ファイルは、実行者の権限ではなく、所有者の権限で実行される。

`/usr/bin/passwd` の所有者は `root` ユーザであるため、`$ passwd` は `root` ユーザの権限で実行される。

そのため一般ユーザは、書き込み権限のない `/etc/shadow` ファイルの自身のパスワードを変更することができる。

ただし `/usr/bin/passwd` のプログラムの内部では、一般ユーザが「他のユーザのパスワード」を変更しようとした場合には、エラーを出すように制御されている。

```console:パスワードの有効期間を設定（maxdays）
$ passwd -x 日数 ユーザ名   # 期限を過ぎるとパスワードの変更が要求される
```

```console:パスワード期限切れ後の猶予日数を設定（inactive）
$ passwd -i 日数 ユーザ名   # 猶予期間中にパスワードの変更をしないとアカウントがロックされる
```

## `$ chage`
change age

ユーザのパスワードとアカウントの有効期限を管理するためのコマンド。

```console:基本構文
$ chage [-option] ユーザ名
```

```console:ユーザアカウントの有効期限を確認する（list）
$ chage -l ユーザ名
```

```console:アカウントの有効期限を設定する（expiredate）
$ chage -E YYYY-MM-DD ユーザ名
$ chage -E -1 ユーザ名   # 有効期限を無期限（制限なし）にする
```

```console:パスワードの有効期間を設定する（maxdays）
$ chage -M 日数 ユーザ名   # 期限を過ぎるとパスワードの変更が要求される
```

```console:パスワードを変更できるまでの最小日数を設定する（mindays）
$ chage -m 日数 ユーザ名   # 指定した日数が経過しないと、新しいパスワードに変更できない
```

```console:パスワード期限切れ後の猶予日数を設定（inactive）
$ chage -I 日数 ユーザ名   # 猶予期間中にパスワードの変更をしないとアカウントがロックされる
```

```console:パスワードの最終更新日を設定する（lastday）
$ chage -d YYYY-MM-DD ユーザ名
```

`YYYY-MM-DD` の代わりに 1970年1月1日 からの日数を指定してもよい。

```console:次回ログイン時にパスワードの変更を強制する
$ chage -d 0 ユーザ名   # パスワードの変更日を期限切れの古いhに強制変更
```

## `$ last`

```console:ログインしたユーザの履歴を表示する
$ last
```

このコマンドは `/var/log/wtmp` （who temporary）を参照している。この `/var/log/wtmp` ファイルはバイナリ形式であるため、`$ cat` や `$ less` では読むことができない。

## `$ who`

```console:現在ログイン中のユーザを表示する
$ who
```

このコマンドは `var/run/utmp` ファイル（user temporary）を参照している。


## `$ w`

```console:現在ログイン中のユーザを表示する
$ w
```

`$ who` コマンド同様に `/var/run/utmp` ファイル（user temporary）を参照しているが、`proc/` 配下の情報を利用して CPU 使用率や実行コマンドまで確認することができる（`$ who` よりも情報量が多い）。

# グループの種類

複数のユーザをまとめて管理するための仕組み。

ファイルやディレクトリのアクセス制御を行う際に、個々のユーザではなくグループ単位で権限を設定できるため、管理がしやすくなる。

**各ユーザは最低 1 つのグループに所属する**。

1 人のユーザは複数のグループに所属することができる。

- プライマリグループ
- サブグループ

## プライマリグループ

ユーザが所属するメインのグループ。

**基本グループ** とも呼ばれる。

ユーザがファイルを作成すると、自動的にプライマリグループがファイルの所有グループになる。

## サブグループ

プライマリグループ以外に所属できるグループ。

**参加グループ** とも呼ばれる。

`$ groups` コマンドで確認できる。
    
## `/etc/group`

グループ情報が記載されたファイル。

[`/etc/passwd`](#etcpasswd) と同様に 1 グループあたりの情報が 1 行のテキストファイルになっていて、各項目は `:` で区切られている。

パーミッション は通常、 `-rw-r--r--` となっている。

```plaintext:/etc/group
グループ名:パスワード:GID:メンバー
```

| フィールド | 説明 |
|:-|:-|
| グループ名 | グループの名前 |
| パスワード |  グループのパスワード。通常は `x` と表示される。<br>実際のパスワードは [シャドウパスワード](#etcshadow) として `/etc/gshadow` に保存される。 |
| GID | グループ ID |
| メンバー | グループに所属するユーザのリスト（カンマ `,` 区切り） |	

## `/etc/gshadow`

[`/etc/shadow`](#etcshadow) 同様に、グループのパスワードが暗号化され、格納されたファイル。

## `$ groups`

```console:自分が所属しているグループを表示する
$ groups
```

```console:特定のユーザが所属しているグループを確認する
$ groups ユーザ名
```

## `$ groupadd`

```console:グループを作成する
$ groupadd グループ名
```

```console:GID を指定して、グループを作成する
$ groupadd -g GID グループ名
```

## `$ groupdel`

削除しようとするグループを [プライマリグループ](#プライマリグループ) として所属しているユーザがいる場合、削除することはできない。

```console:グループを削除する
$ groupdel グループ名
```

## `$ groupmod`

```console:基本構文
$ groupmod [-option] グループ名
```

```console:グループID（GID）を変更する
$ groupmod g GID グループ名
```

```console:グループ名を変更する
$ groupmod -n 新グループ名 旧グループ名
```