成果物ポリシー チェック

Azure DevOps Services

成果物ポリシーは、運用環境など、重要な環境にデプロイする前に適用されます。 そのようなポリシーは、指定のパイプライン実行で、デプロイ可能なあらゆる成果物に対して評価され、成果物が準拠しない場合、デプロイが禁止されます。 成果物を評価するためのチェックを追加するには、カスタム ポリシーを構成する必要があります。 このガイドでは、カスタム ポリシーの作成方法を説明します。

注意

現在のところ、サポートされている成果物の種類は、コンテナー イメージ用と Kubernetes 環境用です

前提条件

読み書きが簡単なポリシーを定義するには Rego を使用します。

Rego クエリ言語に関する知識を身に着けてください。 基本は大切です。

JSON など、構造化されたドキュメント モデルをサポートするため、Rego では Datalog を拡張します Rego クエリは、OPA に格納されているデータに対するアサーションです。 こうしたクエリは、システムに求められる状態に違反するデータ インスタンスを列挙するポリシーを定義する目的で利用できます。

カスタム ポリシーの作成

以下は、共有されているサンプル ポリシーです。 要件に基づいて、独自のポリシー セットを構築できます。

特定のプロジェクト/パイプラインを確認する

このポリシーでは、イメージが Azure Pipelines と Pipeline-foo によって構築されているか確認されます。 これを機能させるには、パイプライン定義で name フィールドを AzureDevOps_$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r) のようなものにオーバーライドする必要があります。 パイプライン実行に名前を付ける方法の詳細についてはこちらを参照してください。

allowedBuilder := "AzureDevOps_pipeline-foo"

checkBuilder[errors] {
    trace("Check if images are built by Azure Pipelines")
    resourceUri := values[index].build.resourceUri    
    image := fetchImage(resourceUri)
    builder := values[index].build.build.provenance.builderVersion
    trace(sprintf("%s: builder", [builder]))
    not startswith(builder, "allowedBuilder")
    errors := sprintf("%s: image not built by Azure Pipeline [%s]", [image,builder])
}

fetchRegistry(uri) = reg {
    out := regex.find_n("//.*/", uri, 1)
    reg = trim(out[0], "/")
}

fetchImage(uri) = img {
    out := regex.find_n("/.*@", uri, 1)
    img := trim(out[0], "/@")
}

許可されているレジストリを確認する

このポリシーでは、イメージが、許可されているレジストリからのもののみか確認します。

allowlist = {
 "gcr.io/myrepo",
 "raireg1.azurecr.io"
}

checkregistries[errors] {
    trace(sprintf("Allowed registries: %s", [concat(", ", allowlist)]))
    resourceUri := values[index].image.resourceUri
    registry := fetchRegistry(resourceUri)
    image := fetchImage(resourceUri)
    not allowlist[registry]
    errors := sprintf("%s: source registry not permitted", [image]) 
}

fetchRegistry(uri) = reg {
    out := regex.find_n("//.*/", uri, 1)
    reg = trim(out[0], "/")
}

fetchImage(uri) = img {
    out := regex.find_n("/.*@", uri, 1)
    img := trim(out[0], "/@")
}

禁止されているポートを確認する

このポリシーでは、コンテナー イメージで公開されている禁止ポートがないか確認します。

forbiddenPorts = {
    "80",
    "22"
}

checkExposedPorts[errors] {
    trace(sprintf("Checking for forbidden exposed ports: %s", [concat(", ", forbiddenPorts)]))
    layerInfos := values[index].image.image.layerInfo
    layerInfos[x].directive == "EXPOSE"
    resourceUri := values[index].image.resourceUri
    image := fetchImage(resourceUri)
    ports := layerInfos[x].arguments
    trace(sprintf("exposed ports: %s", [ports]))
    forbiddenPorts[ports]
    errors := sprintf("%s: image exposes forbidden port %s", [image,ports])
}

fetchRegistry(uri) = reg {
    out := regex.find_n("//.*/", uri, 1)
    reg = trim(out[0], "/")
}

fetchImage(uri) = img {
    out := regex.find_n("/.*@", uri, 1)
    img := trim(out[0], "/@")
}

以前のデプロイを確認する

このポリシーでは、Check が構成されている特定の環境/リソースにデプロイされる前に、1 つまたは複数の環境にイメージが事前デプロイされているか確認します。

predeployedEnvironments = {
    "env/resource1",
    "env2/resource3"
}

checkDeployedEnvironments[errors] {
    trace(sprintf("Checking if the image has been pre-deployed to one of: [%s]", [concat(", ", predeployedEnvironments)]))
    deployments := values[index].deployment
    deployedAddress := deployments[i].deployment.address
    trace(sprintf("deployed to : %s",[deployedAddress]))
    resourceUri := deployments[i].resourceUri
    image := fetchImage(resourceUri)
    not predeployedEnvironments[deployedAddress]
    trace(sprintf("%s: fails pre-deployed environment condition. found %s", [image,deployedAddress]))
    errors := sprintf("image %s fails pre-deployed environment condition. found %s", [image,deployedAddress])
}

fetchRegistry(uri) = reg {
    out := regex.find_n("//.*/", uri, 1)
    reg = trim(out[0], "/")
}

fetchImage(uri) = img {
    out := regex.find_n("/.*@", uri, 1)
    img := trim(out[0], "/@")
}