3-2. ユーザー管理とセキュリティ - passwd, sudoers, 最小権限

所要時間: 40-50分(がっつりなら2セッション分) ゴール: Linuxのユーザー/グループ/権限モデルを理解し、本番運用に耐える「最小権限」設計ができる。sudoers を安全に書ける コミット内容: useradd / sudoers の検証ログを ~/learn/linux/day14 にまとめる

この章が終わるとできること

  • /etc/passwd の7フィールドと、/etc/shadow /etc/group の関係を説明できる
  • useradd / adduser の差を理解し、適切に新規ユーザーを作れる
  • visudo で安全に sudoers を編集し、/etc/sudoers.d/ でルールを分割できる
  • 最小権限 の sudoers ルール(コマンド単位の許可)が書ける
  • root ログイン無効化、退職者対応の手順を答えられる
  • /var/log/auth.log で sudo 実行記録を読める

Day 3 / Day 15 とのつながり

  • Day 3 でちらっと触れた「ユーザー」「グループ」の正体に、今日本格的に踏み込む
  • 昨日(Day 15)の SSH 鍵認証と組み合わせて、専用デプロイユーザー を作る基礎が完成
  • Day 11(systemd)の User=appuser で出てきた「専用ユーザー」を、今日自分の手で作る

これができると何が嬉しいか

  • root で全員ログイン」みたいな悪夢の運用を絶対に書かなくなる
  • 監査ログ(誰が・いつ・何をしたか)を残せる ─ コンプライアンス対応の土台
  • 退職者・委託先終了時に 30秒 で安全に締め出せる手順が手に入る

大前提: なぜ「ユーザー管理」が本番運用の根幹なのか

「本番サーバーに root で全員ログインする」運用、まだ世の中に存在します。これは事故が起きた時:

  1. 誰がやったか分からない: ログに root しか残らず、犯人特定不能
  2. 被害が最大化する: ミス・侵入のどちらでも全権限を持つアカウントが乗っ取られる
  3. 法令違反になることも: 個人情報保護法・SOX法・PCI-DSS などは「アクセス制御と監査」を要求する

正しい運用は 「1人1アカウント+必要な権限だけ+全操作を記録」。これが最小権限の原則(Principle of Least Privilege, PoLP)

そして Linux のユーザー管理は、表向きシンプルですが、触ったら戻せないファイルがいくつもあります(/etc/passwd, /etc/shadow, /etc/sudoers)。直接編集して構文ミス → ログインできなくなる、という事故が頻発します。今日は「事故らない手順」を含めて身に着けます。


セッション①: ユーザー/グループの基礎と内部構造(25-30分)

0. 録画スタート

mkdir -p ~/log ~/learn/linux/day14
cd ~/learn/linux/day14
script ~/log/linux_day14.log

1. /etc/passwd の構造

Linux のユーザー管理を理解する入り口は、/etc/passwd を読めるようになることです。この1ファイルを音読できれば、ユーザー管理のほぼすべてが繋がります。

  • 何のコマンドか: /etc/passwd は「このシステムに存在するユーザー全員のリスト」が : 区切りで並んでいる、誰でも読めるテキストファイル
  • いつ使うか: 新しいサーバーに入った時に「どんなアカウントが存在するか」を把握する時、サービスアカウント(postgres, www-data)の有無を確認する時、UID 衝突や nologin 設定を調べる時
  • 解決する具体的な問題: 「Linux のユーザーとは何か」をファイルの実体として見ることで、抽象概念から「ただのテキスト1行」に降ろせる
# 自分の行を見てみる(macOS では DSCLが本体だが、Linux 互換のpasswdは存在しない)
# Linux VMに繋いで実行する想定:
cat /etc/passwd | head -5
# root:x:0:0:root:/root:/bin/bash
# daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
# bin:x:2:2:bin:/bin:/usr/sbin/nologin
# sys:x:3:3:sys:/dev:/usr/sbin/nologin
# sync:x:4:65534:sync:/bin:/bin/sync

/etc/passwd の7フィールド

各行は : 区切りで7フィールド:

root:x:0:0:root:/root:/bin/bash
 │   │ │ │  │     │       │
 │   │ │ │  │     │       └─ ログインシェル
 │   │ │ │  │     └───────── ホームディレクトリ
 │   │ │ │  └─────────────── GECOS(フルネームなど)
 │   │ │ └────────────────── プライマリGID
 │   │ └──────────────────── UID
 │   └────────────────────── パスワード(今は "x" でshadowへ)
 └────────────────────────── ユーザー名

UID 0 = root(特権)。1-999 はシステム/サービスアカウント、1000以上が一般ユーザー。

/etc/passwd vs /etc/shadow vs /etc/group の役割分担(重要)

ざっくり言うと

Linux のユーザー情報は 3つのファイルに分散している。それぞれ役割と権限が違う。

まず昔の素朴な構成

昔は /etc/passwd 1ファイルにパスワードハッシュも直書きされていた。

/etc/passwd (mode 644: 全員読める)
  root:$6$xxxxx$yyyyyy:0:0:root:/root:/bin/bash
                ↑
              ハッシュとはいえ全員に見える
この状態の問題発生フロー
/etc/passwd は 644(全員読める)
   ↓
攻撃者がログインユーザーで cat /etc/passwd
   ↓
ハッシュをローカルに持ち帰り
   ↓
オフラインで辞書攻撃・レインボーテーブル攻撃
   ↓
パスワード突破
解決策: ハッシュだけ /etc/shadow に隔離

1988年ごろから「パスワードハッシュは別ファイル(root しか読めない)」設計に。

/etc/passwd  (644 全員読める): ユーザー名・UID・ホーム・シェル
/etc/shadow  (600 root だけ): パスワードハッシュ + 有効期限
/etc/group   (644 全員読める): グループ名・GID・所属ユーザー

イメージ:

  • /etc/passwd = 電話帳の表紙(誰でも見ていい一覧)
  • /etc/shadow = 金庫の中(root だけが開けられる)
  • /etc/group = クラブの名簿(誰がどの部活か)
対比表
ファイル何を持つパーミッション編集コマンド
/etc/passwdユーザー名・UID・ホーム・シェル644(全員読める)useradd / adduser
/etc/shadowパスワードハッシュ・有効期限600(root だけ)passwd / chage
/etc/groupグループ名・GID・所属ユーザー644(全員読める)groupadd / usermod -aG
sudo cat /etc/shadow | head -3
# root:$6$xxxxx$yyyyyy:19500:0:99999:7:::
# daemon:*:19500:0:99999:7:::

* または ! から始まるパスワードフィールド = パスワードログイン無効(鍵認証のみのアカウント)。

一番覚えやすい説明
  • passwd: 誰がいるか(公開情報)
  • shadow: その人の合言葉(極秘情報)
  • group: 誰がどのチームか(公開情報)

2. /etc/group の構造

ユーザーが分かったら次は グループ。「複数ユーザーをまとめて権限を付ける」仕組みで、Linux の権限モデル(rwx の真ん中の桁)の正体です。

  • 何のコマンドか: /etc/group はグループ名・GID・所属ユーザー一覧を : 区切りで持つテキストファイル
  • いつ使うか: 新メンバーを developers グループに入れる時、docker グループの危険性を判断する時、ファイルアクセスを「グループ単位」で開放する時
  • 解決する具体的な問題: 1人ずつ権限を付けて回る運用の崩壊を防ぐ。「グループに入れる」だけで全ファイルの権限が自動的に揃う
cat /etc/group | head -10
# root:x:0:
# daemon:x:1:
# sudo:x:27:alice,bob
# docker:x:998:alice

primary group vs supplementary group の違い

ざっくり言うと

ユーザーはプライマリ1個 + サプリメンタリ複数個のグループに所属できる。新規作成ファイルのデフォルトオーナーになるのが「プライマリ」、追加権限のために入るのが「サプリメンタリ」。

まず普通のパターン
id alice
# uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),998(docker)

                  primary           supplementary(複数OK)
alice というユーザー
  ├─ primary group:        alice (gid 1000)   ← 1個だけ
  └─ supplementary groups: sudo, docker, developers ...  ← 複数OK
「touch すると何が起きるか」で違いが見える
alice@host:~$ touch newfile.txt
alice@host:~$ ls -l newfile.txt
-rw-r--r-- 1 alice alice  0 May 21 10:00 newfile.txt

                  user  group primary group になる

新規ファイルのグループはプライマリで決まる。sudo グループや docker グループにはならない。

イメージ
  • primary: 「本籍地」。新しい家(ファイル)を建てるとここの住人になる
  • supplementary: 「バイトの掛け持ち」。それぞれの権限(sudo / docker / developers)だけ追加でもらえる
違い
primary groupsupplementary group
1個だけ何個でも
設定箇所/etc/passwd の4列目(GID)/etc/group の最終列
新規ファイル作成時このグループがオーナーに関係ない
追加コマンドusermod -g <group>置換usermod -aG <group>追加
一番覚えやすい説明
  • primary: あなたが「何者か」を決める ID
  • supplementary: あなたが「何の特権を持つか」を増やす

usermod -g-aG を間違えるな

usermod -g docker alice    # NG: alice の primary を docker に「置換」してしまう
usermod -aG docker alice   # OK: docker を「追加」(既存所属はそのまま)

-a を忘れると 既存の supplementary が全部消える。sudo グループから外れて何もできなくなる事故が定番。

docker グループは実質 root と同等

docker グループに入れる = docker run -v /:/host --privileged ...(docker = 軽量な仮想環境を起動するツール。詳しくは「インフラ」章。-v でホスト側ディレクトリをコンテナに繋ぐオプション)でホストのrootファイルシステムをコンテナにマウントできる = root権限と同等。

開発機なら割り切ってOKだが、**本番サーバーでは「docker操作したい人にも sudo + audit log を通させる」**運用が安全。「docker groupに入れちゃえばsudo要らなくて楽」は監査の穴になる。

3. useradd vs adduser、/etc/skel

ユーザーを作るコマンドは2系統あります。同じディストリで両方使えることが多いので、違いと使い分けが分からないと混乱します。

  • 何のコマンドか: useradd は低レベルの公式ツール(全フラグ手動指定)、adduser は Debian/Ubuntu の高レベルラッパー(対話的、/etc/skel 自動コピー)
  • いつ使うか: 新メンバー追加(手動なら adduser が楽)、Ansible / cloud-init で自動化する時(useradd で全フラグ明示)、/etc/skel で全社員共通の .bashrc を配る時
  • 解決する具体的な問題: 「ホームディレクトリ作り忘れ」「シェル指定し忘れ」のような典型ミスを adduser 側が吸収してくれる
# Ubuntu/Debian 系: adduser(対話的、便利)
sudo adduser alice
# Adding user `alice' ...
# Adding new group `alice' (1001) ...
# Adding new user `alice' (1001) with group `alice' ...
# Creating home directory `/home/alice' ...
# Copying files from `/etc/skel' ...
# New password: ...
 
# 低レベル: useradd(手動でフラグ指定)
sudo useradd -m -s /bin/bash -G sudo,docker bob
sudo passwd bob
 
# 確認
id alice
getent passwd alice
ls -la /home/alice

useradd vs adduser の違い

ざっくり言うと

両方ともユーザーを作るが、性格が真逆useradd は素の Linux 公式(不親切)、adduser は Debian/Ubuntu の親切ラッパー。

まず素の useradd で作るとこうなる
sudo useradd alice
# ...終了。何も聞かれない

なんとなく成功した気になるが:

ls /home/alice
# ls: cannot access '/home/alice': No such file or directory
 ホームがない!
 
getent passwd alice
# alice:x:1001:1001::/home/alice:/bin/sh
 シェルが /bin/sh(bashじゃない)
 
sudo su - alice
# パスワード設定されていないのでログインできない
useradd の問題発生フロー
useradd alice
   ↓
ホームディレクトリ作成されない(-m を忘れたから)
   ↓
シェルがデフォルト(/bin/sh)
   ↓
パスワード未設定で対話ログイン不可
   ↓
「alice ログインできない」と問い合わせ
解決策その1: useradd を「全フラグ明示」で使う
sudo useradd -m -s /bin/bash -G sudo,docker alice

                ホーム  シェル       追加グループ
sudo passwd alice    # パスワードも別途設定
解決策その2: adduser を使う(楽)
sudo adduser alice
# 対話的に:
#   ホーム作成 → /etc/skel コピー → パスワード設定 → 氏名・電話番号入力
# 全部やってくれる
対比表
useraddadduser
種類低レベル公式高レベルラッパー (Perl スクリプト)
ホームディレクトリ-m 必須自動作成
/etc/skel コピーしないする
パスワード設定別途 passwd対話で設定
シェルディストリのデフォルト/bin/bash
対話性非対話対話的
用途Ansible / cloud-init 等の自動化人間が手で作る時
ディストリどこでも動くDebian/Ubuntu のみ
イメージ
  • useradd = 「全部自分で指定する DIY」
  • adduser = 「店員さんが対話で全部聞いてくれる」
一番覚えやすい説明
  • 人間が手で作る → adduser
  • スクリプトで自動化 → useradd(全フラグ明示)

/etc/skel の役割

新規ユーザーのホームディレクトリ初期内容をここからコピーする。

ls -la /etc/skel/
# .bashrc
# .bash_logout
# .profile

使い所: 全社員の .bashrc に共通の alias を入れたい → /etc/skel/.bashrc を整備しておけば、新規ユーザー追加時に自動配布される。Ansible 等を使わない小規模運用で便利。

4. パスワードポリシー(passwd, chage, PAM)

パスワード認証を残す運用なら、パスワードの強度と寿命を制御する仕組みが必要です。Linux では passwd / chage / PAM の3点セットで管理します。

  • 何のコマンドか: passwd は変更、chage は有効期限など寿命管理、PAM は「強さ」のポリシーを /etc/security/pwquality.conf で宣言する
  • いつ使うか: 退職予定者のアカウントに失効日をセットする時、社内規定で「最低12文字+3種類」を強制する時、初回ログイン時にパスワード変更を強制する時
  • 解決する具体的な問題: 「password123」のような脆弱パスワードを物理的に設定不能にする。期限切れの放置アカウントを自動的に無効化する
# パスワード変更(本人 or root)
passwd                 # 自分のパスワードを変える
sudo passwd alice      # rootが alice のを変える
 
# パスワード有効期限設定(chage = change age)
sudo chage -l alice                              # 状況確認
sudo chage -M 90 alice                           # 90日で期限切れ
sudo chage -M 90 -m 7 -W 14 -I 30 alice          # 細かい設定
 
# 強制的にパスワード変更を促す
sudo chage -d 0 alice                            # 次回ログイン時に変更必須

chage の各オプション

  • -M 90: 最大有効日数(90日でパスワード失効)
  • -m 7: 最小変更可能日数(前回変更から7日経たないと変更不可、頻繁な変更で履歴を回避するのを防ぐ)
  • -W 14: 期限切れ警告日数(14日前から警告)
  • -I 30: 猶予期間(期限切れ後30日でアカウント無効化)
  • -E 2026-12-31: アカウント失効日

PAMで強いパスワードを強制する

Linux のパスワード検証は PAM(Pluggable Authentication Modules)が担う。pam_pwquality でポリシーを設定:

# /etc/security/pwquality.conf(一例)
minlen = 12              # 最低12文字
minclass = 3             # 大文字/小文字/数字/記号のうち3種類
maxrepeat = 3            # 同じ文字を3回まで
dictcheck = 1            # 辞書攻撃のような単語を弾く

これを入れると「password123」みたいなのは設定不能になる。

最近のNIST推奨はもっと別物

昔は「90日でパスワード変更必須」が常識だったが、NIST SP 800-63B(2017〜)では頻繁な強制変更は推奨されないようになった。理由:

  • 強制変更すると人間は「Password1」→「Password2」→「Password3」のような予測可能な変更をする
  • 結局セキュリティが下がる

現代の推奨:

  • 長いパスフレーズ(または鍵認証)
  • 漏洩が確認された時だけ強制変更
  • 多要素認証(MFA)

「90日ローテーション」は今でも企業の規程に残っているが、本質的なセキュリティ向上にはなっていないことを知っておく。


セッション②: sudoers と最小権限、監査(25-30分)

5. sudo vs su の本質的な違い

ざっくり言うと

両方とも「別のユーザーで何かやる」道具だが、設計思想が真逆

  • su = 「ユーザーごと切り替わる」(パスワードはターゲットユーザーのもの)
  • sudo = 「自分のままで、1コマンドだけ別ユーザー権限を借りる」(パスワードは自分のもの)

まず素朴な su のパターン

alice@host:~$ su -
Password: ___ rootのパスワードを入力
root@host:~# rootに「丸ごと」変身
root@host:~# apt update
root@host:~# vim /etc/nginx/nginx.conf
root@host:~# exit
alice@host:~$
alice のシェル
   ↓ su -
root のシェル(環境ごと全部 root)
   ↓ exit
alice に戻る

この方式の問題発生フロー

チーム5人で1台のサーバーを運用
   ↓
全員 root のパスワードを知っている必要がある
   ↓
退職者が出たら root のパスワードを変えないといけない
   ↓
変えるのを忘れる → 退職者がまだ入れる
   ↓
さらに /var/log/auth.log には全員「root」としか出ない
   ↓
誰が rm -rf したか分からない

sudo は「自分のパスワードで、1コマンドだけ昇格」

alice@host:~$ sudo apt update
[sudo] password for alice: ___    ← alice 自身のパスワード
(apt update root 権限で実行される)
alice@host:~$ すぐ alice に戻る
alice のシェル
  └─ sudo apt update      ← この1コマンドだけ root 権限
alice のシェル(継続)

イメージ:

  • su = 変身(30分間プリキュアになる)
  • sudo = 代行(この書類だけ部長にハンコ押してもらう)

監査ログでの差

/var/log/auth.log:

# su の場合
session opened for user root(uid=0) by alice
(以降のコマンドは「root が何かやった」としか残らない)

# sudo の場合
sudo: alice : TTY=pts/0 ; USER=root ; COMMAND=/usr/bin/apt update
sudo: alice : TTY=pts/0 ; USER=root ; COMMAND=/bin/systemctl restart nginx
(誰が何をやったか1行ずつ残る)

対比表

susudo
何を入力ターゲットのパスワード自分のパスワード
シェル切り替わる(root に変身)切り替わらない(コマンド単発)
監査ログ「root が何かした」「alice が root として X した」
パスワード共有必要不要
きめ細かい制御不可(全権限 or なし)可能(コマンド単位で許可)
退職者対応root パスワード変更必須sudoers から削除するだけ

一番覚えやすい説明

  • su = アカウントごと変身(パスワード共有・監査ログ崩壊・退職対応地獄)
  • sudo = 権限だけ借りる(最小権限・監査ログ追跡可能・退職対応簡単)
# 普通の sudo
sudo apt update
 
# 別ユーザーになって実行(変身ではなく権限借りる)
sudo -u www-data ls /var/www
 
# どうしても root シェルが欲しい時(極力避ける)
sudo -i           # フル環境
sudo su -         # 同上の別書き方
 
# 直前のコマンドに sudo を付け足す
sudo !!

sudo = substitute user do

(“super user do” は俗説、開発者本人は前者と説明)。

1980年代に開発開始、Todd C. Miller がメンテし続けて現在に至る Unix 系で最も普及している権限委譲ツール。

6. /etc/sudoers の構造と visudo

sudo の挙動を定義するのが /etc/sudoers ですが、このファイルは触り方を間違えるとサーバーから締め出される最も危険な設定ファイルの1つ。専用エディタの visudo で守られた手順で触ります。

  • 何のコマンドか: visudo は sudoers をロック + 構文チェック付きで編集するための専用コマンド
  • いつ使うか: チームに新しい sudo 権限を付与する時、CI/CD 用の NOPASSWD ルールを追加する時、本番の運用ルールを更新する時
  • 解決する具体的な問題: 「sudo 自体が動かなくなりサーバーを救出できない」事故を、構文チェックで未然に防ぐ
# 絶対に直接編集するな。必ず visudo を使う
sudo visudo
 
# ファイル分割: /etc/sudoers.d/ 配下に個別ファイルを置くのが現代流
sudo visudo -f /etc/sudoers.d/dev_team

visudo を必ず使う理由

/etc/sudoers の構文ミスがあると、sudo 自体が動かなくなる。rootパスワードが分からない / rootログイン無効 の状態でこれをやると、サーバーを救うのが超大変(シングルユーザーモード起動が必要)。

visudo は:

  1. 編集中はファイルをロック(同時編集防止)
  2. 保存時に構文チェックを実行 → エラーがあれば保存しない
  3. デフォルトエディタは EDITOR 環境変数(vimnano

絶対に sudo vi /etc/sudoers しないこと。

sudoers の文法

# 構文: ユーザー  ホスト=(実行ユーザー)  コマンド

# alice はどのホストでも、すべてのユーザーになって、すべてのコマンドが実行可能
alice  ALL=(ALL:ALL)  ALL

# sudo グループ全員に同じ権限
%sudo  ALL=(ALL:ALL)  ALL

# deploy ユーザーは systemctl restart nginx だけパスワード無しで実行可能
deploy  ALL=(root)  NOPASSWD: /bin/systemctl restart nginx

# 複数コマンド
deploy  ALL=(root)  NOPASSWD: /bin/systemctl restart nginx, /usr/bin/rsync

%groupname: グループ指定(先頭の %NOPASSWD:: パスワード入力スキップ(CI/CDで重要) !: 否定(このコマンドだけ禁止)

Defaults: 全体設定

Defaults  timestamp_timeout=15      # sudo のパスワードキャッシュ15分
Defaults  logfile=/var/log/sudo.log  # ログファイル指定
Defaults  requiretty                  # ttyからのみ許可(スクリプト経由禁止)

7. 最小権限の sudoers 設計

sudoers の文法が分かったら、次は設計です。「最小権限の原則(PoLP)」を sudoers ファイルにどう落とすかが、本番運用の品質を分けます。

  • 何のコマンドか: /etc/sudoers.d/ 配下に「役割ごとのファイル」を作り、%groupname 単位で「許可するコマンドだけ」を列挙する
  • いつ使うか: 開発者に本番への限定アクセスを与える時、デプロイユーザーに systemctl restart app だけ通す時、監視ユーザーに読み取り系コマンドだけを許可する時
  • 解決する具体的な問題: 「sudo 持ち = 何でもできる」状態を解体し、「この人はこの3コマンドだけ」と明文化することで、誤操作と侵入時被害の両方を最小化する
# /etc/sudoers.d/dev_team の例
sudo visudo -f /etc/sudoers.d/dev_team
# 開発者グループ: アプリケーションの再起動とログ確認のみ
%developers  ALL=(root) NOPASSWD: /bin/systemctl restart app, /bin/systemctl status app
%developers  ALL=(root) NOPASSWD: /usr/bin/tail -f /var/log/app/*.log
%developers  ALL=(root) NOPASSWD: /usr/bin/journalctl -u app

# 明示的に禁止しておく
%developers  ALL=(root) !/bin/su, !/usr/bin/passwd

最小権限の原則(PoLP)

ジョブをこなすのに必要な最小限の権限だけ与える

良い例:

  • デプロイユーザー: アプリの再起動と特定ディレクトリへの書き込みのみ
  • 監視ユーザー: 読み取り権限のみ(tail -f, df -h, top など)
  • DBバックアップ用ユーザー: pg_dump 実行と /var/backups 書き込みのみ

なぜ重要か:

  • 侵入されてもダメージが小さい: 監視ユーザーが乗っ取られても、アプリは止められない
  • ヒューマンエラーが減る: 全権限を持つと、操作ミスで本番が壊れる
  • 退職時の引継ぎが簡単: 「このユーザーが何できるか」が明確

アンチパターン: 全員 sudo ALL NOPASSWD

# NG: 楽だからとこう書く
%developers  ALL=(ALL:ALL) NOPASSWD: ALL

「sudo は全員ノーパス、全コマンド許可」。これは「全員 root を持っている」のと同じ

問題点:

  • 誤操作が即本番障害: rm -rf /var/log が一瞬で通る
  • 侵入時の被害最大化: 開発者の鍵が漏れたら、即root権限の侵入
  • 監査ログがあっても遅い: ログを見るのは事故が起きた後

正解: 最小権限。必要なコマンドだけNOPASSWD、それ以外はsudoでパスワード認証。

アンチパターン: 共有アカウントを作る

# NG: チーム全員が同じユーザー `deploy` でログイン

問題:

  • 誰がやったか分からない: ログには deploy としか出ない
  • 鍵管理がカオス: 誰の公開鍵が ~deploy/.ssh/authorized_keys にあるか分からなくなる
  • 退職対応が困難: 1人辞めるたびに全員のパスワード/鍵を変える必要

正解: 1人1アカウント。例えば全員に個別アカウントを発行し、それぞれに sudo -u deploy ... の権限を付ける。これで「誰が deploy として何を実行したか」が sudo.log に残る。

アンチパターン: 平文パスワードをファイルに置く

# NG: パスワードをスクリプトに直書き
mysql -uroot -p'P@ssw0rd123' -e "SELECT * FROM users"

問題:

  • ps aux で他ユーザーから見える: コマンドライン引数は全員に見える
  • bashの履歴(~/.bash_history)に残る
  • GitHub にプッシュした瞬間漏洩

正解:

  • 環境変数(.env.gitignore
  • シークレットマネージャー(AWS Secrets Manager、HashiCorp Vault)
  • .my.cnf のようなツール標準の設定ファイル(パーミッション600で)

8. root を完全に無効化する運用

sudo 運用が回り始めたら、最後の仕上げとして root アカウント自体を物理的に閉鎖します。これで「root に直接入る」という攻撃ベクトル全体が消えます。

  • 何のコマンドか: passwd -l でパスワードをロック、usermod -s /usr/sbin/nologin でシェルを無効化、両方で root の対話ログインを塞ぐ
  • いつ使うか: VPS の初期セットアップ最終段階、社内サーバーをセキュリティ強化する時、CIS Benchmark に準拠させる時
  • 解決する具体的な問題: 「root のパスワード推測攻撃」を、推測対象を消すことで根絶する。Ubuntu Server などはこの状態がデフォルト
# rootのパスワードを無効化(パスワードログイン不能に)
sudo passwd -l root
 
# rootのシェルを無効化(rootでログイン試行しても何もできない)
sudo usermod -s /usr/sbin/nologin root
 
# Ubuntu 系は最初からこれに近い設定(root のパスワードが未設定 → ロック状態)
sudo passwd -S root
# root L 01/01/2024 0 99999 7 -1   ← L = locked

「root を直接使わない」運用

多くのモダンなディストリ(Ubuntu Server 等)は初期状態でrootのパスワードが未設定で、最初のユーザーが sudo グループに入っている。これは意図的な設計。

メリット:

  • パスワード認証でrootに入る攻撃ベクトルが消える
  • 全操作が sudo 経由 = 監査ログが取れる
  • 「うっかりrootでログイン」が物理的に起きない

rootのシェルにどうしても入る必要がある場合:

sudo -i        # フル環境のrootシェル
sudo su -      # 別の書き方(同等)

どちらも sudo.log に記録される。

AWS のEC2や多くのVPSも、デフォルトでこの設計(rootログイン無効、ubuntuec2-user などの初期ユーザーが sudo 持ち)。

9. 監査ログを読む

sudoers を整え、root を閉じても、ログを誰も見ないなら侵入に気づけません。最小権限運用と監査ログ確認はセットです。

  • 何のコマンドか: /var/log/auth.log(Debian系)/ /var/log/secure(RHEL系)/ journalctl -u sshd で、ログイン・sudo 実行・認証失敗をすべて遡って読む
  • いつ使うか: 朝の業務開始時の流し見、インシデント発生時の犯人特定、退職者の最終ログイン日時の確認、不審な海外IPからのアクセスチェック
  • 解決する具体的な問題: 「侵入されたのに気づかない」最悪のシナリオを、ログ確認の習慣で防ぐ。事故が起きた時の「いつ・誰が・何を」も即特定できる
# sudoの実行履歴
sudo tail -100 /var/log/auth.log               # Debian/Ubuntu
sudo tail -100 /var/log/secure                 # RHEL/CentOS
sudo journalctl -u sudo                        # systemd 系で sudo の journal
 
# SSHログイン履歴
sudo journalctl -u ssh
sudo journalctl -u sshd
 
# 直近のログイン成功者
last | head -20
 
# 失敗ログイン(不正アクセス試行の検知)
sudo lastb | head -20
 
# 現在ログイン中のユーザー
who
w

監査ログを「見る習慣」が大事

監査ログは「事故が起きてから初めて見る」のではなく、定期的に流し見する習慣をつけると、異常に気づきやすい。

本番でチェックすべきパターン:

  • 業務時間外のログイン
  • 海外IPからのログイン試行
  • sudo の異常な使い方(大量の cat /etc/shadow など)
  • root ログイン試行(無効化していても試行ログは残る)

/var/log/auth.log の例:

May 14 10:00:01 prod sshd[1234]: Accepted publickey for deploy from 203.0.113.5 port 51234 ssh2
May 14 10:00:05 prod sudo: deploy : TTY=pts/0 ; PWD=/home/deploy ; USER=root ; COMMAND=/bin/systemctl restart app
May 14 10:05:30 prod sshd[1235]: Failed password for invalid user admin from 198.51.100.10 port 51235 ssh2

1行目: deployユーザーが公開鍵で正常ログイン 2行目: deployが systemctl restart app を実行(監査記録) 3行目: 不正な admin ログイン試行(攻撃)

10. 実例: 開発者ごとに個別アカウント発行

シナリオ: 新規エンジニア Bob に本番サーバーへのアクセスを与える。

# 1. ローカルでBobの公開鍵を受け取る(GitHubなどから)
curl https://github.com/bob.keys > /tmp/bob.pub
 
# 2. サーバーで個別アカウント作成
sudo adduser --disabled-password --gecos "Bob Tanaka" bob
sudo mkdir -p /home/bob/.ssh
sudo chmod 700 /home/bob/.ssh
sudo cp /tmp/bob.pub /home/bob/.ssh/authorized_keys
sudo chmod 600 /home/bob/.ssh/authorized_keys
sudo chown -R bob:bob /home/bob/.ssh
 
# 3. 必要なグループに追加
sudo usermod -aG developers bob
 
# 4. sudoers で最小権限付与
sudo visudo -f /etc/sudoers.d/bob
# 中身:
# bob ALL=(root) NOPASSWD: /bin/systemctl restart app
# bob ALL=(root) NOPASSWD: /usr/bin/journalctl -u app
 
# 5. ログインを試す(別端末で)
# ssh bob@example.com
# sudo systemctl restart app
 
# 6. 監査ログで確認
sudo grep "bob" /var/log/auth.log

退職時の対応

# 1. アカウントをロック(即時アクセス遮断)
sudo usermod -L bob
sudo usermod -s /usr/sbin/nologin bob
 
# 2. SSH 鍵を無効化
sudo mv /home/bob/.ssh/authorized_keys /home/bob/.ssh/authorized_keys.disabled
 
# 3. プロセスを終了
sudo pkill -KILL -u bob
 
# 4. 一定期間後に削除(監査ログ保全のため、即削除しない運用が多い)
sudo deluser --remove-home bob

練習課題

# 1. ローカル(Mac)では試しづらいので、UbuntuのDocker内で練習する
# (docker = 軽量な仮想環境を起動するツール。-it で対話シェル、--rm で終了時に自動削除、
#  ubuntu:24.04 が使うイメージ。Docker 自体は「インフラ」章で詳しくやる。
#  今は「捨てて良い Ubuntu 環境がワンコマンドで作れる便利な道具」とだけ理解すればOK)
# Docker がインストールされていないなら https://docs.docker.com/desktop/ から入手
docker run -it --rm ubuntu:24.04 bash
 
# コンテナ内で:
apt update && apt install -y sudo vim adduser
 
# 2. 新規ユーザー作成
adduser --disabled-password --gecos "" alice
adduser --disabled-password --gecos "" bob
 
# 3. /etc/passwd と /etc/shadow を観察
grep -E "^(alice|bob)" /etc/passwd
grep -E "^(alice|bob)" /etc/shadow
 
# 4. グループ作成と所属
addgroup developers
usermod -aG developers alice
id alice
 
# 5. sudoers 設計
cat > /etc/sudoers.d/developers <<'EOF'
%developers ALL=(root) NOPASSWD: /usr/bin/apt update
%developers ALL=(root) /usr/bin/apt install *
EOF
# 構文チェック
visudo -c
 
# 6. aliceでsudo実行
su - alice
sudo apt update            # NOPASSWD で通る
sudo apt install -y curl   # パスワード求められる
sudo rm /etc/passwd        # 拒否されることを確認

締め: git で証跡を残す

exit  # script から抜ける
 
cd ~/learn/linux/day14
git init
git add .
git commit -m "feat(linux): ユーザー管理・sudoers・最小権限の設計を整理"

チェックリスト

  • /etc/passwd の7フィールドを言える
  • /etc/shadow がなぜ別ファイルか説明できる
  • useraddadduser の使い分けを判断できる
  • id で自分の所属グループを確認できる
  • visudo を使わずに /etc/sudoers を直接編集することの危険性を説明できる
  • 最小権限の sudoers 設計を1つ書ける
  • root を完全無効化する手順を3行で書ける
  • /var/log/auth.log の sudo 実行記録を読める
  • 退職者対応の手順を即答できる

詰まった時のチートシート

やりたいことコマンド
新規ユーザー作成sudo adduser <name>
既存ユーザーにグループ追加sudo usermod -aG <group> <user>
所属確認id <user>
パスワード変更sudo passwd <user>
アカウント無効化sudo usermod -L <user>
ログインシェル無効化sudo usermod -s /usr/sbin/nologin <user>
sudoers編集sudo visudo または sudo visudo -f /etc/sudoers.d/myrules
sudoers構文チェックsudo visudo -c
sudo履歴sudo journalctl -u sudo or grep sudo /var/log/auth.log
直近ログインlast
失敗ログインsudo lastb
現在の接続中who, w
ユーザー削除sudo deluser --remove-home <user>
パスワード有効期限sudo chage -M 90 <user>

「実務OK」基準

  • /etc/passwd を見て、サービスアカウントと一般ユーザーを区別できる
  • visudo を使う癖がついている: 直接編集は絶対しない
  • 最小権限の sudoers を書ける: コマンド単位での権限委譲ができる
  • 共有アカウント禁止の理由を3つ即答できる: 監査・侵入時被害・退職対応
  • 退職者対応の手順を間違えない: ロック → 鍵削除 → プロセス停止 → 一定期間後削除
  • 監査ログ(auth.log, sudo.log)を流し見できる: 異常パターンを察知

さらに深掘るなら

  • man sudoers: 全文法と注意点が網羅されている。読み切れば事故率が激減
  • PAM: Linux認証システム全般を支える土台。/etc/pam.d/ の中を覗いてみる
  • 書籍: 『UNIXシステム管理 改訂版』(O’Reilly) - 古いが基本概念は今でも有効
  • 公式: https://www.sudo.ws/ (sudoの本家、開発者ブログでセキュリティ動向)
  • CIS Benchmarks: Linux ディストリのセキュリティハードニングガイド(業界デファクト)
  • NIST SP 800-53 / 800-63B: アクセス制御・認証の国際標準

アンチパターン / 初心者やらかし事例

NG 1: vim /etc/sudoers で直接編集 → 構文エラー → sudo 使えなくなる

sudo vim /etc/sudoers   # 1行ミス → 全員 sudo 失効

→ 対策: 必ず sudo visudo を使う。構文チェックが入って、エラーがあれば保存させてくれない。

NG 2: usermod -G dev user-a 忘れ)で既存グループから外す

sudo usermod -G dev alice   # alice の既存グループが消える!sudo グループも消えて事故

→ 対策: 追加は必ず -aG(append + G)。sudo usermod -aG dev alice

NG 3: chmod 777 で「全員 root 並みの権限」を量産

→ Day 3 でも触れたが、ユーザー管理章でも再強調。本来は 適切なユーザー / グループを作って所有権で解決

NG 4: 退職者のアカウントを rm -rf /home/user だけで済ませる

→ プロセスがまだ動いている / cron が残っている / ssh セッションが残っているケースあり。 → 対策: usermod -L でロック → SSH 鍵を authorized_keys から削除 → 関連プロセス kill → 一定期間後に削除(バックアップ取った上で)。


自己評価チェックリスト

  • /etc/passwd の7フィールドを書ける
  • visudo を反射で打てる(sudoers 直接編集しない)
  • 「コマンド単位の sudo 許可」のルールが書ける
  • usermod -aG <group> <user>-a の意味を答えられる
  • 退職者対応の4ステップ(ロック→鍵削除→プロセス停止→削除)を即答できる

次のレッスン: Day 17 - Nginx

明日は Nginx ─ Linux 上で動くアプリを「Web に公開する」ための定番ソフトウェア。

リバースプロキシ・ロードバランサ・静的配信・proxy_pass・ヘッダ転送・gzip・ログ・セキュリティ設定まで。今日学んだ「専用ユーザー」「最小権限」がそのまま Nginx の運用設計に活きる。

Day 17: Nginx