Skip to main content

Scripts for Docker integration with Jenkins using PKCS11 library

Get DigiCert​​®​​ Software Trust Manager client tools set up and integrated with Jenkins and Docker Content Trust so that it can be automated into a CI/CD pipeline.

Prerequisites

Docker Content Trust setup

Docker Content Trust only works with DigiCert​​®​​ Software Trust Manager on Linux.

Belangrijk

Make sure you configure the Jenkins agent to run on the same machine and user where the Docker Content trust is set up. The repository and generated keys remain on the machine where it is setup and cannot be ported or managed by PKCS11.

Download and set up PKCS11 library

The following process guides you through the process to download and register the DigiCert​​®​​ Software Trust Manager PKCS11 library so that Docker can pick it up.

  1. Sign in to DigiCert ONE.

  2. Navigate to DigiCert​​®​​ Software Trust Manager > Resources > Client tool repository.

  3. Select Linux as the operating system.

  4. Click the download icon next to DigiCert​​®​​ Software Trust Manager PKCS#11 Library.

  5. Rename smpkcs11.so to libykcs11.so.

  6. Copy libykcs11.so to /usr/local/lib.

Set up Docker root key

You need to generate the Docker root key. The root key needs to have a certificate with “CN=root” in it. The following example generates it on DigiCert​​®​​ Software Trust Manager with keytool provided with Java.

  1. Create a PKCS11 configuration file with the following parameters:

    name=signingmanager
    library="<Path to PKCS11 shared library file(smpkcs11.so)>"
    slotListIndex=0
  2. Name the file pkcs11properties.cfg.

  3. Run the keytool command to generate the root key.

    keytool -keystore NONE -storetype PKCS11 -storepass NONE -providerClass 
    sun.security.pkcs11.SunPKCS11 -providerArg <Path to pkcs11properties.cfg> -genkeypair -keyalg EC -keysize 256 -dname “CN=root” -alias docker_root_key

Belangrijk

The delegation key must be an ECDSA 256-bit key to work with Docker. Docker keys do not work with RSA keys.

Set up Docker delegation key

A delegation key and certificate is required to sign images in Docker. You can do this in Software Trust Manager or using SMCTL:

Add delegation key as Docker signer

  1. Initialize the Docker repository.

  2. Generate the repository keys internally.

  3. Add the delegation key as a delegation for the repository.

  4. Download the certificate you generated for the Docker delegation key in Software Trust Manager or SMCTL.

  5. Reference the downloaded certificate in this command:

    docker trust signer add --key <Docker Delegation Key.crt from previous step> "<Name of the delegation>" <Registry URL>/<Repository Name>

    Command sample

    docker trust signer add --key digicert_delegation.crt "Digicert" digicert/hello-digicert
  6. To inspect the delegation, run:

    docker trust inspect –pretty <Registry URL>/<Repository Name>

When an image push is done with content trust enabled, Docker signs the tag using the delegation key and pushes the trust data to the remote notary server. When an image pull/run is done with content trust enabled, the image is verified.

Integration with Jenkins

Agent setup for pipeline

You can only use a Linux node as an agent for the Docker Signing pipeline.

Make sure the node is setup on Jenkins to connect to the Linux machine and the user where the Docker Content Trust was setup.

In the example below, a node is defined connecting to the Linux machine where the Docker Content Trust is setup and labelled ‘Linux’.

pipeline {
    agent{ label 'linux' }
}

Integration with Jenkins

Environment variables setup for Jenkins plugin in pipeline script

The client tools need these environment variables to connect with DigiCert​​®​​ Software Trust Manager to provide its service.

To integrate as environment variables that are part of the pipeline:

Docker build without content trust

Sometimes no trust data is associated with images built on other base images. When DOCKER_CONTENT_TRUST is enabled for the entire pipeline as an environment variable, the build stage or step will fail due to missing trust data in one of the base images.

To disable content trust for the specific build operation, use:

stage('Docker Build') {
    steps {
       sh 'docker build -t <Registry URL>/<Repository Name>:<Tag> --disable-content-trust=true .'
    }
}

Docker signed push tags

To push signed tags when DOCKER_CONTENT_TRUST is set for the entire pipeline as an environment variable:

stage('Docker Push Signed Tags') {
   steps {
        sh 'DOCKER_CONTENT_TRUST=1 docker push <Registry URL>/<Repository Name>:<Tag>'
    }
}

The signing is automatically done with the delegation key from DigiCert​​®​​ Software Trust Manager using the PKCS11 library because we have set the DOCKER_CONTENT_TRUST environment variable for the entire pipeline.

To push signed tags with DOCKER_CONTENT_TRUST enabled only for the specific operation:

stage('Docker Push Signed Tags') {
   steps {
        sh 'DOCKER_CONTENT_TRUST=1 docker push <Registry URL>/<Repository Name>:<Tag>'
    }
}

Opmerking

If a tag is not specified in the push operation then the image is not signed and trust metadata will not be pushed to the notary server.

Pulling and verifying signed images

Tip

This operation is not restricted to the machine where the Docker Content Trust is set up. It can be done on any machine.

When DOCKER_CONTENT_TRUST is enabled for the entire pipeline as an environment variable, a docker pull/run of any signed image will automatically verify the image:

stage('Docker Verify') {
    steps {
        sh 'docker pull <Registry URL>/<Repository Name>:<Tag>'
    }
}

When DOCKER_CONTENT_TRUST is not enabled for the entire pipeline as an environment variable, it can be enabled only for a specific operation:

stage('Docker Verify') {
    steps {
        sh 'DOCKER_CONTENT_TRUST=1 docker pull <Registry URL>/<Repository Name>:<Tag>'
    }
}

Sample pipeline

pipeline {
    agent{ label 'linux' }

    tools {
        gradle 'Gradle'
    }
    environment {
        SM_CLIENT_CERT_PASSWORD="gxmiK9Oe72Pn"
        SM_CLIENT_CERT_FILE="/home/siddharth/smtools/local_pkcs12.p12"
        SM_HOST="https://clientauth.one.digicert.com"
        SM_API_KEY="01ff018928e385329550b6e7a7_9b38fc5fbb4ef99ceeb7d61e6984107efa4283583cb7a64f5e292582cd3ed848"
    }

    stages {
        stage('Checkout') {
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '*/main']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'Siddharth-Srinivas', url: 'https://github.com/Siddharth-Srinivas/jenkins-test-repo.git']]])
            }
        }
        stage('Clean') {
            steps {
                sh "./gradlew clean"
            }
        }
        stage('Test') {
            steps {
                withGradle {
                    sh "./gradlew test"
                }
            }
        
            post {
                success {
                    junit "**/build/test-results/test/TEST-*.xml"
                }
            }
        }
        stage('Assemble') {
            steps {
                withGradle {
                    sh "./gradlew build"
                }
            }
        
            post {
                success {
                    archiveArtifacts "app/build/libs/app.jar"
                }
            }
        }
        stage('Docker Build') {
            steps {
                sh "docker build -t siddharthsrinivas/hello-world:${env.BUILD_NUMBER} ."
            }
        }
        stage('Docker Push Signed Tags') {
            steps {
                sh "docker tag siddharthsrinivas/hello-world:${env.BUILD_NUMBER} siddharthsrinivas/hello-world:latest"
                sh "DOCKER_CONTENT_TRUST=1 docker push siddharthsrinivas/hello-world:latest"
                sh "DOCKER_CONTENT_TRUST=1 docker push siddharthsrinivas/hello-world:${env.BUILD_NUMBER}"
            }
        }
    
        stage('Docker Verify') {
            steps {
                sh "DOCKER_CONTENT_TRUST=1 docker pull siddharthsrinivas/hello-world:${env.BUILD_NUMBER}"
                sh "DOCKER_CONTENT_TRUST=1 docker pull siddharthsrinivas/hello-world "
            }
        }    
    }
}