GitLab CI/CD: Architecting, Deploying, and Optimizing Pipelines
Optimization Security and Monitoring
Template Container Scanning
Container Scanning is a critical part of Software Composition Analysis (SCA), inspecting Docker images and their base layers for known vulnerabilities. GitLab CI/CD offers a free Container Scanning template—powered by Trivy by default (or GRype)—to help you keep your images secure.
1. Enabling Container Scanning
Add the built-in Container Scanning template to your .gitlab-ci.yml
:
include:
- template: Jobs/Build.gitlab-ci.yml
- template: Security/Container-Scanning.gitlab-ci.yml
container_scanning:
variables:
CS_DEFAULT_BRANCH_IMAGE: $CI_REGISTRY_IMAGE/$CI_DEFAULT_BRANCH:$CI_COMMIT_SHA
Note
By default, the container_scanning
job runs in the test
stage. Override CS_DEFAULT_BRANCH_IMAGE
to scan a different image tag.
1.1 Scanning Remote Images
Override CS_IMAGE
and log level:
include:
- template: Security/Container-Scanning.gitlab-ci.yml
variables:
SECURE_LOG_LEVEL: debug
container_scanning:
variables:
CS_IMAGE: example.com/user/image:tag
1.2 Authenticating to a Private Registry
If your registry requires authentication, log in during before_script
and supply credentials as CI variables:
container_scanning:
before_script:
- apk add --no-cache python3 py3-pip
- pip3 install awscli
- export AWS_ECR_PASSWORD=$(aws ecr get-login-password --region us-east-1)
- docker login -u AWS -p "$AWS_ECR_PASSWORD" <aws_account_id>.dkr.ecr.us-east-1.amazonaws.com
include:
- template: Security/Container-Scanning.gitlab-ci.yml
variables:
CS_IMAGE: <aws_account_id>.dkr.ecr.us-east-1.amazonaws.com/<image>:<tag>
CS_REGISTRY_USER: AWS
CS_REGISTRY_PASSWORD: "$AWS_ECR_PASSWORD"
AWS_DEFAULT_REGION: us-east-1
2. Container Scanning CI/CD Variables
These variables control which image is scanned and how verbose the logs are:
Variable | Default | Description |
---|---|---|
CS_DEFAULT_BRANCH_IMAGE | $CI_REGISTRY_IMAGE/$CI_DEFAULT_BRANCH:$CI_COMMIT_SHA | Image tag for default branch |
CS_IMAGE | — | Custom image:tag to scan |
CS_REGISTRY_USER | — | Username for private registry |
CS_REGISTRY_PASSWORD | — | Password/token for registry login |
SECURE_LOG_LEVEL | info | Log verbosity (debug or info ) |
CS_ANALYZER_IMAGE | $CI_TEMPLATE_REGISTRY_HOST/.../container-scanning:latest | Analyzer container used for scanning |
CS_SCHEMA_MODEL | — | Schema version of the scanning output |
3. Allowlisting Vulnerabilities
To ignore specific CVEs, add a vulnerabilities-allowlist.yaml
in your repo:
generalAllowlist:
CVE-2019-8696:
CVE-2014-8166: cups
CVE-2017-18248:
images:
registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256:
CVE-2018-4180:
your.private.registry:5000/centos:
CVE-2015-1419: libxml2
CVE-2015-1447:
Warning
Allowlisting will mark these CVEs as approved and they will not fail your pipeline. Use with caution!
4. CycloneDX SBOM Output
Container Scanning also generates a CycloneDX SBOM artifact (gl-sbom-*.cdx.json
), following the OWASP standard for Software Bill of Materials.
5. Integrating into a Full Pipeline
Below is an example .gitlab-ci.yml
snippet that combines build, SAST, secret detection, and container scanning:
stages:
- .pre
- test
- containerization
- dev-deploy
- stage-deploy
include:
- component: gitlab.com/gitlab-components/code-quality/[email protected]
- template: Jobs/SAST.gitlab-ci.yml
- component: gitlab.com/gitlab-components/secret-detection/[email protected]
- template: Security/Container-Scanning.gitlab-ci.yml
variables:
DOCKER_USERNAME: siddharth67
IMAGE_VERSION: "$CI_PIPELINE_ID"
DOCKER_IMAGE: $DOCKER_USERNAME/solar-system:$IMAGE_VERSION
CS_ANALYZER_IMAGE: "$CI_TEMPLATE_REGISTRY_HOST/security-products/container-scanning:6"
CS_SCHEMA_MODEL: 15
container_scanning:
stage: containerization
needs:
- docker_push
image: "$CS_ANALYZER_IMAGE$CS_IMAGE_SUFFIX"
variables:
CS_IMAGE: docker.io/$DOCKER_USERNAME/solar-system:$IMAGE_VERSION
GIT_STRATEGY: none
allow_failure: true
artifacts:
reports:
container_scanning: gl-container-scanning-report.json
cyclonedx: "**/gl-sbom-*.cdx.json"
6. Demo: Generating Vulnerabilities
To demonstrate detection, switch your Dockerfile
from Alpine to Debian:
# Before: minimal Alpine image
FROM node:18-alpine3.11
# After: standard Debian-based Node.js
FROM node:18
WORKDIR /usr/app
COPY package*.json ./
RUN npm install
COPY . .
ENV MONGO_URI=uriPlaceholder
ENV MONGO_USERNAME=usernamePlaceholder
ENV MONGO_PASSWORD=passwordPlaceholder
EXPOSE 3000
CMD ["npm", "start"]
Commit to a feature branch to trigger the pipeline. You’ll see the Container Scanning job in the containerization
stage.
After completion, open the Container Scanning log to view the summary table or raw output.
Additional deployment jobs will follow.
7. Inspecting the Reports
7.1 JSON Vulnerability Report
The gl-container-scanning-report.json
artifact lists vulnerabilities in structured JSON:
{
"vulnerabilities": [
{
"id": "de666e5aa0b170e90b8d7018c398ba76c577c",
"severity": "Low",
"location": {
"dependency": {
"package": {
"name": "apt",
"version": "2.6.1"
},
"image": "docker.io/siddharth67/solar-system:1165883818"
}
},
"identifiers": [
{ "type": "cve", "name": "CVE-2011-3374" }
],
"description": "apt-key in apt, all versions, do not correctly validate gpg keys, leading to a potential MITM attack."
}
]
}
7.2 CycloneDX SBOM
The SBOM artifact follows the CycloneDX spec:
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"component": {
"type": "container",
"name": "docker.io/siddharth67/solar-system",
"version": "1.1.1"
},
"tools": [
{ "vendor": "aquasecurity", "name": "trivy", "version": "0.48.3" }
]
}
Links and References
- GitLab Container Scanning Documentation
- Trivy Scanner on GitLab
- OWASP CycloneDX Specification
- GitLab CI/CD Variables
You now have a fully configured Container Scanning pipeline with vulnerability reports and SBOM output. Integrate additional scanners (Dependency, SAST, DAST) as needed based on your security requirements.
Watch Video
Watch video content