ConftestとCircleCIで継続的に構造データにPolicyを適用する
構造化されたデータにPolicyを適用したい、って気持ちはチームでコラボレーションしていたら自然と生まれてくる欲求だと思います。コードの場合は最近だと優秀なLinterがあるおかげである程度は強制することができるのですが、例えばYAMLだったりiniファイルだったりはどうでしょう?これらの構造化されたデータに対して、自分で作ったPolicyを適用できたら素敵だと思いませんか?そこで取り上げたいのがConftestです。以前このブログでも紹介したことがあるので、初めて聞いたという方はこちらの記事も合わせて読んでみてください。
今回はConftestをただ単体で使うのではなく、CircleCIと組み合わせて継続的にPolicyを適用する方法について見ていきます。これを実現したいがためにconftest-orbというCircleCIのOrbを作りました。
概要
CircleCIでconftest-orbを使った最小限のYAMLは以下のようになります。
version: 2.1 orbs: conftest: kenfdev/conftest-orb@x.y # バージョンは指定してください workflows: build: jobs: - conftest/test: pre-steps: - checkout file: config_to_test.yaml
前提条件は以下の通りです:
これらを守った上でconfig_to_test.yaml
に対してPolicyを適用します。
Serverless FrameworkのYAMLに適用してみる
では、もうちょっと具体例をあげてみます。Serverless FrameworkのYAMLを例にとって、Policyを実際に適用してみます。以下のリポジトリに実際にソースを置いています。
.circleci/config.yml
に設定しているCIの内容は以下のとおり:
version: 2.1 orbs: conftest: kenfdev/conftest-orb@0.0.8 workflows: build: jobs: - conftest/test: pre-steps: - checkout file: serverless.yaml
リポジトリの構成も、上で述べている前提条件を守っています。
kenfdev/conftest-serverless-circleci ├── policy │ ├── base.rego │ └── util.rego └── serverless.yaml
そして、Policyを適用する対象となるserverless.yaml
は以下のような内容になっています。
service: aws-python-scheduled-cron frameworkVersion: '>=1.2.0 <2.0.0' provider: name: aws runtime: python2.7 tags: author: 'this field is required' functions: cron: handler: handler.run runtime: python2.7 events: - schedule: cron(0/2 * ? * MON-FRI *)
今回適用するPolicyの詳細(Regoファイル)についてはこの記事では見ません。興味がある方は実際に見てみてください。概要としては次のとおりです。
provider.tags
にauthor
を設定していることprovider.runtime
にPython2.7を設定していないことfunctions
のruntime
にPython2.7を設定していないこと
上のYAMLと照らし合わせて、最初のPolicyは守られているけど、最後の2つに関しては守られていないことがわかります。この状態でCircleCIを走らせると以下のようにちゃんと叱られます。
Policyを一箇所で管理する
ここまでで、いい感じにCIでPolicyを適用できることがわかりました。ただ、結構大きな問題点があります。それは、適用したい構造データと同じリポジトリにPolicyも管理している点です。Policyは再利用するケースが多いと思うので、上で用意したようなPolicyをすべてのリポジトリで管理なんてしていられません。ということでここでConftestの強力な機能であるPolicyのpushとpull機能を紹介します。
v0.15.0時点でpush先、あるいはpull先として使えるのはOCIレジストリになります。Docker Registryが身近で使えるOCI互換のレジストリなので、これをどうにか使えないか試行錯誤してみました。
かなり斜め上な使い方をすることになってしまいますが、GitHub上にPolicyを保存して、更新するたびにこのPolicyを含んだDocker Registryのコンテナイメージを作るようにしてみました。流れのイメージとしては下図のとおりとなります。
この仕組みを使ってCircleCIのOrbに関するベストプラクティスが適用されているか、継続的にチェックしたいと思います。Policyは以下のリポジトリで管理しています。
Policyを含んだDocker Registryがあることで、CircleCI上でConftestを実行する際に一箇所で管理されているPolicyを再利用して適用することができます。
conftest-orbの開発フローで面白い点は、自分自身のCIにCircleCI Orbのベストプラクティスを継続的に適用していることです。ドッグフーディング状態だと言えます。
そんなconftest-orbのCIは以下のように定義しています。
jobs: general_usecase_test: executor: machine steps: - checkout - circleci-cli/install - run: name: Pack the orb.yml command: circleci config pack src > orb.yml - conftest/install # start the OCI registry(this command is declared in a different place) - start_oci_registry: image: kenfdev/circleci-orbs-policies # pull the policies from the OCI registry - conftest/pull: policy_path: policy repository: 127.0.0.1:5000/policies:latest # test with minimum options - conftest/test: policy_path: policy file: orb.yml
ちょっとグチャっとしている点もありますが、それはCI中にDocker Registryを起動する必要があるからです。外部にすでにOCI Registryがあれば、下のようにすっきり書くことができます。
version: 2.1 orbs: conftest: kenfdev/conftest-orb@0.0.8 workflows: build: jobs: - conftest/test: pre-steps: - checkout repository: <path-to-your-oci-registry> file: serverless.yaml
<path-to-your-oci-registry>
からPolicyをpullしてConftestを実行することができます。
このように、Policyを一箇所で管理しつつ、複数のリポジトリに対してCI経由で継続的に適用するということが比較的観点に実現することができます。Conftestのexampleを見ると、下の一覧のようにかなり様々なユースケースに適用できるということがわかるので、興味がある方はぜひconftest-orbも使ってみてください!
- awssam
- compose
- configfile
- docker
- hcl2
- ini
- kubernetes
- serverless
- tekton
- terraform
- ts
- xml
- etc.
まとめ
- conftest-orbを使ってCircleCIで継続的に構造データにPolicyを適用できる
- OCI Registryを使ってPolicyを一箇所で管理して共有することができる
以下のPRもマージされたため、v0.16.0以降ではOCI Registryではなく、HTTPでPolicyを外部から取得できるようになるので、さらに簡単にPolicyを適用できるようになりそうです!