Security¶
Risks¶
CI/CD is the automation of most (if not all) process in your software lifecycle going from building to running the application in production. With so many things happening, attackers have a wide range of capabilities in case of a compromise:
- introduce dubious components (i.e. backdoor) in the application,
- leak (to the Internet) credentials granting access to internal services or infrastructures,
- access said services or infrastructures,
- impersonate an employee,
- leak intellectual property,
- ...
Every CI/CD job is executed inside a container image which contains various tools required by the job. When you are executing the job, you are trusting the people building the image and the tools.
In some cases, the image may have been corrupted by an attacker. This is what we call a supply chain attack. There are famous cases like the Codecov incident in which hackers managed to leak credentials from several services and cloud platforms.
Mitigations¶
Variables scoping¶
To prevent leakage, CI/CD variables has to be present only in jobs that need them. By example in the Maven template, only the mvn-sonar
job actually needs the SONAR_TOKEN
environment variable so others jobs (mvn-build
, mvn-release
...) should not access this secret.
You can find more info about how to protect your CI/CD variables in the official GitLab documentation.
Image selection¶
As much as we can, we try to select either official images (ex: Maven, Python), or at least images maintained by an active community. Each of those images can be freely overridden with the appropriate configuration variable to select fixed versions (more info here) or any alternative that would suit you more.
By default, to be continuous templates mostly use the latest
tag from upstream images since it is a maintenance-less default that works for nearly everyone. However latest
images are prone to supply chain attacks and are also likely to introduce breaking changes.
to be continuous is not responsible of any possible security issue from a default container image.
You should either :
- use a fixed version tag : using the
maven:3.9.1
instead ofmaven:latest
make sure you stay on a specific version of tools- prefer official image with the least tools (prefer minimal size, Alpine distribution or even distro-less if you can find one suited to your needs), the more the image has, heavier is the risk
- build and maintain your own image with a chosen version for each tools
- use no or a minimal distribution
- upgrade tools and important components regularly with safe updates
- root-less image are best to prevent some container escalation vulnerabilities against your runner provider
Tip
Whenever building your own image or using an upstream image, you can use Renovate to watch updates for your tools, test the new version and integrate them seamlessly.
Vulnerability Reports (Trivy)¶
Warning
When reviewing vulnerabilities from containers, you have to consider the following principes :
- containers are usually very short-lived in a CI/CD environment
- no direct user access is possible
- most job does not expose any exteral services (i.e. HTTP server) making attacks reliant on user interaction very hard if not impossible to exploit
In short, risks are often low in the CI/CD context but carefully reviewing vulnerabilities are an essential step to secure your pipeline.
Here are vulnerability reports for each default image used by to be continuous templates (generated every day):
Template | Image Variable | Default Image | Vulnerabilities |
---|---|---|---|
Ansible | ANSIBLE_IMAGE | registry.hub.docker.com/cytopia/ansible:latest-tools |
2 Medium |
Ansible | ANSIBLE_LINT_IMAGE | registry.hub.docker.com/haxorof/ansible-lint:latest |
1 Low |
Amazon Web Services | AWS_CLI_IMAGE | registry.hub.docker.com/amazon/aws-cli:latest |
|
Azure | AZURE_CLI_IMAGE | mcr.microsoft.com/azure-cli:latest |
|
Bash | BASH_BATS_IMAGE | registry.hub.docker.com/bats/bats:latest |
2 Low |
Bash | BASH_SHELLCHECK_IMAGE | registry.hub.docker.com/koalaman/shellcheck-alpine:stable |
20 Medium, 4 Low |
Bruno | BRU_IMAGE | registry.hub.docker.com/library/node:lts-alpine |
1 High, 2 Low |
GitLab Butler | BUTLER_IMAGE | registry.gitlab.com/to-be-continuous/tools/gitlab-butler:latest |
|
Cloud Foundry | CF_CLI_IMAGE | registry.hub.docker.com/governmentpaas/cf-cli |
5 Critical, 21 High, 46 Medium, 2 Low |
Cloud Native Buildpacks | CNB_BUILDER_IMAGE | registry.hub.docker.com/paketobuildpacks/builder:base |
168 Critical, 616 High, 1901 Medium, 5 Low |
Cloud Native Buildpacks | CNB_SKOPEO_IMAGE | quay.io/skopeo/stable:latest |
|
Cloud Native Buildpacks | CNB_TRIVY_IMAGE | registry.hub.docker.com/aquasec/trivy:latest |
2 Low |
Cypress | CYPRESS_IMAGE | registry.hub.docker.com/cypress/included:13.13.3 |
11 Critical, 94 High, 164 Medium, 266 Low, 65 Unknown |
dbt | DBT_IMAGE | registry.hub.docker.com/library/python:latest |
6 Critical, 101 High, 447 Medium, 542 Low, 2 Unknown |
Docker Compose | DCMP_IMAGE | registry.hub.docker.com/library/docker:latest |
1 Low |
DefectDojo | DEFECTDOJO_BASE_IMAGE | registry.hub.docker.com/library/node:alpine3.11 |
1 Critical, 25 High, 3 Medium, 1 Low |
Dependency Track | DEPTRACK_SBOM_SCANNER_IMAGE | registry.gitlab.com/to-be-continuous/tools/dt-sbom-scanner:latest |
|
Docker | DOCKER_BUILDAH_IMAGE | quay.io/buildah/stable:latest |
|
Docker | DOCKER_DIND_IMAGE | registry.hub.docker.com/library/docker:dind |
1 Low |
Docker | DOCKER_HADOLINT_IMAGE | registry.hub.docker.com/hadolint/hadolint:latest-alpine |
8 High, 12 Medium |
Docker | DOCKER_IMAGE | registry.hub.docker.com/library/docker:latest |
1 Low |
Docker | DOCKER_KANIKO_IMAGE | gcr.io/kaniko-project/executor:debug |
3 Critical, 5 High, 10 Medium, 5 Low |
Docker | DOCKER_SBOM_IMAGE | registry.hub.docker.com/anchore/syft:debug |
1 Unknown |
Docker | DOCKER_SKOPEO_IMAGE | quay.io/skopeo/stable:latest |
|
Docker | DOCKER_TRIVY_IMAGE | registry.hub.docker.com/aquasec/trivy:latest |
2 Low |
Google Cloud | GCP_CLI_IMAGE | gcr.io/google.com/cloudsdktool/cloud-sdk:latest |
3 Critical, 120 High, 496 Medium, 379 Low |
Gitleaks | GITLEAKS_IMAGE | registry.hub.docker.com/zricethezav/gitleaks:latest |
1 Medium, 2 Low |
GitLab Package | GLPKG_IMAGE | registry.hub.docker.com/curlimages/curl:latest |
|
Go | GO_CI_LINT_IMAGE | registry.hub.docker.com/golangci/golangci-lint:latest-alpine |
2 Low |
Go | GO_IMAGE | registry.hub.docker.com/library/golang:bookworm |
2 Critical, 70 High, 393 Medium, 262 Low |
Go | GO_SBOM_IMAGE | registry.hub.docker.com/cyclonedx/cyclonedx-gomod:latest |
2 Low |
Go | GO_SEMGREP_IMAGE | registry.hub.docker.com/semgrep/semgrep:latest |
1 High |
Gradle | GRADLE_IMAGE | registry.hub.docker.com/library/gradle:latest |
20 Medium, 80 Low |
Helmfile | HELMFILE_CLI_IMAGE | ghcr.io/helmfile/helmfile:latest |
2 Critical, 6 High, 18 Medium, 3 Low |
Helm | HELM_CLI_IMAGE | registry.hub.docker.com/alpine/helm:latest |
2 Low |
Helm | HELM_KUBE_SCORE_IMAGE | registry.hub.docker.com/zegl/kube-score |
7 Critical, 50 High, 58 Medium, 4 Low |
Helm | HELM_YAMLLINT_IMAGE | registry.hub.docker.com/cytopia/yamllint |
6 High, 12 Medium |
Hurl | HURL_IMAGE | ghcr.io/orange-opensource/hurl:latest |
2 Medium, 2 Low |
k6 | K6_IMAGE | registry.hub.docker.com/grafana/k6:latest |
2 Low |
Kubernetes | K8S_KUBECTL_IMAGE | registry.hub.docker.com/bitnami/kubectl:latest |
1 Critical, 15 High, 18 Medium, 90 Low |
Kubernetes | K8S_KUBE_SCORE_IMAGE | registry.hub.docker.com/zegl/kube-score:latest |
7 Critical, 50 High, 58 Medium, 4 Low |
Lighthouse | LHCI_IMAGE | registry.hub.docker.com/cypress/browsers:latest |
4 Critical, 34 High, 122 Medium, 232 Low, 65 Unknown |
GNU Make | MAKE_IMAGE | registry.hub.docker.com/alpinelinux/build-base |
3 Medium, 3 Low |
Maven | MAVEN_IMAGE | registry.hub.docker.com/library/maven:latest |
13 Medium, 42 Low |
MkDocs | MKD_IMAGE | docker.io/squidfunk/mkdocs-material:latest |
1 High |
MkDocs | MKD_LYCHEE_IMAGE | docker.io/lycheeverse/lychee:latest |
1 Critical, 5 High, 14 Medium, 55 Low |
MobSF | MOBSF_CLIENT_IMAGE | registry.hub.docker.com/badouralix/curl-jq |
2 Low |
Angular | NG_CLI_IMAGE | registry.hub.docker.com/trion/ng-cli-karma:latest |
2 Critical, 82 High, 426 Medium, 358 Low |
Node.js | NODE_IMAGE | registry.hub.docker.com/library/node:lts-alpine |
1 High, 2 Low |
Node.js | NODE_SEMGREP_IMAGE | registry.hub.docker.com/semgrep/semgrep:latest |
1 High |
OpenShift | OS_CLI_IMAGE | quay.io/openshift/origin-cli:latest |
1 Critical, 2 Medium |
PHP | PHP_IMAGE | registry.hub.docker.com/library/php:latest |
1 Critical, 66 High, 378 Medium, 238 Low |
Playwright | PLAYWRIGHT_IMAGE | mcr.microsoft.com/playwright:latest |
209 Medium, 106 Low |
Postman | POSTMAN_IMAGE | registry.hub.docker.com/postman/newman:latest |
4 High, 30 Medium, 5 Low |
pre-commit | PRE_COMMIT_IMAGE | registry.hub.docker.com/library/python:3-alpine |
|
Puppeteer | PUPPETEER_IMAGE | ghcr.io/puppeteer/puppeteer:latest |
6 Critical, 135 High, 529 Medium, 530 Low, 4 Unknown |
Python | PYTHON_IMAGE | registry.hub.docker.com/library/python:3-slim |
1 Critical, 5 High, 15 Medium, 56 Low |
Renovate | RENOVATE_IMAGE | registry.hub.docker.com/renovate/renovate:latest |
1 High, 607 Medium, 74 Low |
Robot Framework | ROBOT_BASE_IMAGE | registry.hub.docker.com/ppodgorsek/robot-framework:latest |
|
Source-to-Image | S2I_DIND_IMAGE | registry.hub.docker.com/library/docker:dind |
1 Low |
Source-to-Image | S2I_SKOPEO_IMAGE | quay.io/skopeo/stable:latest |
|
S3 (Simple Storage Service) | S3_CMD_IMAGE | registry.hub.docker.com/d3fk/s3cmd:latest |
6 Medium, 2 Low |
Scala/SBT | SBT_IMAGE | registry.hub.docker.com/sbtscala/scala-sbt:17.0.2_1.6.2_3.1.3 |
52 Critical, 215 High, 254 Medium, 451 Low, 1 Unknown |
Scala/SBT | SBT_SBOM_IMAGE | registry.hub.docker.com/anchore/syft:debug |
1 Unknown |
semantic-release | SEMREL_IMAGE | registry.hub.docker.com/library/node:lts-slim |
1 Critical, 6 High, 14 Medium, 55 Low |
SonarQube | SONAR_SCANNER_IMAGE | registry.hub.docker.com/sonarsource/sonar-scanner-cli:latest |
4 High, 28 Medium |
Spectral | SPECTRAL_IMAGE | registry.hub.docker.com/stoplight/spectral:latest |
4 High, 29 Medium, 5 Low |
Sphinx | SPHINX_IMAGE | ghcr.io/sphinx-doc/sphinx:latest |
2 Critical, 16 High, 35 Medium, 155 Low |
Sphinx | SPHINX_LYCHEE_IMAGE | registry.hub.docker.com/lycheeverse/lychee:latest |
1 Critical, 5 High, 14 Medium, 55 Low |
SQLFluff lint | SQLFLUFF_IMAGE | registry.hub.docker.com/sqlfluff/sqlfluff:latest |
2 Critical, 11 High, 28 Medium, 84 Low, 1 Unknown |
Test SSL | TESTSSL_IMAGE | registry.hub.docker.com/drwetter/testssl.sh:latest |
|
Terraform | TF_CHECKOV_IMAGE | registry.hub.docker.com/bridgecrew/checkov |
1 Critical, 15 High, 17 Medium, 94 Low |
Terraform | TF_DOCS_IMAGE | quay.io/terraform-docs/terraform-docs:edge |
3 Low |
Terraform | TF_IMAGE | registry.hub.docker.com/hashicorp/terraform:latest |
2 Low |
Terraform | TF_INFRACOST_IMAGE | registry.hub.docker.com/infracost/infracost |
61 Critical, 710 High, 500 Medium, 21 Low |
Terraform | TF_PUBLISH_IMAGE | registry.hub.docker.com/curlimages/curl:latest |
|
Terraform | TF_TFLINT_IMAGE | ghcr.io/terraform-linters/tflint-bundle:latest |
5 Critical, 31 High, 104 Medium, 4 Low |
Terraform | TF_TFSEC_IMAGE | registry.hub.docker.com/aquasec/tfsec-ci |
2 Medium, 2 Low |
Terraform | TF_TRIVY_IMAGE | registry.hub.docker.com/aquasec/trivy |
2 Low |