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

Introduce Conftest

Avatar for yuhara yuhara
September 08, 2020

Introduce Conftest

Avatar for yuhara

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