CircleCI : Config Policy Management ~ Organization 単位で実行可能パイプラインの制御
今日はConfig Policy Management
という機能を見ていきます。
(本機能はFreeバージョンでは利用できずScale以上のプランが必要です)
この機能はCircleCIのOrganization単位で実行可能なパイプラインのルールを制御するものです。ルールというのは例えばインストールを行うミドルウェアのバージョンやOSの設定など指定することで、パイプラインが許可されていないバージョンを利用しようとした場合、アラートを出力(soft_fail
)するかパイプラインを停止(hard_fail
)させることが可能です。
Open Policy Agent(OPA)と Rego言語
このポリシーによるパイプライン制御の挙動はOPA (Open Policy Agent)により行われます。OPAに対して制御ルールを記載するものが、Rego
と呼ばれるポリシーを定義するドキュメント言語です。
OPAはCNCFのオープンソース・ポリシーエンジンで、様々なシステム(Kubernetes、CI/CD、APIゲートウェイなど)にポリシーを適用可能となり、CircleCI専用エージェントではありません。Regoはそのシステム向けの宣言型言語で、JSONなどの構造化データに対して強力な条件検査・制御が行えます。
package で名前空間(モジュール)を定義し、変数やルール(rules)を記述します。例えば以下の様に宣言を行うとパイプラインの中で同じ変数に対して異なる値が指定されるとエラーが発生します。
package example
pi := 3.14
rect := {"width":2, "height":4}
さっそくやってみる
OPAやRegoについては機会があればまた詳細に触れたいと思いますが今日は全容を理解するためにシンプルなパイプライン制御を行ってみます。
パイプラインがNodeを利用する場合、必ず20
以上でなければパイプラインを強制停止させます。
1. CircleCI CLIの設定
この機能はCirclCI CLIから操作を行う必要があるため以下の記事を参考にCLI環境を整備します。
2. Policy機能の有効化
以下のコマンドでまずはPolicyによるパイプライン制御の機能を有効化します。
circleci policy settings --enabled=true --owner-id <your-organization-ID>
true
がレスポンスで戻れば成功です。
{
"enabled": true
}
3. config.yml の入れかえとパイプライン実行
version: 2.1
jobs:
build:
docker:
- image: cimg/node:18.17
steps:
- checkout
- run: node -v
workflows:
main:
jobs:
- build
Nodeバージョン18.17がパイプラインにより起動されるデプロイ環境にインストールされていることを確認します。
4. policy.regoの作成 と 適用
ポリシードキュメントはかならずディレクトリ単位でCircleCIに登録する必要があります。このためディレクトリを作成します。
mkdir policy
つぎにpolicy.rego
を作成します。
package org
import future.keywords
# ポリシー名(必須)
policy_name["node_image_policy"]
# このルールを有効化し、違反時は HARD_FAIL
enable_hard["enforce_node20_min"]
# Docker イメージが cimg/node の場合、バージョンを確認
enforce_node20_min[reason] {
some job_name, job in input.jobs
some container in job.docker
startswith(container.image, "cimg/node:")
parts := split(container.image, ":")
version := parts[1]
major := to_number(split(version, ".")[0])
major < 20
reason := sprintf(
"job %q uses %q (Node < 20 is not allowed)",
[job_name, container.image],
)
}
config.yml
で指定しているNode環境用Dockerイメージのバージョンを確認しています。これによりバージョン20未満のNodeがインストールされることを防止します。
次にpolicy.rego
を適応します。
circleci policy push ./policy/ --owner-id <orgid>
<orgid>
は皆さんの環境ごとに入れ替えてください。以下の様にSuccessfully
が表示されれば適応完了です。
The following changes are going to be made: {
"created": [
"node_image_policy"
]
}
Do you wish to continue? (y/N) Y
Policy Bundle Pushed Successfully
diff: {
"created": [
"node_image_policy"
]
}
コンソールでも以下の様に確認が行えます。
5. パイプラインの実行
最後にパイプラインを実行します。
policy evaluation failed: enforce_node20_min: job "build" uses "cimg/node:18.17" (Node < 20 is not allowed)
パイプライン定義がポリシーに違反しているため、エラーにより処理が停止されています。
6. soft fail
policy.rego
のenable_hard
をenable_rule
に変更して再度パイプラインを実行します。
この通りアラートが表示されながらもパイプラインは実行されます。
7. ログの確認
circleci policy logs --owner-id <orgid>
を実行すると以下の通りアラートの一覧が出力されます。
[
{
"created_at": "2025-09-07T06:05:12.867027Z",
"decision": {
"enabled_rules": [
"enforce_node20_min"
],
"hard_failures": [
{
"reason": "job \"build\" uses \"cimg/node:18.17\" (Node \u003c 20 is not allowed)",
"rule": "enforce_node20_min"
}
],
"status": "HARD_FAIL"
},
"id": "849c1838-066c-4f8f-92e0-72ba8f95145f",
"metadata": {
"build_number": 66,
"project_id": "5cc2323a-511c-4945-a439-e07e04a4530a",
"vcs": {
"branch": "main",
"origin_repository_url": "https://github.com/h-kameda-sakura/apitest",
"target_repository_url": "https://github.com/h-kameda-sakura/apitest"
}
},
"policies": {
"node_image_policy": "6bc8d9c7981499030642475a39130db31cd714717fd5049f18e05c6118c2051b3a44ba953754df8082acf0a7ab4cf3a07f49cdaee12737a45184016a9c2d4d94"
},
"time_taken_ms": 1
},
{
"created_at": "2025-09-07T06:43:50.865578Z",
"decision": {
"enabled_rules": [
"enforce_node20_min"
],
"soft_failures": [
{
"reason": "job \"build\" uses \"cimg/node:18.17\" (Node \u003c 20 is not allowed)",
"rule": "enforce_node20_min"
}
],
"status": "SOFT_FAIL"
},
"id": "a840382a-8337-437b-8b7d-00009db7e10d",
"metadata": {
"build_number": 70,
"project_id": "5cc2323a-511c-4945-a439-e07e04a4530a",
"vcs": {
"branch": "main",
"origin_repository_url": "https://github.com/h-kameda-sakura/apitest",
"target_repository_url": "https://github.com/h-kameda-sakura/apitest"
}
},
"policies": {
"node_image_policy": "90ddeff8deb8ac3f025aebacc20c01ef8b6b27dd9ebaa9f6e679f2663461e00e85c5b313c513d6974d345d1a88d6bf82316a79edcc3f5c36f7ca5580696520f5"
},
"time_taken_ms": 1
}
]
Discussion