Artefaktrichtlinienüberprüfungen

Azure DevOps Services

Artefaktrichtlinien werden vor der Bereitstellung in kritischen Umgebungen wie der Produktion erzwungen. Diese Richtlinien werden anhand aller bereitstellungsfähigen Artefakte in der angegebenen Pipelineausführung ausgewertet und blockieren die Bereitstellung, wenn die Artefakte nicht übereinstimmen. Das Hinzufügen einer Überprüfung zum Auswerten des Artefakts erfordert die Konfiguration der benutzerdefinierten Richtlinie. In diesem Leitfaden wird beschrieben, wie benutzerdefinierte Richtlinien erstellt werden können.

Hinweis

Derzeit werden die unterstützten Artefakttypen für Containerimages und Kubernetes-Umgebungen verwendet.

Voraussetzungen

Verwenden Sie Rego zum Definieren einer Richtlinie, die einfach zu lesen und zu schreiben ist.

Machen Sie sich mit der Rego-Abfragesprache vertraut. Grundlagen werden erstellt.

Um strukturierte Dokumentmodelle wie JSON zu unterstützen, erweitert Rego Datalog. Regoabfragen sind Assertionen für in OPA gespeicherte Daten. Diese Abfragen können verwendet werden, um Richtlinien zu definieren, die Instanzen von Daten auflisten, die den erwarteten Zustand des Systems verletzen.

Erstellen benutzerdefinierter Richtlinien

Im Folgenden finden Sie die freigegebenen Beispielrichtlinien. Basierend auf Ihren Anforderungen können Sie Ihren eigenen Richtliniensatz erstellen.

Überprüfen eines bestimmten Projekts/einer bestimmten Pipeline

Mit dieser Richtlinie wird überprüft, ob die Images von Azure Pipelines und Pipeline-foo erstellt wurden. Damit dies funktioniert, sollte die Pipelinedefinition das Feld name in etwa in etwa überschreiben: AzureDevOps_$(BuildDefinitionName)_$(Date:yyyyMMMdd)$(Rev:.r). Weitere Informationen zum Benennen von Pipelineausführungen finden Sie hier.

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

Überprüfen zulässiger Registrierungen

Mit dieser Richtlinie wird überprüft, ob die Bilder nur von zulässigen Registrierungen stammen.

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

Überprüfen verbotener Ports

Mit dieser Richtlinie wird auf alle verbotenen Ports überprüft, die im Containerimage verfügbar gemacht werden.

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

Überprüfen früherer Bereitstellungen

Mit dieser Richtlinie wird überprüft, ob das Image in einer oder mehreren Umgebungen vorab bereitgestellt wurde, bevor es in bestimmten Umgebungen/Ressourcen mit konfiguriertem Check bereitgestellt wurde.

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