Skip to content

Commit 26be90c

Browse files
authored
Merge pull request #40274 from ystkfujii/feat/blog_2023-03-10-forensic-container-analysis
[ja]Translate blog:forensic-container-analysis into ja
2 parents 47603cc + 2985608 commit 26be90c

File tree

1 file changed

+315
-0
lines changed
  • content/ja/blog/_posts/2023-03-10-forensic-container-analysis

1 file changed

+315
-0
lines changed
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
---
2+
layout: blog
3+
title: "フォレンジックコンテナ分析"
4+
date: 2023-03-10
5+
slug: forensic-container-analysis
6+
---
7+
8+
**Authors:** Adrian Reber (Red Hat)
9+
10+
前回投稿した[Kubernetesにおけるフォレンジックコンテナチェックポイント処理][forensic-blog]では、Kubernetesでのチェックポイントの作成や、それがどのようにセットアップされ、どのように使用されるのかを紹介しました。
11+
機能の名前はフォレンジックコンテナチェックポイントですが、Kubernetesによって作成されたチェックポイントの実際の分析方法については、詳細を説明しませんでした。
12+
この記事では、チェックポイントがどのように分析されるのかについての詳細を提供します。
13+
14+
チェックポイントの作成はまだKubernetesでalpha機能であり、この記事ではその機能が将来どのように動作するのかについてのプレビューを提供します。
15+
16+
## 準備
17+
18+
チェックポイント作成のサポートを有効にするためのKubernetesの設定方法や、基盤となるCRI実装方法についての詳細は[Kubernetesにおけるフォレンジックコンテナチェックポイント処理][forensic-blog]を参照してください。
19+
20+
一例として、この記事内でチェックポイントを作成し分析するコンテナイメージ(`quay.io/adrianreber/counter:blog`)を準備しました。
21+
このコンテナはコンテナ内でファイルを作成することができ、後でチェックポイント内で探したい情報をメモリーに格納しておくこともできます。
22+
23+
コンテナを実行するためにはPodが必要であり、この例では下記のPodマニフェストを使用します。
24+
25+
```yaml
26+
apiVersion: v1
27+
kind: Pod
28+
metadata:
29+
name: counters
30+
spec:
31+
containers:
32+
- name: counter
33+
image: quay.io/adrianreber/counter:blog
34+
```
35+
36+
この結果、`counter`と呼ばれるコンテナが`counters`と呼ばれるPod内で実行されます。
37+
38+
一度コンテナが実行されると、コンテナで下記アクションが行えます。
39+
40+
```console
41+
$ kubectl get pod counters --template '{{.status.podIP}}'
42+
10.88.0.25
43+
$ curl 10.88.0.25:8088/create?test-file
44+
$ curl 10.88.0.25:8088/secret?RANDOM_1432_KEY
45+
$ curl 10.88.0.25:8088
46+
```
47+
48+
最初のアクセスはコンテナ内で`test-file`という内容で`test-file`と呼ばれるファイルを作成します。
49+
次のアクセスで、コンテナのメモリー内のどこかにシークレット情報(`RANDOM_1432_KEY`)を記憶します。
50+
最後のアクセスは内部のログファイルに1行追加するだけです。
51+
52+
チェックポイントを分析する前の最後のステップは、チェックポイントを作成することをKubernetesに指示することです。
53+
前回の記事で説明したように、これには*kubelet*限定の`チェックポイント`APIエンドポイントへのアクセスを必要とします。
54+
55+
*default*名前空間内の*counters*という名前のPod内の*counter*という名前のコンテナに対して、*kubelet* APIエンドポイントが次の場所で到達可能です。
56+
```shell
57+
# Podが実行されているNode上で実行する
58+
curl -X POST "https://localhost:10250/checkpoint/default/counters/counter"
59+
```
60+
61+
厳密には、*kubelet*の自己署名証明書を許容し*kubelet* `チェックポイント`APIの使用を認可するために、下記の`curl`コマンドのオプションが必要です。
62+
63+
```shell
64+
--insecure --cert /var/run/kubernetes/client-admin.crt --key /var/run/kubernetes/client-admin.key
65+
```
66+
67+
チェックポイントの作成が終了すると、`/var/lib/kubelet/checkpoints/checkpoint-<pod-name>_<namespace-name>-<container-name>-<timestamp>.tar`でチェックポイントが利用可能になります。
68+
69+
この記事の後述のステップでは、チェックポイントアーカイブを分析する際に`checkpoint.tar`という名前を使用します。
70+
71+
## `checkpointctl`を使用したチェックポイントアーカイブの分析
72+
73+
チェックポイントが作成したコンテナに関するいくつかの初期情報を得るためには、このように[checkpointctl][checkpointctl]を使用します。
74+
75+
```console
76+
$ checkpointctl show checkpoint.tar --print-stats
77+
+-----------+----------------------------------+--------------+---------+---------------------+--------+------------+------------+-------------------+
78+
| CONTAINER | IMAGE | ID | RUNTIME | CREATED | ENGINE | IP | CHKPT SIZE | ROOT FS DIFF SIZE |
79+
+-----------+----------------------------------+--------------+---------+---------------------+--------+------------+------------+-------------------+
80+
| counter | quay.io/adrianreber/counter:blog | 059a219a22e5 | runc | 2023-03-02T06:06:49 | CRI-O | 10.88.0.23 | 8.6 MiB | 3.0 KiB |
81+
+-----------+----------------------------------+--------------+---------+---------------------+--------+------------+------------+-------------------+
82+
CRIU dump statistics
83+
+---------------+-------------+--------------+---------------+---------------+---------------+
84+
| FREEZING TIME | FROZEN TIME | MEMDUMP TIME | MEMWRITE TIME | PAGES SCANNED | PAGES WRITTEN |
85+
+---------------+-------------+--------------+---------------+---------------+---------------+
86+
| 100809 us | 119627 us | 11602 us | 7379 us | 7800 | 2198 |
87+
+---------------+-------------+--------------+---------------+---------------+---------------+
88+
```
89+
90+
これによって、チェックポイントアーカイブ内のチェックポイントについてのいくつかの情報が、すでに取得できています。
91+
コンテナの名前やコンテナランタイムやコンテナエンジンについての情報を見ることができます。
92+
チェックポイントのサイズ(`CHKPT SIZE`)もリスト化されます。
93+
これは大部分がチェックポイントに含まれるメモリーページのサイズですが、コンテナ内の全ての変更されたファイルのサイズ(`ROOT FS DIFF SIZE`)についての情報もあります。
94+
95+
追加のパラメーター`--print-stats`はチェックポイントアーカイブ内の情報を復号化し、2番目のテーブル(*CRIU dump statistics*)で表示します。
96+
この情報はチェックポイント作成中に収集され、CRIUがコンテナ内のプロセスをチェックポイントするために必要な時間と、チェックポイント作成中に分析され書き込まれたメモリーページ数の概要を示します。
97+
98+
## より深く掘り下げる
99+
100+
`checkpointctl`の助けを借りて、チェックポイントアーカイブについてのハイレベルな情報を得ることができます。
101+
チェックポイントアーカイブをさらに分析するには、それを展開する必要があります。
102+
チェックポイントアーカイブは*tar*アーカイブであり、`tar xf checkpoint.tar`の助けを借りて展開可能です。
103+
104+
チェックポイントアーカイブを展開すると、下記のファイルやディレクトリが作成されます。
105+
106+
* `bind.mounts` - このファイルにはバインドマウントについての情報が含まれており、復元中に全ての外部ファイルとディレクトリを正しい場所にマウントするために必要になります。
107+
* `checkpoint/` - このディレクトリにはCRIUによって作成された実際のチェックポイントが含まれています。
108+
* `config.dump`と`spec.dump` - これらのファイルには、復元中に必要とされるコンテナについてのメタデータが含まれています。
109+
* `dump.log` - このファイルにはチェックポイント作成中に作成されたCRIUのデバッグ出力が含まれています。
110+
* `stats-dump` - このファイルには、`checkpointctl`が`--print-stats`でダンプ統計情報を表示するために使用するデータが含まれています。
111+
* `rootfs-diff.tar` - このファイルには、コンテナのファイルシステム上で変更された全てのファイルが含まれています。
112+
113+
### ファイルシステムの変更 - `rootfs-diff.tar`
114+
115+
コンテナのチェックポイントをさらに分析するための最初のステップは、コンテナ内で変更されたファイルを見ることです。
116+
これは`rootfs-diff.tar`ファイルを参照することで行えます。
117+
118+
```console
119+
$ tar xvf rootfs-diff.tar
120+
home/counter/logfile
121+
home/counter/test-file
122+
```
123+
124+
これでコンテナ内で変更されたファイルを調べられます。
125+
126+
```console
127+
$ cat home/counter/logfile
128+
10.88.0.1 - - [02/Mar/2023 06:07:29] "GET /create?test-file HTTP/1.1" 200 -
129+
10.88.0.1 - - [02/Mar/2023 06:07:40] "GET /secret?RANDOM_1432_KEY HTTP/1.1" 200 -
130+
10.88.0.1 - - [02/Mar/2023 06:07:43] "GET / HTTP/1.1" 200 -
131+
$ cat home/counter/test-file
132+
test-file 
133+
```
134+
135+
このコンテナのベースになっているコンテナイメージ(`quay.io/adrianreber/counter:blog`)と比較すると、コンテナが提供するサービスへの全てのアクセス情報を含んだ`logfile`や予想通り作成された`test-file`ファイルを確認することができます。
136+
137+
`rootfs-diff.tar`の助けを借りることで、作成または変更された全てのファイルを、コンテナのベースイメージと比較して検査することが可能です。
138+
139+
### チェックポイント処理したプロセスを分析する - `checkpoint/`
140+
141+
ディレクトリ`checkpoint/`はコンテナ内でプロセスをチェックポイントしている間にCRIUによって作成されたデータを含んでいます。
142+
ディレクトリ`checkpoint/`の内容は、CRIUの一部として配布されている[CRIT][crit]ツールを使用して分析できるさまざまな[イメージファイル][image-files]で構成されています。
143+
144+
まず、コンテナの内部プロセスの概要を取得してみましょう。
145+
146+
```console
147+
$ crit show checkpoint/pstree.img | jq .entries[].pid
148+
1
149+
7
150+
8
151+
```
152+
153+
この出力はコンテナのPID名前空間の内部に3つのプロセス(PIDが1と7と8)があることを意味しています。
154+
155+
これはコンテナのPID名前空間の内部からの視界を表示しているだけです。
156+
復元中に正確にそれらのPIDが再作成されます。
157+
コンテナのPID名前空間の外部からPIDは復元後に変更されます。
158+
159+
次のステップは、それらの3つのプロセスについての追加情報を取得することです。
160+
161+
```console
162+
$ crit show checkpoint/core-1.img | jq .entries[0].tc.comm
163+
"bash"
164+
$ crit show checkpoint/core-7.img | jq .entries[0].tc.comm
165+
"counter.py"
166+
$ crit show checkpoint/core-8.img | jq .entries[0].tc.comm
167+
"tee"
168+
```
169+
170+
これは、コンテナ内の3つのプロセスが`bash`と`counter.py`(Pythonインタプリター)と`tee`であることを意味しています。
171+
プロセスの親子関係についての詳細は、`checkpoint/pstree.img`に分析するデータがさらにあります。
172+
173+
ここまでで収集した情報をまだ実行中のコンテナと比較してみましょう。
174+
175+
```console
176+
$ crictl inspect --output go-template --template "{{(index .info.pid)}}" 059a219a22e56
177+
722520
178+
$ ps auxf | grep -A 2 722520
179+
fedora 722520 \_ bash -c /home/counter/counter.py 2>&1 | tee /home/counter/logfile
180+
fedora 722541 \_ /usr/bin/python3 /home/counter/counter.py
181+
fedora 722542 \_ /usr/bin/coreutils --coreutils-prog-shebang=tee /usr/bin/tee /home/counter/logfile
182+
$ cat /proc/722520/comm
183+
bash
184+
$ cat /proc/722541/comm
185+
counter.py
186+
$ cat /proc/722542/comm
187+
tee
188+
```
189+
190+
この出力では、まずコンテナ内の最初のプロセスのPIDを取得しています。
191+
そしてコンテナを実行しているシステム上で、そのPIDと子プロセスを探しています。
192+
3つのプロセスが表示され、最初のものはコンテナPID名前空間の中でPID 1である"bash"です。
193+
次に`/proc/<PID>/comm`を見ると、チェックポイントイメージと正確に同じ値を見つけることができます。
194+
195+
覚えておく重要なことは、チェックポイントはコンテナのPID名前空間内の視界が含まれていることです。
196+
なぜなら、これらの情報はプロセスを復元するために重要だからです。
197+
198+
`crit`がコンテナについて教えてくれる最後の例は、UTS名前空間に関する情報です。
199+
200+
```console
201+
$ crit show checkpoint/utsns-12.img
202+
{
203+
"magic": "UTSNS",
204+
"entries": [
205+
{
206+
"nodename": "counters",
207+
"domainname": "(none)"
208+
}
209+
]
210+
}
211+
```
212+
213+
UTS名前空間内のホストネームが`counters`であることを教えてくれます。
214+
215+
チェックポイント作成中に収集された各リソースCRIUについて、`checkpoint/`ディレクトリは対応するイメージファイルを含んでいます。
216+
このイメージファイルは`crit`を使用することで分析可能です。
217+
218+
#### メモリーページを見る
219+
220+
CRITを使用して復号化できるCRIUからの情報に加えて、CRIUがディスクに書き込んだ生のメモリーページを含んでいるファイルもあります。
221+
222+
```console
223+
$ ls checkpoint/pages-*
224+
checkpoint/pages-1.img checkpoint/pages-2.img checkpoint/pages-3.img
225+
```
226+
227+
最初にコンテナを使用した際に、メモリー内のどこかにランダムキー(`RANDOM_1432_KEY`)を保存しました。
228+
見つけることができるかどうか見てみましょう。
229+
230+
```console
231+
$ grep -ao RANDOM_1432_KEY checkpoint/pages-*
232+
checkpoint/pages-2.img:RANDOM_1432_KEY
233+
```
234+
235+
そして実際に、私のデータがあります。
236+
この方法で、コンテナ内のプロセスの全てのメモリーページの内容を簡単に見ることができます。
237+
しかし、チェックポイントアーカイブにアクセスできるなら誰でも、コンテナのプロセスのメモリー内に保存された全ての情報にアクセスできることを覚えておくことも重要です。
238+
239+
#### さらなる分析のためにgdbを使用する
240+
241+
チェックポイントイメージを見るための他の方法は`gdb`です。
242+
CRIUリポジトリは、チェックポイントをコアダンプファイルに変換する[coredump][criu-coredump]スクリプトを含んでいます。
243+
244+
```console
245+
$ /home/criu/coredump/coredump-python3
246+
$ ls -al core*
247+
core.1 core.7 core.8
248+
```
249+
250+
`coredump-python3`スクリプトを実行すると、チェックポイントイメージがコンテナ内の各プロセスに対し1つのコアダンプファイルに変換されます。
251+
`gdb`を使用してプロセスの詳細を見ることもできます。
252+
253+
```console
254+
$ echo info registers | gdb --core checkpoint/core.1 -q
255+
256+
[New LWP 1]
257+
258+
Core was generated by `bash -c /home/counter/counter.py 2>&1 | tee /home/counter/logfile'.
259+
260+
#0 0x00007fefba110198 in ?? ()
261+
(gdb)
262+
rax 0x3d 61
263+
rbx 0x8 8
264+
rcx 0x7fefba11019a 140667595587994
265+
rdx 0x0 0
266+
rsi 0x7fffed9c1110 140737179816208
267+
rdi 0xffffffff 4294967295
268+
rbp 0x1 0x1
269+
rsp 0x7fffed9c10e8 0x7fffed9c10e8
270+
r8 0x1 1
271+
r9 0x0 0
272+
r10 0x0 0
273+
r11 0x246 582
274+
r12 0x0 0
275+
r13 0x7fffed9c1170 140737179816304
276+
r14 0x0 0
277+
r15 0x0 0
278+
rip 0x7fefba110198 0x7fefba110198
279+
eflags 0x246 [ PF ZF IF ]
280+
cs 0x33 51
281+
ss 0x2b 43
282+
ds 0x0 0
283+
es 0x0 0
284+
fs 0x0 0
285+
gs 0x0 0
286+
```
287+
288+
この例では、チェックポイント中の全てのレジストリの値を見ることができ、コンテナのPID 1のプロセスの完全なコマンドライン(`bash -c /home/counter/counter.py 2>&1 | tee /home/counter/logfile`)を見ることもできます。
289+
290+
## まとめ
291+
292+
コンテナチェックポイントを作成することで、コンテナを停止することやチェックポイントが作成されたことを知ることなく、実行中のコンテナのチェックポイントを作成することが可能です。
293+
Kubernetesにおいてコンテナのチェックポイントを作成した結果がチェックポイントアーカイブです。
294+
`checkpointctl``tar``crit``gdb`のような異なるツールを使用して、チェックポイントを分析できます。
295+
`grep`のようなシンプルなツールでさえ、チェックポイントアーカイブ内の情報を見つけることが可能です。
296+
297+
この記事で示したチェックポイントの分析方法のさまざまな例は出発点にすぎません。
298+
この記事ではチェックポイントの分析を始める方法を紹介しましたが、要件によってはかなり詳細に特定の物事を見ることも可能です。
299+
300+
## 参加するためにはどうすればよいですか?
301+
302+
SIG Nodeにはいくつかの方法でアクセスできます。
303+
304+
* Slack: [#sig-node][slack-sig-node]
305+
* Slack: [#sig-security][slack-sig-security]
306+
* [メーリングリスト][sig-node-ml]
307+
308+
[forensic-blog]: https://kubernetes.io/ja/blog/2022/12/05/forensic-container-checkpointing-alpha/
309+
[checkpointctl]: https://github.com/checkpoint-restore/checkpointctl
310+
[image-files]: https://criu.org/Images
311+
[crit]: https://criu.org/CRIT
312+
[slack-sig-node]: https://kubernetes.slack.com/messages/sig-node
313+
[slack-sig-security]: https://kubernetes.slack.com/messages/sig-security
314+
[sig-node-ml]: https://groups.google.com/forum/#!forum/kubernetes-sig-node
315+
[criu-coredump]: https://github.com/checkpoint-restore/criu/tree/criu-dev/coredump

0 commit comments

Comments
 (0)