auditd と audit.log
CentOS 等の Linux において、audit.log を出力する『auditd』というデーモンが標準で動作しています。
これは『監査が必要なアクセスに対してログを取る』仕組みです。
監査とは、何か問題が起きたときに犯人を捜す証拠となるようなものを残す仕組みのことで、例えば秘密の管理簿ファイルを監査する設定にしておけば、誰がその管理簿ファイルへアクセスしたかが後から分かるようになります。
デフォルトでは主に SELinux によるアクセス制御や ssh アクセス、cron によるアクセス等がログされるよう設定されていますが、例えば以下のような設定をすれば、そのファイルにアクセスするたびにログが生成されるため、『いつ誰がそのファイルを触ったか』といったことを後から知ることができます。
ausearch の使い方
audit.log は cat 等で直接見てもタイムスタンプ時刻が UNIX-time となっていたりと色々と分かりにくいです。そのため、ausearch というコマンドが用意されています。
例えば
# ausearch -i
というコマンドを打てば、audit.log およびローテーションされたログを全て、時間やその他の属性値を人間に分かりやすい形で表示してくれます。
-i オプションは interpret (解釈) の略です。
結果からも分かる通り、このコマンドは audit.log ファイルに対してではなく、auditd に対してログ表示を要求します。
ですが以下のようにファイルを指定することもできます。
# ausearch -i -if /var/log/audit/audit.log
auditd はログを非同期で Disk に書き込みます。つまり、ログすべき情報がある程度メモリ上に溜まった、もしくはある程度時間が経ったタイミングで、メモリから audit.log (つまり hdd や ssd 等)に書き込みます。
コマンドを叩いた時点でメモリにあるログはそのままでは出力されません。ですが -l を付けることでメモリ上のログも出力できます。
# ausearch -i -l
これは、auditd のログ用のメモリのバッファがブロックバッファ (ログ複数行) なのですが、このコマンドにより一時的にラインバッファ (ログ 1 行ずつ) に変わります。
ただし、昔はともかく、現在の flush (メモリキャッシュからディスクへ書き込み) 方式はデフォルトで "INCREMENTAL_ASYNC" という方式になっており、ブロックバッファ上限に達しなくてもある時間が経過すればディスクに書き込むようになっています。
そして、ある時間というのも人間の感覚しては差を認識できないくらいのごく短い時間であるため、-l オプションを付けることにあまり意味はありません。
ausearch をリアルタイムに見たいとき
ausearch を tail -f に渡すことはできませんが、逆に tail -f で /var/log/audit.log を標準出力し、それを auserach にパイプラインで渡すことができます。
tail -f /var/log/audit/audit.log | ausearch -i -l
SELinuxのログを抽出したい場合
SELinuxのログは他の監査ログと混ざった状態でaudit.logに出力されます。SELinux関連のログだけ抽出したい場合は -m オプション で avcを指定します。
ausearch -i -m avc
avc とは Access Vector Cache のことで、アクセス拒否される動作については繰り返し行われる可能性が高く、毎回SELinuxのポリシーを聞きに行ってしまうとパフォーマンスに影響が出ます。なのでパフォーマンス向上を目的としてキャッシュするわけです。
SELinuxでトラブルシュートを行うときは、permissiveにして確認するのも良いですが、以下を実行しながら再現させれば状況がリアルタイムに分かります。
tail -f /var/log/audit/audit.log | ausearch -i -l -m avc
SELinux に関するauditログの見方
SELinux は主にプロセスから Kernel へ System Call が発行されたタイミングでAVCと呼ばれる許可ルールキャッシュにより精査され、その System Call が実行許可 or 拒否されます。拒否された場合は例えば以下のように audit.log に "avc: denied" のエラーが出ます。
scontext はプロセスのコンテキストです。プロセス名は comm= に書かれている通り、sshd ですので、sshd のコンテキストが [system_u:system_r:sshd_t:s0-s0:c0.c1023] であることが分かります。
tcontext はそのプロセスがアクセスしようとしているリソースのコンテキストです。リソースはファイル/ディレクトリが有名ですが、ネットワークリソース (TCP/UDP ポート待ち受けやOutbound通信) もあります。
tclass は SELinux のパーミッションのオブジェクトクラスのことで、scontext が行おうとしている操作の種類です。tcp_socket とありますのでこれはリソースが TCP ポートであることが分かります。そのうえで、src= を見ると 10022 とありますので、tcontext の主体は TCP:10022 番ポートであり、このポートにコンテキスト [system_u:object_r:unreserved_port_t:s0] がラベルされていることが分かります。
{ } にあるのは tclass の種類に応じた、具体的なパーミッションの内容です。{ name_bind } とは『インタフェースで TCP/UDP のポートで待ち受け (バインド) する』ための権限です。
なので上記のケースでは、sshd が TCP:10022 番ポートを Listen しようとしたが、SELinux のルールにより拒否された、ということが分かります。
これを解消するためには以下のようにします。TCP:10022 番ポートのコンテキストのタイプを unreserved_port_t から、ssh_port_t というタイプに変更するコマンドです。
# dnf -y install policycoreutils-python-utils # semanage port -a -t ssh_port_t -p tcp 10022
ssh_port_t は元々 TCP:22 番ポートが含まれており、上記コマンドにより TCP:10022 番ポートも追加されます。sshd_t という scontext から ssh_port_t という tcontext への name_bind は許可ルールが元から入っていますので、これでListen出来るようになるわけです。
SELinux の仕組みや許可ルール、パーミッションの種類等を基本から学びたい方は以下のページをご参照下さい。
監査の設定の仕方と確認方法
デフォルトでは監査ルールは何も入っていません。
[root@localhost audit]# auditctl -l No rules
以下の設定を入れることで
[root@localhost audit]# auditctl -w /etc/ssh/sshd_config -p warx -k sshd_config [root@localhost audit]# auditctl -l -w /etc/ssh/sshd_config -p rwxa -k sshd_config [root@localhost audit]#
この設定により、/etc/ssh/sshd_config に関するコマンドが実行されるたびに監査ログが記録されます。例えば上記設定をした後、"# cat /etc/ssh/sshd_config" と打つと audit.log には以下のように出力されます。
type=SYSCALL msg=audit(1521210470.616:549): arch=c000003e syscall=2 success=yes exit=3 a0=7fff120bb8e3 a1=0 a2=1fffffffffff0000 a3=7fff120b99e0 items=1 ppid=43178 pid=43390 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=6 comm="cat" exe="/usr/bin/cat" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="sshd_config"
type=CWD msg=audit(1521210470.616:549): cwd="/etc/audit"
type=PATH msg=audit(1521210470.616:549): item=0 name="/etc/ssh/sshd_config" inode=33964307 dev=fd:00 mode=0100600 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:etc_t:s0 objtype=NORMAL
type=PROCTITLE msg=audit(1521210470.616:549): proctitle=636174002F6574632F7373682F737368645F636F6E666967
1 番目の type=SYSCALL で始まるログは、SYSTEMCALL で cat コマンドを呼び出し、sshd_config を読み込んだことに対するログです。
auid=1000 とあるので、uid=1000 のユーザが読み込んだことが分かります。ausearch -i で読み込むと、この auid=1000 もユーザ名に変換して表示してくれます。
2 番目の type=CWD は Currend Work Directory つまりどのディレクトリからコマンドを起動したかを記録しています。
最後の type=PATH はアクセスしたファイル (sshd_config) のファイル情報です。
auditdの設定ファイル(デフォルト) と マニュアル
auditd の設定ファイルは "/etc/audit/auditd.conf" です。CentOS8 のデフォルトでは以下のようになっています。
[root@localhost ~]# cat /etc/audit/auditd.conf # # This file controls the configuration of the audit daemon # local_events = yes write_logs = yes log_file = /var/log/audit/audit.log log_group = root log_format = ENRICHED flush = INCREMENTAL_ASYNC freq = 50 max_log_file = 8 num_logs = 5 priority_boost = 4 name_format = NONE ##name = mydomain max_log_file_action = ROTATE space_left = 75 space_left_action = SYSLOG verify_email = yes action_mail_acct = root admin_space_left = 50 admin_space_left_action = SUSPEND disk_full_action = SUSPEND disk_error_action = SUSPEND use_libwrap = yes ##tcp_listen_port = 60 tcp_listen_queue = 5 tcp_max_per_addr = 1 ##tcp_client_ports = 1024-65535 tcp_client_max_idle = 0 transport = TCP krb5_principal = auditd ##krb5_key_file = /etc/audit/audit.key distribute_network = no q_depth = 400 overflow_action = SYSLOG max_restarts = 10 plugin_dir = /etc/audit/plugins.d [root@localhost ~]#
コメント