OCIでKspliceを使う Part2

前回「[OCIでKspliceを使う Part1](https://qiita.com/yamada-hakase/items/81b3331e79d59b947509)」の続き。

# 本題に入る前に
唐突だが

**「カーネルをアップデートすると、既存のアプリケーションの動作が不安だ」**

と思っている人もいるのではないだろうか。

**「まったくの杞憂である」と声を大にして言いたい。**

なぜならばカーネルはハードウェアやOSプロセスを管理するものであって、（ユーザ空間で稼働する）アプリケーションの動作には直接関係しないからだ。

**アプリケーションの動作にもっとも影響するのはglibcをはじめとするコアライブラリ群である。**

だからこそOracle LinuxはUEKとRHCKという、まったくベースバージョンの異なるLinuxカーネルを使っているにもかかわらず、ユーザ空間アプリケーションのABI（Application Binary Interface）互換性を保っているのだ。

長年実積のあるテクノロジーだし、技術的にもアプリケーションの動作に直接影響しないので、不安がらずに使って欲しい。とはいえソフトウェアなので「Kspliceのバグによる障害は100%無い」とは言い切れないのだが．．．。

# Kspliceのコマンドを使いこなす

前回はUptrackクライアントを使ってアップデートを適用した。そこからの話を続けたい。

### 適用済みのアップデートを確認する

現在適用済みのKspliceのアップデートを確認する。```Installed updates:```以下に適用されているアップデートが表示される。各行先頭の```[xxxxxxxx]```という記号はアップデートごとに割り当てられているIDで、このIDを使ってアップデートを個別に適用できる。

```shell-session
# uptrack-show
Installed updates:
[jqu0nve5] Add support for runtime configuration of target LIO inquiry strings.
[q5v4oo0p] Denial-of-service in the Infiniband core driver when allocating protection domains.
★中略
[oehos3cn] Known exploit detection.
[s8jh2mwf] Known exploit detection for CVE-2017-7308.
[dcgq70uq] Known exploit detection for CVE-2018-14634.

Effective kernel version is 4.14.35-1844.4.5.2.el7uek
```

### 適用したアップデートを削除する

適用したアップデートは動的に削除することもできる。```-y```オプションを付けると最後の質問が表示されず、そのまま実行される。

```shell-session
# uptrack-remove --all
The following steps will be taken:
Remove [dcgq70uq] Known exploit detection for CVE-2018-14634.
Remove [s8jh2mwf] Known exploit detection for CVE-2017-7308.
Remove [oehos3cn] Known exploit detection.
★中略★
Remove [jqu0nve5] Add support for runtime configuration of target LIO inquiry strings.

Go ahead [y/N]?★yかNを入力
```

アップデートを削除したので、カーネルバージョンは元に戻っている。

```shell-session
# uptrack-uname -r
4.14.35-1844.3.2.el7uek.x86_64

# uname -r
4.14.35-1844.3.2.el7uek.x86_64
```

### 個別のアップデートを適用する

いままでは適用可能なアップデートをすべて適用してきたが、`uptrack-install`を使うと個別にアップデートを適用できる。また前述の`uptrack-remove`では個別削除できる。

```shell-session
# uptrack-install jqu0nve5 -y
The following steps will be taken:
Install [jqu0nve5] Add support for runtime configuration of target LIO inquiry strings.
Installing [jqu0nve5] Add support for runtime configuration of target LIO inquiry strings.
Effective kernel version is 4.14.35-1844.3.2.el7uek
```

念のために確認すると、個別に適用したアップデートが表示された。

```shell-session
# uptrack-show
Installed updates:
[jqu0nve5] Add support for runtime configuration of target LIO inquiry strings.

Effective kernel version is 4.14.35-1844.3.2.el7uek
```

# 設定ファイルを調べる

[Part1](https://qiita.com/yamada-hakase/items/81b3331e79d59b947509)ではKspliceの設定ファイルの中身を見たが、今回はパラメータの意味を説明する。

###  /etc/uptrack/uptrack.confの内容

こちらがデフォルトの設定ファイルの中身である。インストール環境によって少し違いがあるかもしれない。

```shell-session
$ grep -v -e '^\s*#' -e '^\s*$' /etc/uptrack/uptrack.conf
--ここから下が出力--
[Auth]
accesskey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx（意図的に伏せ字）
[Network]
https_proxy =
gconf_proxy_lookup = no
update_repo_url=https://oraclecloud-updates-ksplice.oracle.com/update-repository
user_update_repo_url=https://oraclecloud-updates-ksplice.oracle.com/ksplice/request
[Settings]
install_on_reboot = yes
autoinstall = no
```

### 重要なパラメータ
この中でも重要なパラメータは以下の通り。マニュアル以外にも、パラメータファイル内にコメントで説明が書かれている。

| パラメータ | デフォルト値 | 説明
|:----------|:------------:|:------------
| https_proxy | なし | Internetへのアクセス経路にプロキシがあるときには指定する。ポート8080のプロキシを指定するなら次のように指定する。```https_proxy = http://proxy.example.com:8080/```|
| autoinstall | no | 利用できるようになったアップデートを自動的に適用する。ただしKspliceのクライアントは自動的にアップデートされないので、yum-cron等で自動アップデートすることを推奨 |
| install_on_reboot | yes | リブート時に前回適用した分までのアップデートを適用する。 |
| upgrade_on_reboot | no | リブート時に適用可能なすべてのアップデートを適用する。```install_on_reboot```とは排他の関係で、```upgrade_on_reboot = yes```にするならば、```install_on_reboot```は```no```もしくはコメントアウトする。 |

下記のデフォルト値であれば「自動適用はしないが、手動でインストールしたものはリブート時に自動適用する」ということになる。

```
install_on_reboot = yes
autoinstall = no
```

自動適用するときには、```install_on_reboot = yes```と```upgrade_on_reboot = yes```のどちらでもよいが、ブートシーケンスの最中でトラブルがあるとイヤなので次のようにしたい。さらにコンサバに行くならば```install_on_reboot = no```にして、起動してから次のcronが実行されるまでアップデートが適用されない状態にする。cronの話は後ほど。

```
install_on_reboot = yes
autoinstall = yes
```


# アップデートを自動適用する

アップデートを自動適用するには```autoinstall = yes```に変更する。デーモン系のプログラムでパラメータを変更したときには、設定を反映するために再起動などが必要だ。しかしKspliceではcronやブート時に利用しているだけなので再起動は不要である。これから、その内容を見ていくことにする。

### cronの設定を確認する

cronの設定を確認する。uptrackパッケージに含まれているcron関連のファイルを確認する。2つのファイルがあることが分かる。

```shell-session
$ rpm -ql uptrack | grep cron
/etc/cron.d/uptrack
/usr/lib/uptrack/regenerate-crontab
```

cronの起動ファイルを確認すると毎時1分と31分に```uptrack-upgrade```を実行している。他を調べると毎時3分と33分というサーバもあった。

```shell-session
$ grep -v -e '^\s*#' /etc/cron.d/uptrack ★当然catでもOK
--ここから下が出力--
1,31 * * * * root export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && [ -x /usr/sbin/uptrack-upgrade ] && /usr/sbin/uptrack-upgrade --cron
```

cronの詳細は下記資料を参考のこと。

* [7系：cron を使用した繰り返しジョブのスケジュール設定](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-Automating_System_Tasks#s1-Scheduling_a_Recurring_Job_Using_Cron)
* [6系：Cron と Anacron](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/deployment_guide/ch-Automating_System_Tasks#s1-autotasks-cron-anacron)

rpmに含まれているもう一つのファイル```/usr/lib/uptrack/regenerate-crontab```を見ると、ランダムの数字を生成しているようだ。

```shell-session
$ head -n 15 /usr/lib/uptrack/regenerate-crontab
--ここから下が出力--
#!/bin/sh

cronfile=/etc/cron.d/uptrack
# Run at a random time within 20 minutes of each half hour.
randfirst=$(($(od -An -N2 -d /dev/urandom) % 20))
randsecond=$(($randfirst + 30))
if [ -e "$cronfile" ] && \
   ! echo 5f8ac9a8816940c1e309b2e3e5bf725c '' "$cronfile" | md5sum -c --status; then
```

およその推測がついたのでrpmの```postinstall```セクションを見てみる。このセクションにはインストール終了後に実行するスクリプトが書かれている。20行目付近に```/usr/lib/uptrack/regenerate-crontab```を発見。これまでのことをまとめると、インストール時にランダムの値を生成して30分間隔で実行するように設定している。

```shell-session
$ rpm -q --scripts uptrack
--ここから下が出力--
postinstall scriptlet (using /bin/sh):
if [ $1 -eq 1 ] ; then
    # Initial installation
    /bin/systemctl daemon-reload >/dev/null 2>&1 || :
    /sbin/chkconfig --del uptrack >/dev/null 2>&1 || :
    /sbin/chkconfig --del uptrack-late >/dev/null 2>&1 || :
    /bin/systemctl mask uptrack-late.service >/dev/null 2>&1 || :
    /bin/systemctl enable uptrack.service >/dev/null 2>&1 || :
    /bin/systemctl enable uptrack-prefetch.service >/dev/null 2>&1 || :
fi
★中略★
cronfile=/etc/cron.d/uptrack
if ! [ -e "$cronfile" ] || grep -q '^\*/30' "$cronfile"; then
    /usr/lib/uptrack/regenerate-crontab ★ここで実行している
fi
```

### アップデートの自動インストールを有効化する

すでに説明したように```autoinstall = yes```に変更する。

```shell-session
# cp -p /etc/uptrack/uptrack.conf /etc/uptrack/uptrack.conf-`date +%Y%m%d`
# sed -i -e "s/^autoinstall = no/autoinstall = yes/" /etc/uptrack/uptrack.conf
```

しばらく放置してから確認する。kspliceのログ```/var/log/uptrack.log```を確認すると、cronの設定通りに毎時1分と31分に実行されていることが分かる。

```shell-session
$ grep  "Invoked by" /var/log/uptrack.log
--ここから下が出力--
2019-05-20 22:31:02,183 DEBUG    Invoked by the cron job.
2019-05-20 23:01:02,144 DEBUG    Invoked by the cron job.
2019-05-20 23:31:02,077 DEBUG    Invoked by the cron job.
2019-05-21 00:01:02,063 DEBUG    Invoked by the cron job.
```

念のためcronのログファイル```/var/log/cron```を確認する。すると02:01:01に```uptrack-upgrade```コマンドと、02:12:01に```ksplice```コマンドが実行されている。後者の```ksplice```コマンドは拡張クライアントのコマンドである。想定外の事態が発生したので「拡張クライアントも実行されるかもしれない」問題編へ。

```shell-session
# tail -n 8 /var/log/cron
May 21 02:01:01 testweb01 CROND[17215]: (root) CMD (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && [ -x /usr/sbin/uptrack-upgrade ] && /usr/sbin/uptrack-upgrade --cron) ★この行
May 21 02:01:01 testweb01 run-parts(/etc/cron.hourly)[17214]: starting 0anacron
May 21 02:01:01 testweb01 run-parts(/etc/cron.hourly)[17228]: finished 0anacron
May 21 02:01:01 testweb01 anacron[17226]: Anacron started on 2019-05-21
May 21 02:01:01 testweb01 anacron[17226]: Normal exit (0 jobs run)
May 21 02:10:01 testweb01 CROND[17297]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 21 02:12:01 testweb01 CROND[17318]: (root) CMD (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && [ -x /usr/bin/ksplice ] && (/usr/bin/ksplice --cron user upgrade; /usr/bin/ksplice --cron xen upgrade)) ★この行
```

# 拡張クライアントも実行される？

cronのファイルを調べると```uptrack```に加えて```ksplice```もある。

```shell-session
# ls -l /etc/cron.d
total 16
-rw-r--r--. 1 root root 128 Nov 20 02:22 0hourly
-rw-r--r--. 1 root root 818 May 16 01:21 ksplice  ★これ
-rw-r--r--. 1 root root 108 Oct 31  2018 raid-check
-rw-------. 1 root root 235 Aug 25  2018 sysstat
-rw-r--r--. 1 root root 747 Apr  2 10:42 uptrack
```

cronファイル```/etc/cron.d/ksplice```がどのrpmに属しているか調べると、拡張クライアントの```ksplice-tools```に含まれている。

```shell-session
# rpm -qf /etc/cron.d/ksplice
ksplice-tools-1.0.38-1.el7.x86_64
```

実行される時間を確認すると、毎時12分と42分で```/var/log/cron```のログ通り。

```shell-session
# grep -v -e '^\s*#' /etc/cron.d/ksplice   ★当然catでもOK
--ここから下が出力--
12,42 * * * * root export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && [ -x /usr/bin/ksplice ] && (/usr/bin/ksplice --cron user upgrade; /usr/bin/ksplice --cron xen upgrade)
```

本題では無いので詳細は省略するけれど、```/etc/cron.d/ksplice```の内容を実行しても、カーネルにアップデートは適用されなかった。あらためて```/etc/cron.d/ksplice```の内容をよく見ると、ユーザ空間のアップデートを適用するコマンドだった。ユーザ空間のアップデートは無効になっているので、cronジョブが実行されても何も影響は無いということらしい。フー。

```shell-session
/usr/bin/ksplice --cron user upgrade
```

# エクスプロイト実行検出機能

2019年4月からは、既知の脆弱性を突いた攻撃があったとき、それをロギングする機能が追加された。詳しくは以下のブログを見ていただくとして、設定手順を紹介する。

* [Using Ksplice To Detect Exploit Attempts](https://blogs.oracle.com/linux/using-ksplice-to-detect-exploit-attempts)

1. ksplice-known-exploit-detectionをイントールする。

```shell-session
# yum install -y ksplice-known-exploit-detection
```

2.uptrck.confの末尾に以下の2行を追加する。

```shell-session:/etc/uptrack/uptrack.conf 
[Known-Exploit-Detection]
enabled = yes
```

3.追加したパラメータを有効化するためにkspliceを実行する。

```shell-session
# ksplice kernel upgrade
```

4.有効になると、以下のようにカーネルパラメータが設定される。

```shell-session
# cat /proc/sys/kernel/known_exploit_detection
1
```

5.既知の脆弱性に対する攻撃があったときは、kspliceで適用したパッチで防御するとともに、/var/log/messagesには以下のように攻撃の痕跡が表示される。

```shell-session
Apr 02 13:36:16 ol-7-sys log-known-exploit[22360]: exploit attempt detected; id=CVE-2017-101234 pid=22358 uid=1001 comm=a.out lost=0
```

# いくつか補足事項

### Kspliceクライアントのアップデートも検討する

これまでアップデートが自動適用する方法を説明してきたが、kspliceクライアント自身は更新しない。そのため自動適用するときは、yum-cronなどで```uptrack*```や```ksplice*```に該当するパッケージを自動でアップデートすることも検討する。

* [7系:YUM-CRON を使用したパッケージデータベースの自動更新および更新のダウンロード](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/sec-automatically_refreshing_the_package_database_and_download_updates)

### yum updateでカーネルをアップデートする必要はあるか？

**Yes.**
Kspliceを有効にすると停止時間ゼロでアップデートを適用できる。しかし再起動するときには、再び累積のアップデートを適用する必要がある。数が増えるほど時間がかかり、また複雑性も増加する。

そのためOSを再起動しなくても```yum update```でカーネルも定期的にアップデートすることが推奨されている。そして何かのメンテナンスタイミングで再起動すれば、新しいカーネルが利用される。

### Kspliceがセットアップされている環境では```yum update kernel*```に時間がかかる

[Part1](https://qiita.com/yamada-hakase/items/81b3331e79d59b947509)の冒頭で少し触れたが、Kspliceが設定されている環境で```yum update kernel*```を実行すると、内部的にinitrdやinitramfsが再作成される。これは非Ksplice環境では起きない動作だ。

アップデートの最中に`top`コマンドでプロセスを確認すると、`dracut`や`gzip`、`cpio`などが活発に動作し、initrdやinitramfsが再作成されていることがわかる。

### Ksplice 30日トライアル
OCIでは追加のサポート契約なしにKspliceを利用できるが、オンプレミスなど他の環境では利用できない。30日トライアルが提供されているので、興味のあるかたは検討してはどうだろう。
https://ksplice.oracle.com/try/trial

# コマンド・リファレンス

Ksplice Uptrackクライアントのコマンド・リファレンスは以下のマニュアルを参照のこと。

* [uptrack-upgradeコマンドによるKspliceの更新の管理](https://docs.oracle.com/cd/F22978_01/oracle-linux/ksplice-user/ol_ksplice_updates.html)

マニュアルを補足すると、Kspliceを無効化するには以下のように空ファイルを作成する。するとuptrack-upgradeを実行してもアップデートはできず、また再起動時にもアップデートは適用されない。当然cronジョブも実行されない。

```shell-session
# touch /etc/uptrack/disable
```

# まとめ
**Part1**

* Kspliceを使うと、再起動しなくても新しいカーネルアップデートを適用できる
* Oracle Cloud Infrastructure Compute/Databaseでは、デフォルトでKspliceを利用できる
* KspliceはUEKとRHCKの両方で利用できる
* 操作コマンドには、uptrackクライアントと拡張クライアントという2種類のコマンドがある
* 拡張クライアントを使うとglibcとopensslも対象にできる
* Oracle Linux以外にCentOSやRHEL、Ubuntuでも利用できる。OCIの場合は追加料金不要 


**Part2**

* アップデートは手動で適用することも、自動で適用することもできる
* 適用したアップデートは削除できる
* アップデートの適用と削除は個別IDごとに指定できる
* 自動適用を有効にするとcronジョブで30分間隔で実行される
* 設定ファイルは```/etc/uptrack/uptrack.conf```のみ
* 拡張クライアントがインストールされていても、ユーザー空間アップデート用の設定を追加しない限り、適用されることは無い
* Ksplice環境ではinitrdやinitramfs再作成されるので、カーネルアップデート時に時間がかかる

# おわりに

一通り読んでみていかがだろうか。正直なところマニュアル以外の情報が少なく、最初は取っつきにくさもあった。だけれど仕組みやコマンド体系を理解すれば、シンプルなのでは無いだろうか。まあライブ・パッチング自体の仕組みは高度な実装だが利用者には関係ないことだ。

また今回は紹介していないが、拡張クライアントやSNMPプラグインなどさまざまな機能がある。興味があればそれらも調べて欲しい。