NoteStack

This page is a beginner-friendly note about aggregating CSP report logs across multiple days, focusing on sudo, wildcard expansion, permissions, and how to read the results without panic.

「Permission denied で詰まった」CSPログを全日集計するための sudo とワイルドカードの落とし穴

CSPログを「全日分で集計したい」ときに、sudo と * の挙動で迷わないための判断だけまとめます。

まず何に詰まったか:ファイルはあるのに grep が No such / Permission denied

最初は「CSPログを全日分で集計したい」だけでした。

でも実際にやると、No such file or directoryPermission denied が交互に出て、どこが問題なのか分からなくなりました。

このときの状況(ありがちな)
  • ls /var/www/.../logs/csp-report-YYYYMMDD.jsonl は見える
  • でも grep ... csp-report-*.jsonlNo such になる
  • sudo を付けても直らない(むしろ No such に戻る)
ポイント(先に言い切る)

原因はだいたい「ワイルドカード(*)の展開は sudo の前に起きる」と、「logs が apache:apache で閉じてある」の組み合わせでした。

原因1:* は sudo の前に展開される(だから root でも拾えない)

自分が一番勘違いしていたのはここです。

起きていたこと

sudo wc -l /var/www/.../logs/csp-report-*.jsonl* は、root ではなく自分のシェル(alma)側で展開されます。

そして alma が /var/www/.../logs を一覧できないなら、* は展開されず、文字列のまま root に渡ります。

結果どうなるか
  • root は「csp-report-*.jsonl という名前のファイル」を探しに行く
  • そんなファイルは無いので No such file or directory

なので、「root側で * を展開させる」のが最初の一手になります。

解決:sudo bash -c で root 側に展開させる(まず存在確認)

ここから一気に迷いが減りました。

全日分のファイル一覧(存在確認)
sudo bash -c 'ls -lh /var/www/sakura.yugien.xyz/logs/csp-report-*.jsonl'

これで一覧が出れば、「ファイルが無い」問題ではありません。

全日分の行数(中身があるか)
sudo bash -c 'wc -l /var/www/sakura.yugien.xyz/logs/csp-report-*.jsonl'

行数が 1 以上なら、次は「grep条件が合ってない」側を疑えます。

原因2:権限が閉じているのは正常(apache:apache / 750)

ここも「直さなきゃ」と思いがちですが、私は直さない方針にしました。

確認コマンド
ls -ld /var/www/sakura.yugien.xyz/logs
判断

drwxr-x--- かつ apache:apache のように「other が ---」なら、alma が入れないのは仕様どおりです。

ログは証跡なので、閲覧者を増やすより、必要なときだけ sudo で読むほうが安心でした。

原因3:キー名が違う(ハイフンではなくアンダースコア)

ログは見えているのに集計が「何も出ない」場合、ここにハマります。

自分のログで実際に出ていたキー
  • effective_directive
  • violated_directive
  • blocked_uri
  • document_uri

effective-directive みたいなハイフン区切りではなかった)

まず実物を1行だけ見る
sudo bash -c 'head -n 1 /var/www/sakura.yugien.xyz/logs/csp-report-*.jsonl'

キー名が分かれば、その形式に合わせて集計できます。

全日分の集計:directive / blocked_uri / document_uri のTOPを出す

「どれが多い?」を先に出すと、次の判断が早いです。

directive(どの種類が多いか)
sudo bash -c '
grep -h -E ""(effective_directive|violated_directive)"" /var/www/sakura.yugien.xyz/logs/csp-report-*.jsonl | sed -E "s/.*\"(effective_directive|violated_directive)\":\"([^\"]+)\".*/\2/" | sort | uniq -c | sort -nr | head -5
'
blocked_uri(何がブロックされたか)
sudo bash -c '
grep -h ""blocked_uri"" /var/www/sakura.yugien.xyz/logs/csp-report-*.jsonl | sed -E "s/.*\"blocked_uri\":\"([^\"]+)\".*/\1/" | sort | uniq -c | sort -nr | head -10
'
document_uri(どのページで起きてるか)
sudo bash -c '
grep -h ""document_uri"" /var/www/sakura.yugien.xyz/logs/csp-report-*.jsonl | sed -E "s/.*\"document_uri\":\"([^\"]+)\".*/\1/" | sort | uniq -c | sort -nr | head -10
'

集計結果の読み方:危ないものと「仕様っぽいもの」を分ける

ログを見ると全部怖く見えますが、私は「まず分ける」ことにしました。

だいたい無視してOK(まず落ち着く)
  • browser-extension://(拡張機能由来)
  • data: / about:
一応チェック(でも即遮断しない)
  • 見覚えのない外部ドメインの script-src / script-src-elem
  • 短時間に同じ内容が大量(自動化っぽい)
仕様か設計ミスかの切り分け(よく出る)
  • blocked_uri: "inline" → インラインstyle/scriptがある(または計測系が混ざる)
  • img-src が多い → 外部画像(CDN/別ドメイン)を使っている

運用方針:権限は閉じたまま、必要なときだけ sudo で読む

最終的に「楽さ」より「証跡」を優先することにしました。

方針
  • Report-Only のまま観測を続ける(いきなり enforce しない)
  • ログは apache:apache / 750 のまま(alma に読ませない)
  • 集計は sudo bash -c で root 側に * を展開させる
補足

運用を楽にしたいなら、権限を緩めるよりrootで動く集計スクリプトを1つ置くほうが安全だと感じました。

よくある質問(FAQ)

Q. sudo を付けたのに No such file になるのはなぜ?

A. ワイルドカード(*)は sudo の前に展開されます。展開できない権限だと、* が文字列のまま root に渡り、存在しないファイル名として扱われます。

Q. logs を alma が読めるようにしてもいい?

A. できますが、ログは証跡なので閲覧者を増やすのはリスクも増えます。私は「都度 sudo で読む」方針にしました。

Q. violated-directive で grep しても出ません

A. ログのキー名が violated_directive のようにアンダースコアになっている可能性があります。まず head -n 1 で実物を見てください。

Q. すぐ enforce にした方が安全?

A. いきなり強制にすると、外部JS/解析/広告/外部画像が止まりやすいです。まずは Report-Only で「何が起きているか」を把握するのが安全です。