成品原則檢查

Azure DevOps Services

部署至生產環境等重要環境之前,會強制執行成品原則。 這些原則會根據指定管線執行中的所有可部署成品進行評估,並在成品不符合時封鎖部署。 新增檢查以評估 Artifact 需要設定自訂原則。 本指南說明如何建立自訂原則。

注意

目前支援的成品類型適用于容器映射和 Kubernetes 環境

必要條件

使用 Rego 定義容易讀取和寫入的原則。

熟悉 Rego 查詢語言。 基本概念將會執行。

為了支援 JSON 之類的結構化檔模型,Rego 會擴充 Datalog。 Rego 查詢是 OPA 中所儲存資料的判斷提示。 這些查詢可用來定義原則,這些原則會列舉違反系統預期狀態的資料實例。

建立自訂原則

以下是共用的範例原則。 根據您的需求,您可以建置自己的一組原則。

檢查特定專案/管線

此原則會檢查映射是否由 Azure Pipelines 和 Pipeline-foo 所建置。 若要這樣做,管線定義應該將名稱欄位覆寫為類似: AzureDevOps_$ (BuildDefinitionName) _$ (Date:yyyyMMMdd) $ (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], "/@")
}

檢查先前的部署

此原則會先檢查映射是否已預先部署到一/多個環境,再部署至已設定檢查的特定環境/資源。

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], "/@")
}