conftest を用いて Spring Boot 向けの設定ファイルをテスト
目的
アプリケーションの実装については UnitTest / Ingtegration Test などを実施することで自動テストが可能ですが、設定ファイルの定義などについての検証がおろそかになりがちです。
Infrastracture as Code を志向していればしているほどその傾向は強くなり、基本的に設定ファイルに類するものについても各種スタックに適合したテストツールを用いた自動テストを実施するのが望ましいとは思います。(Ansible であれば molecule、など)
この記事では、YAMLファイルのテストを行うツールとして、conftest
について記載します。
汎用的な記述は世間に溢れていると思うので、Java界隈でよく使われるSpring Boot の設定ファイルについてどのように応用するか概略だけ書きます。
conftest の使い方
汎用的なドキュメントについては以下などを参照ください。
References
- conftest: https://www.conftest.dev/
- conftest GitHub: https://github.com/open-policy-agent/conftest
- conftest examples: https://github.com/open-policy-agent/conftest/tree/master/examples
- OPA(Open Policy Agent): https://www.openpolicyagent.org/
基本的な使い方
ある程度基礎的なことも一応書いておいた方が良いと思うので概要だけ書きます。
conftest は YAML の構文を解析してテストを行うためのツールです。
事例では Kubernetes の manifest file についての検証を行う例が多いですが、YAML ファイルに対してであればどのアプリケーション向けのものでも検証を行うことができます。
YAML の妥当性の検証は OPA (Open Policy Agent)と呼ばれる形式のポリシーファイルを作成し、そのポリシーに沿っているか否かで判定を行います。
サンプル
conftest の公式サイトに掲載されている例を転記します。
package main
deny[msg] {
input.kind == "Deployment"
not input.spec.template.spec.securityContext.runAsNonRoot
msg := "Containers must not run as root"
}
deny[msg] {
input.kind == "Deployment"
not input.spec.selector.matchLabels.app
msg := "Containers must provide app label for pod selectors"
}
上記が OPA 形式のポリシーファイルです。
ここでは、Kubernetes の manifest の検証定義が記載されています。以下の条件に合致する場合、msg で定義されているエラーメッセージが表示され、conftest としてもエラーと判定されます。
- Deployment で
runAsNonRoot=True
が指定されていない場合(Root ユーザーでの動作を許可している場合) - app ラベルが設定されていない場合
上記 OPA ファイルを使って conftest を実行した例が以下。deployment.yml に runAsNonRoot=True ならびに app label の記述がされていない例です。
$ conftest test deployment.yaml
FAIL - deployment.yaml - Containers must not run as root
FAIL - deployment.yaml - Containers must provide app label for pod selectors
2 tests, 0 passed, 0 warnings, 2 failures, 0 exceptions
Spring Boot での使い方
Spring Boot では application.yml という名前で設定情報を記述します。
正確には様々なコンテキストごとに設定ファイルを用意する形になっています(たとえば Spring Cloud では bootstrap.yml という設定ファイルを読み込むようになっている)。
それぞれの設定ファイルに対して、OPAでポリシーを記述することで、Spring Bootの設定ファイルに対するconftestを実行することができます。
今回の私のケースでは以下の状況でした。
- Spring Boot(application.yml) ならびに Spring Cloud(bootstrapm.yml)を使用
- それ以外にもymlファイルを用いているが、ポリシーを用いての検証は上記2つについて実施。他のものについては最低限YAMLの構文チェックのみ実施する。
こちらにあわせてポリシーについても作成をしました。
ポリシーの種類
name | description |
---|---|
application | application.yml を検証するための Policy |
bootstrap | bootstrap.yml を検証するための Policy |
general | 標準的な Policy 。yaml の構文チェックのみ実施する |
ポリシーの中身
application.yml については、記述内容はそれぞれのアプリケーション次第になりそうです。なのでここでは詳述しません。
bootstrap.yml については、Spring Cloud の一般的な設定に対するチーム内での制約を記述する形になるので、ここではbootstrap.ymlのポリシーを一部引用します。
bootstrap.rego
package main
# spring.application
deny[msg] {
not input.spring.application.name
msg = "Should set `spring.application.name`"
}
# spring.zipkin
deny[msg] {
not input.spring.zipkin.service.name
msg = "Should set `spring.zipkin.service.name`"
}
# spring.cloud.vault
deny[msg] {
input.spring.cloud.vault.authentication != "APPROLE"
msg = "`spring.cloud.vault.authentication` should set `APPROLE`"
}
deny[msg] {
not input.spring.cloud.vault.kv.enabled = true
msg = "`spring.cloud.vault.kv.enabled` should set `true`"
}
上2つは、appliction名やzipkinで使用するサービス名については指定をする(未指定の場合はエラー)という制約、下2つについてはSpring Cloud Vaultに対する制約(APPEOLEを使う、KVを有効にする)について記述しています。
これらのルールに合致していない場合は conftest 実行時にエラーになります。
general.rego
YAML の構文チェックも conftest で実施をしています。こちらは何もしないポリシーファイルを置いておき、そちらを検証するという体で YAML の検証をしています(ポリシーの評価に関わらず構文エラーがあればエラー)。
package main
# If no policy was specified, warn log will be output. so we add a dummy policy.
deny[msg] {
not true
msg:= "test"
}
動作方法
conftestをイチからインストールするのは手間なので、提供されている Docker Image を用いて動かすのが楽だと思います。以下はbootstrap.ymlを動作させる例です。
docker run --rm -v $(pwd):/project openpolicyagent/conftest test --policy ${CONFTEST_POLICY} ./${PROJECT}/src/main/resources/bootstrap.yml
ポリシーに合致している場合は成功、失敗した場合はエラーとなります。
実際には複数のポリシーを一括でテストしているので、以下のような簡易的なShell Scriptを用意し、こちら経由で実施をしています。複数のプロジェクトに対して複数のポリシーで検証をし、一つでもエラーが発生したら全体的にエラーになる、という動きになっています。
ポリシーファイルについては、${CONFTEST_ROOT}の下に、それぞれのポリシーを表現したregoファイルを置いてあります。
#!/bin/sh
CONFTEST_ROOT=./conftest/policy
PROJECTS="sada masashi" #対象のプロジェクトを記述
for PROJECT in ${PROJECTS}
do
echo "${PROJECT} - bootstrap policy"
docker run --rm -v $(pwd):/project openpolicyagent/conftest test --policy ${CONFTEST_ROOT}/bootstrap ./${PROJECT}/src/main/resources/bootstrap.yml || RET=$?
echo ""
echo "${PROJECT} - application policy"
docker run --rm -v $(pwd):/project openpolicyagent/conftest test --policy ${CONFTEST_ROOT}/application ./${PROJECT}/src/main/resources/application.yml || RET=$?
echo ""
echo "${PROJECT} - general policy"
docker run --rm -v $(pwd):/project openpolicyagent/conftest test --policy ${CONFTEST_ROOT}/general ./${PROJECT}/src/main/resources/*.yml || RET=$?
echo ""
done
exit ${RET}
まとめにかえて
conftest は kubernetes の manifest の検証という文脈で多く用いられていますが、YAMLファイルに関してであればあらゆるタイプのものに対応が可能な汎用的な設定ファイルテストツールです。
ということで、興味の有る方はお試しください。
Discussion