aqua の Policy as Code
CLI ツールを YAML でバージョン管理できるツール aqua を開発しています。
今回は aqua のセキュリティ強化の一環として導入された Policy as Code に関する機能を紹介します。
aqua では利便性だけでなくセキュリティも重要であると考えています。
先日も checksum の検証によって改竄を検知する機能を導入しました。
今回はそれに続くセキュリティ関連の機能になります。
aqua を通じてツールをインストールする際、以下のような脅威が考えられます。
- セキュリティ的に問題のあるバージョンが実行される
- 修正バージョンがリリース済みだが、古いバージョンが使われている
- 最新バージョンに問題があるので downgrade すべきだが、されていない
- local registry や github_content registry を通じて悪意のあるツールがインストールされる
- 怪しげなサードパーティの github_content registry が使われるのを防ぎたい
- standard registry だけを許可したい
- 古い registry が使われるのを防ぎたい
- 悪意のある aqua.yaml と local registry を作成して、悪意のあるツールが実行されるのを防ぎたい
こういった脅威を防ぐために、 aqua.yaml とは別に policy ファイルというファイルでインストール・実行しても良い package を定義し、それに違反したものは install, 実行出来ないようにすることが出来るようになりました。
Getting Started
aqua の最新版を install してください。
aqua.yaml を作成します。
aqua init
aqua g -i hashicorp/terraform
policy ファイルとして aqua-policy.yaml を作成します(名前は自由です)。
aqua init-policy
# aqua Policy
# https://aquaproj.github.io/docs/tutorial-extras/policy-as-code
registries:
- type: standard
ref: semver(">= 3.0.0")
packages:
- registry: standard
Policy ファイルのフォーマットは aqua.yaml に似せています(全く同じではありません)。
環境変数 AQUA_POLICY_CONFIG
で aqua-policy.yaml へのパスを指定しましょう。この環境変数がないと policy は機能しません。
環境変数 AQUA_GLOBAL_CONFIG
と同様に :
つなぎで複数指定することが出来ます(複数指定した場合、いずれかの policy ファイルで許可されたら許可されたことになります)。
export AQUA_POLICY_CONFIG=$PWD/aqua-policy.yaml
上の設定では standard registry の package を許可しています。
local registry を作成しましょう。
packages:
- type: github_release
repo_owner: suzuki-shunsuke
repo_name: github-comment
description: CLI to create a GitHub comment
asset: github-comment_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz
version_constraint: semver(">= 4.3.0")
version_overrides:
- version_constraint: "true"
rosetta2: true
supported_envs:
- darwin
- amd64
- type: github_release
repo_owner: suzuki-shunsuke
repo_name: tfcmt
asset: tfcmt_{{.OS}}_{{.Arch}}.tar.gz
version_constraint: semver(">= 3.2.5")
version_overrides:
- version_constraint: "true"
supported_envs:
- darwin
- linux
registries:
- type: standard
ref: v3.94.1 # renovate: depName=aquaproj/aqua-registry
- name: local
type: local
path: registry.yaml
packages:
- name: hashicorp/terraform@v1.3.4
そして local registry の package を追加します。
aqua g -i local,suzuki-shunsuke/tfcmt local,suzuki-shunsuke/github-comment
install してみましょう。
$ aqua i
ERRO[0000] install the package aqua_version=1.24.0 doc="https://aquaproj.github.io/docs/reference/codes/002" env=darwin/arm64 error="this package isn't allowed" package_name=suzuki-shunsuke/github-comment package_version=v5.0.0 program=aqua registry=local
ERRO[0000] install the package aqua_version=1.24.0 doc="https://aquaproj.github.io/docs/reference/codes/002" env=darwin/arm64 error="this package isn't allowed" package_name=suzuki-shunsuke/tfcmt package_version=v4.0.0 program=aqua registry=local
INFO[0000] download and unarchive the package aqua_version=1.24.0 env=darwin/arm64 package_name=hashicorp/terraform package_version=v1.3.4 program=aqua registry=standard
FATA[0002] aqua failed aqua_version=1.24.0 env=darwin/arm64 error="it failed to install some packages" program=aqua
policy によって期待通り tfcmt と github-comment の install に失敗しました。
実行にも失敗します。
$ tfcmt -v
FATA[0000] aqua failed aqua_version=1.24.0 doc="https://aquaproj.github.io/docs/reference/codes/002" env=darwin/arm64 error="validate the installed package for security: this package isn't allowed" exe_name=tfcmt package=suzuki-shunsuke/tfcmt package_version=v4.0.0 policy_files="[/Users/shunsukesuzuki/Documents/test/aqua/pr-1308-2/aqua-policy.yaml]" program=aqua
多くのユースケースでは standard registry だけで十分で、 github_content registry や local registry だけで十分でしょう。
なので github_content registry や local registry を禁止することで悪意のあるツールが意図的に実行されるリスクはだいぶ下がります。
特定の local registry や github_content registry を許可することも出来ます。
許可してみましょう。
registries:
- type: standard
ref: semver(">= 3.0.0")
- name: local
type: local
path: registry.yaml
packages:
- registry: standard
- registry: local
install, 実行できました。
$ tfcmt -v
INFO[0000] download and unarchive the package aqua_version=1.24.0 env=darwin/arm64 exe_name=tfcmt exe_path=/Users/shunsukesuzuki/.local/share/aquaproj-aqua/pkgs/github_release/github.com/suzuki-shunsuke/tfcmt/v4.0.0/tfcmt_darwin_arm64.tar.gz/tfcmt package=suzuki-shunsuke/tfcmt package_name=suzuki-shunsuke/tfcmt package_version=v4.0.0 program=aqua registry=local
tfcmt version 4.0.0 (047e980d083da80303e6e8f4ebf6d5c9e7859716)
$ github-comment -v
INFO[0000] download and unarchive the package aqua_version=1.24.0 env=darwin/arm64 exe_name=github-comment exe_path=/Users/shunsukesuzuki/.local/share/aquaproj-aqua/pkgs/github_release/github.com/suzuki-shunsuke/github-comment/v5.0.0/github-comment_5.0.0_darwin_arm64.tar.gz/github-comment package=suzuki-shunsuke/github-comment package_name=suzuki-shunsuke/github-comment package_version=v5.0.0 program=aqua registry=local
github-comment version 5.0.0 (64d3b0b4fd3b8b05bd43e7dde9a7181577b34d70)
特定の package だけ許可することも出来ます。 local registry の tfcmt だけ許可します。
registries:
- type: standard
ref: semver(">= 3.0.0")
- name: local
type: local
path: registry.yaml
packages:
- registry: standard
- name: suzuki-shunsuke/tfcmt
registry: local
$ tfcmt -v
tfcmt version 4.0.0 (047e980d083da80303e6e8f4ebf6d5c9e7859716)
$ github-comment -v
FATA[0000] aqua failed aqua_version=1.24.0 doc="https://aquaproj.github.io/docs/reference/codes/002" env=darwin/arm64 error="validate the installed package for security: this package isn't allowed" exe_name=github-comment package=suzuki-shunsuke/github-comment package_version=v5.0.0 policy_files="[/Users/shunsukesuzuki/Documents/test/aqua/pr-1308-2/aqua-policy.yaml]" program=aqua
version による制限も出来ます。
構文は version_overrides や version_constraint と同じです。
expr という評価エンジンが使われ、 semver は hashicorp/go-version によって評価されます。
tfcmt の >= 4.0.0 を許可します。
registries:
- type: standard
ref: semver(">= 3.0.0")
- name: local
type: local
path: registry.yaml
packages:
- registry: standard
- name: suzuki-shunsuke/tfcmt
registry: local
version: semver(">= 4.0.0")
問題なく実行できます。
$ tfcmt -v
tfcmt version 4.0.0 (047e980d083da80303e6e8f4ebf6d5c9e7859716)
tfcmt を v3.0.0 に downgrade しようとすると失敗します。
# 一部抜粋
- name: suzuki-shunsuke/tfcmt@v3.0.0 # downgrade
registry: local
$ tfcmt -v
FATA[0000] aqua failed aqua_version=1.24.0 doc="https://aquaproj.github.io/docs/reference/codes/002" env=darwin/arm64 error="validate the installed package for security: this package isn't allowed" exe_name=tfcmt package=suzuki-shunsuke/tfcmt package_version=v3.0.0 policy_files="[/Users/shunsukesuzuki/Documents/test/aqua/pr-1308-2/aqua-policy.yaml]" program=aqua
github_content registry も許可できます。
# 一部抜粋
registries:
- name: aqua-registry
type: github_content
repo_owner: aquaproj
repo_name: aqua-registry
ref: semver(">= 3.0.0")
path: registry.yaml
standard registry, github_content registry の version 制約 (ref
) を省略すると、任意の version が許可されます。
# 一部抜粋
registries:
- type: standard
- name: aqua-registry
type: github_content
repo_owner: aquaproj
repo_name: aqua-registry
path: registry.yaml
Getting Started は以上になります。
Policy as Code によるレビュー負荷の軽減とセキュリティの向上
Policy as Code に関しては Hashicorp の Sentinel のドキュメントが参考になるでしょう。
Policy が言わばガードレールとなることで、 Policy に違反していない限りは自由に aqua.yaml を更新してよいということになります。
これは aqua.yaml を Renovate で自動 update している場合に、 review なしでも安心してマージできるようにするのにも役立つでしょう。
Renovate の PR の自動 merge のために aqua.yaml に CODEOWNER を設定してないとすると、人間が Renovate の PR に commit を追加して aqua.yaml を悪意を持って書き換えることが出来てしまいますが、 policy ファイルを使えばそれを防ぐことも出来ます
(policy ファイルに CODEOWNER を設定するなどして policy ファイルの改竄を防ぐ必要はあるでしょう)。
aqua.yaml の修正に review が必須となると、 update の頻度が高ければ高いほど review の負荷は大きくなり、人は消耗し、 review は雑になって問題を見過ごすようになります。
policy によって review が不要になれば負担はなくなりますし、 policy があっても運用ルール上 review は必須だとしても、 policy で機械的にチェックできる部分はチェックされ、人間はそれ以外の部分に注力して review が出来るようになるでしょう。
Monorepo の場合
Monorepo で多くの aqua.yaml を管理している場合、それら全てに関してセキュリティ的に問題がないかチェックする必要があります。
policy ファイルは aqua.yaml からは独立しており、 Monorepo で複数の aqua.yaml がある場合でも policy ファイルを共通化することが出来ます。
policy ファイルはセキュリティチームで管理しつつ、個々の aqua.yaml の管理は各チームに任せるという運用も考えられます。
例えば tfaction では Monorepo の working directory ごとに terraform や tflint, tfsec といったツールのバージョンを管理するようになっています。
こうすることで update を working directory ごとに段階的に行うことが出来るようになります。
全部の working directory でバージョンを統一となると、 working directory の数が増えた場合に一括で上げるのが困難になり、上げたくても上げられない・新規のプロジェクトなのに古いバージョンを使わないといけないといったことが考えられます。
tfaction のやり方ではそういった問題を防げるといったメリットがあるものの、
大量(規模が大きければ 1000 以上とかも考えられます)の aqua.yaml の update を全部セキュリティチームや SRE チームといった特定のチームがチェックするというのは難しいでしょう。
なので aqua.yaml の管理を各チームに任せるということになると思いますが、それでも最低限のガバナンスは効かせたいところでしょう。 policy ファイルを活用することでガバナンスを効かせつつ aqua.yaml の管理を安全に各チームに任せることが出来ます。
活用方法
CI
リポジトリ直下に Policy ファイルを置いて、環境変数 AQUA_POLICY_CONFIG
を設定しましょう。
GitHub Actions であれば、以下のように workflow 単位で AQUA_POLICY_CONFIG
を設定すれば良いでしょう。
env:
AQUA_POLICY_CONFIG: ${{ github.workspace }}/aqua-policy.yaml
ローカル開発
dotfiles か何かで Policy ファイルを管理し、 .bashrc や .zshrc などで AQUA_POLICY_CONFIG
を設定すれば良いでしょう。
まずは standard registry だけを許可し必要に応じて github_content registry や local registry を個別に許可すれば安全でしょう。
さいごに
aqua v1.24.0 で導入された Policy as Code に関する機能を紹介しました。
公式ドキュメントも参照してください。
Policy を設定することで危険なツールの実行を防ぐことが出来るので、設定することをお勧めします。
特に standard registry 以外の registry (local registry や github_content registry) は悪用されるリスクもあるので、デフォルトで無効化することも検討しています。詳細は Issue を見てください。
Discussion