こんにちは!JFrog Developer AdvocateのよしQ(よしきゅー)です。
前回のブログでは「JFrog Xrayを利用したオープンソースソフトウェア(OSS)脆弱性スキャン」と題して、OSS脆弱性がスキャンする姿をお見せしつつ、システムの現場でどのようなメリットがあるかについて挙げました。
ただ、私は気になっています。
- 「それってソースコードでもやってくれるサービスってあるよね?」
- 「なんでビルドした後にできるアーティファクトでチェックすんの?」
こんなことを思った方もいるのではないでしょうか。
今回のブログでは、なぜアーティファクトを対象にすべきなのか、アーティファクト管理がなぜ重要なのかについてお伝えしたいと思います。
「アーティファクト」とは?
この記事の中には、「アーティファクト」というキーワードが非常に多く登場します。
よくわからん!という方は、以下の記事を先にご確認ください。(弊社 よこなが非常にわかりやすくまとめています!)
blog.jfrog.co.jp
これをもとに、この記事では以下のようなものとして扱います。
- アーティファクトとは、「ソースコードをビルドした結果得られるバイナリファイル」を指します。
- アーティファクトは、その特徴を示す情報*1として「メタデータ」を持っている。
アーティファクトを「なぜ」管理するべきなのか
ここからが本題です。なぜアーティファクトを管理するべきなのか。
それを語るために、アーティファクトがどういった特徴をもっているのかを考えながら、整理してみたいと思います。
アーティファクトの特徴1: コンピュータ上の実行形式である
アーティファクトは先に述べた通り、「ソースコードからビルドした結果得られるバイナリファイル」です。
なぜビルドするのか、シンプルに言えば、コンピュータで実行できる形にする必要があるため。
テキストで書かれたソースコードそのものでは、コンピュータが理解できる形式ではありません。
実行のためにはコンピュータが理解できる形式に変換(コンパイル)し、関連するライブラリ・パッケージと関連づけ(リンク)する必要があります。
この形にならなければ、コンピュータ上で動かすこともできません。その実行形式の多くはバイナリになります。
通常、単体テストや結合テストなど、テスト工程はさまざまあるものの、一度ビルドされ生成されたアーティファクトは(問題がなければ)本番環境にデプロイされ、 新たなバージョンがリリースされるまで使いつづけられます。
エンジニアは、本番環境にデプロイすべきアーティファクトを把握する必要があり、現在本番環境で運用されているアーティファクトを素早く特定する必要があります。
アーティファクトの特徴2: ビルドするごとに異なるものが作成される
ソースコードに変更が加えられる毎に新たな実行形式が必要となり、その都度ビルドが行われ、新たなアーティファクトが生まれますが、ビルドする環境は刻一刻と変化しています。
変更が加えられなくともビルドが行われれば、新しいアーティファクトが生まれることになります。
例えば、使用するOSSライブラリ・パッケージに対して、具体的なバージョンが指定されていない場合、最新版を利用することが多くあります。
ビルドの前後で依存するライブラリ・パッケージの階層に何らかの変更が加えられた場合、依存関係が変わるため全く別物になります。
(環境ごとにリリースする都度ビルドをする場合、同じソースコードであっても完全一致するわけではないので、テスト・QAの正しさが保証されなくなります。)
また、昨今はアジャイル開発やCI/CDといった考え方の普及に伴い、ビルドする回数は増加しています。
いつ、どのような状態で作られたアーティファクトなのかを管理し、実行環境で使うべきアーティファクトを適切に利用する必要があります。
アーティファクトの特徴3: 数も種類も増え続けている
前の特徴で触れたアジャイル開発やCI/CDといった考え方の普及の結果、システムアーキテクチャも変化しており、生まれてくるアーティファクトも変化しています。
開発の効率化のためにOSSを活用することは今では一般的になってきており、外部で作られたアーティファクトを内包することが多くなっています。
運用方法も変化しており、サーバレスなアーキテクチャやマイクロサービスの台頭により、サービスを複数のアプリケーションで構成する場合は、1システムで利用するアーティファクトを複数になってきています。
また、IaC (Infrastracture as Code) やコンテナ技術の活用によって作られる1つの実行環境そのものがアーティファクトとして生成されるようになってきました。
さらにIoTの普及もあり、アーティファクトの数も種類も増え続けています。
このように、数多くのアーティファクトを組み合わせながらシステムアーキテクチャを構成するため、個々のアーティファクトを独立して管理のではなく、まとめて管理できるようにしていく必要があります。
アーティファクトの特徴4: それぞれのアーティファクトの特徴が一見してわからない
アーティファクトは多くの場合バイナリ形式であり、ほとんどの人がその内容を読むことができず、特徴を掴むことができません。
(バイナリエディタなどを使ってポイントを読み取ることができる人って本当にすごいと思う。)
アーティファクトが生まれた環境がどんな環境で、どういった内容なのかを記録しておかなければ、その正しさを担保することができなくなります。
アーティファクトを脆弱性スキャンの対象にすべき理由
冒頭に挙げた疑問について考えましょう。
脆弱性スキャンは、ソースコードに対して実施するサービスもあるなか、なぜアーティファクトをスキャン対象とすべきなのでしょうか。
ソースコードの状態で脆弱性スキャンを実施することは、開発段階では少しでも早くその課題に気づくことができる点で非常に有用ですが、実行形式にビルドする段階で状況が変化する可能性があります。
アーティファクトは不変であり、最終的に使用される実行形式の状態であるということが重要なポイントです。
アーティファクトは内包する依存関係や構造がすでに確定した形になっており、問題がある場合は、それを解決した新しいバージョンのアーティファクトを作成する必要があります。
脆弱性スキャンをアーティファクトに対して行うべき最大の理由は、時間経過に左右ない不変な状態のものに対して行うことで、実行時の影響を正しく評価できることにあります。
まとめ: アーティファクト管理の重要性
ここまでアーティファクトの特徴を整理しつつ、アーティファクトの重要性を述べてきました。
最終的な実行形式であり、かつ不変的なアーティファクトですが、開発・運用の過程で大量に作られるなかで、それぞれの特徴を捉えながら正しくバージョン管理をしていくことが求められています。
では、このようにシステムの中で大切なアーティファクトを管理していけばよいでしょうか。
アーティファクトを「どのように」管理すべきか
ファイルサーバで管理してるけど、どうなの?
ファイルサーバに、フォルダ構造や命名規則などの一定のルールを設けて管理されている場合があるかと思います。
例えば、上記の画像の例。アーティファクトごとに日付・環境名・テスト結果をファイル名として管理しています。
この場合、使用すべきアーティファクトがどれかを明示することはできると思いますが、本番環境で利用しているアーティファクトがどれで、そのベースとなるソースコードはどれなのかをすぐに特定できるでしょうか。
前者は日付・環境名で探すことはできても、問題特定のためのアクションにはまた別管理された情報が必要になります。
他にも、実際に環境にデプロイする際に自動化ツールがアクセス可能な形にする必要があったり、特徴3に挙げたような複数のアーティファクトの利用となった場合、管理の複雑さが増していきます。
ソースコードと同じ管理方法ではだめなの?
ソースコードを管理する場合は、gitを始めとするVCS(Version Control System)を用いることが一般的かと思います。
VCSを利用することで、ソースコードはバージョン管理され、誰が・いつ・どんな変更を行ったかといった変更履歴が保持され、それらをチームで共有することができます。
では、アーティファクトはVCSで管理できないのでしょうか?
VCSのメリットで挙げた「どんな変更を行ったか」の差分に注目します。
ソースコードは、テキストで記載されているプログラムの内容の比較ができるので、変更の差分が取得可能ですが、アーティファクトは、バイナリファイルであり、差分を取ることができません。
変更箇所として、ソースコードは差分だけが保持されますが、アーティファクトはファイル全量が差分として扱われます。
さらに、誰が・いつ・そんな変更を・どのような状況でアーティファクトを作ったかについては、特に「どのような状況で」ビルドを行ったかまで管理するのは、依存関係すべての情報を持つ必要があります。
特徴2に挙げたような、大量にビルドが発生し、歴史を重ねていくことで、差分量がVCSの容量を圧迫していく可能性があり、依存関係の情報もつど取得・保管することになれば、さらに容量を圧迫する可能性があります。
上記いずれの方法でも全く管理できないということはありませんが、先に挙げたようなアーティファクトの特徴にあった管理をすることが望ましいと言えます。
バイナリ・リポジトリを用いた管理のすゝめ
バイナリ・リポジトリは、その名前の通り「バイナリの貯蔵庫・保管庫」であり、以下はバイナリ・リポジトリで、一般公開されている広く知られたもの(パブリック・リポジトリ)の例としていくつか挙げています。
- Java系: Maven Central
- C, C++系: Conan
- .NET系: NuGet
- JavaScript系: npm
- Ruby系: RubyGems
- Docker系: DockerHub
プライベート・リポジトリとして権限制御を含むプロジェクト独自のアーティファクトを管理するバイナリ・リポジトリも存在しており、よりアーティファクト管理に適しています。
JFrog Artifactory
JFrog Artifactoryは、さまざまなアーティファクトを統合的に管理する「バイナリ・リポジトリマネージャ」です。 先に挙げたアーティファクトの特徴を意識しており、必要な情報を管理することができます。
Artifactoryは以下のような特徴があります。
Artifactoryの特徴1: ユニバーサル・バイナリ・リポジトリマネージャ
前回の記事でも紹介していますが、JFrogの製品はユニバーサル性を意識しており、30以上のパッケージマネージャに対応しています。
Artifactoryの特徴2: メタデータを用いた管理が容易
アーティファクトは、リリース時にある環境から別の環境へ移したり、エンジニア間でシェアしたりすることがあり、作業対象を誤らずに見分けることができるよう、メタデータが非常に重要です。
メタデータとして、すでに例示したビルドした人やサービス、リリースバージョン、ビルド時刻、ビルド環境の他、ビルドに使用したGitブランチやタグ、OSS依存関係の情報、テスト状況などもメタデータに持たせることも可能であり、アーティファクトの状態を適切に使うことができます。
Artifactoryの特徴3: パブリック・リポジトリのアーティファクトも含めて一元管理
ビルド時にOSSなどの外部パブリック・リポジトリのアーティファクトを取得し、キャッシュとして保管することができます。
これにより、パブリック・リポジトリに対してプロキシとして機能することができ、ビルドの高速化が図れる他、パブリック・リポジトリが何らかの問題で使えない状態である場合も、キャッシュを利用してビルドが可能となります。
Artifactoryの特徴4: チェックサムを用いたファイル管理
登録されたアーティファクトは、自動的に物理ファイルとファイル名やパスなど付随するデータに分けて保管されます。
具体的には、物理ファイルはファイルストアに、ファイル名やパスはリレーショナルDBに保管されます。
特に物理ファイルについては、チェックサムを用いて同一性を確認しており、重複した登録を防ぎ、使用ディスク容量が肥大化することを防ぎます。
また、環境ごとにリポジトリを用意した場合も、コピーであれば、ファイルストアのファイルはそのままで、リポジトリ管理のメタデータだけがレコードを増やす形になります。
Artifactoryの特徴5: 外部ツールとのインテグレーションが容易
CIサーバプラグインやREST API、専用CLI(JFrog CLI)、Webhookを用いることで、Artifactoryと外部ツールとのインテグレーションが容易に実施できます。
CIサーバプラグインは、例えばJenkinsやAzure DevOpsなどで提供しており、仮にプラグインが用意されていない場合もREST APIやCLI経由でインテグレーションが可能です。
すでにCI/CDツールやプロジェクト管理ツールを用いている場合でも、現在のフローを活かしながら、Artifactoryを利用を開始することが可能となっています。
JFrog Artifactoryを知っていただくために
JFrogでは無料でご利用いただける学習コンテンツを用意しております。
英語のコンテンツになりますが、概要に関しては、以下の学習コンテンツをご覧ください。
また、お問合せがありましたら、お問合せフォームや、弊社日本チームのTwitterへご連絡ください。
*1:ビルドした人の名前、ビルドしたサービスの名前、リリースバージョン、ビルド実行時刻、ビルド実行環境等