Linux auditdでアクセス拒否されたファイルを探し出す

Linuxで、こんな状況に遭遇することが、たまにある。
「アプリが動かない。ログによると、どこかのファイルで Permission denied / Operation not permitted になっているみたい。でもどこで?」
例えば、アプリ作成者の想定外の場所でエラーが起こっていたり、プロトタイピングなどでエラー処理を手抜きしていると、ログに十分な情報がなく、そんな困った状況になりがち。
しかし、最近のLinuxでは、auditdを使って、簡単に問題ファイルを特定できる。
たまに auditd を使うので、記事にまとめてみた。

1. auditdの概要

Auditdは、Linuxカーネルとアプリケーションのやりとりを監査(audit)するOSの機能。
RHEL系ではデフォルト ON になっているので、ツールの追加インストールは不要。
開発目標の一つに監査オーバーヘッドの最小化を掲げており、性能の足を引っ張ることも、ほとんどない優れもの。

1.1. Kernel内の仕掛け

以下の図は、本家サイトにあるプレゼン資料 “Updated version of the 2007 Red Hat Summit slides” より引用した。


Kernel内の監視ポイント(Filter)
左側の App が、Linux Kernelとやりとりするとき、重要なポイントに 関門(Filter) をおいて、App の動きを監視する。
関門(Filter)は以下の5つ。
関門(Filter) 役割
User Trusted App(後述)から監査イベントを受け取る
Entry 監査準備:リソース確保、Kernel突入時刻の記録など
Exit 監査ログの出力、リソース解放
Task Appの子プロセス(fork)を追跡
Exclude 対象外イベントの除去
また、PAM と連携して、Appの実行ユーザの変化を追跡する。
最後は、関心ある監査イベントだけ、カーネルから Audit Daemon プロセスに渡す。

1.2. 周辺ツール

再び、プレゼン資料 “Updated version of the 2007 Red Hat Summit slides” より引用。


周辺ツール
図に書かれた各コンポーネント/周辺ツールを説明する。

Auditd & Logs

図の中心にある Auditd は、Kernelから受け取った監査イベントを Logs にログ出力する。
このログの実体は、CentOS6のマシンを見ると/var/log/audit/audit.logにある(設定ファイル /etc/audit/auditd.conf より)。

Ausearch, Aureport, Aulast

Logs に蓄積された監査イベントを、検索/整形表示/サマライズするツール。
蓄積された後にバッチ的に処理するのでなく、監査イベント発生のタイミングで即アクションを起こしたいときは、Audispd を使う。Audispd から警報を鳴らす、アカウントをロックするなど、色々な外部ツールへの連携が想定されている。

Auditctl

赤い箱で書かれた Auditctl は、Kernel側の制御を行う。監査ルールの設定など。

Trusted App

Trusted Appは、Auditが動作するのに、悪意ある動作をしないと信用しているソフトウェア達で、Trusted App自身も監視イベントを発生できる。
Trusted Appが生成した監視イベントは、Kernel内のUser関門で処理され、Auditdを経由して、Logsへ格納されることになる。
Trusted Appには、PAM、Login、sshd、crond、semanage などが該当する。

2. 使い方

2.1. 監査ルールの設定

auditctlコマンドで、監査ルールの追加や削除を行う。
コマンドラインオプションの基本形は -a (追加) または -d (削除) に続けて
    filter,action   -S syscall   -F condition   -k label
-S-F は、必要な数だけ、複数渡すことができる。
一つのルール内で、複数の-SはOR条件、複数の-FはAND条件となる。
各項目の説明は以下。太字はデフォルト。
項目 値の範囲 説明
filter user,exit,task,exclude 関門を指定 ※entryは指定不可
action always, never 監査イベントを生成(always)するか否か(never)
syscall all, 2, open 等 システムコール名やシステムコール番号を指定 ※ allはワイルドカード
condition euid=0, arch=b64 など多彩 監査イベントを抜き出す条件を指定
label 任意の文字列 監査イベントにラベルを付け、ログを後から検索できる
filterで、user,task を使うことはあまりない。大抵 exit だけか、監査イベントの抑制のために exclude を利用する程度。
actionで、never を使うことは殆ど無い。通常は alwaysを指定する。
syscall は、ausyscall コマンドが返却するテーブルの値を利用することができる。
ausyscall コマンドはこんな感じ。詳しくは “man ausyscall” を参照。
[root@localhost ~]# ausyscall i386 open
open               5
mq_open            277
openat             295
perf_event_open    336
open_by_handle_at  342

[root@localhost ~]# ausyscall x86_64 open --exact
2

-F condition 指定

-Fオプションは、多様なフィールドを使って条件を作り、監査イベントを絞り込む。
詳細は “man 8 auditctl” の -F の項を見てもらうとして、ここではよく使いそうなフィールドを挙げてみる。なお、右辺の即値は例。
条件 意味
a0>3 システムコールの第一引数が 3 を超えるとき
※ 同様に a1,a2,a3 も利用可
arch=b64 64bitのシステムコールのとき ※ 32bitはb32
dir=/tmp /tmp 配下の全ファイルを監視
filetype=socket 対象ファイルがソケットのとき
inode=1187942 inode番号が1187942のとき
perm=rwxa open() が Read,Write,eXecute,Attribute-change の何れかを要求するとき
exit=EACCES システムコールが errno=EACCES で失敗のとき
※ 成功なら exit=0
success=0 システムコールが失敗(0)したとき
※ 成功なら success=1
右辺には即値しか使えないので、”-F uid=euid” みたいには書けない。
代わりに -C uid=euid と書く。

2.2. 監視ルールの一覧

現在設定されているルールは、-l オプションで表示できる。
    auditctl -l

2.3. 監視ログの表示

監視ログは、ausearchコマンドで検索できる。
最も簡単な方法は、ルールに付けたラベル(-kオプション)をキーワードにして、そのルールに該当したイベントだけ抜き出すこと。
    ausearch -i -k label
-i オプションを渡すと、ログ中の数字を、人間にわかりやすい形式に変換(interpret)して表示する。UNIXタイムスタンプや、システムコール番号、エラー番号などを変換してくれる。
-k以外にも、さまざま絞込みをかけられるので、詳しくは “man 8 ausearch” を参照。

3. 実践編

試しに、/tmp配下のファイルで、実際にアクセスエラーを発生させ、ログからファイルと原因を特定してみる。

3.1. /tmpをウォッチする

まず、監査ルールの設定と確認より。
Kernel内のexitフィルターに、/tmp内の全ファイルを監視する “dir=/tmp” というルールを追加する。システムコールの選択は Kernel に任せる。よって-Sオプションは省略。
どんなアクセスで失敗するかわからないから、”perm=rwxa” を条件とする。
アクセス失敗した時だけログしたいので “success=0” も条件に加える。
[root@localhost ~]# auditctl -a exit,always -F dir=/tmp -F perm=rwxa -F success=0 -k access_fail

[root@localhost ~]# auditctl -l
LIST_RULES: exit,always dir=/tmp perm=rwxa success=0 key=access_fail
できた。

3.2. アクセスエラーを発生させる

/tmp配下のファイルで、意図的に、アクセスエラーを発生させてみる。
具体的には、ユーザ testuser1とtestuser2を作り、testuser1で作成した/tmp/my_fileを、testuser2から削除してみる。
ユーザ作成:
[root@localhost ~]# useradd testuser1
[root@localhost ~]# useradd testuser2
testuser1になり、ファイル /tmp/my_file を作成:
[root@localhost ~]# su - testuser1
[testuser1@localhost ~]$ echo hi > /tmp/my_file
[testuser1@localhost ~]$ cat /tmp/my_file
hi
testuser2になり、ファイル /tmp/my_file を削除:
[root@localhost ~]# su - testuser2
[testuser2@localhost ~]$ rm /tmp/my_file
rm: remove write-protected regular file ‘/tmp/my_file’? y
rm: cannot remove ‘/tmp/my_file’: Operation not permitted
果たして、/tmp ディレクトリの sticky bit のお陰で、ファイル削除に失敗した。
めでたし。

3.3. ウォッチの解除

監査ログを見る前に、これ以上ログが増えないよう、念の為にルールを削除しておく。
[root@localhost ~]# auditctl -d exit,always -F dir=/tmp -F perm=rwxa -F success=0 -k access_fail

[root@localhost ~]# auditctl -l
No rules

3.4. 監査ログの検査

監査ログを詳しく見てみる。
[root@localhost ~]# ausearch -i -k access_fail
----
type=CONFIG_CHANGE msg=audit(10/25/2014 22:02:24.220:423) : auid=root ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op="add rule" key=access_fail list=exit res=yes
----
type=PATH msg=audit(10/25/2014 22:10:57.528:439) : item=1 name=/tmp/my_file inode=100957948 dev=08:02 mode=file,664 ouid=testuser1 ogid=testuser1 rdev=00:00 obj=unconfined_u:object_r:user_tmp_t:s0 objtype=DELETE
type=PATH msg=audit(10/25/2014 22:10:57.528:439) : item=0 name=/tmp/ inode=100663425 dev=08:02 mode=dir,sticky,777 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:tmp_t:s0 objtype=PARENT
type=CWD msg=audit(10/25/2014 22:10:57.528:439) :  cwd=/home/testuser2
type=SYSCALL msg=audit(10/25/2014 22:10:57.528:439) : arch=x86_64 syscall=unlinkat success=no exit=-1(Operation not permitted) a0=0xffffffffffffff9c a1=0x62b0c0 a2=0x0 a3=0x7fff0ab0eb40 items=2 ppid=7754 pid=7776 auid=root uid=testuser2 gid=testuser2 euid=testuser2 suid=testuser2 fsuid=testuser2 egid=testuser2 sgid=testuser2 fsgid=testuser2 tty=pts0 ses=1 comm=rm exe=/usr/bin/rm subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=access_fail
ちゃんとログがとれている模様。
かなりドッサリだけれども、---- で仕切られた一塊が、イベント1つに相当。
1つ目のイベントは「ルールが設定された」と言っているだけ。
2つ目のイベントを詳しくみる。

1行目

まず、1行目をわかりやすく分解してみた。
type=PATH
msg=audit(10/25/2014 22:10:57.528:439) :
item=1
name=/tmp/my_file inode=100957948 dev=08:02 mode=file,664
ouid=testuser1 ogid=testuser1 rdev=00:00
obj=unconfined_u:object_r:user_tmp_t:s0
objtype=DELETE
msg=audit(10/25/2014 22:10:57.528:439) は、イベント発生時刻と、イベントのシリアル番号 439。続く3行のシリアル番号も 439 なので、同じイベントの一部だと判断できる。
name=/tmp/my_fileから、問題ファイルのパス /tmp/my_file が判る。もしパス情報が利用できない場合、inode番号 100957948 から、”find /tmp -inum 100957948” という風に見つけることもできる。
ouidやogidは、ファイル所有者と所有グループ。testuser1:testuser1 になっている。
objはSELinux関連の情報。

2行目

親ディレクトリの情報。
type=PATH
msg=audit(10/25/2014 22:10:57.528:439) :
item=0
name=/tmp/ inode=100663425 dev=08:02 mode=dir,sticky,777
ouid=root ogid=root rdev=00:00
obj=system_u:object_r:tmp_t:s0
objtype=PARENT
mode=dir,sticky,777から、/tmp には sticky bit がついているようだ。
sticky bitがついていると、ディレクトリのモードが777でも、その配下のファイルは、ファイルオーナーしか削除できない。

3行目

削除しようとしたプロセスのカレントディレクトリ(CWD)の情報。
type=CWD
msg=audit(10/25/2014 22:10:57.528:439) :
cwd=/home/testuser2

4行目

実際に失敗したシステムコールと、それを呼び出したプロセスの情報。
type=SYSCALL
msg=audit(10/25/2014 22:10:57.528:439) :
arch=x86_64 syscall=unlinkat
success=no exit=-1(Operation not permitted)
a0=0xffffffffffffff9c a1=0x62b0c0 a2=0x0 a3=0x7fff0ab0eb40
items=2
ppid=7754 pid=7776
auid=root uid=testuser2 gid=testuser2 euid=testuser2 suid=testuser2
fsuid=testuser2 egid=testuser2 sgid=testuser2 fsgid=testuser2
tty=pts0 ses=1
comm=rm exe=/usr/bin/rm
subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
key=access_fail
arch=x86_64 syscall=unlinkatから、システムコールは x86_64版の unlinkat と判明。
success=no exit=-1 から、システムコールの戻り値は -1。エラー時は errno を負数にして返す決まりなので、実際は正負逆の 1 = EPERM が返却されている。ausearchの-iオプションのお陰で、カッコ内で Operation not permitted と表示されている。
a0~a3 は、このシステムコールに渡された引数。
カーネルソースから、unlinkatの関数シグニチャはこんなだと分かり:
    long sys_unlinkat(int dfd, const char __user * pathname, int flag);
この情報を元に引数の意味を解釈すると・・・
a0=0xffffffffffffff9cは、64bitの2の補数で -100 なので、第一引数には -100 が渡っている。これはカーネルヘッダーの一つ linux/include/linux/fcntl.h で定義されている AT_FDCWD に該当する。
a1=0x62b0c0 は、このプロセスのユーザ空間でのポインタアドレス。削除しようとしたファイルのパスが入っていたはず。もうプロセスは寿命を終えているで、今から内容を確認することはできない。
a2=0x0 はフラグ。値0。
すなわち、以下の呼出しがあり、戻り値は EPERM だったと判明する。
    sys_unlinkat(AT_FDCWD, 0x62 b0c0, 0) = -1  ※EPERM
横道にそれるけれど、sys_unlinkat() は、カーネルのVFSのソースコード linux/fs/namei.c に定義がある。
ppid=7754 pid=7776 は、EPERM をもらったプロセスのPIDとPPID。
tty=pts0は、このプロセスが動作していた擬似端末(今回のテストではSSHでログインしたから pts 系)。ログインセッションの履歴をたどれば、どこから誰が操作したかも追跡できる可能性が高い。
exe=/usr/bin/rmは、このプロセスを生成した実行ファイルが /usr/bin/rmだと言っている。

4. まとめ

Auditdを利用すると、以下の様な情報を、アプリ実行中に、簡単に取得できる。
  • エラーの発生時刻はいつか
  • エラーが発生したファイルはどれか
  • その理由は何だったか
  • どのプロセスがエラーを受けたか
  • どのログインセッションから生成されたプロセスなのか
また、ファイル置換(inode番号が変化)や、特定ファイルをピンポイントで監視するなどにも対応しており、痒いところに手が届くツールとなっている。
今回はファイル操作についてまとめたけれど、auditは他にも様々な使い方ができる。
使いこなせば、大変お役立ちなツールと思う。

参考ドキュメント


今日はここまで。

CentOS7のVMwareイメージを作成

CentOS7が7月7日にリリースされた。
これまでLinux系のテスト他は、CentOS6.5のVMwareイメージでやっていたのだけれど、ようやく CentOS7 のイメージも作成したので、その時のメモ。
関連して、RHEL7系のNIC port名の決定ルールも記載しておく。

大まかな流れ

  1. 最小構成の仮想マシンを作成
  2. 準仮想化ドライバ向けマシン設定(SCSIとNIC)
  3. CentOS7のインストール
  4. 不要パッケージの削りこみ
  5. アップデート
  6. NIC port名を旧仕様(ethN)に戻す
  7. VMware Tools のインストール
  8. 公開鍵の登録
  9. 仮想マシンの調整とテンプレート化

NIC port名について

CentOS7では、Systemdとudevの仕組みによって、ハードウェア情報からNIC port名(eth0など)を固定的に決めている。
一方、VMをクローンすると、普通は仮想NICのMACアドレスが変化する。そうしないと、クローンしたVM間で通信できないから。
すると、CentOS7のデフォルト動作では、仮想NICとNIC設定ファイル(/etc/sysconfig/network-scripts/ifcfg-eno16780032など)の対応関係が取れなくなり、NICにIPアドレスが設定されない、といったことになる。
対策は色々と考えられるけど、今回は単純にNIC port名を旧仕様に戻すことにした。
そうすれば、最初に見つけたNIC port に対して昔ながらのeth0というNIC Port名が使われ、”DEVICE=eth0” の指定を持つ設定ファイルを単純に参照するようになる。
仮想NICは、勝手に壊れることはないので、今回の利用目的には十分。

ダウンロードISO

以下のサイトにあるミラーから、ISOファイルを取得。
その他、こんなISOイメージもあるけれど
ISO 内容物
CentOS-7.0-1406-x86_64-DVD.iso インストーラがインストールできる全パッケージを含む
CentOS-7.0-1406-x86_64-Everything.iso インストーラが直接インストールできないパッケージも含む
足りないパッケージは必要に応じて yum すれば良いので、今回は Minimal を使う。

CentOS7 リリースメモ(参考)

以下の場所にあり。

1. 最小構成の仮想マシンを作成

以下の構成で作成。さくらのマイクロサーバやAmazon EC2のt2.microと同じ程度。
要素 補足
CPU プロセッサ数1、コア数1 後で増やせる
メモリ 1GB 普通に使えるレベルの最少値
HDD 20GB SCSI 5GBでもインストールは可能
手順の詳細:
  1. 新規仮想マシン作成ウィザード
    “カスタム(C) (上級)” を選択
  2. 仮想マシンのハードウェア互換性の選択
    “Workstation 10.0” を選択(デフォルト)
  3. ゲストOSのインストール
    インストーラディスクイメージファイル(M)(iso):
    ダウンロードしたファイル “CentOS-7.0-1406-x86_64-Minimal.iso” を選択
  4. ゲストOSの選択
    Linux|”Red Hat Enterprise Linux 6 64 ビット” を選択(CentOS7推奨値)
  5. 仮想マシンの名前
    “CentOS7 x86_64 Micro Basic Server” と入力
    VMイメージの格納場所も指定
  6. プロセッサ構成
    プロセッサ数(P): “1”、プロセッサごとのコアの数(C): “1” を選択
  7. 仮想マシンのメモリ
    “1024MB” を指定
  8. ネットワークの種類
    “NATを使用(E)” を選択
  9. I/Oコントローラタイプの選択
    “LSI Logic(L) (推奨)” を選択
  10. ディスクタイプの選択
    “SCSI(S) (推奨)” を選択
  11. ディスクの選択
    “仮想ディスクの新規作成(V)” を選択
  12. ディスク容量の指定
    • ディスク最大サイズ(GB)(S): “20.0GB” を指定(VMwareによる推奨値)
    • 今すぐ全ディスク容量を割り当てる(A) をチェック
    • 仮想ディスクを単一ファイルとして格納(O) を選択
  13. ディスクファイルの指定
    デフォルトでOK
  14. 仮想マシンを作成する準備完了
    「ハードウェアをカスタマイズ(C)…」ボタンをクリック
  15. ハードウェア
    • プロセッサ|”Intel VT-x/EPTまたはAMD-V/RVIを仮想化(V)” をチェック
    • プロセッサ|”CPUパフォーマンスカウンタを仮想化(U)” をチェック
    • USBコントローラ|削除
    • サウンドカード|削除
    • プリンタ|削除
    • ディスプレイ|”3Dグラフィックのアクセラレーション(3)” をチェック
以上で仮想マシンを作成完了。
一旦、VMware Workstation を閉じる。

2. 準仮想化ドライバ向けマシン設定

SCSIとNICに準仮想化ドライバ(Paravirtual Driver)を利用するため、仮想マシンのコントローラの種類を変える。
VMware Workstationでは、GUIによる変更はできないため、直接エディタで変更する。
編集するファイルは、作成したVMイメージの格納ディレクトリ内にある vmx ファイル。
前述の手順の通りなら、ファイル名はこれ。
  • “CentOS7 x86_64 Micro Basic Server.vmx”
変更は2点(イメージのオレンジ色部分)
- scsi0.virtualDev = "lsilogic"
+ scsi0.virtualDev = "pvscsi"
- ethernet0.virtualDev = "e1000"
+ ethernet0.virtualDev = "vmxnet3"

3. CentOS7のインストール

仮想マシンをPower Onして、CentOS7のインストールを開始。
  • Language: “English” を選択
  • DATE&TIME: “Asia/Tokyo timezone” を選択
  • KEYBOARD: “Japanese(OADG 109A)” を選択
  • INSTALLATION DESTINATION
    • Local Standard Disks: “VMware, VMware Virtual S” をチェック
    • Other Storage Options: “I will configure partitioning” を選択
Doneを選ぶと、パーティション作成画面に入る。以下のように切る。
  • New mount points will use the following partitioning scheme
    “Standard Partition” を選択
  • 「+」ボタンでパーティションを入力
Mount Point Desired Capacity
swap 1GB
/boot 1GB
/ 空欄(=残り全部)
その後「Done」ボタン→「Accept Changes」ボタン→「Begin Installation」ボタンへ。
インストールは1~2分で完了(速い!)。その間に”Root Password”を入力しておく。
Rebootボタンを押すと、約10秒ほどで再起動した。CentOS6と較べて、速いね!

起動確認

rootでログインし、SCSIとNICに、ちゃんと準仮想化ドライバが利用されているか確認。
[root@localhost ~]# dmesg | egrep 'vmx|pv|SCSI'
[    0.312693] SCSI subsystem initialized
[    0.612189] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 252)
[    0.876010] VMware PVSCSI driver - version 1.0.2.0-k
[    0.876321] vmw_pvscsi: using 64bit dma
[    0.905027] vmw_pvscsi 0000:03:00.0: vmw_pvscsi: host->max_id: 16
[    0.905462] vmw_pvscsi 0000:03:00.0: irq 73 for MSI/MSI-X
[    0.905541] vmw_pvscsi: using MSI-X
[    0.905621] scsi0 : VMware PVSCSI storage adapter rev 2, req/cmp/msg rings: 8/8/1 pages, cmd_per_lun=64
[    0.905826] vmw_pvscsi 0000:03:00.0: VMware PVSCSI rev 2 host #0
[    1.046887] sd 0:0:0:0: [sda] Attached SCSI disk
[    5.055713] VMware vmxnet3 virtual NIC driver - version 1.1.30.0-k-NAPI
[    5.055822] vmxnet3 0000:0b:00.0: # of Tx queues : 1, # of Rx queues : 1
[    5.073693] vmxnet3 0000:0b:00.0: irq 76 for MSI/MSI-X
[    5.073776] vmxnet3 0000:0b:00.0: irq 77 for MSI/MSI-X
[    5.074981] vmxnet3 0000:0b:00.0 eth0: NIC Link is Up 10000 Mbps
[   10.387881] vmxnet3 0000:0b:00.0 eno16777728: intr type 3, mode 0, 2 vectors allocated
[   10.388222] vmxnet3 0000:0b:00.0 eno16777728: NIC Link is Up 10000 Mbps
vmxファイルを編集したとおり、pvscsiとvmxnet3になっている。
この時点で、Root領域(”/“ パーティション)の使用量は 800MB 程度だった。Mininalはさすがに小さい。

4. 不要パッケージの削りこみ

この仮想マシンでは使わないパッケージを削除。
削ったパッケージは、もし必要になったら、その段階で yum で組み込むことにする。

4.1. kdump

kexec-tools(kdump)は、メモリを1GBに設定したのと(=1GB以下だとデフォルトでは無効化されている)、たぶんカーネルダンプを見ることは、しばらく無いので削除。
[root@localhost ~]# rpm -e iprutils alsa-tools-firmware alsa-lib alsa-firmware btrfs-progs fxload-2002_04_11 postfix kexec-tools biosdevname

4.2. NetworkManager

CentOS7で導入された NetworkManager も、当面利用しないので削除してしまう。
関連パッケージは意外に多い。
[root@localhost ~]# rpm -e NetworkManager NetworkManager-tui NetworkManager-glib avahi avahi-libs avahi-autoipd dnsmasq gsettings-desktop-schemas glib-networking libsoup ModemManager-glib ppp

5. アップデート

先週水曜の 9/24 に、20年モノの、とっても怖いBashバグ Shellshock が公表された。今後もいつ何が公表されるかわからないし、OSインストールした後は、必ずアップデートもしておく。

5.1. IPアドレスの仮設定

下準備として、IPアドレスを仮設定する。
まず、NIC port名を調べる。
[root@localhost ~]# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno16777728: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
NIC port名は eno16777728 (enはEtherNet、oはOn-board、数字は様々)なので、これに仮IPを設定する。デフォルトゲートウェイとDNSサーバも。
[root@localhost ~]# ip addr add 192.168.170.64/24 dev eno16777728
[root@localhost ~]# ip route add default via 192.168.170.2
[root@localhost ~]# echo "nameserver 192.168.170.2" > /etc/resolv.conf
導通確認:
[root@localhost ~]# curl -s --get http://www.google.co.jp | head -1 | cut -b-70
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage"

5.2. yum update

[root@localhost ~]# yum update
...
Install   1 Package
Upgrade  61 Packages

Total download size: 88 M
Is this ok [y/d/N]: y
...
Importing GPG key 0xF4A80EB5:
 Userid     : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
 Fingerprint: 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5
 Package    : centos-release-7-0.1406.el7.centos.2.3.x86_64 (@anaconda)
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Is this ok [y/N]: y
...
Complete!

おまけ1:カーネル

新カーネル kernel-3.10.0-123.8.1.el7.x86_64 もインストールされた。
[root@localhost ~]# rpm -q kernel
kernel-3.10.0-123.el7.x86_64
kernel-3.10.0-123.8.1.el7.x86_64

おまけ2: Shellshock

Shellshockもパッチがあたった(10/1時点では、水平展開中なので完全Fix版ではないらしい)
Bashのチェンジログ:
[root@localhost ~]# rpm -q --changelog bash | head
* Thu Sep 25 2014 Ondrej Oprala <ooprala@redhat.com> - 4.2.45-5.4
- CVE-2014-7169
  Resolves: #1146324

* Thu Sep 25 2014 Ondrej Oprala <ooprala@redhat.com> - 4.2.45-5.3
- amend patch to match upstream's
  Related: #1146324

* Mon Sep 15 2014 Ondrej Oprala <ooprala@redhat.com - 4.2.45-5.2
- Fix-up the patch
実際にバグを試してみると…
アップデート前のBashの動作:
[root@localhost ~]# env x='(){ :;};echo Vulnerable' bash -c "echo this is a test"
Vulnerable
this is a test
アップデート後のBashの動作:
[root@localhost ~]# env x='(){ :;};echo Vulnerable' bash -c "echo this is a test"
this is a test
“Vulnerable” という文字列が表示されなくなって、無事に修正された。

6. NIC port名を旧仕様に戻す

やることは3つ。
  • /etc/default/grubを編集して “net.ifnames=0” をカーネルに渡す
  • /etc/sysconfig/network-scripts/ifcfg-eth0 を作成する
  • 再起動して動作を確認

6.1. /etc/default/grubを編集

以下のように変更した。”net.ifnames=0” を渡す。ついでに “rhgb” も削除している。
--- grub.bak    2014-10-01 18:47:06.089423340 +0900
+++ /etc/default/grub   2014-10-01 18:47:23.068425001 +0900
@@ -5,3 +5,3 @@
 GRUB_TERMINAL_OUTPUT="console"
-GRUB_CMDLINE_LINUX="vconsole.keymap=jp106 crashkernel=auto  vconsole.font=latarcyrheb-sun16 rhgb quiet"
+GRUB_CMDLINE_LINUX="vconsole.keymap=jp106 crashkernel=auto  vconsole.font=latarcyrheb-sun16 net.ifnames=0 quiet"
 GRUB_DISABLE_RECOVERY="true"
initramfsへ反映。grub2-mkconfigコマンドを使う。
[root@localhost ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-123.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-123.el7.x86_64.img
Found linux image: /boot/vmlinuz-3.10.0-123.8.1.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-123.8.1.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-5a1329a865ac45aa959bb41cf24662cf
Found initrd image: /boot/initramfs-0-rescue-5a1329a865ac45aa959bb41cf24662cf.img
done

6.2. ifcfg-eth0 を作成

/etc/sysconfig/network-scripts/ifcfg-eth0 を作成する。
[root@localhost ~]# cat > /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF
TYPE=Ethernet
DEVICE="eth0"
BOOTPROTO=static
ONBOOT=yes
IPADDR=192.168.170.64
NETMASK=255.255.255.0
GATEWAY=192.168.170.2
EOF

6.3. 再起動して動作確認

仮想マシンを “shutdown -r now” で再起動し、rootで再びログイン。

新カーネル(ついで)

せっかく再起動するので、grub のブート画面で新カーネルを選び、新カーネルが起動できることも確認。
[root@localhost ~]# uname -r
3.10.0-123.8.1.el7.x86_64
特にエラーなどなければ、旧カーネルは削除。
[root@localhost ~]# rpm -e kernel-3.10.0-123.el7.x86_64

syslog

/var/log/messagesに変なエラーが出ていないことを確認。特に eth 周り。

NIC port名、通信

設定の反映状況の確認と、導通確認する。
[root@localhost ~]# ip addr show | grep eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.170.64/24 brd 192.168.170.255 scope global eth0

[root@localhost ~]# curl -s --get http://www.google.co.jp | head -1 | cut -b-70
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage"
www.google.co.jp からデータを取ってこれている。

クローン後の通信(気になる場合)

この仮想マシンを一旦落とし、VMware で仮想マシンをクローンして、同じIPアドレスで同様に通信できることを確認。

6.4. NIC port命名ルール(補足)

RHEL7では、次のようにNIC port名は決まる仕様とのこと。
1から順に、どれかのルールに該当したら命名が完了する。
  1. もし ifcfg-xxxx に HWADDR 指定があり、NICのMACアドレスとマッチすれば、そのファイルの DEVICE に指定した名前になる。ファイル名の xxxx 部分は何でもOK
    • 関連ファイル /usr/lib/udev/rules.d/60-net.rules
  2. もし kernel cmdline に biosdevname=0 の指定がなく、かつ “biosdevname” コマンドの結果を利用できるなら、その結果が名前となる
    • 関連ファイル /usr/lib/udev/rules.d/71-biosdevname.rules
  3. もし kernel cmdline に net.ifnames=0 の指定がないなら、変数ID_NET_{ONBOARD, SLOT, PATH} をこの順に見て、値があれば、その名前になる
    • 関連ファイル
      /usr/lib/udev/rules.d/75-net-description.rules
      /usr/lib/udev/rules.d/80-net-name-slot.rules
  4. 以上のどれにも該当しなければ、昔ながらの ethN を使う。
今回、ifcfg-eth0 に HWADDR を書いておらず(ルール1適用外)、biosdevname をアンインストールしており(ルール2適用外)、kernel cmdlineに net.ifnames=0 を指定したから(ルール3適用外)、結局、NIC port名は eth0 となった。
ルール3で使われる変数の値は、以下のように調べることができる。
[root@localhost ~]# ls /sys/class/net/ | while read f
> do { echo "$f:"; udevadm info /sys/class/net/$f|grep ID_NET_; } done
eno16777728:
E: ID_NET_LABEL_ONBOARD=enEthernet0
E: ID_NET_NAME_MAC=enx000c299129d8
E: ID_NET_NAME_ONBOARD=eno16777728
E: ID_NET_NAME_PATH=enp2s0
E: ID_NET_NAME_SLOT=ens32
lo:
参考にした資料は以下。udevルールを工夫すると、もっと色々とできるみたい。
CentOS6.5の実装(70-persistent-net.rules)より、筋が良くなっていると思う。

7. VMware Tools のインストール

VMware Workstation “10.0.3 build-1895310” が提供する VMware Tools は、RHEL7 に対応していない(今後も対応するのか不明)。
以下の公式ページをみると、Open-vmware-toolsを使えとのこと。
また、次のページのFAQには、各OSディストリビューションに含まれるものを使えば良いとあるので、yumで入れる。

7.1. yumでインストール

[root@localhost ~]# yum install open-vm-tools
...
================================================================================
 Package               Arch           Version                Repository    Size
================================================================================
Installing:
 open-vm-tools         x86_64         9.4.0-3.el7            base         429 k
Installing for dependencies:
 libdnet               x86_64         1.12-13.1.el7          base          31 k
 libicu                x86_64         50.1.2-11.el7          base         6.9 M
...
Total download size: 7.3 M
Installed size: 25 M
Is this ok [y/d/N]: y
...
Complete!
インストール完了!
systemctl status vmtoolsd でサービスを確認できる。

7.2. パワーオン スクリプトが正常に実行されません

しかし今度は、仮想マシンの起動時に以下のメッセージで怒られるようになる。
この仮想マシンで VMware Tools パワーオン スクリプトが正常に実行されませんでした。カスタム パワーオン スクリプトをこの仮想マシンで構成している場合は、スクリプトにエラーがないことを確認してください。サポート リクエストを提出してこの問題を報告することもできます。
この辺りを参考に調べると、ifconfig コマンドが存在しないことが原因↓と判明。
[root@localhost ~]# /etc/vmware-tools/poweron-vm-default
Wed Oct 1 12:01:55 JST 2014 : Executing '/etc/vmware-tools/poweron-vm-default'
Wed Oct 1 12:01:55 JST 2014 : Executing '/etc/vmware-tools/scripts/vmware/network'

Oct 01 12:01:55 network: ifconfig not in search path.
それはそうだ、CentOS7だもん。
準仮想化ドライバを導入した時のように、vmxファイルを編集して、機能を無効化できるようだけど、今回は素直に ifconfig コマンド(net-tools)を入れます。
[root@localhost ~]# yum install net-tools
...
Total download size: 304 k
Installed size: 917 k
Is this ok [y/d/N]: y
...
Installed:
  net-tools.x86_64 0:2.0-0.17.20131004git.el7

Complete!
今度は、同じスクリプトでエラーがでなくなった。OS起動での文句も無くなった。
[root@localhost ~]# /etc/vmware-tools/poweron-vm-default
Wed Oct 1 12:07:16 JST 2014 : Executing '/etc/vmware-tools/poweron-vm-default'
Wed Oct 1 12:07:16 JST 2014 : Executing '/etc/vmware-tools/scripts/vmware/network'

8. 公開鍵の登録

この仮想マシンはテンプレート化するので、クローンしたもの全て、手元の秘密鍵でログインできるようにし、今後のSSHログインを簡単にする。
SSHクライアントの公開鍵を転送して ~/.ssh/authorized_keys に登録しておく。
終わったら shutdown -h now でOSを落とす。

9. 仮想マシンの調整とテンプレート化

仮想マシンの最終調整をして、テンプレート化する。
  • ハードウェア|CD/DVD(SATA)
    “起動時に接続(O)”をチェックOFF、物理ドライブを使用する(P):”自動検出” を選択
  • ハードウェア|ディスプレイ
    モニタ設定を指定(S):各モニタの最大解像度(N): 640x480
    ※ ほとんどリモートログインでしか利用しないので。
  • オプション|VMware Tools
    “ホストとゲスト時間を同期(S)”をチェック
  • オプション|詳細
    デバッグ情報を収集(O): “なし”
    “クローン作成に使用するテンプレートモードを有効にする(T)”をチェック
VMware WorkstationのUIを使い、テンプレートとなるスナップショットを作成する。
Ctrl-Mからスナップショットマネージャを起動。スナップショット名は「OS基本設定済み2014/10/1」など。詳細にはIPアドレスなどを書いておく。
以上で、クローンして直ぐ使えるイメージができた。大団円。