Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduce Conftest

yuhara
September 08, 2020

Introduce Conftest

yuhara

September 08, 2020
Tweet

More Decks by yuhara

Other Decks in Technology

Transcript

  1. 構成とフローの概略図
 Kubernetes Project Project A Project B Service A Team

    Service B Team Repository(GCP) Namespace A Namespace B Repository(k8s) Cloud Spanner Cloud Spanner Cloud Pub/Sub BigQuery Kubernetes Cluster CircleCI YAML HCL (Terraform)
  2. Production Readiness Checklist
 • サービスを安全にリリースするためのチェックリスト
 • マイクロサービスのリリース前にチェックを行う
 • 例)
 ◦

    Kubernetes
 ▪ CPUやMemoryのrequestsとlimits 
 ▪ preStop
 ▪ livenessProbe / readinessProbe
 ▪ runAsNonRoot
 ▪ HorizontalPodAutoscaler
 ▪ PodDisruptionBudget
 ◦ GCP
 ▪ Databaseのバックアップ
 ▪ Cloud StorageのObject Lifecycle Management 

  3. Gatekeeper
 • Gatekeeper
 ◦ OPAをKubernetes上で使えるよう にしたもの
 ◦ KubernetesのAdmission Controllerと連携してOPAを利用
 ◦

    Webhook先をOPAにすることで API Server側でポリシーチェック
 https://www.openpolicyagent.org/docs/latest/kubernetes-introduction/
  4. なぜConftestを使い始めたか
 • もともとCIでterraform planやkubectl validate/dry-runでの失敗を通知していて、ポ リシーチェックも導入しやすかった
 • Conftestが様々なフォーマットに対応している
 ◦ GCPのクラウドリソースはHCL形式のTerraformで管理


    ◦ KubernetesのマニフェストはYAMLで管理
 • KubernetesではRegoで記述したポリシーをCIとAPI Server側で両側面でチェックで きる
 ◦ CI時のチェックはConftest
 ◦ API Server側でのチェックはGatekeeper

  5. テストシナリオ
 • 例)HorizontalPodAutoscalerのspec.minReplicasが3以上であること
 apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: php-apache

    spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: php-apache minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource:       <以下、省略> minReplicasが省略されていたり、
 値が3未満の場合は事前に気付きたい 

  6. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } • 例)HorizontalPodAutoscalerのspec.minReplicasが3以上であること

  7. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } package名は任意。

  8. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } ルール名は deny, violation, warn を使うことができる。 
 deny, violationではルールに合致するとExit codeが1, warnではルールに合致してもExit codeが0 
 ルール名をviolation_xxxなどのように指定してもOK 
 

  9. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } ルールに合致した場合に返す値 

  10. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } 入力データ(input)のkindがHorizontalPodAutoscalerであるか評価 
 (Gatekeeperでは入力データが input.review.objectなのでConftestとGatekeeper両方でポリシーを使う場合は入 力データを評価するような判定を入れると良い) 

  11. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } input.spec.minReplicas が3以上であればgoodという変数にtrueが代入。3未満ならfalseが代入される。 

  12. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } パイプの左のgoodという変数に値を渡しています。つまりsatisfiedは要素が1つのarrayとなります。ただし minReplicasが省略されている場合はgoodが空なのでsatisfiedは要素が0のarrayです。 
 satisfied minReplicasが3以上 [true] minReplicasが3未満 [false] minReplicasが省略 []
  13. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } any関数でsatisfied内に1つでもtrueがある場合はtrueとなる。 
 satisfied any(satisfied) minReplicasが3以上 [true] true minReplicasが3未満 [false] false minReplicasが省略 [] false
  14. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } spec.minReplicasが3以上でない場合を条件として合致させたいため、否定のnotを使用 
 satisfied any(satisfied) not any(satisfied) minReplicasが3以上 [true] true false minReplicasが3未満 [false] false true minReplicasが省略 [] false true
  15. Regoでポリシーを記述
 package hpa description := "This is production readiness check

    itme, please check http://~" violation_min_replicas_is_not_set[{"msg": msg, "description": description}] { input.kind = "HorizontalPodAutoscaler" satisfied := [good | good := input.spec.minReplicas >= 3] not any(satisfied) msg := sprintf("minReplicas in HorizontalPodAutoscaler %s must be set", [input.metadata.name]) } 最後にmsgを生成

  16. コマンド実行時の出力(JSON)
 [ { "filename": "sample-hpa.yaml", "warnings": [], "failures": [ {

    "msg": "minReplicas in HorizontalPodAutoscaler sample must be set", "metadata": { "description": "This is a production readiness check item, please check https://~" } } ], "successes": [] } ] $ conftest test --policy policy/hpa --namespace hpa --input yaml --output json sample-hpa.yaml ConftestをCIに組み込んで、
 適切な情報をディベロッパーにフィードバック

  17. ポリシーの開発とテスト
 • OPAではポリシーをコードで開発、運用できる(Policy as Code)
 • Regoのポリシーをテストするフレームワークがある
 • テスト用のルールはtest_xxxとする
 •

    withキーワードを使って入力データをMockのデータに置き換えできる
 package hpa msg := "minReplicas in HorizontalPodAutoscaler sample must be set" test_min_replicas_less_than_three { violation_min_replicas_is_not_set[{"msg": msg, "description": description}] with input as { "kind": "HorizontalPodAutoscaler", "metadata": {"name": "php-apache"}, "spec": {"maxReplicas": 10, "minReplicas": 1} } }
  18. テスト実行
 • opa testコマンドを使ってテストを実行
 • --coverage --format=jsonオプションをつけるとカバレッジも報告される
 $ opa test

    -v hpa.rego hpa_test.rego data.hpa.test_min_replicas_less_than_three: PASS (2.977518ms) -------------------------------------------------------------------------------- PASS: 1/1 $ opa test --coverage --format=json hpa.rego hpa_test.rego | jq .coverage 60