jenkins
sidebar_position: 2 sidebar_label: "Jenkins" title: Integrating Scribe in your Jenkins pipeline
Use the following instructions to integrate your Jenkins pipelines with Scribe.
1. Obtain a Scribe Hub API Token
Create an API token in Scribe Hub > Account > Tokens. Copy it to a safe temporary notepad until you complete the integration.
The token is a secret and will not be accessible from the UI after you finalize the token generation.
2. Add the API token to Jenkins secrets
-
Log in to your Jenkins account and select Dashboard > Manage Jenkins > Manage credentials (under Security options).
-
Select 'Global' in the list of domains:
-
In the Global credentials section, click + Add Credentials. A new Credentials form opens.
-
Copy the Scribe Hub API Token to the Password field and set the username to
SCRIBE_CLIENT_ID
. -
Set ID to
scribe-auth-id
(lowercase). -
Click Create.
3. Install Scribe CLI
Valint - Scribe CLI is required to generate evidence such as SBOMs and SLSA provenance. Install Valint on your build runner with the following command:
sh 'curl -sSfL https://get.scribesecurity.com/install.sh | sh -s -- -b ./temp/bin'
Alternatively, add an installation stage at the beginning of your relevant builds as follows:
stage('install-valint') {
steps {
sh 'curl -sSfL https://get.scribesecurity.com/install.sh | sh -s -- -b ./temp/bin'
}
}
Note: To avoid potentially costly commits, add the Scribe output directory **/scribe
to your .gitignore file.
4. Instrument your build scripts
Basic usage
Generate an SBOM of an image built in the pipeline by adding a step to call Valint at the end of the build.
Example Jenkinsfile in declarative syntax:
pipeline {
agent any
environment {
PATH="./temp/bin:$PATH"
}
stages {
stage('install-valint') {
steps {
sh 'curl -sSfL https://get.scribesecurity.com/install.sh | sh -s -- -b ./temp/bin'
}
}
stage('bom') {
steps {
withCredentials([token(credentialsId: 'scribe-auth-id', variable: 'SCRIBE_TOKEN')]) {
sh '''
valint bom busybox:latest \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_API_TOKEN
'''
}
}
}
}
Jenkinsfile scripted syntax:
node {
withEnv([
"PATH=./temp/bin:$PATH"
]) {
stage('install') {
sh 'curl -sSfL https://get.scribesecurity.com/install.sh | sh -s -- -b ./temp/bin'
}
stage('bom') {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')]) {
sh '''
valint bom busybox:latest \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_TOKEN '''
'''
}
}
}
Additional examples
Following are more examples of integration of Valint with Jenkins deployed in different forms. In these example we added Valint usage examples that generate source code SBOM by calling it in the build script right after the code is checked out and SLSA provenance generation.
Details
Jenkins over Docker
Make sure you have the following Jenkins extensions installed:Example SLSA prvenance generation and verification
pipeline {
agent any
stages {
stage('slsa-provenance') {
agent {
docker {
image 'scribesecurity/valint:latest'
reuseNode true
args "--entrypoint="
}
}
steps {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')])
sh '''
valint slsa busybox:latest \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_TOKEN '''
}
}
stage('verify') {
agent {
docker {
image 'scribesecurity/valint:latest'
reuseNode true
args "--entrypoint="
}
}
steps {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')])
sh '''
valint verify busybox:latest -i statement-slsa \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_TOKEN '''
}
}
}
}
Jenkins over Kubernetes
Prerequisites
Jenkins over Kubernetes installed.
Example SBOM generation
pipeline {
agent {
kubernetes {
yamlFile 'jenkins/k8s/scribe-test/KubernetesPod.yaml'
}
}
stages {
stage('checkout-bom') {
steps {
container('git') {
sh 'git clone -b v1.0.0-alpha.4 --single-branch https://github.com/mongo-express/mongo-express.git mongo-express-scm'
}
container('valint') {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')]) {
sh '''
valint bom dir:mongo-express-scm \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_TOKEN '''
}
}
}
}
stage('image-bom') {
steps {
container('valint') {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')]) {
sh '''
valint bom mongo-express:1.0.0-alpha.4 \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_TOKEN '''
}
}
}
}
}
}
This example uses Jenkins over k8s plugin with the Pod template as follows:
metadata:
labels:
some-label: jsl-scribe-test
spec:
containers:
- name: jnlp
env:
- name: CONTAINER_ENV_VAR
value: jnlp
- name: valint
image: scribesecurity/valint:latest
command:
- cat
tty: true
- name: git
image: alpine/git
command:
- cat
tty: true
Example SLSA generationa nd verification
pipeline {
agent {
kubernetes {
yamlFile './KubernetesPod.yaml'
}
}
stages {
stage('slsa-provenance') {
steps {
container('valint') {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')]) {
sh '''
valint slsa mongo-express:1.0.0-alpha.4 \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_TOKEN '''
}
}
}
}
stage('verify') {
steps {
container('valint') {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')]) {
sh '''
valint verify mongo-express:1.0.0-alpha.4 -i statement-slsa \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_TOKEN '''
}
}
}
}
}
}
This example uses Jenkins over k8s plugin with the Pod template defined as follows:
metadata:
labels:
some-label: jsl-scribe-test
spec:
containers:
- name: jnlp
env:
- name: CONTAINER_ENV_VAR
value: jnlp
- name: valint
image: scribesecurity/valint:latest
command:
- cat
tty: true
- name: git
image: alpine/git
command:
- cat
tty: true
Vanilla Jenkins (without an agent)
Prerequisites
curl
installed on your build node in Jenkins.
Sample integration code
pipeline {
agent any
environment {
PATH="./temp/bin:$PATH"
}
stages {
stage('install') {
steps {
cleanWs()
sh 'curl -sSfL https://raw.githubusercontent.com/scribe-security/misc/master/install.sh | sh -s -- -b ./temp/bin'
}
}
stage('checkout') {
steps {
sh 'git clone -b v1.0.0-alpha.4 --single-branch https://github.com/mongo-express/mongo-express.git mongo-express-scm'
}
}
stage('dir-bom') {
steps {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')]) {
sh '''
valint bom dir:mongo-express-scm \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_TOKEN '''
}
}
}
stage('image-bom') {
steps {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')]) {
sh '''
valint bom mongo-express:1.0.0-alpha.4 \
--context-type jenkins \
--output-directory ./scribe/valint testing \
-P $SCRIBE_TOKEN '''
}
}
}
}
}
Example SLSA provenance
pipeline {
agent any
stages {
stage('install') {
steps {
cleanWs()
sh 'curl -sSfL https://raw.githubusercontent.com/scribe-security/misc/master/install.sh | sh -s -- -b ./temp/bin'
}
}
stage('slsa-provenance') {
steps {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')]) {
sh '''
valint slsa busybox:latest \
--context-type jenkins \
--output-directory ./scribe/valint \
-P $SCRIBE_TOKEN '''
}
}
}
stage('image-bom') {
steps {
withCredentials([usernamePassword(credentialsId: 'scribe-auth-id', passwordVariable: 'SCRIBE_TOKEN')]) {
sh '''
valint verify busybox:latest -i statement-slsa \
--context-type jenkins \
--output-directory ./scribe/valint testing \
-P $SCRIBE_TOKEN '''
}
}
}
}
}
Details
Using an OCI registry as an evidence store instead of Scribe Hub
For on-prem deployment scenarios where you do not want to utilize Scribe Hub as a SaaS you can store, retrieve, and verify evidence with an OCI Resitry (learn more)Related flags:
--oci
Enable OCI store.--oci-repo
- Evidence store location.
- Allow Valint Read and Write access to this registry.
- Login to the registry, for example with
docker login
.
Basic usage
A basic usage generating SBOM of an image built in the pipeline by adding a step to call Valint at the end of the build.
Example Jenkinsfile in declarative syntax:
pipeline {
agent any
environment {
PATH="./temp/bin:$PATH"
}
stages {
stage('install') {
steps {
sh 'curl -sSfL https://get.scribesecurity.com/install.sh | sh -s -- -b ./temp/bin'
}
}
stage('bom') {
steps {
sh '''
valint [bom,slsa,evidence] [target] \
-o [attest, statement] \
--context-type jenkins \
--output-directory ./scribe/valint \
--oci --oci-repo=[my_repo]
}
}
}
stage('verify') {
steps {
sh '''
valint verify [target] \
-i [attest, statement, attest-slsa, statement-slsa, attest-generic, statement-generic] \
--context-type jenkins \
--output-directory ./scribe/valint \
--oci --oci-repo=[my_repo] '''
}
}
}
}
}
Example Jenkinsfile in scripted syntax.
node {
withEnv([
"PATH=./temp/bin:$PATH"
]) {
stage('install') {
sh 'curl -sSfL https://get.scribesecurity.com/install.sh | sh -s -- -b ./temp/bin -D'
}
stage('bom') {
sh '''
valint [bom,slsa,evidence] [target] \
-o [attest, statement] \
--context-type jenkins \
--output-directory ./scribe/valint \
--oci --oci-repo=[my_repo] '''
}
}
stage('verify') {
withCredentials([
token(credentialsId: 'scribe-auth-id', variable: 'SCRIBE_TOKEN')
]) {
sh '''
valint verify [target] \
-i [attest, statement, attest-slsa, statement-slsa, attest-generic, statement-generic] \
--context-type jenkins \
--output-directory ./scribe/valint \
--oci --oci-repo=[my_repo] '''
}
}
}
}
5. Signing with x509 keys
You can sign evidence with x509 file based keys.
Related flags:
--key
x509 Private key path.--cert
- x509 Certificate path.--ca
- x509 CA Chain path.
While using
x509
, for examplevalint slsa busybox:latest --attest.default x509 --key my_key.pem ..
Related environment:
ATTEST_KEY
x509 Private key pemATTEST_CERT
x509 Cert pemATTEST_CA
x509 CA Chain pem
While using
x509-env
, for exampleATTEST_KEY=$(cat my_key.pem) .. valint slsa busybox:latest --attest.default x509-env
While using
x509-env
Refrain from usingslsa
command--all-env
Further secure access to
attest-key
credential is recommended, for example using a Role-Based Access Control plugin.
Example of generating and verifying a SLSA provenance attestation
withCredentials([file(credentialsId: 'attest-key', variable: 'ATTEST_KEY_PATH'),
file(credentialsId: 'attest-cert', variable: 'ATTEST_CERT_PATH'),
file(credentialsId: 'attest-ca', variable: 'ATTEST_CA_PATH')
{
sh '''
valint slsa [target] \
--key $ATTEST_KEY_PATH \
--cert $ATTEST_CERT_PATH \
--ca $ATTEST_CA_PATH \
--context-type jenkins \
-o attest \
--attest.default x509 \
--output-directory ./scribe/valint \
'''
}
Verification:
withCredentials([file(credentialsId: 'attest-cert', variable: 'ATTEST_CERT_PATH'),
file(credentialsId: 'attest-ca', variable: 'ATTEST_CA_PATH')
{
sh '''
valint verify [target] \
--cert $ATTEST_CERT_PATH \
--ca $ATTEST_CA_PATH \
--context-type jenkins \
-i attest-slsa \
--attest.default x509 \
--output-directory ./scribe/valint \
'''
}
Using custom x509 keys
x509 signer allows you store utilize file based keys for signing.
Related flags:
--key
x509 Private key path.--cert
- x509 Certificate path.--ca
- x509 CA Chain path.
While using
x509
, for examplevalint slsa busybox:latest --attest.default x509 --key my_key.pem ..
Related environment:
ATTEST_KEY
x509 Private key pem content.ATTEST_CERT
- x509 Cert pem content.ATTEST_CA
- x509 CA Chain pem content.
While using
x509-env
, for exampleATTEST_KEY=$(cat my_key.pem) .. valint slsa busybox:latest --attest.default x509-env
While using
x509-env
Refrain from usingslsa
command--all-env
Alternative evidence stores
You can learn more about alternative stores here.
OCI Evidence store
Valint supports both storage and verification flows for attestations
and statement
objects utilizing OCI registry as an evidence store.
Using OCI registry as an evidence store allows you to upload, download and verify evidence across your supply chain in a seamless manner.
Related flags:
--oci
Enable OCI store.--oci-repo
- Evidence store location.
Before you begin
Evidence can be stored in any accusable registry.
- Write access is required for upload (generate).
- Read access is required for download (verify).
You must first login with the required access privileges to your registry before calling Valint.
For example, using docker login
command or Docker Pipeline custom registry.
Usage
Following is a Jenkinsfile in the declarative syntax.
pipeline {
agent any
environment {
PATH="./temp/bin:$PATH"
}
stages {
stage('install') {
steps {
sh 'curl -sSfL https://get.scribesecurity.com/install.sh | sh -s -- -b ./temp/bin'
}
}
stage('bom') {
steps {
sh '''
valint [bom,slsa,evidence] [target] \
-o [attest, statement] \
--context-type jenkins \
--output-directory ./scribe/valint \
--oci --oci-repo=[my_repo] '''
}
}
stage('verify') {
steps {
sh '''
valint verify [target] \
-i [attest, statement, attest-slsa, statement-slsa, attest-generic, statement-generic] \
--context-type jenkins \
--output-directory ./scribe/valint \
--oci --oci-repo=[my_repo] '''
}
}
}
}
Following is a Jenkinsfile in the scripted syntax.
node {
withEnv([
"PATH=./temp/bin:$PATH"
]) {
stage('install') {
sh 'curl -sSfL https://get.scribesecurity.com/install.sh | sh -s -- -b ./temp/bin -D'
}
stage('bom') {
sh '''
valint [bom,slsa,evidence] [target] \
-o [attest, statement] \
--context-type jenkins \
--output-directory ./scribe/valint \
--oci --oci-repo=[my_repo] '''
}
stage('verify') {
withCredentials([
sh '''
valint verify [target] \
-i [attest, statement, attest-slsa, statement-slsa, attest-generic, statement-generic] \
--context-type jenkins \
--output-directory ./scribe/valint \
--oci --oci-repo=[my_repo] '''
}
}
}
Use
jenkins
as context-type.