Japan
サイト内の現在位置
ソフトウェアサプライチェーン対策の紹介
NECセキュリティブログ2022年6月3日
NECサイバーセキュリティ戦略統括部 セキュリティ技術センターの森本です。
ソフトウェア開発やシステム開発におけるサプライチェーンは、開発から運用までのライフサイクル全体を通して、ハードウェア、ソフトウェア、プロセス、人、サプライヤなどのあらゆる要素が関係するとされています [1] [2]。そのため、マルウェア感染、ソーシャルエンジニアリング、ソフトウェア脆弱性、物理的な攻撃など、想定される脅威は多岐に渡ります。さらに組織内や組織間で発生する調達や供給の連鎖を突き詰めれば、ソフトウェアライフサイクル全体の保護範囲も拡大するため、すべてを網羅的に考慮して対策することは事実上困難と言えます。その中でもより現実的なアプローチとして、対象範囲を絞ったソフトウェアサプライチェーンセキュリティと呼ばれる分野が提唱されています [3] [4]。
ソフトウェアサプライチェーンセキュリティは、主にソフトウェアライフサイクルやソフトウェア成果物に注目し、ソフトウェア成果物(ファイルバンドル)への関連度が高いリソース(ソースコード、依存ライブラリ、開発環境など)を中心に保護するアプローチとなります。一方、対象範囲にソフトウェアの運用工程までを含むか否か、外部サービス(クラウドサービス)を含むか否かなど、主張の分かれる点も存在します。
今回は、自組織で対応できる範囲、かつソフトウェアライフサイクルにおける開発から納品までの工程に注目した有力なガイドラインやフレームワークを紹介します。これらで扱われる保護資産の例として、アプリケーション本体に影響するソースコードや依存パッケージ、それらを直接的に扱う開発ツールや開発プロセスは明示的な対象となりますが、関連性の低い開発ツールや自組織の対策が及びにくいクラウドサービスへの言及は限定的な扱いとなります。以降の説明では、ソフトウェアサプライチェーンは上記の対象範囲を指すものとします。
ソフトウェアサプライチェーンを意識したソフトウェア開発
ソフトウェアライフサイクルにおける開発工程は、本番環境で稼働させるためのソフトウェアを実装・納品するプロセスであり、ソフトウェアサプライチェーンにおける要所と言えます。コーディング、ビルド、パッケージングといった一連の工程を経て安全なソフトウェアを納品するためには、各工程における署名技術や脆弱性診断によってソフトウェアの信頼性を確保することが重要になります。
また、コードリポジトリやビルドツールなどの開発ツールへの侵害もソフトウェア成果物の信頼性に関与するため、ソフトウェア成果物本体と併せた対策が求められます。近年は、開発環境自体にクラウド技術、コンテナ技術、CI/CD(Continuous Integration/Continuous Delivery)、IaC (Infrastructure as Code)などが導入されるケースもあり、これらの対策にも追随していくことが求められます。
ソフトウェアサプライチェーンに関する取り組みとしてGoogleやLinux Foundationなどは、ソフトウェアサプライチェーンにおけるソフトウェアの完全性を保証するSLSA(Supply chain Levels for Software Artifacts)と呼ばれるフレームワークを公開しています [5] [6]。図1は開発者がソースコードを作成してエンドユーザが成果物を受け取るまでのフローにどのような脅威が存在するかを示しています(図1の赤字部分A~H)。ソースコード管理ツールやビルド環境において悪意のあるソースコードやパッケージが挿入されるケースなど、開発工程の各所で脅威が存在することが分かります。
また、SLSAでは、ソフトウェア成果物を作成する手順やそれらの完全性を証明する手順が記載されたファイルのフォーマットも定義されています。
同様の取り組みとしてLinux Foundation傘下のCloud Native Computing Foundation(CNCF)は、ガイドラインのSoftware Supply Chain Best Practices [7]を公開しています。このガイドラインではCI/CDやIaCなどの比較的新しい技術で構成された開発環境の対策が説明されています。より具体的には、クラウド技術やコンテナ技術でビルド環境、テスト環境、本番環境が構築され、IaCやCI/CDの導入によって開発工程が自動化されるモデルを対象としています。
上述のフレームワークやガイドラインはデファクトスタンダードの扱いには至っていませんが、有力なリファレンスの一つと言えます。特に、Linux Foundationは、ソフトウェアサプライチェーンに関連するガイドやツールなど、対策の見当をつける上で参考となるプロジェクトを広くホストしています。以降、Linux FoundationやCNCFが公開しているガイドラインやフレームワークを中心にソフトウェアサプライチェーン対策の具体例を紹介していきます。
CNCF : Software Supply Chain Best Practices
表1は、Software Supply Chain Best Practicesで言及されている対策の一例になります。
表1.ソフトウェア開発工程の脅威モデル
カテゴリ | 対策例 |
ソースコード |
|
依存パッケージ |
|
アーティファクト |
|
CI/CD |
|
IaC |
|
その他 |
|
ソフトウェア成果物は主に開発者自身が作成したソースコードや外部から提供された依存パッケージから構成されます。そのため、開発環境を構成するコンポーネントの中でも重点的な保護が必要となります。
ソースコードの完全性対策については、ソースコード管理ツールによる署名を実施することで改ざんや否認の防止が実現でき、ハードウェアトークンや第3者機関の証明書を組み込むことで対策を強化することも可能です。また、ソースコード管理ツールの利用における2段階認証の導入、権限の最小化、開発者と独立した承認者のレビューも改ざんの防止に有効と言えます。脆弱性の低減については、ソースコードを静的に診断するSAST(Static application security testing)やアプリケーションを動的に診断するDAST(Dynamic Application Security Testing)といった自動診断ツールを利用することで効率的に脆弱性を検出することが可能です。
ソースコードから参照される依存ライブラリ(OSSや社外製品)は、ソースコードと同様に完全性の検証や脆弱性診断を実施する必要があります。加えて、OSSやサードパーティ製品を使用する場合はソフトウェアライセンスも考慮が必要となります。いずれの対策実施においてもまずはアプリケーションの詳細な依存関係を把握する必要があります。
依存関係の把握が求められた事例として、去年の年末に注意喚起が行われた「Apache Log4j」の脆弱性が挙げられます。この脆弱性はJavaで書かれたログ出力ライブラリ「Apache Log4j」に起因してリモートコード実行が可能となるものでした。特に重要となるのは、多くのシステムの構成管理において当該ライブラリの利用が明示的に管理されておらず、当該ライブラリを含んでいるかどうかの判断に迷うケースが散見されたことです。これは開発者がJavaで実装されたライブラリやフレームワークを導入した際に内部に含まれる当該ライブラリの存在を意識しなかった、または、構成管理の対象としていなかった点が原因と考えられます。このように開発者が明示的に導入(直接依存)したパッケージのみを構成管理している場合、間接的に導入(推移依存)されたライブラリのリスクを見落とす可能性があります。ただし、これらを網羅的に把握するには依存パッケージの内部構成にも精通している必要があり、開発者のスキルに依存することになります。そこで、ソフトウェアパッケージの詳細な依存関係を把握する現実的な手段として二つの方針が挙げられます。
- 開発元が提供しているSBOM(Software Bill Of Materials)と呼ばれるソフトウェアの構成情報を入手する
- SCA(Software Composition Analysis)と呼ばれる依存関係を解析するツールを利用して独自に解析する
SBOMは、特定の製品に含まれるソフトウェアコンポーネント、ライセンス、依存関係を一覧化したものになります。脆弱性やソフトウェアライセンスは、パッケージ名やバージョン情報に紐づくため、これらの正確な情報が提供されるSBOMを利用することで高い精度の診断が期待できます。次に、FOSSology [8]やBlack Duck [9]などのSCAツールは製品に含まれるソースコードやバイナリファイルの参照情報を解析することで依存関係を明らかにするものです。SCAツールは依存関係を独自に解析するツールであるため、正確な構成情報が開発元から提供されるSBOMよりも精度が落ちる傾向があります。そのため、基本的にSBOMを利用する方法が推奨とされています。ただし、すべての製品ベンダがSBOMを提供していないケースやSCAツールに付随した脆弱性診断やライセンス診断機能が重宝するケースもあるため、いずれも有力な手段となります。
次に、ソフトウェアアーティファクト(ソースコードや依存パッケージからビルドされたバイナリファイルやコンテナイメージ)についても、ソースコードと同様にチェックサムや署名を付与することで完全性を保証することが求められます。さらに、ビルド工程で同じ⼊力が与えられた際に同等の出力(アーティファクト)を⽣成し、意図しない変更(悪意のある機能または偶発的な機能)を検出する仕組みを導入することで信頼性の高い開発プロセスを実現可能です。CNCFは、各工程の入力や出力をプロセスとして定義したうえでそれらを署名・検証する機能を提供するin-toto [10]と呼ばれるフレームワークも公開しています。
Software Supply Chain Best Practicesでは、開発工程の自動化を支える技術であるCI/CDやIaCに関する対策も言及されています。CI/CDは従来開発者が手動で行っていたビルドやテストの作業をソフトウェアエージェントに委任して自動化する技術になります。そのため、CI/CDツールはビルド環境、テスト環境、本番環境、ソースコード管理ツールなど様々な環境へのアクセス権が付与されます。そのため、CI/CDツールの構成変更には強力な認証認可を採用することや侵害による影響範囲を限定するために権限を分離・最小化することが求められます。例として、CIとCDの機能が統合されたツールではなくそれぞれの機能が独立したツールを導入する方法が挙げられます。また、リポジトリから本番環境にアプリケーションを配置する際に、CDツールから本番環境にアクセスするpush方式ではなく、本番環境からポーリング処理でダウンロードするpull方式を採用することで、CDツールに本番環境への認証情報を付与しない構成も有効とされています。
IaCは、コードとして記述された構成情報を元に仮想マシンやネットワークなどのリソースを自動プロビジョニングする技術になります。具定例として、クラウドリソースの構成を記述するAWSのCloudFormationサービスやコンテナイメージの雛型となるDockerfileなどが該当します。IaCは手動操作のミスを減らすことができることやそれ自体が構成管理ツールとして機能することがセキュリティ上の利点になります。ただし、IaCで定義された構成と実環境の構成が乖離する場合、これらの利点が失われる可能性があります。そのため、IaCで構築した環境では手動変更を許可しない、定期的に構成ファイルと実環境の整合性を検査するなどの運用が有効となります。さらに、IaCで記述された構成情報は、開発環境や本番環境などの実環境に反映されるため、実行前に対象リソースの脆弱性や設定ミスを検査することも重要です。
クラウド技術やコンテナ技術を採用する際には、責任共有モデルやコンテナの実行権限などが重要となりますが、関連するセキュリティ対策については多数のガイドラインが発行されていますので説明は割愛します。
上述のとおり、ソフトウェア開発プロセスでは、アプリケーション本体や開発環境の構成コンポーネントの保護が求められます。さらに、フレームワークのSLSAや in-totoではソフトウェア開発から実装までのプロセスに注目して、どの段階でも真正であることを実証する仕組みが提供されています。以降、ソフトウェアサプライチェーンの完全性を強化する実装技術であるSPDXやin-totoについて紹介していきます。
SPDX
- パッケージ名
- サプライヤ名
- SBOM作成者
- パッケージバージョン
- コンポーネントのハッシュ
- コンポーネントの識別子
- コンポーネント間の関係
ここでは、Linux Foundationが中心に開発してきたSPDXを紹介します。SPDXの仕様はSPDX Specificationとして定義され、準拠したファイルがSPDX Documentと呼ばれます。SPDX Specificationはいくつかのカテゴリで定義され、カテゴリによっては対応コンポーネントに応じた数のインスタンスが管理されています。表2は、SPDXで定義された仕様を一部抜粋して列挙したものになります。
表2. SPDXの仕様抜粋
セクション例 | フィールド例 |
Document creation | SPDX Documentの作成者、作成場所、作成日時 |
Package | 構成パッケージの名前、バージョン、ライセンス、配布元、SPDX識別子 |
File | 構成ファイルのファイル名、ファイルタイプ、チャックサム、SPDX識別子 |
Snippet | コードスニペットのバイト範囲、SPDX識別子、関連ファイル |
Relationships between SPDX elements | SPDX要素間の関係 |
Document creationと呼ばれるセクションには、SPDX Document自体の作成情報が管理されています。具体的にはいつ、どこで、だれがこのSPDX Documentを作成したのかが記録されます。その他には、実際にSBOMの対象となるパッケージ、パッケージ内のファイル、ファイル内の一部を指すスニペット(例:ソースコード内のコード断片)をそれぞれ管理するセクションが存在します。これらのセクションでは関連するパッケージ数、ファイル数に応じてそれぞれのインスタンスが定義されています。これらのインスタンスにはSPDX内の識別子とともにパッケージ名やチェックサムなどの情報が格納されます。パッケージはファイルやスニペットよりも抽象度の高い管理情報となるため、基本的な要素となります。SPDXから最低限の必須情報を記述することで成立する仕様であるSPDX-Lite [15]も主にパッケージ粒度の情報で構成されています。
Relationships between SPDX elementsのセクションは、「foo.c(c言語のソースコードファイル)はbar.tgz(ARCHIVEファイル)に含まれる」、「パッケージAはビルドおよび実行するためにパッケージBに依存する」など、コンポーネント間の関係を表したセクションになります。このようにSPDX Documentには、SBOM(SPDX Dockment)の作成情報から管理対象であるパッケージの構成情報が一通り記述されます。
続いて、SPDXドキュメントのサンプルプロジェクト [16]を確認しながら実装例を紹介していきます。
図2はサンプルパッケージのディレクトリ構成を表しています。このパッケージは単純な「helloworld」プログラムを含む1つのCソースファイルがMakefileを介して単一のバイナリファイルとしてコンパイルされることを想定しています。
Content
|---- build
| |____ hello
|____ src
|____ Makefile
|____ hello.c
図2. SPDXのサンプルプロジェクト
図3、図4、図5はドキュメント情報、パッケージ情報、ファイル情報から構成されたサンプルパッケージのSPDX Documentの一部になります。SPDX DocumentはJsonやXMLなどのいくつかのフォーマット形式をサポートしていますが、こちらのファイルは、属性(keyやTag)と対応する値(Value)をテキスト形式で列挙したTag:Value形式で構成されています。
このSPDX Documentのセクションには前述したようにSPDX Document自体の作成者情報(図3: Creatorタグ)、パッケージの名前(図4: PackageNameタグ)、ファイルのチェックサム(図5: FileChecksumタグ)などの情報が含まれ、いずれのセクションにおいてもSPDX内の識別子である「SPDXID」が割り当てられています。Relationshipのタグを確認すると、SPDXIDで指定されたコンポーネント間の関係として「このSPDX Documentが helloパッケージを説明している」、「helloバイナリファイルがhello.cやMakefileから作成される」「Makefileはhelloパッケージのビルドツールである」という情報が記述されています。
SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: hello
DocumentNamespace: https://swinslow.net/spdx-examples/example1/hello-v3
Creator: Person: Steve Winslow (steve@swinslow.net)
図3. ドキュメント情報
##### Package: hello
PackageName: hello
SPDXID: SPDXRef-Package-hello
PackageDownloadLocation:git+https://github.com/swinslow/spdx-examples.git#example1/content
FilesAnalyzed: true
PackageVerificationCode: 9d20237bb72087e87069f96afb41c6ca2fa2a342
(省略)
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-hello
図4. パッケージ情報
FileName: /build/hello
SPDXID: SPDXRef-hello-binary
FileType: BINARY
FileChecksum: SHA1: 20291a81ef065ff891b537b64d4fdccaf6f5ac02
(省略)
FileName: /src/Makefile
SPDXID: SPDXRef-Makefile
FileType: SOURCE
FileChecksum: SHA1: 69a2e85696fff1865c3f0686d6c3824b59915c80
(省略)
FileName: /src/hello.c
SPDXID: SPDXRef-hello-src
FileType: SOURCE
FileChecksum: SHA1: 20862a6d08391d07d09344029533ec644fac6b21
(省略)
Relationship: SPDXRef-hello-binary GENERATED_FROM SPDXRef-hello-src
Relationship: SPDXRef-hello-binary GENERATED_FROM SPDXRef-Makefile
Relationship: SPDXRef-Makefile BUILD_TOOL_OF SPDXRef-Package-hello
図5. ファイル情報
SPDX Documentはソフトウェアと人の両方から読み書きができる形式で構成されているため、機械的に参照することで脆弱性診断や完全性検証の作業を自動化することが可能です。一方、完全なSPDX Documentを自動生成するようなツールは存在せず、最終的には人手による作成作業が必要となります。したがって、詳細なSBOMを作成するほどコストがかかる点は現状の課題といえます。
in-toto
SBOMはパッケージやファイルに注目して、構成情報を管理する技術となりますが、次にご紹介するin-totoは、コーディングからエンドユーザのインストールまで開発手順自体の完全性を保証するように設計されています。具体的には、開発プロセス上のステップが、誰にどのような順序で実行されたのかを署名付きの記録で保存することでこれらを実現しています。
in-totoの成果物は主に開発工程の全体像が定義されたサプライチェーンレイアウトファイルと工程単位の手順が定義されたリンクメタデータファイルで構成されます。これらがソフトウェア成果物(前述のhelloバイナリが相当)と同梱されることで開発手順の完全性を保証します。表3は各ファイルの概要を表し、図6、図7はサプライチェーンレイアウトとリンクメタデータのサンプルを一部抜粋したものになります。
表3. ファイル情報
in-totoの出力ファイル | 構成内容 |
サプライチェーンレイアウトファイル |
|
リンクメタデータファイル |
|
"signed" : {
"_type" : "layout",
"expires" : EXPIRES,
"keys" : {
ALICES_KEYID:ALICES_PUBKEY,
ELEANORS_KEYID : ELEANORS_PUBKEY,
},
"steps" : [
{省略},
{
"_name": "compilation",
"expected_materials": [
["MATCH", "src/foo.c", "WITH", "PRODUCTS", "FROM", "checkout-vcs"]
],
"expected_products": [
["CREATE", "foo"]
],
"expected_command": "gcc -o foo src/foo.c",
},
{省略}
]
"inspect": [],
},
"signatures" : [
{ "keyid" : ALICES_KEYID,
"method" : "ed25519",
"sig":"90d2a06c7a6c2a6a93a9f5771eb2e5ce0c93dd580bebc2080d10894623cfd6eaedf4df84891d5aa37ace3ae3736a698e082e12c300dfe5aee92ea33a8f461f02"
}
]
図6. サプライチェーンレイアウト
in-totoではなんらかの入力や出力がある手順を「ステップ」(図6: stepsタグ)と呼び、ソースファイルからバイナリファイルを出力する「ビルドステップ」やソフトウェア成果物のファイル群からアーカイブファイルを生成する「パッケージングステップ」などが該当します。
"signed" : {
"_type" : "link",
"name": "compilation",
"command" : "gcc -o foo foo.c",
"materials": {
"src/foo.c": { "sha256": "2a0ffef5e9709e6164c629e8b31bae0d",}
},
"products": {
"foo": { "sha256": "78a73f2e55ef15930b137e43b9e90a0b",}
},
"byproducts": {
"stdin": "",
"stdout": "",
"return-value": "0"
},
"signatures" : [
{ "keyid" : ELEANORS_KEYID,
"method" : "ed25519",
"sig" :
"ae3aee92ea33a8f461f736a698e082e12c300dfe5022a06c7a6c2a6a93a9f5771eb2e5ce0c93dd580bebc2080d10894623cfd6eaedf1d5aa394df84890d7ace3"
}
]
図7. リンクメタデータファイル
レイアウトファイルには各ステップの要件や検証手順(図6: inspectタグ)、具体的には想定される入出力ファイル(図6: expected_materialsタグ、expected_productsタグ)や実行コマンド(図6: expected_commandタグ)が定義されます。入出力ファイルについては、特定の手順で出力されたファイルのみを許可する、指定されたファイルパスのみを出力として許可するなどの制約が指定可能です。
1つのプロジェクトに1つのファイルが紐づくレイアウトファイルに対して、リンクメタデータファイルは、レイアウトに含まれる各ステップ単位で生成されます。図7は、ビルド手順のリンクメタデータのみを抜粋していますが、ソースコードへのタグ付けステップやパッケージングステップについても同様のファイルが作成されます。
また、サプライチェーンレイアウトファイルの作成者(管理者)とリンクメタデータファイルの作成者(実作業者)は異なる場合があり、リンクメタデータファイルは該当ステップを実行した作業者の秘密鍵によって署名されます(図7: signatures タグ)。リンクメタデータファイルには、実際に扱われた入出力ファイル(図7: materialsタグ、productsタグ)のパスやチェックサムに加えて、副次的な入出力(図7: byproductsタグ)である標準入力や標準出力を記録する領域も確保されています。
in-totoフレームワークは、最終的なサプライチェーンレイアウト、リンクメタデータ、ソフトウェア成果物について下記を検証するツールも提供しています。
- レイアウトファイル、リンクメタデータファイルの署名が有効期限であること
- レイアウトファイルが管理者によって署名されていること
- 各ステップが作業者によって署名されていること
- 入出力が定義されたルールに準拠していること
- 検査の結果が期待通りであること
このようにソフトウェア成果物の利用者は、SBOMやその他署名技術と併せて、各作業手順の妥当性を確認することで、開発プロセスと成果物の信頼性を検証することが可能になります。
まとめ
ご紹介したガイドラインやフレームワークはソフトウェアサプライチェーンのリスクを低減するアプローチの一例になります。特に開発プロセス全体の完全性を保護するアプローチは、ソフトウェア成果物の信頼性を高めるうえで今後も期待される分野と言えます。一方、これらはあくまで組織内の開発プロセスに注目したテクニックであるため、SBOMやin-totoに未対応のベンダが提供するパッケージやクラウドサービスに依存する場合、自組織の対応には限界があるといえます。今回、ご紹介した内容以外にも、業務委託先や関連企業で実施すべき対策を整理したNIST SP 800-171 [17]やOSSコンプライアンスを推進するOpenChainプロジェクト [18]も関連するアプローチとなります。サプライチェーンの対策は一朝一夕で解決できるものではありませんが、この分野の動向調査や導入を検討されている方は、上記の資料や活動も参考にされてはいかがでしょうか。
参考資料
- [1]
- [2]
- [3]
- [4]
- [5]
- [6]
- [7]
- [8]
- [9]
- [10]
- [11]
- [12]
- [13]
- [14]
- [15]
- [16]
- [17]
- [18]
執筆者プロフィール
森本 康太(もりもと こうた)
セキュリティ技術センター セキュリティ実装技術チーム
NECグループのセキュア開発・運用を推進。
執筆者の他の記事を読む
アクセスランキング