Azure Pipelines
Cimon Attest Task
The best method to run Cimon Attest in Azure Pipelines is through the dedicated extension that allows generating and attesting your provenance seamlessly within any Azure Pipelines build. The extension can be found at the official Visual Studio Marketplace here.
The extension is currently supported only for Ubuntu-based hosted runners:
vmImage: 'ubuntu-latest'
vmImage: 'ubuntu-22.04'
vmImage: 'ubuntu-20.04'
Installation
Prerequisites
Before installing the Azure Pipelines Extension, ensure that you have the following prerequisites:
- An Azure DevOps organization with sufficient permissions to install extensions.
- Access to the Azure Pipelines service in your organization.
Install Azure Pipelines Extension
To install the Cimon Extension in your organization, follow these steps:
- Sign in to your Azure DevOps organization.
- Navigate to the Cimon extension on Visual Studio Marketplace - https://marketplace.visualstudio.com/items?itemName=CycodeLabs.cimon.
- Click the "Get it free" button to start the installation process.
- Select the organization where you want to install the extension and click Install.
- Wait for the installation to complete. Once installed, you will see a success message.
Example Usage
Once the extension is installed, you may edit the desired Azure Pipeline workflow and add the CimonAttest@0
task once created the desired artifacts. You can attest for any artifact, as long as they have a unique SHA256 digest.
The following Azure Pipelines workflow simulates how to generate provenance for specified hashes of dist/artifact1
and dist/artifact2
.
The workflow has the following steps:
- Build artifacts: This step simulates a process in which artifacts are created before the
CimonAttest@0
invocation. The artifacts could be of any kind -.jar
,.war
,.whl
,.dll
,.exe
, etc. In the example, we generate two stub artifacts. - Generate sign key: This step creates a private key that will be used for the signature process. It could be substituted for any other key in the PEM format of the supported keys (see more on supported format here. This step is optional.
- CimonAttest task: This step uses the CimonAttest task, the subject's input, and the signature key (if provided) to generate SLSA provenance by extracting the relevant information from the build and signing it.
trigger:
- main
pool:
vmImage: ubuntu-latest
steps:
- script: |
mkdir dist
echo artifact123 > dist/artifact1
echo artifact321 > dist/artifact2
displayName: Build artifacts
- script: |
openssl genrsa -out private-key.pem 3072
displayName: Generate sign key
- task: CimonAttest@0
inputs:
clientId: "$(CIMON_CLIENT_ID)"
secret: "$(CIMON_SECRET)"
subjects: |
dist/artifact1
dist/artifact2
signKey: private-key.pem
More examples could be found in the examples page.
Cimon Attest Parameters
Name | Default | |
---|---|---|
clientId | Cimon client ID for authentication | |
secret | Cimon secret for authentication | |
url | Cimon endpoint for authentication | |
subjects | A white space seperated list of paths, or base64-encoded subjects. Each path can be file, directory or image reference | |
imageRef | (deprecated) The container reference to generate provenance for. Either subjects or imageRef are required | |
signKey | Input path to a private ECDSA/RSA/ED25519 key used to sign provenance statement. Can be an absolute path or a relative path to the working directory | |
provenanceOutput | provenance.intoto.jsonl | Provenance output path. Can be an absolute path or a relative path to the working directory |
signedProvenanceOutput | provenance.intoto.jsonl.sig | Signed provenance output path. Can be an absolute path or a relative path to the working directory |
reportJobSummary | true | Enable to report the provenance documents as job summary output |
reportArtifact | true | Enable to report the provenance documents as job artifacts |
logLevel | info | Log level (Used for debugging) |
failOnError | false | Fail the CI if Cimon encountered an error |
releasePath | Path to Cimon release file (Used for debugging) |
Cimon Attest Output
Cimon Attest task provides output information that can be used when task execution is over:
In the example, we use two output variables of the CimonAttest
task:
provenanceOutput
- Path to a file that contains provenance output. It should exist if the task succeeded.signedProvenanceOutput
- Path to a file that contains signed provenance output. It should exist if the task succeeded and was given a signing key.
steps:
- task: CimonAttest@0
inputs: ...
name: cimonAttest
# provenanceOutput is the path to the provenance output file
- script: |
cat $(cimonAttest.provenanceOutput) | jq
condition: ne(variables['cimonAttest.provenanceOutput'], '')
displayName: Print provenance
# signedProvenanceOutput is the path to the signed provenance output file
# relevant only if signature keys were given.
- script: |
cat $(cimonAttest.signedProvenanceOutput) | jq
condition: ne(variables['cimonAttest.signedProvenanceOutput'], '')
displayName: Print signed provenance
Job Summary Report
Cimon Attest uploads the provenance document as a job summary for the Azure Pipelines job, which is available in the "Extensions" tab. The report could be turned off by introducing the reportJobSummary: false
parameter.
Additional info for how it works can be found here.
Output Artifacts
Cimon Attest uploads the provenance document as an artifact for the Azure Pipelines job so that it will be available for download and optionally transferred to the consumers. The artifact upload could be turned off by introducing the reportArtifact: false
parameter.
Additional info for publishing and downloading job artifacts can be found here.
Cimon Integration with Cycode
Cimon Attest uploads signed or unsigned provenance documents to the Cycode platform for storage, enrichment, and verification. For that, you need to supply the task with service account credentials or personal access token, together with the endpoint URL:
steps:
- task: CimonAttest@0
inputs:
clientId: "$(CIMON_CLIENT_ID)"
secret: "$(CIMON_SECRET)"
url: "$(CIMON_URL)"
subjects: $(hashes)
signKey: $(signKey)
Examples
The following examples use Azure Pipelines task syntax but apply to all other implementations of Cimon Attest for different platforms.
Generate provenance for given subjects without signature
steps:
- script: |
mkdir dist
echo artifact123 > dist/artifact1
echo artifact321 > dist/artifact2
displayName: "Build artifacts"
- task: CimonAttest@0
inputs:
clientId: "$(CIMON_CLIENT_ID)"
secret: "$(CIMON_SECRET)"
subjects: |
dist/artifact1
dist/artifact2
Generate provenance for given subjects with signature
steps:
- script: |
mkdir dist
echo artifact123 > dist/artifact1
echo artifact321 > dist/artifact2
displayName: "Build artifacts"
- script: |
openssl genrsa -out private-key.pem 3072
displayName: Generate sign key
- task: CimonAttest@0
inputs:
clientId: "$(CIMON_CLIENT_ID)"
secret: "$(CIMON_SECRET)"
subjects: |
dist/artifact1
dist/artifact2
signKey: private-key.pem
Generate provenance for the entire directory
steps:
- script: |
mkdir dist
echo artifact123 > dist/artifact1
echo artifact321 > dist/artifact2
displayName: "Build artifacts"
- task: CimonAttest@0
inputs:
clientId: "$(CIMON_CLIENT_ID)"
secret: "$(CIMON_SECRET)"
subjects: |
dist
Generate provenance for predefined subjects with designated hashes
steps:
- script: |
mkdir dist
echo artifact123 > dist/artifact1
echo artifact321 > dist/artifact2
echo "##vso[task.setvariable variable=hashes]$(sha256sum dist/artifact1 dist/artifact2 | base64 -w0)"
displayName: "Build artifacts and calculate hashes"
- task: CimonAttest@0
inputs:
clientId: "$(CIMON_CLIENT_ID)"
secret: "$(CIMON_SECRET)"
subjects: $(hashes)
Generate provenance for an container image reference
steps:
- task: CimonAttest@0
inputs:
clientId: "$(CIMON_CLIENT_ID)"
secret: "$(CIMON_SECRET)"
subjects: "cycodelabs/cimon@sha256:ad4ab84178621f359a5ec1ba9eff8ba46626d8d1999416646b6aaa96bfcbf802"
Generate provenance and upload it together with the artifacts
steps:
- script: |
mkdir dist
echo artifact123 > dist/artifact1
echo artifact321 > dist/artifact2
displayName: "Build artifacts"
- task: CimonAttest@0
inputs:
clientId: "$(CIMON_CLIENT_ID)"
secret: "$(CIMON_SECRET)"
subjects: |
dist
reportArtifact: false
provenanceOutput: dist/provenance.jsonl
- publish: dist
artifact: myartifact