Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

Docker Content Trust

Azure DevOps Services

Docker Content Trust (DCT) lets you use digital signatures for data sent to and received from remote Docker registries. These signatures let you verify the integrity and publisher of specific image tags on the client side or at runtime.

Note

To sign an image, you need a Docker Registry with an attached Notary server (examples include Docker Hub or Azure Container Registry).

Signing images in Azure Pipelines

Prerequisites on the development machine

  1. Use Docker trust's built-in generator or manually generate delegation key pair. If the built-in generator is used, the delegation private key is imported into the local Docker trust store. Otherwise, you need to manually import the private key into the local Docker trust store. See Manually Generating Keys for details.
  2. Use the delegation key generated in the previous step to upload the first key to a delegation and initiate the repository.

Tip

To view the list of local Delegation keys, use the Notary CLI to run the following command: $ notary key list.

Set up pipeline for signing images

  1. Get the delegation private key from the local Docker trust store on your development machine, and add it as a secure file in Pipelines.

  2. Authorize this secure file for use in all pipelines.

  3. The service principal associated with containerRegistryServiceConnection must have the AcrImageSigner role in the target container registry.

  4. Create a pipeline based on the following YAML snippet:

    pool:
     vmImage: 'ubuntu-latest'
    
    variables:
     system.debug: true
     containerRegistryServiceConnection: serviceConnectionName
     imageRepository: foobar/content-trust
     tag: test
    
    steps:
    - task: Docker@2
     inputs:
     command: login
     containerRegistry: $(containerRegistryServiceConnection)
    
    - task: DownloadSecureFile@1
     name: privateKey
     inputs:
     secureFile: cc8f3c6f998bee63fefaaabc5a2202eab06867b83f491813326481f56a95466f.key
    - script: |
     mkdir -p $(DOCKER_CONFIG)/trust/private
     cp $(privateKey.secureFilePath) $(DOCKER_CONFIG)/trust/private
    
    - task: Docker@2
     inputs:
     command: build
     Dockerfile: '**/Dockerfile'
     containerRegistry: $(containerRegistryServiceConnection)
     repository: $(imageRepository)
     tags: |
     $(tag)
    
     - task: Docker@2
     inputs:
     command: push
     containerRegistry: $(containerRegistryServiceConnection)
     repository: $(imageRepository)
     tags: |
     $(tag)
     env:
     DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: $(DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE)
     DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE: $(rootPassphrase)
    

    In the previous example, the DOCKER_CONFIG variable is set by the login command in the Docker task. Set up DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE and DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE as secret variables for your pipeline.

    DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE in this example refers to the private key's passphrase (not the repository passphrase). We only need the private key's passphrase in this example because the repository has been initiated already (prerequisites).


Feedback

Was this page helpful?

Additional resources