パーミッションと所有者
Unixの「全てはファイル」哲学において、パーミッション管理はセキュリティの要。
115 分で読めます57,352 文字
パーミッションと所有者
Unixの「全てはファイル」哲学において、パーミッション管理はセキュリティの要。 適切なパーミッション設定は、不正アクセス防止・データ保護・システム安定性の基盤となる。
この章で学ぶこと
- ファイルパーミッションの読み方・変更方法をマスターする
- 所有者とグループの管理ができる
- 特殊パーミッション(SUID/SGID/Sticky Bit)を理解する
- ACL(Access Control List)で細かなアクセス制御ができる
- umaskの仕組みと適切な設定方法を理解する
- セキュリティベストプラクティスを実践できる
- パーミッション関連のトラブルシューティングができる
前提知識
このガイドを読む前に、以下の知識があると理解が深まります:
- 基本的なプログラミングの知識
- 関連する基礎概念の理解
- ファイルの作成・コピー・移動・削除 の内容を理解していること
1. パーミッションの基本
1.1 パーミッションの読み方
# パーミッションの表示
$ ls -la
-rwxr-xr-- 1 user group 4096 Jan 1 file.txt
│├─┤├─┤├─┤ │ │
│ │ │ │ │ └── グループ
│ │ │ │ └── 所有者
│ │ │ └── other: 読み取りのみ (r--)
│ │ └── group: 読取+実行 (r-x)
│ └── owner: 全権限 (rwx)
└── タイプ: - file, d dir, l link
# ファイルタイプ一覧
# - : 通常ファイル
# d : ディレクトリ
# l : シンボリックリンク
# c : キャラクタデバイス(/dev/tty等)
# b : ブロックデバイス(/dev/sda等)
# p : 名前付きパイプ(FIFO)
# s : ソケット
# 各パーミッションの意味
# ファイルの場合:
# r (read) : ファイルの内容を読み取れる(cat, less等)
# w (write) : ファイルの内容を変更できる(vi, echo >>等)
# x (execute) : ファイルを実行できる(./script.sh)
#
# ディレクトリの場合:
# r (read) : ディレクトリ内のファイル一覧を見れる(ls)
# w (write) : ディレクトリ内にファイルを作成・削除できる
# x (execute) : ディレクトリに入れる(cd)、中のファイルにアクセスできる1.2 パーミッションとディレクトリの関係
# ディレクトリのパーミッション実験
# ケース1: x がないディレクトリ
$ mkdir /tmp/test_dir
$ chmod 644 /tmp/test_dir # rw-r--r-- (xなし)
$ ls /tmp/test_dir # エラー: Permission denied
$ cd /tmp/test_dir # エラー: Permission denied
# ケース2: r がないディレクトリ
$ chmod 311 /tmp/test_dir # --x--x--x (rなし)
$ cd /tmp/test_dir # OK: 入れる
$ ls /tmp/test_dir # エラー: 一覧表示できない
$ cat /tmp/test_dir/known.txt # OK: ファイル名を知っていればアクセス可能
# ケース3: w + x の組み合わせ
$ chmod 733 /tmp/test_dir # rwx-wx-wx
$ touch /tmp/test_dir/new.txt # OK: ファイル作成可能
$ rm /tmp/test_dir/old.txt # OK: ファイル削除可能
$ ls /tmp/test_dir # エラー: 一覧表示はできない
# ケース4: w があっても x がなければ書き込み不可
$ chmod 622 /tmp/test_dir # rw--w--w- (xなし)
$ touch /tmp/test_dir/new.txt # エラー: x がないのでアクセス不可1.3 数値(8進数)表現
# 各ビットの値
# r = 4 (100 in binary)
# w = 2 (010 in binary)
# x = 1 (001 in binary)
# 計算方法: 各カテゴリのビットを足す
# rwx = 4+2+1 = 7
# rw- = 4+2+0 = 6
# r-x = 4+0+1 = 5
# r-- = 4+0+0 = 4
# -wx = 0+2+1 = 3
# -w- = 0+2+0 = 2
# --x = 0+0+1 = 1
# --- = 0+0+0 = 0
# よく使うパーミッション
chmod 777 file # rwxrwxrwx — 全員にフルアクセス(非推奨)
chmod 755 file # rwxr-xr-x — 実行ファイル/ディレクトリの標準
chmod 750 file # rwxr-x--- — グループまで実行可能
chmod 700 file # rwx------ — 所有者のみフルアクセス
chmod 644 file # rw-r--r-- — 通常ファイルの標準
chmod 640 file # rw-r----- — グループまで読み取り可能
chmod 600 file # rw------- — 秘密ファイル(SSH鍵等)
chmod 555 file # r-xr-xr-x — 読取+実行のみ(編集不可)
chmod 444 file # r--r--r-- — 読み取り専用
chmod 400 file # r-------- — 所有者のみ読み取り
# ディレクトリによく使うパーミッション
chmod 755 dir/ # rwxr-xr-x — 公開ディレクトリ
chmod 750 dir/ # rwxr-x--- — グループ限定ディレクトリ
chmod 700 dir/ # rwx------ — 個人ディレクトリ
chmod 1777 dir/ # rwxrwxrwt — 共有ディレクトリ(/tmp等)
chmod 2755 dir/ # rwxr-sr-x — SGIDディレクトリ
# 4桁表記(特殊ビット含む)
# 1つ目の数字: 特殊ビット
# 4 = SUID
# 2 = SGID
# 1 = Sticky Bit
chmod 4755 file # SUID + rwxr-xr-x
chmod 2755 dir/ # SGID + rwxr-xr-x
chmod 1777 dir/ # Sticky + rwxrwxrwx
chmod 6755 file # SUID + SGID + rwxr-xr-x1.4 シンボリック表現
# 対象の指定
# u = user (所有者)
# g = group (グループ)
# o = others (その他)
# a = all (全員、ugo と同じ)
# 操作の指定
# + = 権限を追加
# - = 権限を削除
# = = 権限を設定(指定した権限のみにする)
# 基本的な使い方
chmod u+x file.txt # 所有者に実行権追加
chmod g-w file.txt # グループから書込権削除
chmod o=r file.txt # その他に読取のみ設定
chmod a+r file.txt # 全員に読取権追加
chmod ug+rw file.txt # 所有者とグループに読み書き追加
chmod u=rwx,g=rx,o=r file # 明示的に全て設定(= 754)
# 複数の操作を同時に
chmod u+x,g-w,o-rwx file # 所有者に+x、グループから-w、その他から全削除
chmod a=r,u+w file # 全員にr、所有者に+w(= 644)
# 参照コピー
chmod --reference=ref.txt target.txt # ref.txt と同じパーミッションに設定
# 再帰的に変更
chmod -R 755 dir/ # ディレクトリ内を全て再帰的に変更
# ディレクトリとファイルを区別して再帰的に設定
# ディレクトリ: 755, ファイル: 644 にしたい場合
find /path -type d -exec chmod 755 {} \;
find /path -type f -exec chmod 644 {} \;
# 大文字 X: ディレクトリまたは既に実行権があるファイルにのみ x を設定
chmod -R u=rwX,g=rX,o=rX dir/
# → ディレクトリには x が付く
# → ファイルには x が付かない(元々 x があるファイルを除く)
# verbose モード: 変更内容を表示
chmod -v 644 *.txt
# mode of 'file1.txt' changed from 0755 (rwxr-xr-x) to 0644 (rw-r--r--)
# mode of 'file2.txt' retained as 0644 (rw-r--r--)
# changes モード: 実際に変更があった場合のみ表示
chmod -c 644 *.txt
# mode of 'file1.txt' changed from 0755 (rwxr-xr-x) to 0644 (rw-r--r--)1.5 stat コマンドによる詳細表示
# stat でパーミッションの詳細を確認
$ stat file.txt
File: file.txt
Size: 4096 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 1234567 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ user) Gid: ( 1000/ group)
Access: 2026-01-15 10:30:00.000000000 +0900
Modify: 2026-01-14 09:20:00.000000000 +0900
Change: 2026-01-14 09:20:00.000000000 +0900
Birth: 2026-01-10 08:00:00.000000000 +0900
# macOS の stat(BSD版)
$ stat -f "%Sp %Su %Sg %z %N" file.txt
# -rw-r--r-- user group 4096 file.txt
# Linux の stat(GNU版)でフォーマット指定
$ stat -c "%A %U %G %s %n" file.txt
# -rw-r--r-- user group 4096 file.txt
# 数値表現で表示(Linux)
$ stat -c "%a %n" file.txt
# 644 file.txt
# macOS での数値表現
$ stat -f "%OLp %N" file.txt
# 644 file.txt
# アクセス時刻の確認
$ stat -c "Access: %x\nModify: %y\nChange: %z" file.txt
# Access: 2026-01-15 10:30:00
# Modify: 2026-01-14 09:20:00
# Change: 2026-01-14 09:20:00
# 複数ファイルのパーミッション一括確認
$ stat -c "%a %A %U:%G %n" /etc/passwd /etc/shadow /etc/group
# 644 -rw-r--r-- root:root /etc/passwd
# 640 -rw-r----- root:shadow /etc/shadow
# 644 -rw-r--r-- root:root /etc/group2. 所有者とグループ
2.1 chown — 所有者の変更
# 基本構文: chown [OPTION] [OWNER][:[GROUP]] FILE
# 所有者変更(要root)
sudo chown user file.txt # 所有者をuserに変更
sudo chown user:group file.txt # 所有者+グループを同時に変更
sudo chown :group file.txt # グループのみ変更(chgrpと同等)
sudo chown user: file.txt # 所有者変更 + グループを所有者のデフォルトグループに
# 再帰的に変更
sudo chown -R user:group dir/ # ディレクトリ内を全て変更
sudo chown -R --preserve-root user:group / # / への再帰変更を防止
# verbose/changes モード
sudo chown -v user:group file.txt # 変更内容を全て表示
sudo chown -c user:group file.txt # 実際に変更があった場合のみ表示
# 参照コピー
sudo chown --reference=ref.txt target.txt # ref.txt と同じ所有者に設定
# シンボリックリンクの扱い
sudo chown user symlink # リンク先のファイルを変更
sudo chown -h user symlink # シンボリックリンク自体を変更
# from オプション: 現在の所有者が一致する場合のみ変更
sudo chown --from=olduser newuser file.txt
sudo chown --from=:oldgroup user:newgroup file.txt
# 実践例: Webサーバーのドキュメントルート
sudo chown -R www-data:www-data /var/www/html/
sudo chown -R nginx:nginx /usr/share/nginx/html/
# 実践例: ホームディレクトリの修復
sudo chown -R $USER:$(id -gn $USER) ~/
# 実践例: 特定ユーザーのファイルだけ変更
sudo find /shared -user olduser -exec chown newuser {} \;2.2 chgrp — グループの変更
# 基本構文: chgrp [OPTION] GROUP FILE
# グループ変更
sudo chgrp developers project/ # グループをdevelopersに変更
sudo chgrp -R developers project/ # 再帰的にグループ変更
# verbose モード
sudo chgrp -vc developers *.py # 変更があったファイルのみ表示
# 参照コピー
sudo chgrp --reference=ref.txt target.txt
# 自分が所属するグループへの変更はsudo不要
# (自分がそのグループのメンバーの場合)
chgrp mygroup file.txt
# 実践例: 共有プロジェクトディレクトリ
sudo chgrp -R devteam /opt/project/
sudo chmod -R g+rw /opt/project/
sudo chmod g+s /opt/project/ # 新規ファイルにもグループを継承2.3 ユーザーとグループの管理
# 現在のユーザー情報
whoami # 現在のユーザー名
id # UID, GID, 全グループ一覧
id -u # UID のみ
id -g # プライマリGID のみ
id -G # 全GID一覧
id -Gn # 全グループ名一覧
id username # 特定ユーザーの情報
# グループ一覧
groups # 自分のグループ一覧
groups username # 特定ユーザーのグループ一覧
getent group # システム全体のグループ一覧
getent group groupname # 特定グループのメンバー確認
# ユーザー追加
sudo useradd -m -s /bin/bash newuser # ホーム作成 + シェル指定
sudo useradd -m -G sudo,docker newuser # 追加グループ指定
sudo adduser newuser # 対話形式(Debian系)
# グループの作成・管理
sudo groupadd developers # グループ作成
sudo groupadd -g 1500 custom # GID指定で作成
sudo groupdel oldgroup # グループ削除
# ユーザーをグループに追加
sudo usermod -aG docker $USER # dockerグループに追加
sudo usermod -aG sudo,adm,www-data user # 複数グループに追加
# 注意: -a を忘れると既存グループから外れる!
# sudo usermod -G docker user ← 危険!docker以外から全て外れる
# グループの変更を反映
newgrp docker # 新しいグループでシェル開始
# または一度ログアウトして再ログイン
# ユーザーのプライマリグループ変更
sudo usermod -g newgroup user
# グループからユーザーを削除
sudo gpasswd -d user groupname
# /etc/passwd の確認
getent passwd username
# username:x:1000:1000:Full Name:/home/username:/bin/bash
# ユーザー名:パスワード(x=shadow):UID:GID:コメント:ホーム:シェル
# /etc/group の確認
getent group groupname
# groupname:x:1000:user1,user2
# グループ名:パスワード:GID:メンバー一覧
# /etc/shadow(パスワード情報、要root)
sudo getent shadow username2.4 UID と GID の理解
# UID/GIDの範囲(一般的なLinuxディストリビューション)
# 0 : root
# 1-999 : システムユーザー/グループ(デーモン等)
# 1000+ : 一般ユーザー/グループ
# 65534 : nobody/nogroup(権限なしユーザー)
# 重要なシステムユーザー
id root # uid=0(root) gid=0(root)
id nobody # uid=65534(nobody) gid=65534(nogroup)
id www-data # uid=33(www-data) gid=33(www-data) (Debian系)
# Docker でのUID/GIDマッピング
# コンテナ内のUID = ホストのUID
# コンテナ内でroot(0)で実行 → ホストでもroot権限
# セキュリティのため非rootユーザーでの実行を推奨
docker run --user 1000:1000 myimage
# ファイルのUID/GIDを数値で確認
ls -ln file.txt
# -rw-r--r-- 1 1000 1000 4096 Jan 1 file.txt
# 存在しないUID/GIDのファイル
# ユーザー削除後やNFSマウント時に発生
$ ls -la orphaned.txt
-rw-r--r-- 1 5001 5001 100 Jan 1 orphaned.txt
# 数値表示 = そのUID/GIDに対応するユーザー/グループが存在しない
# 孤児ファイルの検索
find / -nouser -o -nogroup 2>/dev/null3. umask — デフォルトパーミッション
3.1 umaskの仕組み
# umask は新規ファイル/ディレクトリのパーミッションを制御する「マスク」
# 「この権限は付与しない」というビットを指定
# 基本計算:
# ファイルの最大パーミッション : 666 (実行権なし)
# ディレクトリの最大パーミッション: 777
# umask = 022 の場合:
# ファイル : 666 - 022 = 644 (rw-r--r--)
# ディレクトリ: 777 - 022 = 755 (rwxr-xr-x)
# umask = 002 の場合:
# ファイル : 666 - 002 = 664 (rw-rw-r--)
# ディレクトリ: 777 - 002 = 775 (rwxrwxr-x)
# umask = 077 の場合:
# ファイル : 666 - 077 = 600 (rw-------)
# ディレクトリ: 777 - 077 = 700 (rwx------)
# 現在のumask確認
umask # 数値表示(例: 0022)
umask -S # シンボリック表示(例: u=rwx,g=rx,o=rx)
# umask の一時変更(現在のシェルのみ)
umask 077 # セキュアな設定
touch secret.txt # → 600 (rw-------)
mkdir private/ # → 700 (rwx------)
# umask の恒久設定
# ~/.bashrc または ~/.zshrc に追加
echo "umask 022" >> ~/.bashrc3.2 umask の正確な計算方法
# 実は「引き算」ではなく「ビット演算」
# result = max_perm AND (NOT umask)
#
# 例: umask=033 の場合
# ファイル: 666 AND (NOT 033)
# 666 = 110 110 110
# 033 = 000 011 011
# NOT = 111 100 100
# AND = 110 100 100 = 644
#
# 引き算だと 666 - 033 = 633 になるが、実際は 644
# → ビット演算なので「引きすぎ」は起きない
# 検証
$ umask 033
$ touch test_umask.txt
$ stat -c "%a" test_umask.txt
644 # 633 ではなく 644
# よく使われるumask値
# 022 : デフォルト(一般的なLinux)
# 002 : グループ共有向き(Red Hat系のデフォルト)
# 027 : セキュア(otherに何も許可しない)
# 077 : 最もセキュア(所有者のみ)
# 000 : 最も緩い(テスト用)
# プロセスごとのumask
# umask はプロセスの属性であり、子プロセスに継承される
bash -c 'umask; umask 077; umask'
# 0022 ← 親のumask
# 0077 ← 変更後のumask(このサブシェル内のみ)
umask # 親シェルでは変更されていない
# 00223.3 umask のユースケース別設定
# 個人作業用(デフォルト)
umask 022
# ファイル: 644, ディレクトリ: 755
# チーム開発用
umask 002
# ファイル: 664, ディレクトリ: 775
# グループメンバーがファイルを編集できる
# セキュアサーバー用
umask 077
# ファイル: 600, ディレクトリ: 700
# 所有者以外は一切アクセス不可
# 条件付きumask設定(~/.bashrc)
# SSH接続時はセキュアに
if [ -n "$SSH_CLIENT" ]; then
umask 077
else
umask 022
fi
# ディレクトリ別umask(direnvとの組み合わせ)
# /shared/project/.envrc
# umask 002
# systemd サービスでのumask設定
# /etc/systemd/system/myapp.service
# [Service]
# UMask=00274. 特殊パーミッション
4.1 SUID(Set User ID)
# SUID: 実行時にファイル所有者の権限で実行される
# 数値: 4000
# シンボリック: u+s
# 表示: -rwsr-xr-x(所有者のxがsに変わる)
# SUID の設定
chmod u+s executable
chmod 4755 executable
# SUID が大文字Sの場合: 実行権がない + SUID設定
# -rwSr-xr-x → 所有者にxがなくSUIDが設定されている(意味がない設定)
# 代表的なSUID付きコマンド
$ ls -la /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 May 28 2020 /usr/bin/passwd
# → 一般ユーザーが実行してもroot権限で/etc/shadowを更新
$ ls -la /usr/bin/sudo
-rwsr-xr-x 1 root root 166056 Jan 19 2021 /usr/bin/sudo
# → root権限でコマンドを実行
$ ls -la /usr/bin/ping
-rwsr-xr-x 1 root root 64424 Jun 28 2019 /usr/bin/ping
# → rawソケットを使用するためroot権限が必要
# SUID付きファイルの検索(セキュリティ監査)
find / -perm -4000 -type f 2>/dev/null
find / -perm -4000 -type f -exec ls -la {} \; 2>/dev/null
# SUID のセキュリティリスク
# - 不適切なSUID設定は権限昇格の脆弱性につながる
# - カスタムスクリプトにはSUIDを設定しない
# - 定期的にSUID付きファイルを監査する
# - シェルスクリプトのSUIDは多くのOSで無視される
# SUID付きファイルの一覧を保存(ベースライン作成)
find / -perm -4000 -type f 2>/dev/null | sort > /tmp/suid_baseline.txt
# 定期的に比較
find / -perm -4000 -type f 2>/dev/null | sort | diff /tmp/suid_baseline.txt -4.2 SGID(Set Group ID)
# SGID on ファイル: 実行時にファイルグループの権限で実行される
# SGID on ディレクトリ: 新規作成ファイルに親ディレクトリのグループが継承される
# 数値: 2000
# シンボリック: g+s
# 表示: -rwxr-sr-x(グループのxがsに変わる)
# ファイルへのSGID設定
chmod g+s executable
chmod 2755 executable
# ディレクトリへのSGID設定(最も実用的な使い方)
chmod g+s /shared/project/
chmod 2775 /shared/project/
# SGIDディレクトリの動作確認
$ mkdir /tmp/sgid_test
$ sudo chown :developers /tmp/sgid_test
$ chmod 2775 /tmp/sgid_test
$ ls -la /tmp/ | grep sgid_test
drwxrwsr-x 2 user developers 4096 Jan 1 sgid_test
# ^ s が付いている
$ touch /tmp/sgid_test/newfile.txt
$ ls -la /tmp/sgid_test/newfile.txt
-rw-r--r-- 1 user developers 0 Jan 1 newfile.txt
# ^ 親ディレクトリのグループ(developers)が継承された
# SGID なしの場合
$ mkdir /tmp/nosgid_test
$ sudo chown :developers /tmp/nosgid_test
$ chmod 775 /tmp/nosgid_test
$ touch /tmp/nosgid_test/newfile.txt
$ ls -la /tmp/nosgid_test/newfile.txt
-rw-r--r-- 1 user user 0 Jan 1 newfile.txt
# ^ ユーザーのプライマリグループになる
# チーム共有ディレクトリの正しい設定
sudo mkdir -p /opt/shared/project
sudo groupadd devteam
sudo chown root:devteam /opt/shared/project
sudo chmod 2775 /opt/shared/project
# → メンバーが作成したファイルは全てdevteamグループになる
# SGID付きファイルの検索
find / -perm -2000 -type f 2>/dev/null
find / -perm -2000 -type d 2>/dev/null # ディレクトリも4.3 Sticky Bit
# Sticky Bit: ディレクトリ内のファイル削除を所有者とrootのみに制限
# 数値: 1000
# シンボリック: +t
# 表示: drwxrwxrwt(otherのxがtに変わる)
# Sticky Bitの設定
chmod +t /shared/
chmod 1777 /shared/
# /tmp が代表的な Sticky Bit ディレクトリ
$ ls -ld /tmp
drwxrwxrwt 20 root root 4096 Jan 1 /tmp
# ^ t が付いている
# Sticky Bitの動作確認
# ユーザーAがファイルを作成
$ touch /tmp/userA_file.txt
# ユーザーBが削除を試みる
$ sudo -u userB rm /tmp/userA_file.txt
rm: cannot remove '/tmp/userA_file.txt': Operation not permitted
# → Sticky Bitにより、所有者以外は削除できない
# ただし所有者とrootは削除可能
$ rm /tmp/userA_file.txt # OK (所有者)
$ sudo rm /tmp/userA_file.txt # OK (root)
# Sticky Bit + SGID の組み合わせ(チーム共有)
sudo mkdir /shared/team
sudo chown root:devteam /shared/team
sudo chmod 3775 /shared/team
# → 3 = SGID(2) + Sticky(1)
# → グループは継承されるが、他人のファイルは削除できない
# 大文字T: 実行権がない + Sticky Bit設定
# drwxrwxrwT → otherにxがなくSticky設定(意味がない設定)
# Sticky Bit付きディレクトリの検索
find / -perm -1000 -type d 2>/dev/null4.4 特殊パーミッションの表示と確認
# ls -la での特殊パーミッション表示
# SUID: 所有者のx位置
# s = SUID + 実行権あり
# S = SUID + 実行権なし(通常は設定ミス)
# SGID: グループのx位置
# s = SGID + 実行権あり
# S = SGID + 実行権なし
# Sticky: otherのx位置
# t = Sticky + 実行権あり
# T = Sticky + 実行権なし
# 具体的な表示例
# -rwsr-xr-x : SUID設定、全員実行可能
# -rwxr-sr-x : SGID設定
# drwxrwxrwt : Sticky Bit設定
# -rwSr--r-- : SUID設定だが所有者に実行権なし(問題あり)
# -rwxr-Sr-- : SGID設定だがグループに実行権なし(問題あり)
# drwxrwxrwT : Sticky設定だがotherに実行権なし(問題あり)
# stat での数値確認
stat -c "%a %A %n" /usr/bin/passwd
# 4755 -rwsr-xr-x /usr/bin/passwd
stat -c "%a %A %n" /tmp
# 1777 drwxrwxrwt /tmp
# 全ての特殊パーミッション付きファイルを検索
find / -perm /7000 -type f 2>/dev/null | head -20
# /7000 = SUID(4000) OR SGID(2000) OR Sticky(1000) のいずれか5. ACL(Access Control List)
5.1 ACLの基本概念
# ACL = 標準のuser/group/other以上の細かなアクセス制御
# 特定のユーザーやグループに個別の権限を付与できる
# ACLが必要なケース:
# - 所有者グループ以外の特定グループにもアクセスを許可したい
# - 特定のユーザーだけに書き込み権限を与えたい
# - 複数のグループに異なるレベルのアクセスを設定したい
# ACLのインストール確認
which getfacl setfacl
# Ubuntu/Debian: sudo apt install acl
# CentOS/RHEL: sudo yum install acl
# ファイルシステムのACLサポート確認
mount | grep acl
# ext4, xfs, btrfs は通常ACLをサポート
# mount -o acl でマウントされていること
# tune2fs でACLサポート確認(ext4)
sudo tune2fs -l /dev/sda1 | grep -i acl
# Default mount options: ... acl ...5.2 getfacl — ACLの表示
# 基本的なACL表示
$ getfacl file.txt
# file: file.txt
# owner: user
# group: group
user::rw- # 所有者の権限
group::r-- # グループの権限
other::r-- # その他の権限
# ACLが設定されている場合
$ getfacl file.txt
# file: file.txt
# owner: user
# group: group
user::rw- # 所有者
user:alice:rw- # aliceに個別のrw権限
user:bob:r-- # bobに個別のr権限
group::r-- # 所有者グループ
group:devteam:rw- # devteamグループにrw権限
mask::rw- # 有効な最大権限
other::r-- # その他
# ACLが設定されているファイルの見分け方
$ ls -la
-rw-rw-r--+ 1 user group 4096 Jan 1 file.txt
# ^ + マークがACL設定済みの印
# ディレクトリのACL(デフォルトACL含む)
$ getfacl dir/
# file: dir/
# owner: user
# group: group
user::rwx
group::r-x
other::r-x
default:user::rwx # 新規ファイルのデフォルト: 所有者
default:user:alice:rw- # 新規ファイルのデフォルト: alice
default:group::r-x # 新規ファイルのデフォルト: グループ
default:mask::rwx # 新規ファイルのデフォルト: mask
default:other::r-x # 新規ファイルのデフォルト: その他
# 再帰的にACL表示
getfacl -R dir/
# 数値で表示
getfacl --omit-header -e n file.txt
# ACL付きファイルだけを検索
getfacl -R -s -p dir/ 2>/dev/null5.3 setfacl — ACLの設定
# 基本構文: setfacl [OPTIONS] [操作] FILE
# ユーザーACLの追加
setfacl -m u:alice:rw file.txt # aliceにrw権限を追加
setfacl -m u:bob:r file.txt # bobにr権限を追加
setfacl -m u:charlie:rwx script.sh # charlieにrwx権限を追加
# グループACLの追加
setfacl -m g:devteam:rw file.txt # devteamグループにrw権限
setfacl -m g:qa:r file.txt # qaグループにr権限
# その他のACL設定
setfacl -m o::r file.txt # other の権限を設定
# 複数のACLを同時に設定
setfacl -m u:alice:rw,u:bob:r,g:devteam:rw file.txt
# ACLの削除
setfacl -x u:alice file.txt # aliceのACLエントリを削除
setfacl -x g:devteam file.txt # devteamのACLエントリを削除
# 全てのACLを削除
setfacl -b file.txt # 全ACL削除(基本パーミッションは残る)
# デフォルトACL(ディレクトリ用)
# 新規作成されるファイル/ディレクトリに自動適用されるACL
setfacl -d -m u:alice:rw dir/ # デフォルトACLを設定
setfacl -d -m g:devteam:rwx dir/ # デフォルトACLを設定
# デフォルトACLの削除
setfacl -k dir/ # デフォルトACLのみ削除
# 再帰的にACLを設定
setfacl -R -m u:alice:rw dir/ # 既存ファイルにも適用
setfacl -R -d -m u:alice:rw dir/ # 既存ディレクトリにデフォルトACL
# ACLのバックアップと復元
getfacl -R dir/ > acl_backup.txt # バックアップ
setfacl --restore=acl_backup.txt # 復元
# mask の設定
setfacl -m m::r file.txt # maskをrに設定
# mask はACLユーザー/グループの有効な最大権限を制限する
# 例: u:alice:rw でも mask::r なら、実効権限は r のみ
# mask の自動再計算を防ぐ
setfacl -n -m u:alice:rw file.txt # maskを自動更新しない5.4 ACLの実践パターン
# パターン1: プロジェクトディレクトリの共有設定
sudo mkdir -p /projects/webapp
sudo chown root:devteam /projects/webapp
sudo chmod 2770 /projects/webapp
# 開発チーム: フルアクセス
setfacl -R -m g:devteam:rwx /projects/webapp
setfacl -R -d -m g:devteam:rwx /projects/webapp
# QAチーム: 読み取りのみ
setfacl -R -m g:qa:rx /projects/webapp
setfacl -R -d -m g:qa:rx /projects/webapp
# 外部コンサルタント: 特定ディレクトリのみ
setfacl -m u:consultant:rx /projects/webapp/docs
setfacl -R -m u:consultant:rx /projects/webapp/docs/
# パターン2: ログファイルのアクセス制御
# 特定ユーザーにログ閲覧権限を付与
setfacl -m u:logviewer:r /var/log/app/app.log
setfacl -d -m u:logviewer:r /var/log/app/
# パターン3: Webサーバーとデプロイユーザーの共存
setfacl -R -m u:www-data:rx /var/www/html/
setfacl -R -m u:deploy:rwx /var/www/html/
setfacl -R -d -m u:www-data:rx /var/www/html/
setfacl -R -d -m u:deploy:rwx /var/www/html/
# パターン4: バックアップ用の読み取り専用アクセス
setfacl -R -m u:backup:rx /important/data/
setfacl -R -d -m u:backup:rx /important/data/
# ACLの確認(結果の見方)
$ getfacl /projects/webapp/newfile.txt
# file: projects/webapp/newfile.txt
# owner: developer1
# group: devteam
user::rw-
user:consultant:r-x #effective:r-- ← mask による制限
group::rwx #effective:rw- ← mask による制限
group:devteam:rwx #effective:rw- ← mask による制限
group:qa:r-x #effective:r-- ← mask による制限
mask::rw- ← 有効な最大権限
other::---5.5 ACL と標準パーミッションの関係
# ACL と chmod の相互作用
# chmod はACLのmaskに影響する
# 例: ACLでaliceにrwx権限を設定
setfacl -m u:alice:rwx file.txt
getfacl file.txt
# user:alice:rwx
# mask::rwx
# chmod でグループ権限を変更すると mask も変わる
chmod 644 file.txt
getfacl file.txt
# user:alice:rwx #effective:r-- ← mask により制限!
# mask::r-- ← chmod がmaskを変更した
# 対処法: chmod 後に mask を再設定
chmod 644 file.txt
setfacl -m m::rwx file.txt # mask を明示的にrwxに設定
# ACL設定時の優先順位
# 1. 所有者(user::)→ 常に適用
# 2. 名前付きユーザーACL(user:name:) → mask で制限
# 3. 所有者グループ(group::) → mask で制限(ACLが存在する場合)
# 4. 名前付きグループACL(group:name:) → mask で制限
# 5. その他(other::) → 常に適用
# cp と mv でのACL保持
cp --preserve=all src.txt dst.txt # ACLを保持してコピー
cp -a src/ dst/ # ACLを保持して再帰コピー
mv src.txt dst.txt # 同一FS内ならACL保持
# tar でのACL保持
tar --acls -czf backup.tar.gz dir/ # ACL付きでアーカイブ
tar --acls -xzf backup.tar.gz # ACL付きで展開
# rsync でのACL保持
rsync -avA src/ dst/ # -A でACLを同期6. セキュリティ用途のパーミッション設定
6.1 SSH 関連の必須パーミッション
# SSH は厳格なパーミッションチェックを行う
# 不適切なパーミッションだとSSH接続が拒否される
# ホームディレクトリ
chmod 755 ~ # または 700
# ホームディレクトリが他人に書き込み可能だとSSH拒否
# .ssh ディレクトリ
chmod 700 ~/.ssh # 所有者のみ
chown $USER:$(id -gn) ~/.ssh
# 秘密鍵
chmod 600 ~/.ssh/id_rsa # 所有者のみ読み書き
chmod 600 ~/.ssh/id_ed25519 # Ed25519鍵
# 400 でもOK(読み取り専用)
chmod 400 ~/.ssh/id_rsa # より安全
# 公開鍵
chmod 644 ~/.ssh/id_rsa.pub # 誰でも読み取り可能
# authorized_keys
chmod 600 ~/.ssh/authorized_keys
# または 644
# known_hosts
chmod 644 ~/.ssh/known_hosts
# config ファイル
chmod 600 ~/.ssh/config
# SSH サーバー側の設定
chmod 600 /etc/ssh/sshd_config
chmod 600 /etc/ssh/ssh_host_*_key # ホスト秘密鍵
chmod 644 /etc/ssh/ssh_host_*_key.pub # ホスト公開鍵
# 一括修正スクリプト
fix_ssh_permissions() {
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_* 2>/dev/null
chmod 644 ~/.ssh/*.pub 2>/dev/null
chmod 600 ~/.ssh/authorized_keys 2>/dev/null
chmod 600 ~/.ssh/config 2>/dev/null
chmod 644 ~/.ssh/known_hosts 2>/dev/null
echo "SSH permissions fixed."
}
# SSH パーミッションエラーの確認
ssh -vvv user@host 2>&1 | grep -i permission
# debug1: identity file /home/user/.ssh/id_rsa type 0
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# @ WARNING: UNPROTECTED PRIVATE KEY FILE! @
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Permissions 0644 for '/home/user/.ssh/id_rsa' are too open.6.2 Webサーバーのパーミッション設定
# ===== Apache / Nginx 共通 =====
# ドキュメントルート
sudo chown -R root:www-data /var/www/html/
sudo chmod -R 750 /var/www/html/
# ファイル: 640 (rw-r-----)
# ディレクトリ: 750 (rwxr-x---)
find /var/www/html -type f -exec chmod 640 {} \;
find /var/www/html -type d -exec chmod 750 {} \;
# アップロードディレクトリ
sudo mkdir -p /var/www/html/uploads
sudo chown www-data:www-data /var/www/html/uploads
sudo chmod 770 /var/www/html/uploads
# CGI/スクリプト
sudo chmod 750 /var/www/cgi-bin/*.cgi
# 設定ファイル
sudo chmod 600 /etc/apache2/apache2.conf
sudo chmod 600 /etc/nginx/nginx.conf
sudo chmod 600 /etc/nginx/conf.d/*.conf
# SSL証明書
sudo chmod 600 /etc/ssl/private/server.key
sudo chmod 644 /etc/ssl/certs/server.crt
# ログファイル
sudo chmod 640 /var/log/apache2/*.log
sudo chmod 640 /var/log/nginx/*.log
# ===== PHP-FPM =====
# phpのセッション/テンプファイル
sudo chown www-data:www-data /var/lib/php/sessions
sudo chmod 730 /var/lib/php/sessions
# .htaccess のセキュリティ(Apache)
# .htaccess 自体のパーミッション
chmod 644 /var/www/html/.htaccess
# .env ファイルへのWebアクセスをブロック
# .htaccess に追加:
# <Files ".env">
# Require all denied
# </Files>
# ===== WordPress の推奨パーミッション =====
# ファイル: 644
# ディレクトリ: 755
# wp-config.php: 440 または 400
# .htaccess: 644
find /var/www/wordpress -type f -exec chmod 644 {} \;
find /var/www/wordpress -type d -exec chmod 755 {} \;
chmod 440 /var/www/wordpress/wp-config.php6.3 データベースのパーミッション設定
# ===== MySQL / MariaDB =====
# データディレクトリ
sudo chown -R mysql:mysql /var/lib/mysql/
sudo chmod 750 /var/lib/mysql/
sudo chmod 660 /var/lib/mysql/ib_logfile*
# 設定ファイル
sudo chmod 644 /etc/mysql/my.cnf
sudo chmod 640 /etc/mysql/conf.d/*.cnf
# ログファイル
sudo chmod 640 /var/log/mysql/error.log
sudo chown mysql:adm /var/log/mysql/error.log
# ===== PostgreSQL =====
# データディレクトリ
sudo chown -R postgres:postgres /var/lib/postgresql/
sudo chmod 700 /var/lib/postgresql/*/main/
# 認証設定
sudo chmod 640 /etc/postgresql/*/main/pg_hba.conf
sudo chown postgres:postgres /etc/postgresql/*/main/pg_hba.conf
# ===== SQLite =====
# データベースファイル
chmod 660 /path/to/database.db
# ディレクトリにも書き込み権限が必要(WALモード用)
chmod 770 /path/to/
# ===== Redis =====
sudo chown redis:redis /var/lib/redis/
sudo chmod 750 /var/lib/redis/
sudo chmod 640 /etc/redis/redis.conf6.4 アプリケーションのパーミッション設定
# ===== 秘密情報ファイル =====
# .env ファイル
chmod 600 .env
chmod 600 .env.production
# API キーファイル
chmod 600 credentials.json
chmod 600 service-account.json
chmod 600 api_key.txt
# 暗号化キー
chmod 600 encryption.key
chmod 600 master.key
# ===== Docker =====
# Docker ソケット
sudo chmod 660 /var/run/docker.sock
sudo chown root:docker /var/run/docker.sock
# Docker Compose ファイル(秘密情報を含む場合)
chmod 600 docker-compose.override.yml
# ===== systemd サービス =====
# ユニットファイル
sudo chmod 644 /etc/systemd/system/myapp.service
# 環境変数ファイル(秘密情報含む)
sudo chmod 600 /etc/myapp/env
sudo chown root:root /etc/myapp/env
# ===== cron =====
# crontab ファイル
chmod 600 /var/spool/cron/crontabs/*
# cronスクリプト
chmod 700 /etc/cron.d/myscript
chmod 755 /etc/cron.daily/backup.sh
# ===== Git フック =====
chmod 755 .git/hooks/pre-commit
chmod 755 .git/hooks/post-merge
# ===== Python 仮想環境 =====
chmod 755 venv/bin/activate
chmod 755 venv/bin/python6.5 重要なシステムファイルの標準パーミッション
# 認証関連
ls -la /etc/passwd # 644 -rw-r--r-- (全員が読める)
ls -la /etc/shadow # 640 -rw-r----- (rootとshadowグループのみ)
ls -la /etc/group # 644 -rw-r--r-- (全員が読める)
ls -la /etc/gshadow # 640 -rw-r----- (rootとshadowグループのみ)
ls -la /etc/sudoers # 440 -r--r----- (rootのみ読み取り)
# ネットワーク設定
ls -la /etc/hosts # 644 -rw-r--r--
ls -la /etc/hostname # 644 -rw-r--r--
ls -la /etc/resolv.conf # 644 -rw-r--r--
# サービス設定
ls -la /etc/ssh/sshd_config # 600 -rw------- (rootのみ)
ls -la /etc/crontab # 644 -rw-r--r--
# ブート関連
ls -la /boot/vmlinuz-* # 600 -rw------- (Debian系)
ls -la /boot/grub/grub.cfg # 400 -r-------- (rootのみ読み取り)
# デバイスファイル
ls -la /dev/null # 666 crw-rw-rw-
ls -la /dev/zero # 666 crw-rw-rw-
ls -la /dev/random # 666 crw-rw-rw-
ls -la /dev/sda # 660 brw-rw---- (rootとdiskグループ)
ls -la /dev/tty # 666 crw-rw-rw-
# パーミッション監査: 重要ファイルのチェック
check_critical_permissions() {
echo "=== Critical File Permissions ==="
for f in /etc/passwd /etc/shadow /etc/group /etc/sudoers \
/etc/ssh/sshd_config; do
if [ -f "$f" ]; then
stat -c "%a %A %U:%G %n" "$f"
fi
done
}7. パーミッション管理の実践テクニック
7.1 find を使ったパーミッション操作
# 特定のパーミッションを持つファイルを検索
find /path -perm 777 # 正確に 777 のファイル
find /path -perm -777 # 少なくとも 777 を含む
find /path -perm /777 # いずれかのビットが一致
# 世界書き込み可能なファイルを検索(セキュリティ監査)
find / -perm -002 -type f 2>/dev/null
# -002 = other に w がある全てのファイル
# 世界書き込み可能なディレクトリ(Sticky Bitなし)を検索
find / -perm -002 -not -perm -1000 -type d 2>/dev/null
# SUID/SGID 付きファイルの検索
find / -perm -4000 -type f 2>/dev/null # SUID
find / -perm -2000 -type f 2>/dev/null # SGID
find / -perm /6000 -type f 2>/dev/null # SUID または SGID
# 実行権限のあるファイルを検索
find /path -perm /111 -type f # 誰かが実行可能
# パーミッションが不適切なファイルを修正
# ファイル: 644, ディレクトリ: 755 に統一
find /path -type f -not -perm 644 -exec chmod 644 {} \;
find /path -type d -not -perm 755 -exec chmod 755 {} \;
# 所有者がいないファイルを検索
find / -nouser 2>/dev/null
find / -nogroup 2>/dev/null
find / -nouser -o -nogroup 2>/dev/null
# 特定ユーザーのファイルを検索
find / -user username 2>/dev/null
find / -uid 1000 2>/dev/null
find / -group groupname 2>/dev/null
find / -gid 1000 2>/dev/null
# 最近パーミッションが変更されたファイル
find / -cmin -60 2>/dev/null # 過去60分以内にctime変更
# ctime = inode変更時刻(パーミッション変更を含む)
# 書き込み可能なSUIDファイル(深刻な脆弱性)
find / -perm -4002 -type f 2>/dev/null7.2 パーミッション設定スクリプト
#!/bin/bash
# fix-web-permissions.sh
# Webプロジェクトのパーミッションを修正するスクリプト
WEB_ROOT="${1:?Usage: $0 <web-root-path>}"
WEB_USER="www-data"
WEB_GROUP="www-data"
# 存在確認
if [ ! -d "$WEB_ROOT" ]; then
echo "Error: $WEB_ROOT does not exist"
exit 1
fi
echo "Fixing permissions for: $WEB_ROOT"
# 所有者設定
echo "Setting ownership to ${WEB_USER}:${WEB_GROUP}..."
sudo chown -R "${WEB_USER}:${WEB_GROUP}" "$WEB_ROOT"
# ディレクトリ: 755
echo "Setting directory permissions to 755..."
find "$WEB_ROOT" -type d -exec chmod 755 {} \;
# ファイル: 644
echo "Setting file permissions to 644..."
find "$WEB_ROOT" -type f -exec chmod 644 {} \;
# 実行可能ファイル: 755
echo "Setting executable permissions..."
find "$WEB_ROOT" -name "*.sh" -exec chmod 755 {} \;
find "$WEB_ROOT" -name "*.py" -exec chmod 755 {} \;
find "$WEB_ROOT" -name "*.cgi" -exec chmod 755 {} \;
# 秘密ファイル: 600
echo "Securing sensitive files..."
find "$WEB_ROOT" -name ".env" -exec chmod 600 {} \;
find "$WEB_ROOT" -name "*.key" -exec chmod 600 {} \;
find "$WEB_ROOT" -name "*.pem" -exec chmod 600 {} \;
find "$WEB_ROOT" -name "wp-config.php" -exec chmod 440 {} \;
# アップロードディレクトリ
if [ -d "$WEB_ROOT/uploads" ]; then
echo "Setting upload directory permissions..."
chmod 770 "$WEB_ROOT/uploads"
fi
# ログディレクトリ
if [ -d "$WEB_ROOT/logs" ]; then
echo "Setting log directory permissions..."
chmod 750 "$WEB_ROOT/logs"
find "$WEB_ROOT/logs" -type f -exec chmod 640 {} \;
fi
echo "Done! Permissions fixed."#!/bin/bash
# permission-audit.sh
# セキュリティ監査用パーミッションチェックスクリプト
echo "============================================"
echo " Permission Security Audit Report"
echo " Date: $(date '+%Y-%m-%d %H:%M:%S')"
echo " Host: $(hostname)"
echo "============================================"
echo ""
# 1. 世界書き込み可能ファイル
echo "=== World-Writable Files ==="
world_writable=$(find / -perm -002 -type f -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null)
if [ -n "$world_writable" ]; then
echo "$world_writable" | head -20
echo "Total: $(echo "$world_writable" | wc -l) files"
else
echo "None found. [OK]"
fi
echo ""
# 2. 世界書き込み可能ディレクトリ(Sticky Bitなし)
echo "=== World-Writable Directories (without Sticky Bit) ==="
ww_dirs=$(find / -perm -002 -not -perm -1000 -type d \
-not -path "/proc/*" -not -path "/sys/*" 2>/dev/null)
if [ -n "$ww_dirs" ]; then
echo "$ww_dirs" | head -20
echo "Total: $(echo "$ww_dirs" | wc -l) directories"
echo "[WARNING] These directories should have Sticky Bit set"
else
echo "None found. [OK]"
fi
echo ""
# 3. SUID/SGID ファイル
echo "=== SUID Files ==="
find / -perm -4000 -type f -not -path "/proc/*" -not -path "/sys/*" \
-exec ls -la {} \; 2>/dev/null | head -20
echo ""
echo "=== SGID Files ==="
find / -perm -2000 -type f -not -path "/proc/*" -not -path "/sys/*" \
-exec ls -la {} \; 2>/dev/null | head -20
echo ""
# 4. 孤児ファイル
echo "=== Orphaned Files (no user/group) ==="
orphans=$(find / -nouser -o -nogroup 2>/dev/null | head -20)
if [ -n "$orphans" ]; then
echo "$orphans"
echo "[WARNING] These files have no valid owner/group"
else
echo "None found. [OK]"
fi
echo ""
# 5. 重要ファイルのパーミッションチェック
echo "=== Critical File Permissions ==="
check_perm() {
local file="$1"
local expected="$2"
if [ -f "$file" ]; then
actual=$(stat -c "%a" "$file" 2>/dev/null || stat -f "%OLp" "$file" 2>/dev/null)
if [ "$actual" = "$expected" ]; then
echo "[OK] $file ($actual)"
else
echo "[WARN] $file ($actual, expected $expected)"
fi
fi
}
check_perm "/etc/passwd" "644"
check_perm "/etc/shadow" "640"
check_perm "/etc/group" "644"
check_perm "/etc/sudoers" "440"
check_perm "/etc/ssh/sshd_config" "600"
echo ""
# 6. SSH 鍵のパーミッション
echo "=== SSH Key Permissions ==="
if [ -d ~/.ssh ]; then
ls -la ~/.ssh/ 2>/dev/null
ssh_dir_perm=$(stat -c "%a" ~/.ssh 2>/dev/null || stat -f "%OLp" ~/.ssh 2>/dev/null)
if [ "$ssh_dir_perm" != "700" ]; then
echo "[WARN] ~/.ssh should be 700, is $ssh_dir_perm"
fi
fi
echo ""
echo "============================================"
echo " Audit Complete"
echo "============================================"7.3 よくあるパーミッション設定パターン
# ===== パターン1: 共有プロジェクトディレクトリ =====
sudo mkdir -p /opt/project
sudo groupadd project-team
sudo usermod -aG project-team user1
sudo usermod -aG project-team user2
sudo chown root:project-team /opt/project
sudo chmod 2775 /opt/project
# SGID(2) + 所有者rwx(7) + グループrwx(7) + その他rx(5)
# 新規ファイルはproject-teamグループに自動設定
# ===== パターン2: 機密ドキュメント管理 =====
sudo mkdir -p /secure/documents
sudo chmod 700 /secure
sudo chmod 700 /secure/documents
sudo chown manager:management /secure/documents
# ACLで特定メンバーにアクセス許可
setfacl -m u:assistant:rx /secure/documents
setfacl -d -m u:assistant:rx /secure/documents
# ===== パターン3: ログ収集ディレクトリ =====
sudo mkdir -p /var/log/app
sudo chown root:adm /var/log/app
sudo chmod 2750 /var/log/app
# アプリケーションが書き込み、admグループが読み取り
# logrotate 用の設定
sudo chmod 640 /var/log/app/*.log
# ===== パターン4: CI/CDデプロイ用 =====
sudo mkdir -p /var/www/app
sudo groupadd deployers
sudo chown root:deployers /var/www/app
sudo chmod 2775 /var/www/app
# デプロイユーザーに権限
sudo usermod -aG deployers deploy-bot
setfacl -R -m g:deployers:rwx /var/www/app
setfacl -R -d -m g:deployers:rwx /var/www/app
# Webサーバーには読み取りのみ
setfacl -R -m u:www-data:rx /var/www/app
setfacl -R -d -m u:www-data:rx /var/www/app
# ===== パターン5: バックアップディレクトリ =====
sudo mkdir -p /backup
sudo chown root:backup /backup
sudo chmod 770 /backup
# バックアップスクリプトはbackupグループで実行
# 個別バックアップの保護
sudo chmod 600 /backup/*.tar.gz
# ===== パターン6: 一時的な作業ディレクトリ =====
sudo mkdir -p /tmp/shared-work
sudo chmod 1777 /tmp/shared-work
# Sticky Bit: 他人のファイルは削除不可、全員が書き込み可能8. Linux のセキュリティモジュール
8.1 SELinux の基本
# SELinux (Security-Enhanced Linux)
# Red Hat系(RHEL, CentOS, Fedora)でデフォルト有効
# 標準のUNIXパーミッションに加えて、強制アクセス制御(MAC)を提供
# SELinuxの状態確認
getenforce
# Enforcing : ポリシーを強制(違反はブロック)
# Permissive : ポリシー違反をログのみ(ブロックしない)
# Disabled : SELinux無効
sestatus
# SELinux status: enabled
# SELinuxfs mount: /sys/fs/selinux
# SELinux root directory: /etc/selinux
# Loaded policy name: targeted
# Current mode: enforcing
# 一時的にモード変更(再起動で戻る)
sudo setenforce 0 # Permissive に変更
sudo setenforce 1 # Enforcing に変更
# 恒久的な設定変更
sudo vi /etc/selinux/config
# SELINUX=enforcing ← enforcing, permissive, disabled
# SELinuxコンテキストの表示
ls -Z file.txt
# -rw-r--r--. user group unconfined_u:object_r:user_home_t:s0 file.txt
# ↑ユーザー ↑ロール ↑タイプ ↑レベル
ps -eZ | grep httpd
# system_u:system_r:httpd_t:s0 1234 ? 00:00:01 httpd
# SELinuxコンテキストの変更
sudo chcon -t httpd_sys_content_t /var/www/html/index.html
sudo chcon -R -t httpd_sys_content_t /var/www/html/
# デフォルトコンテキストに復元
sudo restorecon -v file.txt
sudo restorecon -Rv /var/www/html/
# SELinuxブール値の管理
getsebool -a # 全ブール値を表示
getsebool httpd_can_network_connect # 特定のブール値
# ブール値の設定
sudo setsebool httpd_can_network_connect on # 一時的
sudo setsebool -P httpd_can_network_connect on # 恒久的
# よく使うSELinuxブール値
sudo setsebool -P httpd_can_network_connect on # Apache外部接続許可
sudo setsebool -P httpd_enable_homedirs on # ホームディレクトリ許可
sudo setsebool -P httpd_can_sendmail on # メール送信許可
# SELinux違反ログの確認
sudo ausearch -m AVC -ts recent
sudo sealert -a /var/log/audit/audit.log
sudo journalctl -t setroubleshoot
# ポート管理
sudo semanage port -l | grep http # HTTP関連ポート一覧
sudo semanage port -a -t http_port_t -p tcp 8080 # カスタムポート追加8.2 AppArmor の基本
# AppArmor
# Ubuntu, Debian, SUSE でデフォルト有効
# プロファイルベースの強制アクセス制御
# AppArmorの状態確認
sudo aa-status
# apparmor module is loaded.
# 42 profiles are loaded.
# 25 profiles are in enforce mode.
# 17 profiles are in complain mode.
# プロファイルの場所
ls /etc/apparmor.d/
# プロファイルのモード
# enforce : ポリシーを強制
# complain : ポリシー違反をログのみ(学習モード)
# disabled : プロファイル無効
# モード変更
sudo aa-enforce /etc/apparmor.d/usr.sbin.apache2 # 強制モード
sudo aa-complain /etc/apparmor.d/usr.sbin.apache2 # 学習モード
sudo aa-disable /etc/apparmor.d/usr.sbin.apache2 # 無効化
# プロファイルの読み込み
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.apache2 # 再読み込み
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.apache2 # 削除
# ログの確認(違反の検出)
sudo journalctl -k | grep apparmor
sudo dmesg | grep apparmor
# DENIED を検索
sudo journalctl -k | grep "apparmor.*DENIED"
# プロファイルの生成
sudo aa-genprof /usr/bin/myapp
# → アプリケーションを操作して学習させる
# → プロファイルが自動生成される
# 簡易プロファイル例(/etc/apparmor.d/usr.local.bin.myapp)
# /usr/local/bin/myapp {
# /usr/local/bin/myapp mr, # 自身の読み取り+実行
# /etc/myapp/** r, # 設定ファイル読み取り
# /var/log/myapp/** w, # ログ書き込み
# /tmp/myapp-* rw, # 一時ファイル読み書き
# /usr/lib/** rm, # ライブラリ読み取り+実行
# network tcp, # TCP通信許可
# }8.3 Linux Capabilities
# Linux Capabilities: root権限を細分化した仕組み
# 特定の権限だけをプロセス/ファイルに付与できる
# 主要な Capabilities
# CAP_NET_BIND_SERVICE : 1024未満のポートにバインド
# CAP_NET_RAW : RAWソケットの使用(ping等)
# CAP_SYS_ADMIN : 多くの管理操作
# CAP_DAC_OVERRIDE : ファイルアクセス制御のバイパス
# CAP_CHOWN : ファイル所有者の変更
# CAP_KILL : 他ユーザーのプロセスにシグナル送信
# CAP_SETUID/SETGID : UID/GIDの変更
# ファイルの Capability 確認
getcap /usr/bin/ping
# /usr/bin/ping cap_net_raw=ep
# 全ファイルの Capability を検索
getcap -r / 2>/dev/null
# Capability の設定(要root)
sudo setcap cap_net_bind_service=+ep /usr/bin/myapp
# → myapp は非rootでも80番ポートにバインド可能
# Capability の削除
sudo setcap -r /usr/bin/myapp
# プロセスの Capability 確認
cat /proc/$$/status | grep -i cap
# CapInh: 0000000000000000 (継承可能)
# CapPrm: 0000000000000000 (許可)
# CapEff: 0000000000000000 (有効)
# CapBnd: 000001ffffffffff (バウンディングセット)
# CapAmb: 0000000000000000 (アンビエント)
# 数値を読みやすく変換
capsh --decode=000001ffffffffff
# 実践例: SUIDの代わりにCapabilityを使用
# pingコマンド(従来はSUID)
sudo chmod u-s /usr/bin/ping
sudo setcap cap_net_raw=ep /usr/bin/ping
# → SUIDなしでもpingが動作
# 実践例: Node.jsアプリを非rootで80番ポートで動作
sudo setcap cap_net_bind_service=+ep /usr/bin/node
# または
sudo setcap 'cap_net_bind_service=+ep' $(which node)9. トラブルシューティング
9.1 よくあるパーミッションエラー
# ===== エラー1: Permission denied =====
$ cat /etc/shadow
cat: /etc/shadow: Permission denied
# 原因: 読み取り権限がない
# 解決:
ls -la /etc/shadow # パーミッション確認
sudo cat /etc/shadow # root権限で実行
# ===== エラー2: Operation not permitted =====
$ chown user file.txt
chown: changing ownership of 'file.txt': Operation not permitted
# 原因: chown はroot権限が必要
# 解決:
sudo chown user file.txt
# ===== エラー3: SSH Permission denied =====
# "Permissions 0644 for '~/.ssh/id_rsa' are too open."
# 原因: SSH鍵のパーミッションが緩すぎる
# 解決:
chmod 600 ~/.ssh/id_rsa
chmod 700 ~/.ssh
# ===== エラー4: bash: ./script.sh: Permission denied =====
# 原因: 実行権限がない
# 解決:
chmod +x script.sh
# または
bash script.sh # bash を明示的に呼ぶ
# ===== エラー5: mkdir: cannot create directory: Permission denied =====
# 原因: 親ディレクトリへの書き込み権限がない
# 解決:
ls -la /parent/dir/ # 親ディレクトリのパーミッション確認
sudo mkdir /parent/dir/newdir
# ===== エラー6: rm: cannot remove: Operation not permitted =====
# 原因1: ファイルがimmutableフラグ付き
lsattr file.txt # フラグ確認
# ----i--------e-- file.txt ← i=immutable
sudo chattr -i file.txt # immutableフラグ解除
rm file.txt
# 原因2: Sticky Bit付きディレクトリで他人のファイル
ls -ld /tmp # Sticky Bit確認
# drwxrwxrwt ... ← t がある
# ===== エラー7: cp: cannot create regular file: Permission denied =====
# 原因: コピー先のディレクトリへの書き込み権限がない
ls -la /destination/ # コピー先のパーミッション確認
# 解決:
sudo cp file.txt /destination/
# または
chmod u+w /destination/9.2 ファイル属性(chattr / lsattr)
# chattr: 拡張ファイル属性の設定(パーミッションとは別の制御レイヤー)
# lsattr: 拡張ファイル属性の表示
# 主要な属性
# i (immutable) : 変更・削除・名前変更・リンク作成不可(rootでも!)
# a (append) : 追記のみ可能(ログファイル向き)
# e (extent) : ext4のエクステント使用(通常デフォルト)
# A (noatime) : アクセス時刻を更新しない
# S (sync) : 即座にディスクに書き込み
# d (nodump) : dump によるバックアップ対象外
# c (compress) : 自動圧縮(対応FS必要)
# 属性の表示
lsattr file.txt
# ----i--------e-- file.txt
lsattr -d dir/ # ディレクトリの属性
lsattr -R dir/ # 再帰的に表示
# immutable 属性の設定(最強の保護)
sudo chattr +i important.conf
# → root でも変更・削除できなくなる
# → 解除するには chattr -i が必要
rm important.conf
# rm: cannot remove 'important.conf': Operation not permitted
sudo rm important.conf
# rm: cannot remove 'important.conf': Operation not permitted
# → root でも削除できない!
# immutable の解除
sudo chattr -i important.conf
rm important.conf # OK
# append-only 属性(ログファイル向き)
sudo chattr +a /var/log/secure.log
echo "new entry" >> /var/log/secure.log # OK(追記)
echo "overwrite" > /var/log/secure.log # エラー(上書き不可)
rm /var/log/secure.log # エラー(削除不可)
# 実践例: 重要な設定ファイルの保護
sudo chattr +i /etc/resolv.conf # DNS設定の保護
sudo chattr +i /etc/passwd # パスワードファイルの保護
sudo chattr +i /etc/shadow # シャドウファイルの保護
# 注意: ユーザー管理ツールが動作しなくなるので一時的な保護のみ推奨
# 実践例: ブートファイルの保護
sudo chattr +i /boot/vmlinuz-*
sudo chattr +i /boot/initrd.img-*
# immutable フラグ付きファイルの検索
lsattr -R / 2>/dev/null | grep -- "----i"9.3 デバッグテクニック
# ===== namei: パス全体のパーミッションチェック =====
# ファイルにアクセスできない時、パスのどこで権限がないか確認
namei -l /var/www/html/index.html
# f: /var/www/html/index.html
# dr-xr-xr-x root root /
# drwxr-xr-x root root var
# drwxr-xr-x root root www
# drwxr-xr-x root root html
# -rw-r--r-- root root index.html
# 各ディレクトリの x ビットを確認
# x がないディレクトリがあるとそこでブロックされる
# ===== strace: システムコールレベルでの権限エラー追跡 =====
strace -f -e trace=open,openat,access cat /etc/shadow 2>&1
# openat(AT_FDCWD, "/etc/shadow", O_RDONLY) = -1 EACCES (Permission denied)
# ===== sudo -l: 利用可能なsudo権限の確認 =====
sudo -l
# User user may run the following commands on host:
# (ALL : ALL) ALL
# (root) /usr/bin/systemctl restart apache2
# ===== getfacl: ACLを含む完全なパーミッション確認 =====
getfacl /path/to/file
# ===== /proc/self/status: 現在のプロセスの権限情報 =====
cat /proc/self/status | grep -E "Uid|Gid|Groups|Cap"
# ===== loginctl: ログインセッションの確認 =====
loginctl show-user $USER
# ===== パーミッション変更履歴の確認 =====
# auditd が有効な場合
sudo ausearch -f /path/to/file -ts recent
# ファイルへのアクセス試行と権限変更を記録
# auditルールの追加
sudo auditctl -w /etc/passwd -p wa -k passwd_changes
# -w: 監視対象ファイル
# -p: 監視する操作 (w=write, a=attribute change)
# -k: ログ検索用のキー
# ===== inotifywait: リアルタイムファイル監視 =====
# パーミッション変更をリアルタイムで監視
inotifywait -m -e attrib /path/to/file
# /path/to/file ATTRIB ← パーミッションや属性が変更された
# ===== テスト用ユーザーでの確認 =====
# 特定ユーザーの視点でアクセスをテスト
sudo -u www-data cat /var/www/html/config.php
sudo -u postgres ls /var/lib/postgresql/
# ===== access コマンド(test)での確認 =====
# 現在のユーザーがアクセスできるかテスト
test -r file.txt && echo "Readable" || echo "Not readable"
test -w file.txt && echo "Writable" || echo "Not writable"
test -x file.txt && echo "Executable" || echo "Not executable"
# スクリプトでの活用
if [ ! -r "$config_file" ]; then
echo "Error: Cannot read $config_file" >&2
echo "Current permissions: $(ls -la "$config_file")" >&2
echo "Run: sudo chmod +r $config_file" >&2
exit 1
fi10. macOS 固有のパーミッション
10.1 macOS のパーミッション特性
# macOS は BSD ベースのパーミッションシステム + 独自拡張
# POSIX パーミッション + ACL + SIP + TCC + Sandbox
# 基本的なパーミッション操作はLinuxと同じ
chmod 755 file.txt
chown user:group file.txt
# ただし stat コマンドの書式がBSD形式
# macOS の stat(BSD版)
stat -f "%Sp %Su %Sg %z %N" file.txt
# -rw-r--r-- user staff 4096 file.txt
# 数値表示
stat -f "%OLp %N" file.txt
# 644 file.txt
# macOS のデフォルトグループは "staff"
id
# uid=501(user) gid=20(staff) groups=20(staff),80(admin),...
# macOS のACL
# macOS は独自のACLフォーマットを使用
ls -le file.txt # ACL表示(-e オプション)
# -rw-r--r--+ 1 user staff 4096 Jan 1 file.txt
# 0: user:alice allow read,write
# 1: group:devteam allow read
# macOS ACLの設定
chmod +a "user:alice allow read,write" file.txt
chmod +a "group:devteam allow read" file.txt
chmod +a "user:bob deny write" file.txt # 拒否ルール
# macOS ACLの削除
chmod -a "user:alice allow read,write" file.txt
chmod -a# 0 file.txt # インデックス0のACLを削除
chmod -N file.txt # 全ACL削除
# ACLの順序指定
chmod +a# 0 "user:alice allow read,write" file.txt # 先頭に挿入10.2 SIP(System Integrity Protection)
# SIP: macOS のシステムファイル保護機能
# rootでも保護されたファイル/ディレクトリの変更不可
# SIPの状態確認
csrutil status
# System Integrity Protection status: enabled.
# SIPで保護されるディレクトリ
# /System
# /usr (ただし /usr/local は除く)
# /bin
# /sbin
# /Applications(プリインストールアプリ)
# SIP保護下でのエラー例
sudo rm /usr/bin/python3
# rm: /usr/bin/python3: Operation not permitted
# → SIPにより rootでも削除不可
# SIPの無効化(推奨されない、開発時のみ)
# リカバリモードで起動 → ターミナル → csrutil disable
# 再起動後に有効になる
# /usr/local は SIP の対象外
# Homebrew はここにインストールされる
ls -la /usr/local/bin/10.3 xattr(拡張属性)
# macOS の拡張属性(Extended Attributes)
# ファイルにメタデータを付加する仕組み
# 拡張属性の表示
xattr file.txt
xattr -l file.txt # 値も表示
# よく見る拡張属性
# com.apple.quarantine : ダウンロードしたファイルの隔離フラグ
# com.apple.metadata:kMDItemWhereFroms : ダウンロード元URL
# com.apple.FinderInfo : Finderの表示情報
# com.apple.ResourceFork : リソースフォーク
# 隔離フラグの確認
xattr -p com.apple.quarantine downloaded_file
# 0083;5f8b1234;Chrome;...
# 隔離フラグの削除(Gatekeeperの警告解除)
xattr -d com.apple.quarantine downloaded_file
# ディレクトリ全体から削除
xattr -dr com.apple.quarantine ~/Downloads/app.app
# 全拡張属性の削除
xattr -c file.txt
# 拡張属性の設定
xattr -w com.example.note "important file" file.txt
# 再帰的に拡張属性を削除
xattr -cr dir/
# @ マーク: ls で拡張属性の存在を示す
ls -la
# -rw-r--r--@ 1 user staff 4096 Jan 1 downloaded.zip
# ^ @ は拡張属性あり実践演習
演習1: [基礎] — パーミッション操作
# スクリプトに実行権限を付与
echo '#!/bin/bash' > /tmp/test.sh
echo 'echo "Hello from test.sh!"' >> /tmp/test.sh
echo 'echo "Running as: $(whoami)"' >> /tmp/test.sh
echo 'echo "PID: $$"' >> /tmp/test.sh
# パーミッション確認
ls -la /tmp/test.sh
# -rw-r--r-- 1 user group ... test.sh (実行権なし)
# 実行を試みる(失敗するはず)
/tmp/test.sh
# bash: /tmp/test.sh: Permission denied
# 実行権限付与
chmod +x /tmp/test.sh
ls -la /tmp/test.sh
# -rwxr-xr-x 1 user group ... test.sh (実行権あり)
# 実行
/tmp/test.sh
# Hello from test.sh!
# Running as: user
# PID: 12345
# パーミッションを数値で確認
stat -c "%a %n" /tmp/test.sh 2>/dev/null || stat -f "%OLp %N" /tmp/test.sh
# 755 /tmp/test.sh
# クリーンアップ
rm /tmp/test.sh演習2: [基礎] — umask の理解
# 現在のumaskを確認
echo "Current umask: $(umask)"
echo "Symbolic: $(umask -S)"
# umask 022 でファイル作成
umask 022
touch /tmp/umask_022.txt
mkdir /tmp/umask_022_dir
echo "umask 022:"
stat -c " File: %a %n" /tmp/umask_022.txt 2>/dev/null
stat -c " Dir: %a %n" /tmp/umask_022_dir 2>/dev/null
# File: 644
# Dir: 755
# umask 077 でファイル作成
umask 077
touch /tmp/umask_077.txt
mkdir /tmp/umask_077_dir
echo "umask 077:"
stat -c " File: %a %n" /tmp/umask_077.txt 2>/dev/null
stat -c " Dir: %a %n" /tmp/umask_077_dir 2>/dev/null
# File: 600
# Dir: 700
# umask 002 でファイル作成
umask 002
touch /tmp/umask_002.txt
mkdir /tmp/umask_002_dir
echo "umask 002:"
stat -c " File: %a %n" /tmp/umask_002.txt 2>/dev/null
stat -c " Dir: %a %n" /tmp/umask_002_dir 2>/dev/null
# File: 664
# Dir: 775
# umask を元に戻す
umask 022
# クリーンアップ
rm -f /tmp/umask_*.txt
rmdir /tmp/umask_*_dir演習3: [中級] — チーム共有ディレクトリの構築
# チーム共有ディレクトリを作成して適切なパーミッションを設定
# この演習はroot権限が必要
# 1. グループの作成
sudo groupadd exercise-team 2>/dev/null
# 2. テストユーザーの作成(演習用)
sudo useradd -m -G exercise-team member1 2>/dev/null
sudo useradd -m -G exercise-team member2 2>/dev/null
# 3. 共有ディレクトリの作成
sudo mkdir -p /tmp/team-share
# 4. 所有者とグループの設定
sudo chown root:exercise-team /tmp/team-share
# 5. SGID + Sticky Bit の設定
sudo chmod 3770 /tmp/team-share
# 3 = SGID(2) + Sticky(1)
# 770 = rwx rwx ---
# 確認
ls -ld /tmp/team-share
# drwxrws--T 2 root exercise-team 4096 ... team-share
# s = SGID(新規ファイルにグループが継承される)
# T = Sticky(他メンバーのファイルは削除不可)
# 大文字Tはotherにxがないため
# 6. テスト: member1がファイル作成
sudo -u member1 touch /tmp/team-share/member1_file.txt
ls -la /tmp/team-share/member1_file.txt
# -rw-r--r-- 1 member1 exercise-team ... member1_file.txt
# → グループが exercise-team に自動設定(SGID効果)
# 7. テスト: member2がmember1のファイルを削除(失敗するはず)
sudo -u member2 rm /tmp/team-share/member1_file.txt 2>&1
# rm: cannot remove ...: Operation not permitted(Sticky Bit効果)
# 8. テスト: member2が自分のファイルを作成・削除(成功するはず)
sudo -u member2 touch /tmp/team-share/member2_file.txt
sudo -u member2 rm /tmp/team-share/member2_file.txt
# クリーンアップ
sudo rm -rf /tmp/team-share
sudo userdel -r member1 2>/dev/null
sudo userdel -r member2 2>/dev/null
sudo groupdel exercise-team 2>/dev/null演習4: [中級] — ACL の設定と検証
# ACL を使って複雑なアクセス制御を実装
# 1. テスト環境の作成
mkdir -p /tmp/acl-exercise/docs
mkdir -p /tmp/acl-exercise/code
echo "Secret document" > /tmp/acl-exercise/docs/secret.txt
echo "Public code" > /tmp/acl-exercise/code/main.py
# 2. 基本パーミッションの設定
chmod 700 /tmp/acl-exercise/docs/
chmod 755 /tmp/acl-exercise/code/
# 3. ACLの設定(自分のユーザーで実験)
# 特定ユーザーにdocsへの読み取りアクセスを許可
# (存在するユーザー名で実行してください)
setfacl -m u:$(whoami):rx /tmp/acl-exercise/docs/
setfacl -m u:$(whoami):r /tmp/acl-exercise/docs/secret.txt
# 4. ACLの確認
echo "=== Directory ACL ==="
getfacl /tmp/acl-exercise/docs/
echo ""
echo "=== File ACL ==="
getfacl /tmp/acl-exercise/docs/secret.txt
# 5. デフォルトACLの設定(新規ファイルに自動適用)
setfacl -d -m u:$(whoami):r /tmp/acl-exercise/docs/
# 6. デフォルトACLの検証
touch /tmp/acl-exercise/docs/new_file.txt
echo "=== New file ACL (should inherit default) ==="
getfacl /tmp/acl-exercise/docs/new_file.txt
# 7. ls で + マークを確認
ls -la /tmp/acl-exercise/docs/
# + マークが表示されるはず
# 8. ACLのバックアップと復元
getfacl -R /tmp/acl-exercise/ > /tmp/acl_backup.txt
echo "=== ACL Backup ==="
cat /tmp/acl_backup.txt
# 9. ACLの削除
setfacl -b /tmp/acl-exercise/docs/secret.txt
echo "=== After ACL removal ==="
getfacl /tmp/acl-exercise/docs/secret.txt
# 10. バックアップからの復元
setfacl --restore=/tmp/acl_backup.txt
echo "=== After ACL restore ==="
getfacl /tmp/acl-exercise/docs/secret.txt
# クリーンアップ
rm -rf /tmp/acl-exercise /tmp/acl_backup.txt演習5: [上級] — セキュリティ監査スクリプト
#!/bin/bash
# security-check.sh
# 自分のホームディレクトリのパーミッションを監査
HOME_DIR="${HOME}"
ISSUES=0
echo "============================================"
echo " Home Directory Security Check"
echo " User: $(whoami)"
echo " Home: ${HOME_DIR}"
echo " Date: $(date)"
echo "============================================"
echo ""
# 1. ホームディレクトリのパーミッション
echo "=== 1. Home Directory ==="
home_perm=$(stat -c "%a" "${HOME_DIR}" 2>/dev/null || stat -f "%OLp" "${HOME_DIR}" 2>/dev/null)
if [ "$home_perm" -gt 755 ]; then
echo "[WARN] Home directory is too permissive: $home_perm (should be 755 or less)"
ISSUES=$((ISSUES + 1))
else
echo "[OK] Home directory: $home_perm"
fi
echo ""
# 2. SSH ディレクトリ
echo "=== 2. SSH Configuration ==="
if [ -d "${HOME_DIR}/.ssh" ]; then
ssh_perm=$(stat -c "%a" "${HOME_DIR}/.ssh" 2>/dev/null || stat -f "%OLp" "${HOME_DIR}/.ssh" 2>/dev/null)
if [ "$ssh_perm" != "700" ]; then
echo "[WARN] .ssh directory: $ssh_perm (should be 700)"
ISSUES=$((ISSUES + 1))
else
echo "[OK] .ssh directory: $ssh_perm"
fi
# 秘密鍵のチェック
for key in "${HOME_DIR}"/.ssh/id_*; do
if [ -f "$key" ] && [[ ! "$key" == *.pub ]]; then
key_perm=$(stat -c "%a" "$key" 2>/dev/null || stat -f "%OLp" "$key" 2>/dev/null)
if [ "$key_perm" != "600" ] && [ "$key_perm" != "400" ]; then
echo "[WARN] Private key $key: $key_perm (should be 600 or 400)"
ISSUES=$((ISSUES + 1))
else
echo "[OK] Private key $key: $key_perm"
fi
fi
done
else
echo "[INFO] No .ssh directory found"
fi
echo ""
# 3. 秘密情報ファイル
echo "=== 3. Sensitive Files ==="
for pattern in ".env" ".env.*" "*.pem" "*.key" "credentials*" "secret*"; do
while IFS= read -r -d '' sensitive; do
s_perm=$(stat -c "%a" "$sensitive" 2>/dev/null || stat -f "%OLp" "$sensitive" 2>/dev/null)
if [ "$s_perm" -gt 600 ]; then
echo "[WARN] $sensitive: $s_perm (should be 600 or less)"
ISSUES=$((ISSUES + 1))
else
echo "[OK] $sensitive: $s_perm"
fi
done < <(find "${HOME_DIR}" -maxdepth 3 -name "$pattern" -type f -print0 2>/dev/null)
done
echo ""
# 4. 世界書き込み可能ファイル
echo "=== 4. World-Writable Files ==="
ww_files=$(find "${HOME_DIR}" -perm -002 -type f 2>/dev/null | head -10)
if [ -n "$ww_files" ]; then
echo "$ww_files"
ww_count=$(find "${HOME_DIR}" -perm -002 -type f 2>/dev/null | wc -l)
echo "[WARN] Found $ww_count world-writable files"
ISSUES=$((ISSUES + $ww_count))
else
echo "[OK] No world-writable files found"
fi
echo ""
# 5. 実行可能な隠しファイル
echo "=== 5. Hidden Executable Files ==="
hidden_exec=$(find "${HOME_DIR}" -maxdepth 2 -name ".*" -perm /111 -type f 2>/dev/null | head -10)
if [ -n "$hidden_exec" ]; then
echo "$hidden_exec"
echo "[INFO] Review these hidden executable files"
else
echo "[OK] No suspicious hidden executables"
fi
echo ""
# サマリー
echo "============================================"
if [ $ISSUES -eq 0 ]; then
echo " Result: All checks passed!"
else
echo " Result: $ISSUES issue(s) found"
echo " Run the suggested fixes to resolve them."
fi
echo "============================================"演習6: [上級] — パーミッション変更の監視
# inotifywait を使ったリアルタイムパーミッション監視
# インストール: sudo apt install inotify-tools
#!/bin/bash
# watch-permissions.sh
# 指定ディレクトリのパーミッション変更を監視
WATCH_DIR="${1:-.}"
LOG_FILE="/tmp/permission_changes.log"
echo "Watching permission changes in: $WATCH_DIR"
echo "Log file: $LOG_FILE"
echo "Press Ctrl+C to stop"
# inotifywait で attrib(属性変更)イベントを監視
inotifywait -m -r -e attrib --format '%T %w%f %e' \
--timefmt '%Y-%m-%d %H:%M:%S' \
"$WATCH_DIR" 2>/dev/null | while read -r line; do
timestamp=$(echo "$line" | awk '{print $1, $2}')
filepath=$(echo "$line" | awk '{print $3}')
event=$(echo "$line" | awk '{print $4}')
if [ -e "$filepath" ]; then
perms=$(stat -c "%a %A %U:%G" "$filepath" 2>/dev/null)
echo "[$timestamp] $filepath -> $perms ($event)" | tee -a "$LOG_FILE"
fi
done
# 別ターミナルでテスト:
# chmod 777 /path/to/watched/file
# → 監視画面にリアルタイムで表示される
# auditd を使った監視(より本格的)
# sudo auditctl -w /etc/passwd -p wa -k passwd_watch
# sudo ausearch -k passwd_watchFAQ
Q1: このトピックを学ぶ上で最も重要なポイントは何ですか?
実践的な経験を積むことが最も重要です。理論だけでなく、実際にコードを書いて動作を確認することで理解が深まります。
Q2: 初心者がよく陥る間違いは何ですか?
基礎を飛ばして応用に進むことです。このガイドで説明している基本概念をしっかり理解してから、次のステップに進むことをお勧めします。
Q3: 実務ではどのように活用されていますか?
このトピックの知識は、日常的な開発業務で頻繁に活用されます。特にコードレビューやアーキテクチャ設計の際に重要になります。
まとめ
| カテゴリ | 操作 | コマンド |
|---|---|---|
| パーミッション表示 | 一覧表示 | ls -la, stat |
| パーミッション変更 | 数値指定 | chmod 755 file |
| パーミッション変更 | シンボリック | chmod u+x file |
| パーミッション変更 | 再帰的 | chmod -R 755 dir/ |
| パーミッション変更 | ファイル/ディレクトリ分離 | find -type f/d -exec chmod |
| 所有者変更 | 所有者+グループ | chown user:group file |
| グループ変更 | グループのみ | chgrp group file |
| デフォルトパーミッション | umask設定 | umask 022 |
| 特殊ビット | SUID | chmod u+s file / chmod 4755 |
| 特殊ビット | SGID | chmod g+s dir/ / chmod 2755 |
| 特殊ビット | Sticky | chmod +t dir/ / chmod 1777 |
| ACL表示 | ACL確認 | getfacl file |
| ACL設定 | ユーザーACL | setfacl -m u:user:rw file |
| ACL設定 | グループACL | setfacl -m g:group:rx file |
| ACL設定 | デフォルトACL | setfacl -d -m u:user:rw dir/ |
| ACL削除 | 全削除 | setfacl -b file |
| ファイル属性 | 不変設定 | chattr +i file |
| ファイル属性 | 追記のみ | chattr +a file |
| ファイル属性 | 属性確認 | lsattr file |
| Capability | 確認 | getcap file |
| Capability | 設定 | setcap cap_xxx=+ep file |
| セキュリティ監査 | SUID検索 | find / -perm -4000 |
| セキュリティ監査 | 世界書込検索 | find / -perm -002 |
| セキュリティ監査 | 孤児ファイル | find / -nouser -o -nogroup |
| SELinux | 状態確認 | getenforce, sestatus |
| AppArmor | 状態確認 | aa-status |
パーミッション設定クイックリファレンス
用途 パーミッション コマンド
─────────────────────────────────────────────────
公開Webファイル 644 chmod 644 index.html
公開ディレクトリ 755 chmod 755 public/
実行スクリプト 755 chmod 755 script.sh
SSH秘密鍵 600 or 400 chmod 600 ~/.ssh/id_rsa
.sshディレクトリ 700 chmod 700 ~/.ssh
秘密設定ファイル 600 chmod 600 .env
共有ディレクトリ 2775 chmod 2775 /shared/
一時ディレクトリ 1777 chmod 1777 /tmp/
ログファイル 640 chmod 640 app.log
SSL秘密鍵 600 chmod 600 server.key
SSL証明書 644 chmod 644 server.crt
crontab 600 chmod 600 crontab
sudoers 440 chmod 440 /etc/sudoers
次に読むべきガイド
参考文献
- Kerrisk, M. "The Linux Programming Interface." Ch.15: File Attributes, 2010.
- Shotts, W. "The Linux Command Line." Ch.9: Permissions, 5th ed., 2019.
- Nemeth, E. et al. "UNIX and Linux System Administration Handbook." Ch.5: Access Control, 5th ed., 2017.
- Red Hat. "SELinux User's and Administrator's Guide." Red Hat Enterprise Linux 8 Documentation.
- Ubuntu. "AppArmor." Ubuntu Community Help Wiki.
- POSIX.1-2017. "IEEE Std 1003.1: File Access Permissions."
- Grüenbacher, A. "POSIX Access Control Lists on Linux." USENIX, 2003.