💧

Cosign と SLSA による aqua CLI Version Manager の Security 改善

2022/12/27に公開

CLI ツールを YAML でバージョン管理できるツール aqua を開発しています。

https://aquaproj.github.io/

https://zenn.dev/topics/aquaclivm

aqua v1.26.0 から CosignSLSA を活用し Security を改善した話を紹介します。

https://aquaproj.github.io/docs/reference/cosign-slsa/

aqua ではこれまでも checksum の検証や Policy as Code といったセキュリティの改善を行ってきました。

https://zenn.dev/shunsuke_suzuki/articles/aqua-checksum-verification

https://zenn.dev/shunsuke_suzuki/articles/aqua-policy-as-code

今回は aqua を使ってツールをインストールする過程で改竄 (tampering) されるのを防ぐようにしました。

aqua では以下のような改竄のリスクがあります。

  • aqua-installer (shell script) の改竄
  • aqua の改竄
  • package の改竄

これらのリスクに対し、以下のような対策を施しました。

  • aqua-installer の改竄
    • aqua-installer の実行前に script の checksum を検証する手順をドキュメントで案内
  • aqua の改竄
    • aqua のリリース時に SLSA Provenance を生成
    • aqua-installer で aqua の install 時に SLSA Provenance を検証
  • package の改竄
    • Cosign と SLSA Provenance による検証をサポート

Docker を用いた検証環境の作成

環境を汚さずにコマンドを実行するために Docker を使います。

docker run --rm -ti alpine:3.17.0 sh
apk add curl bash sudo
adduser -u 1000 -G wheel -D foo
visudo # Uncomment "%wheel ALL=(ALL) NOPASSWD: ALL"
su foo
mkdir ~/workspace
cd ~/workspace
export PATH="${AQUA_ROOT_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/aquaproj-aqua}/bin:$PATH"

aqua-installer の検証

従来 aqua-installer を使って次のようなワンライナーで aqua をインストールしていたかと思います。

curl -sSfL https://raw.githubusercontent.com/aquaproj/aqua-installer/v1.1.2/aqua-installer | bash

しかしこれは aqua-installer が改竄されていないか検証していないので少々危険です。
そこで aqua-installer の実行前に checksum を検証しましょう。

curl -sSfL -O https://raw.githubusercontent.com/aquaproj/aqua-installer/v2.0.2/aqua-installer
echo "acbb573997d664fcb8df20a8a5140dba80a4fd21f3d9e606e478e435a8945208  aqua-installer" | sha256sum -c
chmod +x aqua-installer

aqua-installer を更新する度にコード(checksum)を修正する必要がありますが、 aqua-installer の更新頻度は高くないのでさほど問題にはならないでしょう。

aqua の検証

aqua の GitHub Releases を見ると SLSA Provenance multiple.intoto.jsonl があるのが分かるかと思います。

https://github.com/aquaproj/aqua/releases/tag/v1.26.2

aqua-installer を実行して aqua をインストールします。
aqua-installer は v2.0.0 から aqua の SLSA Provenance を検証します。

./aqua-installer

ログを見ると SLSA Provenance が検証されているのが分かります。

INFO[0001] verify a package with slsa-verifier           aqua_version=1.26.2 env=linux/arm64 new_version=v1.26.2 package_name=aquaproj/aqua package_version=v1.26.2 program=aqua registry=
Verified signature against tlog entry index 9918167 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77a4f5de5310f955deac79a5e8f16363b66a038bc6436fd330668a2933d69c75228
Verified build using builder https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.4.0 at commit d37dec79a9b96c85592eb24d69f9972cbd176f9a

この検証をサポートするために aqua-installer に大きな改修を入れました。破壊的変更を含むので v2 に major update しています。
破壊的な変更点としては、 aqua のインストール先を指定できなくなりました。
従来のデフォルトのインストール先にインストールされるので、元々インストール先を指定していない場合は関係ありません。

aqua には aqua 自身を更新する update-aqua というコマンドがありますが、このコマンドでも SLSA Provenance を用いて aqua を検証しています。
aqua-installer v2 では内部的に aqua update-aqua を実行しています

package の検証

Cosign と SLSA Provenance による検証をサポートしました。
といってもこれは package 側が対応していないと検証できませんし、現状対応しているパッケージはほとんどありません。
今後 Cosign や SLSA が普及してくると対応しているパッケージも増えてくるかと思います。

tflint は Cosign による keyless signing に対応しています。

https://github.com/terraform-linters/tflint/pull/1361

Standard Registry ではこの署名を使って tflint を検証する設定が入っています。

https://github.com/aquaproj/aqua-registry/blob/726e274fade1a6fc71cde029f858893131b38078/pkgs/terraform-linters/tflint/registry.yaml#L11-L25

このように以下の 2 つの条件を満たす必要があります。

  1. aqua でインストールするツール側が Cosign による署名か SLSA Provenance を公開している
  2. Registry 側でそれらを使って検証する設定をしておく

tflint を aqua でインストールしてみましょう。
aqua.yaml を生成します。

aqua init

tflint の checksum file が検証されているのを確認するため、 Checksum Verification を有効化してください。

vi aqua.yaml # Checksum Verification を有効化
aqua.yaml
---
# aqua - Declarative CLI Version Manager
# https://aquaproj.github.io/
checksum:
  # https://aquaproj.github.io/docs/reference/checksum/
  enabled: true
  # require_checksum: true
registries:
- type: standard
  ref: v3.110.0 # renovate: depName=aquaproj/aqua-registry
packages:

tflint をインストールします。

aqua g -i terraform-linters/tflint
aqua i

ログを見ると Cosign がインストールされているのが分かります。

INFO[0000] download and unarchive the package            aqua_version=1.26.2 env=linux/arm64 package_name=sigstore/cosign package_version=v1.13.1 program=aqua registry=
INFO[0008] downloading a checksum file                   aqua_version=1.26.2 env=linux/arm64 package_name=sigstore/cosign package_version=v1.13.1 program=aqua registry=

aqua は Cosign を自動で内部的にインストールするので、ユーザーが Cosign をインストールする必要はありません。
内部的にインストールとはどういう意味かというと、 $AQUA_ROOT_DIR/pkgs 配下にはインストールするけど PATH 配下にシンボリックリンクは作成しないという意味です。 aqua は PATH 関係なく絶対パスを指定して Cosign を実行します。
内部的にインストールされる Cosign のバージョンは現状 aqua 内部にハードコードされています。

https://github.com/aquaproj/aqua/blob/25de9cb7b4fc705d94a8a42c4078e6659faa6c14/pkg/cosign/version.go#L3

tflint のインストール時に tflint の checksum file が Cosign で検証されています。

INFO[0002] verify a checksum file with Cosign            aqua_version=1.26.2 env=linux/arm64 package_name=terraform-linters/tflint package_version=v0.44.0 program=aqua registry=standard
tlog entry verified with uuid: fab3e75f7e01ac757d8ddab411a7fd0c8b35c4ea2d0cb31c4c5bfdbe7ac5cf42 index: 9877371
Verified OK

次に SLSA Provenance の検証も見てみましょう。
aquaproj/example-go-slsa-provenance が SLSA Provenance をサポートしているのでインストールしてみます。

aqua g -i aquaproj/example-go-slsa-provenance
aqua i

SLSA Provenance を用いて検証されています。

INFO[0000] verify a package with slsa-verifier           aqua_version=1.26.2 env=linux/arm64 package_name=aquaproj/example-go-slsa-provenance package_version=v0.1.2 program=aqua registry=standard
Verified signature against tlog entry index 9476343 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77a92eb2665ca9575614bc6b0833267eca755ca5d2e8d5a563c2b70c310dad3c0f6
Verified build using builder https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.4.0 at commit 4581df55e03c5155801ad10b88b19e42f99d8861

v0.1.1 をインストールしてみましょう。このバージョンはわざと改竄してあります。

vi aqua.yaml # v0.1.1 に変更
aqua i

期待通り失敗しました。

INFO[0002] verify a package with slsa-verifier           aqua_version=1.26.2 env=linux/arm64 package_name=aquaproj/example-go-slsa-provenance package_version=v0.1.1 program=aqua registry=standard
Verified signature against tlog entry index 9476343 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77a92eb2665ca9575614bc6b0833267eca755ca5d2e8d5a563c2b70c310dad3c0f6
ERRO[0004] install the package                           aqua_version=1.26.2 env=linux/arm64 error="verify a package with slsa-verifier: run slsa-verifier's verify-artifact command: expected tag 'refs/tags/v0.1.1', got 'refs/tags/v0.1.2': tag used to generate the binary does not match provenance" package_name=aquaproj/example-go-slsa-provenance package_version=v0.1.1 program=aqua registry=standard
FATA[0004] aqua failed                                   aqua_version=1.26.2 env=linux/arm64 error="it failed to install some packages" program=aqua

さいごに

以上、 Cosign と SLSA を用いた改竄対策を紹介しました。
ユーザーが特に意識することなく自動で検証されるため、ユーザー体験を損なうことなくセキュリティを改善することができました。
Renovate に続き、 Cosign や SLSA もうまく活用した OSS になったのではないかと思います。
今後 Cosign や SLSA がより普及し、多くのツールを安全にインストールできるようになることを期待していますし、自分も何かしら Contribution できればいいなと思っています(すでにちょっとしています) 。

Discussion