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. CloudNative Days Tokyo 2020



    RegoによるOPAポリシーの開発と

    Conftestを活用したポリシーチェックの実現


    Merpay SRE

    Takaaki Yuhara


    View Slide

  2. Agenda

    Conftest利用の背景

    Regoで記述したポリシーとConftestの活用

    ポリシーの開発とテスト

    01
    02
    03

    View Slide

  3. Conftest利用の背景

    Regoで記述したポリシーとConftestの活用

    ポリシーの開発とテスト

    01
    02
    03

    View Slide

  4. メルペイのシステム概要

    ● マイクロサービスアーキテクチャ

    ● Google Cloud Platform(GCP)を利用

    ● アプリケーションはKubernetes上で稼働

    ● マイクロサービスはそれぞれ下記が割り当てられる

    ○ GCP Project

    ○ Kubernetes Namespace


    View Slide

  5. 構成とフローの概略図

    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)

    View Slide

  6. Production Readiness Checklist

    ● サービスを安全にリリースするためのチェックリスト

    ● マイクロサービスのリリース前にチェックを行う

    ● 例)

    ○ Kubernetes

    ■ CPUやMemoryのrequestsとlimits

    ■ preStop

    ■ livenessProbe / readinessProbe

    ■ runAsNonRoot

    ■ HorizontalPodAutoscaler

    ■ PodDisruptionBudget

    ○ GCP

    ■ Databaseのバックアップ

    ■ Cloud StorageのObject Lifecycle Management

    View Slide

  7. Open Policy Agent(OPA)

    https://www.openpolicyagent.org/docs/latest/
    ● OSSの汎用ポリシーエンジン

    ● CNCFのincubatingのプロジェクト

    ● Regoというポリシー記述言語で

    ポリシーを書く

    ● ポリシーと入力されたデータを評価し結
    果を返す


    View Slide

  8. Gatekeeper

    ● Gatekeeper

    ○ OPAをKubernetes上で使えるよう
    にしたもの

    ○ KubernetesのAdmission
    Controllerと連携してOPAを利用

    ○ Webhook先をOPAにすることで
    API Server側でポリシーチェック

    https://www.openpolicyagent.org/docs/latest/kubernetes-introduction/

    View Slide

  9. Gatekeeper

    ● ConstraintTemplateとConstraint

    というCRDでポリシーを定義

    ● Regoによるポリシーは

    ConstraintTemplate内に記述

    https://github.com/open-policy-agent/gatekeeper

    View Slide

  10. Conftest

    ● Regoで記述したポリシーと入力データをコマンドラインで検証するツール

    ● CI上で使われることを想定している

    ● リモートにあるRegoのポリシーを利用できる

    ● 様々なフォーマットに対応

    ❏ YAML
    ❏ JSON
    ❏ INI
    ❏ TOML
    ❏ HOCON
    ❏ HCL
    ❏ HCL1

    ❏ CUE
    ❏ Dockerfile
    ❏ EDN
    ❏ VCL
    ❏ XML
    ❏ Jsonnet


    View Slide

  11. なぜConftestを使い始めたか

    ● もともとCIでterraform planやkubectl validate/dry-runでの失敗を通知していて、ポ
    リシーチェックも導入しやすかった

    ● Conftestが様々なフォーマットに対応している

    ○ GCPのクラウドリソースはHCL形式のTerraformで管理

    ○ KubernetesのマニフェストはYAMLで管理

    ● KubernetesではRegoで記述したポリシーをCIとAPI Server側で両側面でチェックで
    きる

    ○ CI時のチェックはConftest

    ○ API Server側でのチェックはGatekeeper


    View Slide

  12. Conftest利用の背景

    Regoで記述したポリシーとConftestの活用

    ポリシーの開発とテスト

    01
    02
    03

    View Slide

  13. テストシナリオ

    ● 例)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未満の場合は事前に気付きたい

    View Slide

  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])
    }
    ● 例)HorizontalPodAutoscalerのspec.minReplicasが3以上であること


    View Slide

  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])
    }
    package名は任意。


    View Slide

  16. 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 


    View Slide

  17. デバッグ時の出力

    内部でdata..<ルール名> という形で扱われているためルール名を分けておくと便利 


    View Slide

  18. 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])
    }
    ルールに合致した場合に返す値 


    View Slide

  19. 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両方でポリシーを使う場合は入
    力データを評価するような判定を入れると良い) 


    View Slide

  20. 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が代入される。 


    View Slide

  21. 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が省略 []

    View Slide

  22. 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

    View Slide

  23. 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

    View Slide

  24. 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を生成


    View Slide

  25. コマンド実行時の出力(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に組み込んで、

    適切な情報をディベロッパーにフィードバック


    View Slide

  26. Agenda

    Conftest利用の背景

    Regoで記述したポリシーとConftestの活用

    ポリシーの開発とテスト

    01
    02
    03

    View Slide

  27. ポリシーの開発とテスト

    ● 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}
    }
    }

    View Slide

  28. テスト実行

    ● 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

    View Slide

  29. まとめ

    ● Production Readiness Checklistを適切にチェックし安全にリリースするためにOpen
    Policy AgentのConftestを利用し始めた

    ● KubernetesのYAML manifestやTerraformのHCL等をCIでチェック

    ● Regoで記述したポリシーのテストもCIで実施


    View Slide

  30. ● 本日の内容は、下記のブログでも紹介しています

    https://engineering.mercari.com/blog/entry/introduce_conftest/


    View Slide