Partage via


Vérifications de la stratégie d’artefacts

Azure DevOps Services

Les stratégies d’artefact sont appliquées avant le déploiement dans des environnements critiques tels que la production. Ces stratégies sont évaluées par rapport à tous les artefacts déployables dans l’exécution du pipeline donné et bloquent le déploiement si les artefacts ne sont pas conformes. L’ajout d’une vérification pour évaluer Artifact nécessite que la politique personnalisée soit configurée. Ce guide décrit comment les stratégies personnalisées peuvent être créées.

Notes

Actuellement, les types d’artefacts pris en charge sont destinés aux images conteneur et aux environnements Kubernetes

Prérequis

Utilisez Rego pour définir une stratégie facile à lire et à écrire.

Familiarisez-vous avec le langage de requête Rego. Les bases suffisent.

Pour prendre en charge des modèles de documents structurés comme JSON, Rego étend Datalog. Les requêtes Rego sont des assertions sur les données stockées dans OPA. Ces requêtes peuvent être utilisées pour définir des stratégies qui énumèrent des instances de données qui ne sont pas conformes à l’état attendu du système.

Utilisation de stratégies personnalisées

Vous trouverez ci-dessous les exemples de stratégies partagées. En fonction de vos besoins, vous pouvez créer votre propre ensemble de stratégies.

Vérifier un projet/un pipeline spécifique

Cette stratégie vérifie si les images sont générées par Azure Pipelines et Pipeline-foo. Pour que cela fonctionne, la définition du pipeline doit remplacer le champ de nom par quelque chose comme : AzureDevOps_$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r). Vous trouverez plus d’informations sur la dénomination des exécutions de pipelines ici.

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

Vérifier les registres autorisés

Cette stratégie vérifie si les images proviennent uniquement des registres autorisés.

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

Vérifier les ports interdits

Cette stratégie vérifie les ports interdits exposés dans l’image conteneur.

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

Vérifier les déploiements antérieurs

Cette stratégie vérifie si l’image a été prédéployée sur un ou plusieurs environnements avant d’être déployée sur un environnement ou des ressources spécifiques avec Check configuré.

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