Controlli dei criteri degli artefatti

Azure DevOps Services

I criteri degli artefatti vengono applicati prima della distribuzione in ambienti critici, ad esempio la produzione. Questi criteri vengono valutati in base a tutti gli artefatti distribuibili nell'esecuzione della pipeline specificata e bloccano la distribuzione se gli artefatti non sono conformi. L'aggiunta di un controllo per valutare Artifact richiede la configurazione dei criteri personalizzati. Questa guida descrive come creare criteri personalizzati.

Nota

Attualmente, i tipi di artefatti supportati sono per le immagini del contenitore e gli ambienti Kubernetes

Prerequisiti

Usare Rego per definire criteri facili da leggere e scrivere.

Acquisire familiarità con il linguaggio di query Rego . Le nozioni di base verranno eseguite.

Per supportare modelli di documenti strutturati come JSON, Rego estende Datalog. Le query Rego sono asserzioni sui dati archiviati in OPA. Queste query possono essere usate per definire criteri che enumerare istanze di dati che violano lo stato previsto del sistema.

Creazione di criteri personalizzati

Di seguito sono riportati i criteri di esempio condivisi. In base ai requisiti, è possibile creare un set personalizzato di criteri.

Controllare un progetto o una pipeline specifici

Questo criterio controlla se le immagini vengono compilate da Azure Pipelines e Pipeline-foo. Per il corretto funzionamento, la definizione della pipeline deve eseguire l'override del campo del nome in un modo simile a: AzureDevOps_$(BuildDefinitionName)_$(Date:yyyYMMdd)$(Rev:.r). Per altre informazioni sulle esecuzioni della pipeline di denominazione, vedere qui.

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

Controllare i registri consentiti

Questo criterio controlla se le immagini provengono solo da registri consentiti.

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

Controllare le porte non consentite

Questo criterio verifica la presenza di porte non consentite esposte nell'immagine del contenitore.

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

Controllare le distribuzioni precedenti

Questo criterio controlla se l'immagine è stata pre-distribuita in uno/più ambienti prima di essere distribuita in un ambiente o in risorse specifiche con Check configurato.

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