こんにちは。これは技術記事です。みなさんは、技術記事ですか?
まず、 Haconiwa の近況報告なんですが、この度 mruby で書き直し、ひとまず MRI 版と同じ程度の機能までは実装できました。
これに伴い、Linux用のバイナリを配布する形にインストール方法を変更しました。また、今後MRI版の開発(haconiwa-mri
とプロジェクトをリネーム済みです)は積極的には行わない予定です。何か機能追加したい際は mruby 版の方へPRを!
(一応、MRI版のリリース記事は以下です)
ということで、今日はこのmruby版のHaconiwaを用いて、Dockerのsshdコンテナを再利用してsshdを立ち上げてみる手順を紹介します。
環境について
Ubuntu Xenial に Docker をインストールしたマシンをご用意ください。
Dockerのインストールは公式の手順の通りで。
sshdのファイルシステムを用意する
ひとまず、sshdのコンテナをpullしてきましょう。何でもいいのですが、pull数が多い以下を使います。
$ docker pull rastasheep/ubuntu-sshd:14.04 14.04: Pulling from rastasheep/ubuntu-sshd 56eb14001ceb: Pull complete 7ff49c327d83: Pull complete 6e532f87f96d: Pull complete 3ce63537e70c: Pull complete 44eac7a33f9b: Pull complete 75541fec9952: Pull complete 2e8400dfc265: Pull complete 0b5d47f4abfc: Pull complete 85e1f2a6c198: Pull complete 5dfceaa8deda: Pull complete Digest: sha256:2ddef06b17b83c3becea892eff3fae3587eebd062b151fce1517fed25a50236b Status: Downloaded newer image for rastasheep/ubuntu-sshd:14.04
完了したら、一度立ち上げておきます。一応sshできるかを確認してもいいと思います。
$ docker run -P -d rastasheep/ubuntu-sshd:14.04 dbeddbcba4f5ec0b19d13d71828cff5095383f302619b91bdf16a2afb7ddd82e $ docker inspect dbeddbcb | grep HostPort "HostPort": "32768" $ ssh -p 32768 root@localhost The authenticity of host '[localhost]:32768 ([::1]:32768)' can't be established. ECDSA key fingerprint is SHA256:FET56VENNef0pue72lv2diTZoDny5C2/ie2S6Tfqu38. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '[localhost]:32768' (ECDSA) to the list of known hosts. root@localhost's password: root@dbeddbcba4f5:~# exit
このコンテナのファイルシステムを docker export
でエクスポートします。その後、適当なディレクトリ(今回は /var/lib/haconiwa/sshd_root
)に展開します。
$ docker export dbeddbcb > sshd.tar $ sudo mkdir -p /var/lib/haconiwa/sshd_root $ sudo tar -xf sshd.tar -C /var/lib/haconiwa/sshd_root $ ls -l /var/lib/haconiwa/sshd_root total 8520 drwxr-xr-x 2 root root 4096 Jun 23 23:34 bin drwxr-xr-x 2 root root 4096 Apr 10 2014 boot -rw------- 1 root root 8646656 Jun 24 10:29 core drwxr-xr-x 4 root root 4096 Jul 14 00:01 dev drwxr-xr-x 67 root root 4096 Jul 14 00:01 etc drwxr-xr-x 2 root root 4096 Apr 10 2014 home drwxr-xr-x 12 root root 4096 Jul 8 15:14 lib drwxr-xr-x 2 root root 4096 Jun 23 23:33 lib64 drwxr-xr-x 2 root root 4096 Jun 23 23:33 media drwxr-xr-x 2 root root 4096 Apr 10 2014 mnt drwxr-xr-x 2 root root 4096 Jun 23 23:33 opt drwxr-xr-x 2 root root 4096 Apr 10 2014 proc drwx------ 2 root root 4096 Jul 14 00:02 root drwxr-xr-x 8 root root 4096 Jul 14 00:01 run drwxr-xr-x 2 root root 4096 Jun 24 10:29 sbin drwxr-xr-x 2 root root 4096 Jun 23 23:33 srv drwxr-xr-x 2 root root 4096 Mar 12 2014 sys drwxrwxrwt 2 root root 4096 Jun 23 23:34 tmp drwxr-xr-x 10 root root 4096 Jul 8 15:14 usr drwxr-xr-x 11 root root 4096 Jul 14 00:01 var
最後に、今回はネットワークを分離しないので、sshdのポートとして22番ではなく2222番を使うように、ファイルシステム配下のsshd_configを編集します。
$ sudo vi /var/lib/haconiwa/sshd_root/etc/ssh/sshd_config # Port 22 # -> Port 2222
これでファイルシステムの用意ができました。
Haconiwaを立ち上げる
まずは haconiwa
バイナリをインストールします。バイナリ一つで動きますので、以下の手順でOKです。
VERSION=0.1.3 wget https://github.com/haconiwa/haconiwa/releases/download/v${VERSION}/haconiwa-v${VERSION}.x86_64-pc-linux-gnu.tgz tar xzf haconiwa-v${VERSION}.x86_64-pc-linux-gnu.tgz sudo install hacorb hacoirb haconiwa /usr/local/bin
$ haconiwa haconiwa - The MRuby on Container commands: run - run the container attach - attach to existing container kill - kill the running container version - show version revisions - show mgem/mruby revisions which haconiwa bin uses
続いて、hacoファイル test.haco
を用意します。要するにRubyのDSLです。今回は、以下の感じで。
Haconiwa::Base.define do |config| config.name = "new-haconiwa001" # to be hostname root = Pathname.new("/var/lib/haconiwa/sshd_root") config.add_mount_point "devpts", to: root.join("dev/pts"), fs: "devpts" config.add_mount_point "tmpfs", to: root.join("tmp"), fs: "tmpfs" config.mount_independent_procfs config.chroot_to root config.namespace.unshare "ipc" config.namespace.unshare "uts" config.namespace.unshare "mount" config.namespace.unshare "pid" config.cgroup["pids.max"] = 1024 config.capabilities.drop "cap_sys_admin" end
このファイルをhaconiwaでキックしてみると、隔離された環境でbashが立ち上がっているのがわかると思います。PID、プロセスツリーなども独立。
$ sudo haconiwa run test.haco root@new-haconiwa001:/# ps auxf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.3 18200 3288 ? S 07:08 0:00 /bin/bash root 4 0.0 0.2 15564 2104 ? R+ 07:08 0:00 ps auxf
ここで、上記のhacoファイルに以下の2行を追加して、sshdを起動し、かつデーモン化できるようにしておきます。その後、同じように haconiwa run
でhaconiwaプロセスと立ち上げっぱなしにしておきます。
Haconiwa::Base.define do |config| config.name = "new-haconiwa001" # to be hostname config.init_command = %w(/usr/sbin/sshd -D) # <- ここ config.daemonize! # <- ここも #... end
$ sudo haconiwa run test.haco Container successfullly up. PID={container: 23939, supervisor: 23938}
このコンソールはそのままに、次の手順に入ります。
Haconiwaに入ってみよう
このプロセスにアタッチする方法は二つあります。一つは、 haconiwa attach
を用いる方法です。
以下のようなコマンドを発行します。
$ sudo haconiwa attach test.haco
すると、以下のようにまたbashが立ち上がり、sshdのコンテナに入れていることがわかります。
root@new-haconiwa001:/# ps auxf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 2 0.0 0.3 18200 3344 pts/1 S 07:37 0:00 /bin/bash root 6 0.0 0.2 15564 2216 pts/1 R+ 07:37 0:00 \_ ps auxf root 1 0.0 0.5 61380 5484 pts/0 S+ 07:37 0:00 /usr/sbin/sshd -D
もう一つの方法は、sshdなので、sshで入ってみることです。今、母艦の 2222 番ポートをコンテナもリスンしているはずなので、そこ経由で入ってみましょう。
$ ssh -p 2222 root@localhost root@localhost's password: Last login: Thu Jul 14 07:24:14 2016 from ::1 root@new-haconiwa001:~# ps auxf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.5 61380 5484 pts/0 S+ 07:37 0:00 /usr/sbin/sshd -D root 7 0.0 0.5 66012 5508 ? Ss 07:39 0:00 sshd: root@pts/2 root 9 0.0 0.3 18216 3392 pts/2 Ss 07:39 0:00 \_ -bash root 20 0.0 0.2 15564 2116 pts/2 R+ 07:39 0:00 \_ ps auxf
本当に隔離されてるの??
今、hacoファイルで
config.cgroup["pids.max"] = 1024
と書いてあったことを覚えていますでしょうか。この設定があるということは、 fork bomb を受けても問題がないはずですね。
試してみましょう。
$ sudo haconiwa attach test.haco root@new-haconiwa001:/# :(){ :|:& };: [1] 28 root@new-haconiwa001:/# bash: fork: retry: Resource temporarily unavailable bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes bash: fork: retry: No child processes ...
少し待つとforkが落ち着き、システムの状態が回復します。PIDがずいぶん進んでますね...
root@new-haconiwa001:/# ps auxf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 23 0.0 0.3 18208 3324 pts/1 S 07:43 0:00 /bin/bash root 7178 0.0 0.2 15564 2136 pts/1 R+ 07:44 0:00 \_ ps auxf root 1 0.0 0.5 61380 5484 pts/0 S+ 07:37 0:00 /usr/sbin/sshd -D
ということで、無事リソースの隔離と制限ができているようです。カーネル4.4.0最高!
また、他にも、 cap_sys_admin
ケーパビリティが落とされていることなどもわかります。
$ ssh -p 2222 root@localhost root@new-haconiwa001:~# capsh --print | grep cap_sys_admin root@new-haconiwa001:~#
色々と変えて試してみても良いでしょう(コンテナにアタッチする際は、都度ケーパビリティを決定するので、 haconiwa attach -A/-D
などのオプションで試せます)。
$ sudo haconiwa attach test.haco -D cap_sys_time root@new-haconiwa001:/# date -s 10:00 date: cannot set date: Operation not permitted Thu Jul 14 10:00:00 UTC 2016
コンテナを落とすには?
バージョン 0.1.3 から、 haconiwa kill
で落とせます。よかったよかった。 --signal/-s
で送り込むシグナル名も指定可能です。
$ sudo haconiwa kill test.haco Kill success
こんな感じで、Dockerの資産をある程度利用しつつコンテナで遊ぶことができますので、ちょっとしたこと(例えば、各種OSのビルド環境が作りたい!などなど...)をお試しください。
そしてご覧の通りいろんな機能がありません。ネットワーク分離のことを考えていませんし、rlimit対応もしたいし、setuid/setgidもするなどしたいですし、いつかはオーケストレーションもやっていきたいのですが、頑張ります...。
では、良いお年を!