CI / CD Integration
Integrating Anchore Enterprise into your CI/CD pipeline enables fast shift-left feedback, allowing developers to identify and resolve security issues early in the software development lifecycle. This page provides best practices for tuning your CI/CD integration for performance and actionable feedback.
See the specific subpages for platform-specific guidance.
Requirements
The following a general requirements for CI/CD integration.
Accessibility
Anchore Enterprise should be deployed so that the API is accessible from your pipeline runner. Your Anchore Enterprise deployment must also be able to reach any relevant container registries from which to source images.
For access to the deployment, API keys are recommended.
The primary interface for integrating Anchore Enterprise into CI/CD environments is AnchoreCTL, a CLI tool designed for scripted automation. To ensure compatibility and simplify runner configuration, AnchoreCTL should always be version-aligned with your Anchore Enterprise deployment.
A recommended practice is to fetch AnchoreCTL directly from your Anchore Enterprise installation during the CI job. This guarantees the client version matches the server.
For more details, see Deploying AnchoreCTL.
Modes of Analysis
Anchore Enterprise supports two primary modes of operation for image analysis in CI pipelines: Distributed Analysis or Centralized Analysis. Both modes work with any CI/CD system as long as the AnchoreCTL binary can be installed and run, or you can access the Enterprise APIs directly.
Distributed Analysis (Default Recommended)
In distributed analysis, SBOM generation happens locally on the runner and is then sent to Anchore Enterprise for evaluation.
It is the recommended approach because it offers maximum flexibility in resourcing. You can improve SBOM generation speed by customising your anchoreCTL configuration and providing more CPU and fast I/O to your pipeline runners.
Distributed analysis does not currently support malware scanning. If malware scanning is required, use centralized analysis.
See Distributed Analysis for further information.
Centralized Analysis
In centralized analysis, the Anchore Enterprise deployment itself downloads and analyzes the image content. This is necessary if you require the malware scanning service to unpack and scan container layers.
You may need to enable Malware in your deployment configuration, see
hereSee Centralized Analysis for further information.
If you are using Distributed Analysis, you will want to ensure that your CI runners have fast CPU and I/O, to optimise the cataloging and SBOM generation process used by AnchoreCTL.
If your container images contain a large number of files and packages, you may be able to significantly reduce SBOM generation time by enabling parallelism. AnchoreCTL (v5.18+) can run catalogers in parallel rather than sequentially.
See Configuring AnchoreCTL for further information.
Use Policy Checks
Rather than just reviewing a raw list of vulnerabilities, which can be daunting and lack context, it is a best practice to use the Anchore Enforce policy engine to conduct compliance checks.
Policy-driven gating provides developers with precise, actionable feedback based on your own organizational policy or industry standards (e.g., NIST 800-53, CIS).
Use the following command to evaluate an image against your default policy and fail the CI job if it does not meet compliance requirements.
anchorectl image check <MY_IMAGE> --fail-based-on-results --detail
The --detail flag is essential for developers, as it provides the specific gate, trigger, and remediation recommendations needed to resolve policy violations.
One-Time Scan (Stateless Evaluation)
By default, adding an image to Anchore Enterprise for analysis means that the SBOM will be stored persistently in the deployment, until archived or deleted. This could mean your deployment stores more SBOMs than necessary; you may not care whether an SBOM for a CI build is persisted or not.
Anchore Enterprise has a featured called One Time Scan which can be used to deliver fast feedback in your pipeline jobs, namely vulnerability and policy analysis results, but doing so without persisting the SBOM in your Anchore Enterprise deployment. Use the anchorectl image one-time-scan command to conduct analysis in this mode. As with the anchorectl image check command, you can also pass a flag to fail the pipeline job if the policy analysis fails. For example:
anchorectl image one-time-scan ghcr.io/place/thing:v0.1.0 --from [docker, registry] --fail-on-policy-error
These one-time-scans will show as Stateless Evaluations in your system usage reporting in the Anchore Enterprise admin UI
By default, this command will return a policy check. Using the -o json parameter, JSON results for policy check, vulnerability scan and the SBOM will be returned. These results can then be machine parsed by the CI/CD job to determine actions.
1 - AWS CodeBuild
Image scanning can be integrated into your AWS CodeBuild pipeline using anchorectl. This guide provides an end-to-end example that creates all required AWS resources (ECR, CodeCommit, S3, IAM roles, CodeBuild, and CodePipeline) from scratch. If you already have an existing CodeBuild project and CodePipeline, the key integration points are the install phase (to install anchorectl), the post_build commands, and the artifacts section of the buildspec.yml in Step 5.
Requirements
- Anchore Enterprise is deployed in your environment, with the API accessible from your AWS CodeBuild environment.
- An AWS account with permissions to create ECR repositories, CodeCommit repositories, CodeBuild projects, CodePipeline pipelines, S3 buckets, and IAM roles.
- The AWS CLI installed and configured with valid credentials.
Set the following shell variables for use throughout the guide. Replace the placeholder values with your actual Anchore Enterprise deployment URL, username, and password. The ANCHORECTL_PASSWORD value should be treated as a secret to prevent exposure in logs.
export AWS_REGION=us-east-1
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export APP_NAME=myapp
export ECR_REPO_NAME=$APP_NAME
export CODECOMMIT_REPO_NAME=$APP_NAME-repo
export CODEBUILD_PROJECT_NAME=$APP_NAME-build
export CODEPIPELINE_NAME=$APP_NAME-pipeline
export ARTIFACT_BUCKET=${APP_NAME}-codepipeline-artifacts-${AWS_ACCOUNT_ID}-${AWS_REGION}
export CODEBUILD_ROLE_NAME=${APP_NAME}-codebuild-role
export CODEPIPELINE_ROLE_NAME=${APP_NAME}-codepipeline-role
### Anchore Enterprise connection details
export ANCHORECTL_URL=http://anchore-enterprise-api.example.com:8228
export ANCHORECTL_USERNAME=admin
export ANCHORECTL_PASSWORD=foobar
2. Create AWS Resources
a) ECR Repository
Create an ECR repository to store your container images. Image tag immutability is enabled to ensure each build produces a unique, traceable image tag derived from the git commit hash.
aws ecr create-repository \
--region "$AWS_REGION" \
--repository-name "$ECR_REPO_NAME" \
--image-tag-mutability IMMUTABLE \
--image-scanning-configuration scanOnPush=true
b) CodeCommit Repository
Create a CodeCommit repository to host your application source code.
aws codecommit create-repository \
--region "$AWS_REGION" \
--repository-name "$CODECOMMIT_REPO_NAME" \
--repository-description "Source repo for $APP_NAME"
c) S3 Artifact Bucket
Create an S3 bucket for CodePipeline to store build artifacts (including Anchore scan results). Versioning, encryption, and public access blocking are enabled for security best practices.
### us-east-1 does not support LocationConstraint
if [ "$AWS_REGION" = "us-east-1" ]; then
aws s3api create-bucket \
--bucket "$ARTIFACT_BUCKET" \
--region "$AWS_REGION"
else
aws s3api create-bucket \
--bucket "$ARTIFACT_BUCKET" \
--region "$AWS_REGION" \
--create-bucket-configuration LocationConstraint="$AWS_REGION"
fi
### Enable versioning
aws s3api put-bucket-versioning \
--bucket "$ARTIFACT_BUCKET" \
--versioning-configuration Status=Enabled
### Enable server-side encryption
aws s3api put-bucket-encryption \
--bucket "$ARTIFACT_BUCKET" \
--server-side-encryption-configuration '{
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms"
},
"BucketKeyEnabled": true
}
]
}'
### Block all public access
aws s3api put-public-access-block \
--bucket "$ARTIFACT_BUCKET" \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
3. Create IAM Roles
a) CodeBuild Role
The CodeBuild role needs permissions for CloudWatch Logs, S3 artifact access, CodeCommit source pulls, and ECR push/pull operations.
cat > codebuild-trust-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "codebuild.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
EOF
cat > codebuild-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Logs",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Sid": "ArtifactsBucket",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::$ARTIFACT_BUCKET",
"arn:aws:s3:::$ARTIFACT_BUCKET/*"
]
},
{
"Sid": "CodeCommitSource",
"Effect": "Allow",
"Action": [
"codecommit:GitPull"
],
"Resource": "arn:aws:codecommit:$AWS_REGION:$AWS_ACCOUNT_ID:$CODECOMMIT_REPO_NAME"
},
{
"Sid": "ECRAuth",
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken"
],
"Resource": "*"
},
{
"Sid": "ECRPushPull",
"Effect": "Allow",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:CompleteLayerUpload",
"ecr:GetDownloadUrlForLayer",
"ecr:InitiateLayerUpload",
"ecr:PutImage",
"ecr:UploadLayerPart",
"ecr:BatchGetImage"
],
"Resource": "arn:aws:ecr:$AWS_REGION:$AWS_ACCOUNT_ID:repository/$ECR_REPO_NAME"
}
]
}
EOF
aws iam create-role \
--role-name "$CODEBUILD_ROLE_NAME" \
--assume-role-policy-document file://codebuild-trust-policy.json
aws iam put-role-policy \
--role-name "$CODEBUILD_ROLE_NAME" \
--policy-name "${APP_NAME}-codebuild-inline" \
--policy-document file://codebuild-policy.json
export CODEBUILD_ROLE_ARN=$(aws iam get-role \
--role-name "$CODEBUILD_ROLE_NAME" \
--query 'Role.Arn' \
--output text)
b) CodePipeline Role
The CodePipeline role needs permissions for S3 artifact access, CodeCommit source operations, and CodeBuild build triggers.
cat > codepipeline-trust-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "codepipeline.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
EOF
cat > codepipeline-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3Artifacts",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:GetBucketVersioning",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::$ARTIFACT_BUCKET",
"arn:aws:s3:::$ARTIFACT_BUCKET/*"
]
},
{
"Sid": "CodeCommitSource",
"Effect": "Allow",
"Action": [
"codecommit:GetBranch",
"codecommit:GetCommit",
"codecommit:UploadArchive",
"codecommit:GetUploadArchiveStatus",
"codecommit:CancelUploadArchive"
],
"Resource": "arn:aws:codecommit:$AWS_REGION:$AWS_ACCOUNT_ID:$CODECOMMIT_REPO_NAME"
},
{
"Sid": "CodeBuildStart",
"Effect": "Allow",
"Action": [
"codebuild:BatchGetBuilds",
"codebuild:StartBuild"
],
"Resource": "arn:aws:codebuild:$AWS_REGION:$AWS_ACCOUNT_ID:project/$CODEBUILD_PROJECT_NAME"
}
]
}
EOF
aws iam create-role \
--role-name "$CODEPIPELINE_ROLE_NAME" \
--assume-role-policy-document file://codepipeline-trust-policy.json
aws iam put-role-policy \
--role-name "$CODEPIPELINE_ROLE_NAME" \
--policy-name "${APP_NAME}-codepipeline-inline" \
--policy-document file://codepipeline-policy.json
export CODEPIPELINE_ROLE_ARN=$(aws iam get-role \
--role-name "$CODEPIPELINE_ROLE_NAME" \
--query 'Role.Arn' \
--output text)
4. Create the CodeBuild Project
The CodeBuild project defines the build environment and passes Anchore Enterprise credentials as environment variables. The privilegedMode setting is required for Docker-in-Docker builds.
Note: The ANCHORECTL_PASSWORD is included as a PLAINTEXT environment variable here for simplicity. For production use, store it in AWS Secrets Manager or SSM Parameter Store and reference it with type: SECRETS_MANAGER or type: PARAMETER_STORE in the environmentVariables block.
cat > create-project.json <<EOF
{
"name": "$CODEBUILD_PROJECT_NAME",
"serviceRole": "$CODEBUILD_ROLE_ARN",
"source": {
"type": "CODEPIPELINE",
"buildspec": "buildspec.yml"
},
"artifacts": {
"type": "CODEPIPELINE"
},
"environment": {
"type": "LINUX_CONTAINER",
"image": "aws/codebuild/standard:7.0",
"computeType": "BUILD_GENERAL1_MEDIUM",
"privilegedMode": true,
"environmentVariables": [
{
"name": "AWS_REGION",
"value": "$AWS_REGION",
"type": "PLAINTEXT"
},
{
"name": "IMAGE_REPO_NAME",
"value": "$ECR_REPO_NAME",
"type": "PLAINTEXT"
},
{
"name": "ANCHORECTL_URL",
"value": "$ANCHORECTL_URL",
"type": "PLAINTEXT"
},
{
"name": "ANCHORECTL_USERNAME",
"value": "$ANCHORECTL_USERNAME",
"type": "PLAINTEXT"
},
{
"name": "ANCHORECTL_PASSWORD",
"value": "$ANCHORECTL_PASSWORD",
"type": "PLAINTEXT"
}
]
},
"timeoutInMinutes": 60
}
EOF
aws codebuild create-project \
--region "$AWS_REGION" \
--cli-input-json file://create-project.json
a) Distributed Mode
This is the most easily scalable method for scanning images. Distributed scanning uses the anchorectl utility to build the SBOM directly on the CodeBuild runner and then pushes the SBOM to Anchore Enterprise through the API. This avoids the need to provide registry credentials in the Enterprise backend, since the image is loaded directly from the local Docker daemon.
Clone the CodeCommit repository and create a buildspec.yml with the following content. The buildspec installs anchorectl directly from your Anchore Enterprise deployment (ensuring version compatibility), builds and tags the Docker image using the git commit hash, scans the image with Anchore Enterprise, and exports all scan artifacts.
git clone "$(aws codecommit get-repository \
--region "$AWS_REGION" \
--repository-name "$CODECOMMIT_REPO_NAME" \
--query 'repositoryMetadata.cloneUrlHttp' \
--output text)"
cd "$CODECOMMIT_REPO_NAME"
git checkout -b main
cat > buildspec.yml <<'EOF'
version: 0.2
phases:
install:
commands:
### install anchorectl from your Anchore Enterprise deployment to ensure version compatibility
- curl -sSfL -u "${ANCHORECTL_USERNAME}:${ANCHORECTL_PASSWORD}" "${ANCHORECTL_URL}/v2/system/anchorectl?operating_system=linux&architecture=amd64" | tar -zx -C /usr/local/bin anchorectl
pre_build:
commands:
- AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
### use the short git commit hash as the image tag for traceability
- IMAGE_TAG=$(echo "$CODEBUILD_RESOLVED_SOURCE_VERSION" | cut -c1-7)
- IMAGE_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${IMAGE_REPO_NAME}:${IMAGE_TAG}
- aws ecr get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com
build:
commands:
- |
docker build -t ${IMAGE_REPO_NAME}:${IMAGE_TAG} \
--build-arg CI=aws-codepipeline \
--build-arg REPO=${IMAGE_REPO_NAME} \
--build-arg COMMIT=${CODEBUILD_RESOLVED_SOURCE_VERSION} \
--build-arg COMMIT_SHORT=${IMAGE_TAG} \
--build-arg PIPELINE=${CODEBUILD_INITIATOR} \
--build-arg REGION=${AWS_REGION} \
.
- docker tag ${IMAGE_REPO_NAME}:${IMAGE_TAG} ${IMAGE_URI}
post_build:
commands:
### scan the image from the local Docker daemon (distributed mode) and wait for analysis to complete
### --get all=./ exports all scan artifacts (SBOMs, vulnerabilities, policy evaluation) to the working directory
- |
anchorectl image add ${IMAGE_URI} --dockerfile Dockerfile --from docker --dockerfile Dockerfile --no-auto-subscribe --wait --get all=./ \
--annotation "ci=aws-codepipeline" \
--annotation "repo=${IMAGE_REPO_NAME}" \
--annotation "commit=${CODEBUILD_RESOLVED_SOURCE_VERSION}" \
--annotation "commit_short=${IMAGE_TAG}" \
--annotation "pipeline=${CODEBUILD_INITIATOR}" \
--annotation "region=${AWS_REGION}"
### evaluate the image against your Anchore Enterprise policy
### set --fail-based-on-results to break the build if the policy evaluation returns FAIL
- anchorectl image check ${IMAGE_URI} --fail-based-on-results --detail
- docker push ${IMAGE_URI}
- printf '[{"name":"app","imageUri":"%s"}]' "${IMAGE_URI}" > imagedefinitions.json
artifacts:
files:
- imagedefinitions.json
- content.json
- image-metadata.json
- policy-evaluation.json
- sbom.json
- sbomcyclonedx.json
- sbomspdx.json
- vulnerability.json
EOF
cat > Dockerfile <<'EOF'
FROM public.ecr.aws/ubuntu/ubuntu:latest
ARG CI
ARG REPO
ARG COMMIT
ARG COMMIT_SHORT
ARG PIPELINE
ARG REGION
LABEL org.opencontainers.image.source="${REPO}" \
org.opencontainers.image.revision="${COMMIT}" \
com.anchore.ci="${CI}" \
com.anchore.commit.short="${COMMIT_SHORT}" \
com.anchore.pipeline="${PIPELINE}" \
com.anchore.region="${REGION}"
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
CMD ["python3", "--version"]
EOF
git add .
git commit -m "Initial commit"
git push origin main
cd ..
The --get all=./ flag on anchorectl image add exports the following scan artifacts to the build directory, which are then stored as pipeline artifacts in S3:
| Artifact | Description |
|---|
sbom.json | Anchore-native SBOM format |
sbomcyclonedx.json | CycloneDX SBOM (industry standard) |
sbomspdx.json | SPDX SBOM (industry standard) |
vulnerability.json | Full vulnerability report |
policy-evaluation.json | Policy evaluation results |
content.json | Package and file content listing |
image-metadata.json | Image metadata (digest, distro, layers) |
b) Centralized Mode
This method uses the “analyzer” pods in the Anchore Enterprise deployment to build the SBOM. This can create queuing if there are not enough analyzer processes, and this method will require the operator to provide ECR registry credentials in the Enterprise backend. This method may be preferred in cases where the Anchore Enterprise operator does not control the image build process (the analyzers can simply poll registries to look for new image builds as they are pushed), and this method also allows the operator to simply queue up the image for asynchronous scanning later if vulnerability and policy results are not required immediately. If the user wants malware scanning results from Anchore Enterprise’s clamav integration, the Centralized Scanning method is required.
To use centralized mode, replace the post_build commands in the buildspec above with the following. Note that --from docker is removed, so Anchore Enterprise will pull the image from the registry after it is pushed.
post_build:
commands:
### push the image first so Anchore Enterprise can pull it from the registry
- docker push ${IMAGE_URI}
### queue the image for scanning by Anchore Enterprise analyzers
### --no-auto-subscribe prevents automatic re-scanning on future tag updates
- |
anchorectl image add ${IMAGE_URI} --no-auto-subscribe --wait --get all=./ \
--annotation "ci=aws-codepipeline" \
--annotation "repo=${IMAGE_REPO_NAME}" \
--annotation "commit=${CODEBUILD_RESOLVED_SOURCE_VERSION}" \
--annotation "commit_short=${IMAGE_TAG}" \
--annotation "pipeline=${CODEBUILD_INITIATOR}" \
--annotation "region=${AWS_REGION}"
### evaluate the image against your Anchore Enterprise policy
- anchorectl image check ${IMAGE_URI} --fail-based-on-results --detail
- printf '[{"name":"app","imageUri":"%s"}]' "${IMAGE_URI}" > imagedefinitions.json
6. Create the CodePipeline
The pipeline has two stages: a Source stage that pulls from CodeCommit on each commit to the main branch, and a Build stage that runs the CodeBuild project.
cat > pipeline.json <<EOF
{
"pipeline": {
"name": "$CODEPIPELINE_NAME",
"roleArn": "$CODEPIPELINE_ROLE_ARN",
"artifactStore": {
"type": "S3",
"location": "$ARTIFACT_BUCKET"
},
"stages": [
{
"name": "Source",
"actions": [
{
"name": "Source",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "CodeCommit",
"version": "1"
},
"runOrder": 1,
"configuration": {
"RepositoryName": "$CODECOMMIT_REPO_NAME",
"BranchName": "main",
"PollForSourceChanges": "false"
},
"outputArtifacts": [
{
"name": "SourceOutput"
}
],
"inputArtifacts": []
}
]
},
{
"name": "Build",
"actions": [
{
"name": "Build",
"actionTypeId": {
"category": "Build",
"owner": "AWS",
"provider": "CodeBuild",
"version": "1"
},
"runOrder": 1,
"configuration": {
"ProjectName": "$CODEBUILD_PROJECT_NAME"
},
"inputArtifacts": [
{
"name": "SourceOutput"
}
],
"outputArtifacts": [
{
"name": "BuildOutput"
}
]
}
]
}
],
"version": 1
}
}
EOF
aws codepipeline create-pipeline \
--region "$AWS_REGION" \
--cli-input-json file://pipeline.json
7. Run the Pipeline
Start the pipeline manually:
aws codepipeline start-pipeline-execution \
--region "$AWS_REGION" \
--name "$CODEPIPELINE_NAME"
8. View Results
When the pipeline completes, view the build results in the AWS Console under CodeBuild > Build history > select your build > Build logs. The logs will display the anchorectl output including vulnerability counts and policy evaluation results.
The scan artifacts (SBOMs, vulnerability report, policy evaluation) are stored as build artifacts in the S3 artifact bucket. You can download them from CodePipeline > select your pipeline > BuildOutput artifact, or directly from the S3 bucket.
2 - GitLab
Requirements
- Anchore Enterprise is deployed in your environment, with the API accessible from your GitLab CI environment.
- Credentials for your GitLab Container Registry are added to Anchore Enterprise, under the Anchore account that you intend to use with GitLab CI. See Registries. For information on what registry/credentials must be added to allow Anchore Enterprise to access your GitLab Container Registry, see https://docs.gitlab.com/ee/user/packages/container_registry/.
Ensure that the following variables are set in your GitLab repository (settings -> CI/CD -> Variables -> Expand -> Add variable) or GitLab Group:
ANCHORECTL_USERNAME
ANCHORECTL_PASSWORD (masked)
ANCHORECTL_URL
GitLab has a minimum length of 8 for masked variables. Please ensure both your username and password meet this requirement.

2. Create config file
Create a new file in your repository. Name the file .gitlab-ci.yml.

a) Distributed Mode
This is the most easily scalable method for scanning images. Distributed scanning uses the anchorectl utility to build the SBOM directly on the build runner and then pushes the SBOM to Anchore Enterprise through the API. To use this scanning method, paste the following workflow script into your new .gitlab-ci.yml file. After building the image from your Dockerfile and scanning it with anchorectl, this workflow will display vulnerabilities and policy results in the build log. After pasting, click “Commit changes” to save the new file.
### Anchore Distributed Scan
# you will need three variables defined:
# ANCHORECTL_USERNAME
# ANCHORECTL_PASSWORD
# ANCHORECTL_URL
image: docker:latest
services:
- docker:dind
stages:
- build
- anchore
variables:
### set this to true if you want the result of the policy check to determine whether the job succeeds or not
ANCHORECTL_FAIL_BASED_ON_RESULTS: "false"
ANCHORE_IMAGE: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}
Build:
stage: build
script:
### build and push docker image
- echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
- docker build -t ${ANCHORE_IMAGE} .
- docker push ${ANCHORE_IMAGE}
Anchore:
stage: anchore
before_script:
### install anchorectl binary
- apk add --no-cache curl
- 'curl "$ANCHORECTL_URL/v2/system/anchorectl?operating_system=linux&architecture=amd64" -H "accept: */*" | tar -zx anchorectl && mv -v anchorectl /usr/bin && chmod +x /usr/bin/anchorectl && /usr/bin/anchorectl version'
- export PATH="${HOME}/.local/bin/:${PATH}"
script:
### provide registry credentials for anchorectl
- export ANCHORECTL_REGISTRY_AUTH_AUTHORITY=$CI_REGISTRY
- export ANCHORECTL_REGISTRY_AUTH_USERNAME="$CI_REGISTRY_USER"
- export ANCHORECTL_REGISTRY_AUTH_PASSWORD="$CI_REGISTRY_PASSWORD"
### scan image and push to anchore enterprise
- anchorectl image add --no-auto-subscribe --wait --dockerfile ./Dockerfile --from registry ${ANCHORE_IMAGE}
### then get the results:
- anchorectl image vulnerabilities ${ANCHORE_IMAGE}
- anchorectl image check --detail ${ANCHORE_IMAGE}
b) Centralized Mode
This method uses the “analyzer” pods in the Anchore Enterprise deployment to build the SBOM. This can create queuing if there are not enough analyzer processes, and this method will require the operator to provide registry credentials in the Enterprise backend (if the images to be scanned are in private registries). This method may be preferred in cases where the Anchore Enterprise operator does not control the image build process (the analyzers can simply poll registries to look for new image builds as they are pushed), and this method also allows the operator to simply queue up the image for asynchronous scanning later if vulnerability and policy results are not required immediately. If the user wants malware scanning results from Anchore Enterprise’s clamav integration, the Centralized Scanning method is required. To use this scanning method, paste the following workflow script into your new .gitlab-ci.yml file. After building the image from your Dockerfile,, this workflow will tell Anchore Enterprise to scan the image, then it will display the vulnerability and policy results in the build log. After pasting, click “Commit changes” to save the new file.
### Anchore Centralized Scan
# you will need three variables defined:
# ANCHORECTL_USERNAME
# ANCHORECTL_PASSWORD
# ANCHORECTL_URL
image: docker:latest
services:
- docker:dind
stages:
- build
- anchore
variables:
ANCHORECTL_FAIL_BASED_ON_RESULTS: "false"
ANCHORE_IMAGE: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}
Build:
stage: build
script:
### build and push docker image
- echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
- docker build -t ${ANCHORE_IMAGE} .
- docker push ${ANCHORE_IMAGE}
Anchore:
stage: anchore
before_script:
### install anchorectl binary
- apk add --no-cache curl
- 'curl "$ANCHORECTL_URL/v2/system/anchorectl?operating_system=linux&architecture=amd64" -H "accept: */*" | tar -zx anchorectl && mv -v anchorectl /usr/bin && chmod +x /usr/bin/anchorectl && /usr/bin/anchorectl version'
- export PATH="${HOME}/.local/bin/:${PATH}"
script:
### note that private registries will require registry credentials to be configured in your Anchore deployment
### queue image for scanning
- anchorectl image add --no-auto-subscribe --wait --dockerfile ./Dockerfile ${ANCHORE_IMAGE}
### then get the results:
- anchorectl image vulnerabilities ${ANCHORE_IMAGE}
- anchorectl image check --detail ${ANCHORE_IMAGE}
4. View pipeline
Gitlab will automatically start a pipeline. Navigate to “Build” -> “Pipelines” and then on your running pipeline.

5. View output
Once the build is complete, click on the “anchore” stage and view the output of the job. You will see the results of the vulnerability match and policy evaluation in the output.
3 - Azure Pipelines
Anchore Enterprise can be integrated into Azure DevOps pipelines to generate and analyze SBOMs, perform vulnerability scanning, and enforce policy evaluation as a pipeline gate. This page covers two integration approaches: distributed analysis and centralized analysis.
Prerequisites
The following are required for both integration approaches:
- A running Anchore Enterprise instance. See Deployment for setup instructions.
- An Azure DevOps pipeline.
- An Azure Key Vault variable group named
anchoreCredentials containing your Anchore Enterprise credentials. The following variables are required:
| Variable | Description |
|---|
anchore_url | The URL of your Anchore Enterprise instance |
anchore_endpoint | The hostname of your Anchore Enterprise instance (used to download AnchoreCTL) |
anchore_user | Your Anchore username, or _api_key if using an API key |
anchore_pass | Your Anchore password or API key value |
API keys are the recommended authentication method for CI/CD pipelines. They can be rotated and revoked independently of user accounts. See
API Keys for setup instructions.
Distributed Analysis
In distributed analysis, AnchoreCTL generates the SBOM locally on the pipeline agent and uploads it to Anchore Enterprise for vulnerability matching and policy evaluation. The image is not required to be in a remote registry before scanning.
This is the recommended approach for most pipelines. It requires less infrastructure than centralized analysis and avoids the need for a staging registry.
Distributed analysis does not support malware scanning. If your workflow requires malware scanning via ClamAV, use
Centralized Analysis instead.
How It Works
The anchorectl image add command accepts a --from flag that specifies the source from which AnchoreCTL should generate the SBOM:
--from docker:<image> — generates the SBOM from a locally available Docker image on the pipeline agent.--from registry — pulls the image from a remote registry for local analysis. Use this when the image has already been pushed to a registry in a prior pipeline step, as it captures the registry-assigned digest, which remains consistent as the image moves through environments.
The first positional argument to image add is the tag Anchore Enterprise uses to identify the image in its database. This does not need to be a pullable registry path.
Distributed Pipeline
trigger:
- master
resources:
- repo: self
variables:
- name: imageRef
value: 'production/simpleserver:$(Build.BuildId)'
- group: anchoreCredentials
stages:
- stage: Build
displayName: Build stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Docker@2
displayName: Build image
inputs:
command: build
repository: simpleserver
dockerfile: Dockerfile
tags: |
$(Build.BuildId)
- stage: Security
displayName: Security scan stage
dependsOn: Build
jobs:
- job: Security
displayName: Security
pool:
vmImage: 'ubuntu-latest'
steps:
- script: curl -X GET "https://$(anchore_endpoint)/v2/system/anchorectl?operating_system=linux&architecture=amd64" -H "accept: */*" | tar -zx anchorectl
displayName: Install AnchoreCTL
- script: |
export PATH=$PATH:$HOME/.local/bin
export ANCHORECTL_URL=$(anchore_url)
export ANCHORECTL_USERNAME=$(anchore_user)
export ANCHORECTL_PASSWORD=$(anchore_pass)
# To authenticate with an API key instead:
# export ANCHORECTL_USERNAME=_api_key
# export ANCHORECTL_PASSWORD=$(api_token)
./anchorectl image add $(imageRef) --from docker:simpleserver:$(Build.BuildId) --dockerfile Dockerfile --wait
./anchorectl image vulnerabilities $(imageRef)
./anchorectl image check $(imageRef) --fail-based-on-results
displayName: Anchore Security Scan
- stage: Production
displayName: Production stage
dependsOn: Security
# Push the image to your production registry and deploy
Centralized Analysis
In centralized analysis, the image is pushed to a staging registry and Anchore Enterprise pulls and analyzes it directly using the analyzer service. The SBOM is stored in Anchore Enterprise and available for post-scan reporting, compliance auditing, and policy justification.
This approach is required when malware scanning is enabled. See Malware Scanning for configuration details. Note that enabling malware scanning increases overall scan time.
Providing the Dockerfile via --dockerfile also enables Dockerfile-specific policy checks, such as validating the effective user ID or flagging exposed ports.
Additional Prerequisites
The following are required in addition to the common prerequisites:
A staging registry. Images are pushed here before scanning and promoted to production only after passing policy evaluation. The example below provisions an Azure Container Registry using Terraform:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "blog" {
name = "blog"
location = "West US"
}
resource "azurerm_container_registry" "blog" {
name = "staging"
resource_group_name = azurerm_resource_group.blog.name
location = azurerm_resource_group.blog.location
sku = "Standard"
admin_enabled = true
}
Note: admin_enabled = true enables the ACR built-in admin account, which uses a single shared credential and cannot be scoped or audited per consumer. For production use, set admin_enabled = false and grant access using a service principal or managed identity with the AcrPull and AcrPush roles as appropriate. See Azure Container Registry authentication options for details.
An Azure DevOps service connection. Required for the pipeline to push images to the staging registry. Configure a Docker Registry service connection targeting your Azure Container Registry. See Azure DevOps service connections for instructions.
Registry credentials in Anchore Enterprise. Anchore Enterprise must be able to pull images from the staging registry. See Registry Configuration for instructions.
Centralized Pipeline
trigger:
- master
resources:
- repo: self
variables:
- name: stagedImage
value: 'staging/simpleserver:$(Build.BuildId)'
- name: productionImage
value: 'production/simpleserver:$(Build.BuildId)'
- group: anchoreCredentials
stages:
- stage: Build
displayName: Build and push to staging
# Build and push the image to the staging registry
- stage: Security
displayName: Security scan stage
dependsOn: Build
jobs:
- job: Security
displayName: Security
pool:
vmImage: 'ubuntu-latest'
steps:
- script: curl -X GET "https://$(anchore_endpoint)/v2/system/anchorectl?operating_system=linux&architecture=amd64" -H "accept: */*" | tar -zx anchorectl
displayName: Install AnchoreCTL
- script: |
export PATH=$PATH:$HOME/.local/bin
export ANCHORECTL_URL=$(anchore_url)
export ANCHORECTL_USERNAME=$(anchore_user)
export ANCHORECTL_PASSWORD=$(anchore_pass)
./anchorectl image add $(stagedImage) --dockerfile Dockerfile --wait
./anchorectl image vulnerabilities $(stagedImage)
./anchorectl image check $(stagedImage) --fail-based-on-results
displayName: Anchore Security Scan
- stage: Production
displayName: Production stage
dependsOn: Security
# Push the image to your production registry and deploy
Failing a Pipeline on Policy Evaluation
The --fail-based-on-results flag (shorthand: -f) on anchorectl image check causes AnchoreCTL to return a non-zero exit code when the policy evaluation result is stop. This fails the pipeline stage and prevents the image from being promoted.
anchorectl image check <image> --fail-based-on-results
Example output for a failed evaluation:
✔ Evaluated against policy [failed]
Tag: docker.io/anchore/test_images:convertigo-7.9.2
Digest: sha256:b649023ebd9751db65d2f9934e3cfeeee54a010d4ba90ebaab736100a1c34d7d
Policy ID: anchore_secure_default
Last Evaluation: 2026-02-20T17:19:26Z
Evaluation: fail
Final Action: stop
Reason: policy_evaluation
error: 1 error occurred:
* failed policies:
One-Time Analysis
Anchore Enterprise supports one-time analysis, which performs vulnerability scanning and policy evaluation without storing the SBOM. This is useful for quick feedback during development before pushing to a registry.
For details, see the CI/CD one-time scan documentation or contact the customer success team via the Support Portal.
Next Steps
4 - GitHub
Image Scanning can be easily integrated into your GitHub Actions pipeline using anchorectl.
Ensure that the following variables/secrets are set in your GitHub repository (repository settings -> secrets and variables -> actions):
- Variable ANCHORECTL_URL
- Variable ANCHORECTL_USERNAME
- Secret ANCHORECTL_PASSWORD
These are necessary for the integration to access your Anchore Enterprise deployment. The ANCHORECTL_PASSWORD value should be created as a repository secret to prevent exposure of the value in job logs, while ANCHORECTL_URL and ANCHORECTL_USERNAME can be created as repository variables.

(“Settings” -> “Actions” -> “General” -> “Workflow permissions”) select “Read and write permissions” and click “Save”.

3. Create config file
In your repository, create a new file ( “Add file” -> “Create new file”) and name it .github/workflows/anchorectl.yaml.

4. Set scanning mode
a) Distributed Mode
This is the most easily scalable method for scanning images. Distributed scanning uses the anchorectl utility to build the SBOM directly on the build runner and then pushes the SBOM to Anchore Enterprise through the API. To use this scanning method, paste the following workflow script into your new anchorectl.yaml file. After building the image from your Dockerfile and scanning it with anchorectl, this workflow will display vulnerabilities and policy results in the build log.
name: Anchore Enterprise Distributed Scan
on:
workflow_dispatch:
inputs:
mode:
description: 'On-Demand Build'
env:
ANCHORECTL_URL: ${{ vars.ANCHORECTL_URL }}
ANCHORECTL_USERNAME: ${{ vars.ANCHORECTL_USERNAME }}
ANCHORECTL_PASSWORD: ${{ secrets.ANCHORECTL_PASSWORD }}
## set ANCHORECTL_FAIL_BASED_ON_RESULTS to true if you want to break the pipeline based on the evaluation
ANCHORECTL_FAIL_BASED_ON_RESULTS: false
REGISTRY: ghcr.io
jobs:
Build:
runs-on: ubuntu-latest
steps:
- name: "Set IMAGE environmental variables"
run: |
echo "IMAGE=${REGISTRY}/${GITHUB_REPOSITORY}:${GITHUB_REF_NAME}" >> $GITHUB_ENV
- name: Checkout Code
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: build local container
uses: docker/build-push-action@v3
with:
tags: ${{ env.IMAGE }}
push: true
load: false
Anchore:
runs-on: ubuntu-latest
needs: Build
steps:
- name: "Set IMAGE environmental variables"
run: |
echo "IMAGE=${REGISTRY}/${GITHUB_REPOSITORY}:${GITHUB_REF_NAME}" >> $GITHUB_ENV
- name: Checkout Code
### only need to do this if you want to pass the dockerfile to Anchore during scanning
uses: actions/checkout@v3
- name: Install Latest anchorectl Binary
run: |
mkdir -p $HOME/.local/bin
curl -sSfL "${ANCHORECTL_URL}/v2/system/anchorectl?operating_system=linux&architecture=amd64" \
-H "accept: /" | tar -zx -C $HOME/.local/bin anchorectl
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Generate SBOM and Push to Anchore
run: |
anchorectl image add --no-auto-subscribe --wait --from registry --dockerfile Dockerfile ${IMAGE}
- name: Pull Vulnerability List
run: |
anchorectl image vulnerabilities ${IMAGE}
- name: Pull Policy Evaluation
run: |
# set "ANCHORECTL_FAIL_BASED_ON_RESULTS=true" (see above in the "env:" section) to break the pipeline here if the
# policy evaluation returns FAIL or add -f, --fail-based-on-results to this command for the same result
#
anchorectl image check --detail ${IMAGE}
b) Centralized Mode
This method uses the “analyzer” pods in the Anchore Enterprise deployment to build the SBOM. This can create queuing if there are not enough analyzer processes, and this method may require the operator to provide registry credentials in the Enterprise backend (if the images to be scanned are in private registries). This method may be preferred in cases where the Anchore Enterprise operator does not control the image build process (the analyzers can simply poll registries to look for new image builds as they are pushed), and this method also allows the operator to simply queue up the image for asynchronous scanning later if vulnerability and policy results are not required immediately. If the user wants malware scanning results from Anchore Enterprise’s clamav integration, the Centralized Scanning method is required. To use this scanning method, paste the following workflow script into your new anchorectl.yaml file. After building the image from your Dockerfile,, this workflow will tell Anchore Enterprise to scan the image, then it will display the vulnerability and policy results in the build log.
name: Anchore Enterprise Centralized Scan
on:
workflow_dispatch:
inputs:
mode:
description: 'On-Demand Build'
env:
ANCHORECTL_URL: ${{ vars.ANCHORECTL_URL }}
ANCHORECTL_USERNAME: ${{ vars.ANCHORECTL_USERNAME }}
ANCHORECTL_PASSWORD: ${{ secrets.ANCHORECTL_PASSWORD }}
## set ANCHORECTL_FAIL_BASED_ON_RESULTS to true if you want to break the pipeline based on the evaluation
ANCHORECTL_FAIL_BASED_ON_RESULTS: false
REGISTRY: ghcr.io
jobs:
Build:
runs-on: ubuntu-latest
steps:
- name: "Set IMAGE environmental variables"
run: |
echo "IMAGE=${REGISTRY}/${GITHUB_REPOSITORY}:${GITHUB_REF_NAME}" >> $GITHUB_ENV
- name: Checkout Code
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: build local container
uses: docker/build-push-action@v3
with:
tags: ${{ env.IMAGE }}
push: true
load: false
Anchore:
runs-on: ubuntu-latest
needs: Build
steps:
- name: "Set IMAGE environmental variables"
run: |
echo "IMAGE=${REGISTRY}/${GITHUB_REPOSITORY}:${GITHUB_REF_NAME}" >> $GITHUB_ENV
- name: Checkout Code
uses: actions/checkout@v3
- name: Install Latest anchorectl Binary
run: |
mkdir -p $HOME/.local/bin
curl -sSfL "${ANCHORECTL_URL}/v2/system/anchorectl?operating_system=linux&architecture=amd64" \
-H "accept: /" | tar -zx -C $HOME/.local/bin anchorectl
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Queue Image for Scanning by Anchore Enterprise
run: |
anchorectl image add --no-auto-subscribe --wait --dockerfile ./Dockerfile ${IMAGE}
- name: Pull Vulnerability List
run: |
anchorectl image vulnerabilities ${IMAGE}
- name: Pull Policy Evaluation
run: |
# set "ANCHORECTL_FAIL_BASED_ON_RESULTS=true" (see above in the "env:" section) to break the pipeline here if the
# policy evaluation returns FAIL or add -f, --fail-based-on-results to this command for the same result
#
anchorectl image check --detail ${IMAGE}
5. Run Workflow
Go to “Actions” -> “Anchore Enterprise with anchorectl” and hit “Run workflow”.

6. View Results
When the workflow completes, view the results by clicking on the workflow name (“Anchore Enterprise with anchorectl”), then on the job (“Anchore”), then expand the “Pull Vulnerability List” and/or “Pull Policy Evaluation” steps to see the details.

7. Notifications
You can also integrate your Anchore Enterprise deployment with the GitHub API so that Anchore Enterprise notifications are sent to GitHub Notifications as new issues in a repository.
To configure and enable this please review the GitHub Notifications documentation.
5 - Jenkins
Before getting started, you need to configure your Jenkins instance with the required credentials. Make sure the following values are added under Dashboard → Manage Jenkins → Credentials as credentials of type Secret text:
ANCHORECTL_USERNAME
ANCHORECTL_PASSWORD
ANCHORECTL_URL
These are necessary for the integration to access your Anchore Enterprise deployment. The ANCHORECTL_PASSWORD value should be created as a repository secret to prevent exposure of the value in job logs, while ANCHORECTL_URL and ANCHORECTL_USERNAME can be created as repository variables.
Below are examples of the two types of image scans. For a detailed explanation of their differences, refer to the Images concept page.
a) Distributed
This is the most easily scalable method for scanning images. Distributed scanning uses the anchorectl utility to build the SBOM directly on the build runner and then pushes the SBOM to Anchore Enterprise through the API. The example below demonstrates how to automate distributed analysis within a pipeline.
pipeline {
// Define parameters for user input
parameters {
string(name: 'REGISTRY', defaultValue: 'docker.io', description: 'The container registry to use.', trim: true)
string(name: 'REPOSITORY', defaultValue: 'library/nginx', description: 'The image repository path.', trim: true)
string(name: 'TAG', defaultValue: 'latest', description: 'The image tag to analyze.', trim: true)
choice(name: 'ANCHORECTL_QUIET', choices: ['true', 'false'], description: 'Suppress anchorectl informational messages.')
choice(name: 'ANCHORECTL_FORMAT', choices: ['json', 'csv'], description: 'The output format for anchorectl (e.g., json, csv).')
choice(name: 'ANCHORECTL_FAIL_BASED_ON_RESULTS', choices: ['true', 'false'], description: 'How to handle fail signals (e.g., policy check outcomes)')
}
stages {
stage('Anchore Image Scan') {
environment {
// This is the AnchoreCTL service endpoint (fetched securely from Jenkins credentials)
ANCHORECTL_URL = credentials('ANCHORECTL_URL')
// Define the Anchore account username
ANCHORECTL_USERNAME = credentials('ANCHORECTL_USERNAME')
// Define the Anchore account password
ANCHORECTL_PASSWORD = credentials('ANCHORECTL_PASSWORD')
// Whether to fail the pipeline based on AnchoreCTL scan results (controlled by Jenkins parameter)
ANCHORECTL_FAIL_BASED_ON_RESULTS = "${params.ANCHORECTL_FAIL_BASED_ON_RESULTS}"
// You can also choose to Suppress unnecessary output logs
ANCHORECTL_QUIET = "${params.ANCHORECTL_QUIET}"
// Define the Output format for AnchoreCTL results
ANCHORECTL_FORMAT = "${params.ANCHORECTL_FORMAT}"
}
steps {
script {
echo 'Starting image analysis pipeline.'
// Download and configure the Anchore CLI
sh '''
mkdir -p $HOME/.local/bin
curl -sSfL "${ANCHORECTL_URL}v2/system/anchorectl?operating_system=linux&architecture=amd64" \\
-H "accept: /" | tar -zx -C $HOME/.local/bin anchorectl
export PATH="$HOME/.local/bin:$PATH"
'''
// Add the image to Anchore and wait for analysis to complete
sh "anchorectl image add --wait --from registry ${params.REGISTRY}/${params.REPOSITORY}:${params.TAG}"
// Retrieve and archive vulnerability report
sh "anchorectl image vulnerabilities ${params.REGISTRY}/${params.REPOSITORY}:${params.TAG} | tee vulnerabilities.${ANCHORECTL_FORMAT}"
archiveArtifacts artifacts: "vulnerabilities.${env.ANCHORECTL_FORMAT}"
// Run and archive the policy check
sh """#!/bin/bash
set -o pipefail
anchorectl image check --detail ${params.REGISTRY}/${params.REPOSITORY}:${params.TAG} | tee policy-check.${ANCHORECTL_FORMAT}
"""
archiveArtifacts artifacts: "policy-check.${env.ANCHORECTL_FORMAT}"
// Post-build action to handle policy failure, if configured
if (env.ANCHORECTL_FAIL_BASED_ON_RESULTS == 'true') {
def policyCheckResult = sh(script: "grep -q 'Policy Evaluation: PASS' policy-check.${ANCHORECTL_FORMAT}", returnStatus: true)
if (policyCheckResult != 0) {
error('Policy check failed based on results.')
}
}
}
}
}
}
}
b) Centralized
Centralized Scanning uses analyzer pods in Anchore Enterprise to generate the SBOM. This method is ideal when the operator does not control the image build process, supports asynchronous scanning, and is required for malware detection through ClamAV. After your container image is built, you can trigger a scan by adding the provided stage to your pipeline, which will instruct Anchore Enterprise to analyze the image and display vulnerability and policy results in the build log. Below is an example of how to achieve centralized scanning in your pipeline
pipeline {
// Define parameters for user input
parameters {
string(name: 'REGISTRY', defaultValue: 'docker.io', description: 'The container registry to use.', trim: true)
string(name: 'REPOSITORY', defaultValue: 'library/nginx', description: 'The image repository path.', trim: true)
string(name: 'TAG', defaultValue: 'latest', description: 'The image tag to analyze.', trim: true)
choice(name: 'ANCHORECTL_QUIET', choices: ['true', 'false'], description: 'Suppress anchorectl informational messages.')
choice(name: 'ANCHORECTL_FORMAT', choices: ['json', 'csv'], description: 'The output format for anchorectl (e.g., json, csv).')
choice(name: 'ANCHORECTL_FAIL_BASED_ON_RESULTS', choices: ['true', 'false'], description: 'How to handle fail signals (e.g., policy check outcomes)')
}
stages {
stage('Anchore Image Scan') {
environment {
// This is the AnchoreCTL service endpoint (fetched securely from Jenkins credentials)
ANCHORECTL_URL = credentials('ANCHORECTL_URL')
// Define the Anchore account username
ANCHORECTL_USERNAME = credentials('ANCHORECTL_USERNAME')
// Define the Anchore account password
ANCHORECTL_PASSWORD = credentials('ANCHORECTL_PASSWORD')
// Whether to fail the pipeline based on AnchoreCTL scan results (controlled by Jenkins parameter)
ANCHORECTL_FAIL_BASED_ON_RESULTS = "${params.ANCHORECTL_FAIL_BASED_ON_RESULTS}"
// You can also choose to Suppress unnecessary output logs
ANCHORECTL_QUIET = "${params.ANCHORECTL_QUIET}"
// Define the Output format for AnchoreCTL results
ANCHORECTL_FORMAT = "${params.ANCHORECTL_FORMAT}"
}
steps {
script {
echo "Starting image analysis for: ${params.REGISTRY}/${params.REPOSITORY}:${params.TAG}"
// Download and configure the Anchore CLI
sh '''
mkdir -p $HOME/.local/bin
curl -sSfL "${ANCHORECTL_URL}v2/system/anchorectl?operating_system=linux&architecture=amd64" \\
-H "accept: /" | tar -zx -C $HOME/.local/bin anchorectl
export PATH="$HOME/.local/bin:$PATH"
'''
// Add the image to Anchore and wait for analysis to complete
sh "anchorectl image add --wait ${params.REGISTRY}/${params.REPOSITORY}:${params.TAG}"
// Retrieve and archive vulnerability report
sh "anchorectl image vulnerabilities ${params.REGISTRY}/${params.REPOSITORY}:${params.TAG} | tee vulnerabilities.${ANCHORECTL_FORMAT}"
archiveArtifacts artifacts: "vulnerabilities.${env.ANCHORECTL_FORMAT}"
// Run and archive the policy check
sh """#!/bin/bash
set -o pipefail
anchorectl image check --detail ${params.REGISTRY}/${params.REPOSITORY}:${params.TAG} | tee policy-check.${ANCHORECTL_FORMAT}
"""
archiveArtifacts artifacts: "policy-check.${env.ANCHORECTL_FORMAT}"
// Post-build action to handle policy failure, if configured
if (env.ANCHORECTL_FAIL_BASED_ON_RESULTS == 'true') {
def policyCheckResult = sh(script: "grep -q 'Policy Evaluation: PASS' policy-check.${ANCHORECTL_FORMAT}", returnStatus: true)
if (policyCheckResult != 0) {
error('Policy check failed based on results.')
}
}
}
}
}
}
}
Visualize Vulnerabilities with the Warnings NG Plugin
The Jenkins Warnings Next Generation plugin (warnings-ng) can parse anchorectl vulnerability output and surface findings as tracked issues directly in the Jenkins UI — complete with trend graphs, per-build issue counts, and configurable quality gates.
Prerequisites
- Jenkins Warnings Next Generation plugin installed (Manage Jenkins → Plugins → Available plugins, search for “Warnings Next Generation”)
anchorectl available on the build runner (see Configure Variables above)
Supported Output Variants
The anchoreCtl() tool scans for files matching **/*vulnerabilities*.json and transparently handles all of the following output formats:
| Command | Output Format |
|---|
anchorectl image one-time-scan -o json IMAGE | Single unified envelope (sbom, policyEvaluation, and vulnerabilities in one file) |
anchorectl image one-time-scan -o json --output-directory DIR IMAGE | Standalone *_vulnerabilities.json file (camelCase keys) |
anchorectl image one-time-scan -o json-raw --output-directory DIR IMAGE | Standalone *_vulnerabilities.json file (snake_case keys) |
anchorectl image vulnerabilities -o json IMAGE > *_vulnerabilities.json | Vulnerability report (camelCase keys) from a previously analyzed image |
anchorectl image vulnerabilities -o json-raw IMAGE > *_vulnerabilities.json | Vulnerability report (snake_case keys) from a previously analyzed image |
a) One-Time Scan
Use anchorectl image one-time-scan to analyze an image against Anchore Enterprise policies without adding it to the image inventory.
pipeline {
agent any
stages {
stage('Anchore One-Time Scan') {
environment {
ANCHORECTL_URL = credentials('ANCHORECTL_URL')
ANCHORECTL_USERNAME = credentials('ANCHORECTL_USERNAME')
ANCHORECTL_PASSWORD = credentials('ANCHORECTL_PASSWORD')
}
steps {
script {
sh '''
mkdir -p $HOME/.local/bin
curl -sSfL "${ANCHORECTL_URL}v2/system/anchorectl?operating_system=linux&architecture=amd64" \
-H "accept: /" | tar -zx -C $HOME/.local/bin anchorectl
export PATH="$HOME/.local/bin:$PATH"
'''
sh 'anchorectl image one-time-scan -o json docker.io/library/nginx:latest | tee vulnerabilities.json'
}
}
}
}
post {
always {
recordIssues(tools: [anchoreCtl()])
}
}
}
b) Image Add and Vulnerabilities
Use anchorectl image add to submit an image to Anchore Enterprise for centralized analysis. Once analysis is complete, retrieve the vulnerability report with anchorectl image vulnerabilities and save it to a file the plugin can detect.
pipeline {
agent any
stages {
stage('Anchore Image Scan') {
environment {
ANCHORECTL_URL = credentials('ANCHORECTL_URL')
ANCHORECTL_USERNAME = credentials('ANCHORECTL_USERNAME')
ANCHORECTL_PASSWORD = credentials('ANCHORECTL_PASSWORD')
}
steps {
script {
sh '''
mkdir -p $HOME/.local/bin
curl -sSfL "${ANCHORECTL_URL}v2/system/anchorectl?operating_system=linux&architecture=amd64" \
-H "accept: /" | tar -zx -C $HOME/.local/bin anchorectl
export PATH="$HOME/.local/bin:$PATH"
'''
sh 'anchorectl image add --wait docker.io/library/nginx:latest'
sh 'anchorectl image vulnerabilities -o json docker.io/library/nginx:latest > image_vulnerabilities.json'
}
}
}
}
post {
always {
recordIssues(tools: [anchoreCtl()])
}
}
}
Severity Mapping
Anchore severity levels are mapped to Jenkins issue severities as follows:
| Anchore Severity | Jenkins Severity |
|---|
| Critical | ERROR |
| High | WARNING_HIGH |
| Medium | WARNING_NORMAL |
| Low, Negligible | WARNING_LOW |
To fail the build when a severity threshold is exceeded, add a
qualityGates parameter to the
recordIssues step. See the
Warnings NG plugin documentation for details.