工件策略检查

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

检查以前的部署

此策略检查映像是否已预先部署到一个或多个环境,然后再部署到配置了 Check 的特定环境/资源。

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