概要・前提
Linux の棚卸作業は主に /etc/passwd・/etc/shadow・/etc/group・/etc/sudoers の4ファイルと、lastlog・last コマンドを組み合わせて行います。操作には root 権限(または sudo 実行権限)が必要です。
動作確認環境
- RHEL / CentOS / Rocky Linux 7 〜 9
- Ubuntu 20.04 / 22.04 / 24.04
- Amazon Linux 2 / 2023
ユーザー一覧の取得
/etc/passwd にすべてのローカルユーザーが記録されています。フィールドは ユーザー名:パスワード:UID:GID:コメント:ホームディレクトリ:シェル の順です。
全ユーザー一覧(整形表示)
# UID / GID / ホームディレクトリ / シェルを整形して表示
awk -F: '{printf "%-20s UID=%-6s GID=%-6s HOME=%-25s SHELL=%s\n", $1,$3,$4,$6,$7}' /etc/passwd
ログインシェルを持つ(人間)ユーザーのみ抽出
# /sbin/nologin・/bin/false を除いた実ユーザー
grep -v -E ':/sbin/nologin$|:/bin/false$|:/usr/sbin/nologin$' /etc/passwd | awk -F: '{print $1, $3, $7}'
UID 1000 以上のユーザーのみ(一般ユーザー)
awk -F: '$3 >= 1000 {print $1, $3, $6, $7}' /etc/passwd
グループ別ユーザー一覧
# /etc/group の内容を表示(グループ名:GID:メンバーリスト)
awk -F: '{printf "GROUP=%-20s GID=%-6s MEMBERS=%s\n", $1,$3,$4}' /etc/group
ロック状態の確認
/etc/shadow のパスワードフィールドが !! または ! で始まるアカウントはロック状態です。passwd -S コマンドでも確認できます。
passwd コマンドで一覧確認
# 全ユーザーのステータスを確認(root 権限必要)
for user in $(awk -F: '{print $1}' /etc/passwd); do
passwd -S "$user" 2>/dev/null
done
出力の第2フィールドの意味は以下のとおりです。
| 表示 | 意味 |
|---|---|
| PS | Password Set(有効) |
| LK | Locked(ロック済み) |
| NP | No Password(パスワードなし) |
shadow ファイルを直接確認(ロック状態のみ抽出)
# !! または ! で始まるエントリ=ロックユーザー
sudo awk -F: '$2 ~ /^!/ {print "LOCKED:", $1}' /etc/shadow
usermod でロック/アンロック
# ロック
sudo usermod -L username
# アンロック
sudo usermod -U username
最終ログイン日時
lastlog コマンドは /var/log/lastlog を読み取り、各ユーザーの最終ログイン日時を返します。
全ユーザーの最終ログイン
lastlog
一度もログインしていないユーザーを除外
lastlog | grep -v 'Never logged in' | grep -v 'Username'
特定ユーザーの最終ログイン
lastlog -u username
直近のログイン履歴(last コマンド)
# 直近 50 件
last -n 50
# 特定ユーザー
last username
# 失敗ログイン(lastb は root 権限が必要)
sudo lastb -n 30
特権の確認
Linux の特権ユーザーは UID=0 の root が基本です。UID=0 を持つアカウントが複数存在しないか確認します。
UID=0 のアカウントを確認
awk -F: '$3 == 0 {print "UID=0:", $1}' /etc/passwd
root グループ(GID=0)のメンバー確認
grep '^root:' /etc/group
wheel グループ(管理者グループ)のメンバー確認
grep '^wheel:' /etc/group
su コマンドの実行権限確認
# /etc/pam.d/su で wheel グループ制限を確認
grep -E 'wheel|pam_wheel' /etc/pam.d/su
sudo 権限
/etc/sudoers および /etc/sudoers.d/ 配下のファイルに sudo 権限の定義があります。必ず visudo または cat で確認し、直接編集しないこと。
sudoers の内容を確認
# visudo -c で構文チェックも兼ねる
sudo visudo -c
# 内容を表示(root 権限必要)
sudo cat /etc/sudoers
sudoers.d ディレクトリ配下を一括確認
sudo ls -la /etc/sudoers.d/
sudo grep -r '' /etc/sudoers.d/
NOPASSWD 設定(パスワードなし sudo)を抽出
sudo grep -r 'NOPASSWD' /etc/sudoers /etc/sudoers.d/ 2>/dev/null
特定ユーザーの sudo 権限確認
# そのユーザー自身が実行(-l: list)
sudo -l -U username
パスワード期限
chage コマンドで各ユーザーのパスワードポリシーを確認します。/etc/shadow の第4〜8フィールドに対応しています。
特定ユーザーのパスワード期限情報
sudo chage -l username
全ユーザーのパスワード期限を一覧表示
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
echo "=== $user ==="
sudo chage -l "$user" 2>/dev/null
done
パスワード無期限(Max days = -1)ユーザーを抽出
sudo awk -F: '$5 == 99999 || $5 == -1 {print "NO EXPIRY:", $1}' /etc/shadow
パスワードポリシーのデフォルト値確認
grep -E '^PASS_MAX_DAYS|^PASS_MIN_DAYS|^PASS_WARN_AGE' /etc/login.defs
一定期間未使用ユーザー
90日以上ログインのないユーザーを抽出する例です。lastlog の出力を日数で絞り込みます。
lastlog で 90 日以上未ログインを抽出
lastlog -b 90 | grep -v 'Never logged in' | grep -v 'Username'
一度もログインしたことがないユーザー
lastlog | grep 'Never logged in'
shadow の最終パスワード変更日から未使用を判定
# 第3フィールド:最終パスワード変更日(1970/01/01 からの日数)
# 現在の日数との差分を計算
TODAY=$(( $(date +%s) / 86400 ))
sudo awk -F: -v today="$TODAY" '
$3 != "" && $3 != "0" {
diff = today - $3
if (diff > 90) printf "USER=%-20s LAST_PW_CHANGE=%s days ago\n", $1, diff
}
' /etc/shadow
ホームディレクトリの最終アクセス日で判定
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
homedir=$(getent passwd "$user" | cut -d: -f6)
if [ -d "$homedir" ]; then
atime=$(stat -c %X "$homedir")
now=$(date +%s)
days=$(( (now - atime) / 86400 ))
if [ "$days" -gt 90 ]; then
echo "UNUSED($days days): $user"
fi
fi
done
無効化されたユーザー
Linux でのユーザー無効化は主に ①パスワードロック ②ログインシェルを /sbin/nologin に変更 ③アカウント有効期限の設定 の3方式があります。
方式1:パスワードロック済みユーザー
sudo awk -F: '$2 ~ /^!/ {print "LOCKED:", $1}' /etc/shadow
方式2:nologin シェルのユーザー(サービスアカウント含む)
awk -F: '$7 ~ /nologin|false/ {print "NOLOGIN:", $1, $7}' /etc/passwd
方式3:アカウント有効期限切れのユーザー
# shadow 第8フィールド:アカウント有効期限(日数、空=無制限)
TODAY=$(( $(date +%s) / 86400 ))
sudo awk -F: -v today="$TODAY" '
$8 != "" && $8 != "0" && $8+0 < today {
print "EXPIRED:", $1, "(expired on day " $8 ")"
}
' /etc/shadow
usermod でアカウント有効期限を設定・確認
# 有効期限を設定(例: 2025-12-31)
sudo usermod -e 2025-12-31 username
# 有効期限を削除(無制限)
sudo usermod -e "" username
# 設定確認
sudo chage -l username | grep 'Account expires'