コンテナ向けコマンドラインツール—Buildah、Podman、SkopeoでSnykを活用
2020年12月9日
0 分で読めますコンテナエコシステムが成熟するにつれ、ソフトウェアの選択肢も、それらを組み合わせる方法も、ますます豊富になっています。
選択肢のひとつが、Buildah、Podman、Skopeoの組み合わせです。これらはRed Hatのエコシステムから生まれた、3つのオープンソースのコマンドラインツールです。名前のとおり、BuildahはOCI準拠のコンテナやイメージを構築するための幅広い機能を提供し、PodmanはOCIコンテナの管理と実行を担います。また、Skopeoはコンテナレジストリを操作するためのツールです。
この記事では、オープンスタンダードを活用することで、Snykのコンテナスキャンがこれらすべてのテクノロジーと連携する仕組みを紹介します。
まずはSkopeoを見てみましょう。Skopeoはコンテナイメージをリポジトリ間で移動するコマンドラインツールで、イメージをローカルに保存することもできます。イメージはDockerアーカイブまたはOCIアーカイブとして出力でき、どちらもSnykでファイルシステムからスキャンできます。Quay.ioからイメージをダウンロードし、ローカルのファイルシステムからスキャンしてみましょう。
ご覧のとおり、このイメージはサポート終了(EOL)バージョンのUbuntuを使用しているため、修正されない複数の脆弱性が含まれています。このようにSkopeoを使えば、標準に準拠したあらゆるコンテナレジストリから、Snykがサポートする形式でイメージをダウンロードし、ローカルでスキャンできます。
Buildah
次に、Buildahを見てみましょう。Buildahはイメージを構築するコマンドラインツールで、実行はしないため、Podmanと組み合わせて使うことを想定しています。また、Linuxカーネルのユーザーネームスペースを利用して、ユーザーレベルの権限だけを持つroot相当のシェルを分離する、root権限なしのモードで動作するよう設計されています。これにより管理者は、最小権限の原則をビルド環境で守りながら、開発者にコンテナイメージの構築と管理を任せられます。
BuildahはDockerと同様にDockerfileを使えますが、たとえばBashやPythonなど、ほかのワークフローを使ってコンテナやイメージを開発することもできます。柔軟性が高まるだけでなく、コンテナのビルドをデバッグしやすくなる場合もあります。Buildahではビルド中に中間コンテナをマウントできるため、スクリプトで処理が正しく実行されたかを確認してから続行したり、ソフトウェアをホスト上でビルドしたり、ユーザー入力を受け付けたりできます。これは、Dockerのベストプラクティスとして定着した、複雑になりがちなマルチステージビルドに代わる方法です。
実際にBuildahを使う例を見てみましょう。
まず、Buildahでは、使い慣れたワークフローであればDockerfileをそのまま使ってコンテナをビルドできます。例として、次のDockerfileを見てみましょう。
ここではCentOS 8イメージをベースに、GNU Helloのソースコードをクローンし、前提ソフトウェアをインストールしたうえで、バイナリをビルドしてインストールしています。
bud(build-using-dockerfile)オプションを使うと、Buildahで自動的にビルドできます。
しかし、ソースコードとビルドに必要なソフトウェアがどちらも最終イメージに含まれるため、これは明らかに望ましい方法ではありません。また、このイメージはセキュアなイメージ開発のベストプラクティスの大半に反しています。Dockerを使う場合、ここでのベストプラクティスはマルチステージビルドです。BuildahでマルチステージDockerfileを使うこともできますが、さらに興味深いのは、Buildahのネイティブコマンドを使ってスクリプトを作成する方法です。上のDockerfileで行ったことをそのまま再現するには、次のスクリプトを実行します。
さらにBuildahでは、ビルド中に中間コンテナをマウントできます。そのため、ソースコードのビルドをホスト上で行い、イメージとして確定する前に、生成したバイナリだけをコンテナにコピーできます。こうすれば、ビルド時にホストのリソースを活用できるほか、ホストのパッケージマネージャーを使ってコンテナにパッケージをインストールすることもできます。その場合もroot権限は不要です。Buildahはunshareコマンドを使い、ユーザーネームスペースによって特権なしでのマウントをサポートしています。
上の例のように、unshareコマンドを実行するとrootシェルが使えるようになりますが、これは完全なroot権限を持たないユーザーネームスペース内のものです。これにより、ビルド中にコンテナのファイルシステムをマウントできます。Bashスクリプトなので、プログラミング言語で実現できる機能も活用できます。条件分岐やループを使ったり、処理中にユーザーからの入力を求めたりすることも可能です。
Podman
このスクリプトを実行してイメージをビルドしたら、Snykでスキャンできます。ここで活躍するのがPodmanです。Podmanは、OCIコンテナの開発、管理、実行に使えるデーモンレスのコンテナエンジンです。BuildahとPodmanはオープンスタンダードに基づいているため、Podmanでイメージをディスクに保存し、ファイルシステムからスキャンする方法で、SnykはこれまでもPodmanで作成または取得したイメージをスキャンできました。Podmanでは、標準的なDockerアーカイブ形式とOCIアーカイブ形式のどちらでもイメージを保存でき、どちらもSnykでサポートされています。
ベースイメージはDocker Hubで公開されているため、このイメージをSnyk CLIでスキャンするだけなら、次の方法も使えます。
この場合、SnykはDocker Hubに直接アクセスし、上流のイメージをスキャンします。
しかし、イメージがPodmanのローカル環境にしかない場合や、ログインが必要なDocker Hubのプライベートリポジトリにある場合は、どちらの方法も使えません。例として、Podmanからビルドしたイメージを直接スキャンしてみましょう。
このようなケースでは、SnykはRegistry APIまたはDockerソケットを介して、ローカルのDockerクライアントを使います。システムにDockerバイナリがないため、この例ではSnykがRegistry APIを使おうとしましたが、接続に失敗しました。デフォルトでは、SnykはPodmanのローカル環境にイメージがあることも、Podmanを使って上流のレジストリにアクセスする方法も認識できません。
幸い、Podmanのpodman-dockerパッケージを使えば、簡単に互換性を確保できます。このパッケージは、Podmanバイナリを呼び出すシェルラッパーにすぎない疑似Dockerバイナリを提供し、Podman APIソケットとDockerソケットのデフォルトの場所をシンボリックリンクでつなぎます。インストール直後の設定では、root権限でPodman APIを実行する際のデフォルトである/var/run/podman/podman.sockにリンクが作成されます。
まだ動作しませんが、今度は別のエラーが発生しました。Snykはdockerというバイナリを検出し、特権付きのDockerソケットのデフォルトの場所に接続しようとしています。まだPodman APIを実行していないため接続できず、再び失敗します。
先ほど見たように、podman-dockerパッケージは、Podman APIを特権付きで実行する想定で、/var/run/podman/podman.sockから/var/run/docker.sockへのシンボリックリンクを作成します。
Dockerソケットの主な問題のひとつは、デフォルトで特権付きで実行されることで、環境によってはセキュリティリスクになります。一般的なローカル開発環境では、Podman APIをそのように実行する必要はありません。別の場所で、特権なしのソケットを実行できます。また、DOCKER_HOST環境変数を使えば、その場所をSnykに伝えられます。この変数はtcp://とunix://の両方のURL形式をサポートしています。
別のシェルを開き、特権なしのソケットでPodman APIを実行しましょう。
これはフォアグラウンドで実行されるため、テストが終わったらctrl-Cでプロセスを終了してください。次に、DOCKER_HOST環境変数を設定します。
最後に、Snykでローカルイメージをもう一度スキャンしてみましょう。
成功です。Snykが正しく動作し、特権なしのソケットを使ってPodmanと通信できています。
シェルでDOCKER_HOSTを恒久的に設定するには、exportコマンドを.bashrcファイルに追加します。これで設定が保持されます。
最後に、ログインするたびにこの設定全体が自動的に利用できるようにしたいところです。そのためには、systemdのソケットアクティベーション機能を活用し、ログイン後にソケットへ接続しようとしたとき、自動的にソケットが起動するようにします。
まず、ソケットを設定します。
次に、ソケットをサービスに関連付けます。
最後に、systemdの設定を再読み込みして、サービスを有効にします。
まとめ
以上のように、Podmanを使ったSnyk CLIのイメージスキャンはDockerの場合と同じように機能します。開発者は開発ワークフローの一環として、権限を昇格させることなく、ローカルのDockerイメージまたはOCIイメージを手軽に包括的にスキャンできます。また、オープンスタンダードの力を活用し、SkopeoとBuildahもSnykと連携できることを紹介しました。
Snykアカウントをまだお持ちでない方は、無料で登録して、コンテナイメージとオープンソースの依存関係の両方をスキャンしましょう。
キャプチャー・ザ・フラッグを始めよう
オンデマンドのバーチャル入門ワークショップを視聴して、キャプチャー・ザ・フラッグの課題の解き方を学びましょう。


