Linux基礎

【ausearch】SELinuxのログの見方とトラブルシュート, 監査設定, tail リアルタイム表示~

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" のエラーが出ます。

type=AVC msg=audit(2018年03月07日 01:01:53.995:344) : avc: denied { name_bind } for pid=12225 comm=sshd src=10022 scontext=system_u:system_r:sshd_t:s0-s0:c0.c1023 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket

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 の仕組みや許可ルール、パーミッションの種類等を基本から学びたい方は以下のページをご参照下さい。

【図解/初心者向け】SELinuxとは?〜仕組みやメリット・効果の基礎入門解説〜
SELinuxとは ~概要と仕組み~ SELinux とは Secure-En...

監査の設定の仕方と確認方法

デフォルトでは監査ルールは何も入っていません。

[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 ~]#

コメント

タイトルとURLをコピーしました