はじめに (対象読者・この記事でわかること)

本記事は、Ubuntuサーバーを運用しているシステム管理者や、サーバーのセキュリティ監査を担当するエンジニアを対象としています。
SCP(Secure Copy)でファイル転送が行われた際の接続元IPや実行ユーザー、転送日時といった情報を、標準のログや追加ツールを用いて取得・解析する方法が具体的にわかります。

  • SCP の接続履歴がどこに保存されているかを把握できる
  • auth.logauditdlastlog など複数のログソースから情報を抽出する手順が身につく
  • 実務で役立つフィルタリングやレポート作成のコツが学べる

この背景には、最近増加傾向にある不正ファイル転送や内部不正の兆候を早期に発見したいというニーズがあります。ログの取得・可視化ができれば、問題発生時の原因追及が格段に楽になります。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • Ubuntu(あるいはDebian系)での基本的なコマンド操作(catgrepawk など)
  • Linux の認証系ログ(/var/log/auth.log)や監査システム(auditd)の概要
  • SSH の設定ファイル(/etc/ssh/sshd_config)とその意味

SCPアクセス履歴の概要と取得対象

SCP は SSH をトンネルにしたファイル転送プロトコルです。そのため、SCP の接続情報は SSH の認証ログに記録されます。Ubuntu ではデフォルトで以下の場所にログが出力されます。

ログファイル 主な記録内容 取得できる情報
/var/log/auth.log SSH の認証成功/失敗、キー認証の有無、接続元IP ユーザー名、IP アドレス、接続時刻
auditd (/var/log/audit/audit.log) 詳細なシステムコール、ファイル操作 SCP によるファイルの読み書きパス、実行されたコマンド
lastlog 最終ログイン情報 最近の SSH ログイン時刻と IP(SCP も対象)

なぜ複数のログが必要か
- auth.log は認証情報に特化しているため、接続元とユーザーがすぐに分かりますが、実際に転送したファイル名やサイズは取得できません。
- auditd は細かいシステムコールを記録できるため、scp コマンドが実行した open, read, write などを追跡でき、転送ファイル名やサイズ、成功/失敗のステータスが分かります。
- lastlog はユーザー別の最終ログイン情報をまとめて把握でき、長期間の傾向を把握したいときに便利です。

以上を踏まえて、実務でよく用いる「認証ログ + 監査ログ」の組み合わせで、SCP の全体像を把握する方法を解説します。

SCPアクセス履歴の取得手順と実装方法

ここでは、実際に Ubuntu サーバー上で SCP のアクセス履歴を取得・整形し、検索しやすい形にするまでのフローをステップごとに示します。全体の流れは次の通りです。

  1. SSH の認証ログから SCP 接続レコードを抽出
  2. auditd を有効化し、SCP 関連のシステムコールをキャプチャ
  3. 取得したログを統合し、CSV/JSON 形式で出力
  4. jqawk で簡易レポートを生成

以下、各ステップの詳細です。

ステップ1:auth.log から SCP 接続情報を抽出

SCP は内部的に ssh に対して scp -t <path>(受信側)や scp -f <path>(送信側)というコマンドを実行します。auth.log には次のようなエントリが残ります。

Jan 23 14:05:12 server sshd[27431]: Accepted publickey for alice from 203.0.113.45 port 52784 ssh2: RSA SHA256:...
Jan 23 14:05:12 server sshd[27431]: pam_unix(sshd:session): session opened for user alice by (uid=0)
Jan 23 14:05:12 server sshd[27431]: subsystem request for sftp

SCP の接続は subsystem request for sftp が出ない点がポイントです。また、ssh のコマンドラインに scp が含まれることもあります。以下のシェルスクリプトで対象行だけを抽出できます。

Bash
#!/usr/bin/env bash LOG_FILE="/var/log/auth.log" PATTERN="scp" # 認証成功かつ scp コマンドが含まれる行を抽出 grep "$PATTERN" "$LOG_FILE" | grep "Accepted" > /tmp/scp_auth.log # 必要なカラムだけ整形 (日時, ユーザー, IP) awk ' { # 例: Jan 23 14:05:12 server sshd[27431]: Accepted publickey for alice from 203.0.113.45 port 52784 ssh2 split($0, a, " "); datetime = a[1]" "a[2]" "a[3]; for(i=1;i<=NF;i++){ if($i=="for"){ user=$(i+1); } if($i=="from"){ ip=$(i+1); } } print datetime "," user "," ip; }' /tmp/scp_auth.log > /tmp/scp_auth_parsed.csv echo "SCP 認証ログを /tmp/scp_auth_parsed.csv に出力しました。"

ポイント解説
- grep "$PATTERN"scp が含まれる行だけに絞り、誤検知を減らす。
- awkforfrom の直後のトークンを取得し、CSV 形式に整形。
- 時刻はローカルタイム(auth.log の書式)なので、後で必要なら date -d で UTC へ変換可能。

ステップ2:auditd で SCP のファイル操作を記録

auditd は Linux カーネルの監査フレームワークで、システムコールレベルのトレースが可能です。SCP の転送は内部で open, read, write, close といったファイル系システムコールを行うため、これらを監査対象にすれば転送ファイル名とサイズが取得できます。

2‑1. auditd のインストールと有効化

Bash
sudo apt update sudo apt install -y auditd audispd-plugins sudo systemctl enable --now auditd

2‑2. 監査ルールの設定

以下のルールは、scp コマンドが実行されたプロセス(exe=/usr/bin/scp)の open 系システムコールを記録します。

Bash
# /etc/audit/rules.d/scp.rules に記述 -w /usr/bin/scp -p x -k scp_exec -a always,exit -F arch=b64 -S open,openat,creat -F exe=/usr/bin/scp -k scp_file -a always,exit -F arch=b32 -S open,openat,creat -F exe=/usr/bin/scp -k scp_file
  • -w はバイナリそのものの実行を監視し、-k は検索用キーを付与。
  • -a always,exit はシステムコールが終了したときに必ずログを残す設定です。

設定後は auditd を再起動します。

Bash
sudo systemctl restart auditd

2‑3. ログの抽出例

ausearch コマンドで scp_file キーのログだけを取得し、JSON 形式で保存します。

Bash
sudo ausearch -k scp_file --format=json > /tmp/scp_audit.json

取得した JSON には次のようなエントリが含まれます(抜粋)。

Json
{ "type":"PROCTITLE", "msg":"node=kernel pid=27431 auid=1000 uid=1000 gid=1000 ses=3 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 exe=\"/usr/bin/scp\" comm=\"scp\" args=\"-t /var/backups\"", "timestamp":"2025-01-23T14:05:12.123456Z" } { "type":"SYSCALL", "msg":"node=kernel pid=27431 uid=1000 gid=1000 auid=1000 ses=3 exe=\"/usr/bin/scp\" syscall=2 success=yes exit=3 a0=\"/var/backups/backup.tar.gz\" a1=\"O_WRONLY|O_CREAT|O_TRUNC\" a2=\"0644\"", "timestamp":"2025-01-23T14:05:12.125678Z" }

SYSCALLa0 フィールドが実際に開かれたファイル名です。exe/usr/bin/scp であることを条件にすれば、他の SSH アクティビティと混同しません。

ステップ3:ログの統合と整形

認証ログ(ステップ1)と監査ログ(ステップ2)をキー情報(ユーザー、IP、タイムスタンプ)で結合し、最終的なレポートを CSV にまとめます。以下は jqawk を併用したシンプルなスクリプト例です。

Bash
#!/usr/bin/env bash # 1. 認証ログ CSV を読み込む AUTH_CSV="/tmp/scp_auth_parsed.csv" # 2. 監査ログ JSON を jq でパースし、必要項目だけ抽出 jq -r ' select(.type=="SYSCALL") | "\(.timestamp),\(.msg | capture(\"exe=\\\"(?<exe>[^\\\"]+)\\\"\").exe),\(.msg | capture(\"a0=\\\"(?<filepath>[^\\\"]+)\\\"\").filepath)" ' /tmp/scp_audit.json > /tmp/scp_audit_parsed.csv # 3. 両CSVをマージ(時間差±5秒で同一イベントとみなす) join -t, -1 1 -2 1 <( sort -t, -k1,1 "$AUTH_CSV" ) <( sort -t, -k1,1 /tmp/scp_audit_parsed.csv ) > /tmp/scp_full_report.csv echo "統合レポートが /tmp/scp_full_report.csv に生成されました。"

マージロジックの注意点
- join はキー(ここではタイムスタンプ)で正確に一致する行だけ結合しますが、認証ログと監査ログのタイムスタンプはミリ秒単位でずれることがあります。実務では awk で時刻差を許容範囲(例: ±5 秒)で結合するロジックを追加するとより安全です。

例: 時刻差許容の awk スニペット

Awk
BEGIN{FS=","; OFS=","} NR==FNR { a[$1]=$0; next } { ts=$1 for (t in a) { if ( (ts - t) <= 5 && (ts - t) >= -5 ) { print a[t], $2, $3 } } }

ハマった点やエラー解決

発生した問題 原因 解決策
auditdscp のシステムコールを取得しない 監査ルールに arch が足りていなかった(32bit 環境) 32bit と 64bit 両方の arch を指定 (arch=b64arch=b32)
auth.logscp と分かる文字列が無い SSH の設定で LogLevelINFO になっていた /etc/ssh/sshd_configLogLevel VERBOSE に変更し、SSH デーモンを再起動
join が期待通りにマージできない タイムスタンプ形式が auth.logaudit.log で異なっていた date -d で ISO8601 形式に統一し、数値化した秒数で比較
ausearch が大量出力で処理が遅い 監査対象が広すぎた ルールで key=scp_file を付与し、ausearch -k scp_file に限定

まとめ

本記事では、Ubuntu サーバー上で SCP のアクセス履歴を取得し、実務で活用できる形に加工する手順を解説しました。

  • 認証ログ (auth.log) で接続元 IP とユーザーを把握
  • auditd を用いて転送ファイル名・サイズ・成功/失敗を取得
  • スクリプト でログを CSV/JSON に統合し、検索やレポート作成を自動化

これらを導入することで、SCP を利用した不正転送や内部情報漏洩の兆候を早期に検出でき、監査対応の効率化が期待できます。次回は、取得したデータを ELK スタックや Grafana に可視化する方法を取り上げる予定です。

参考資料