Published on: September 9, 2024
11 min read
Learn how GitLab + Chainguard can help deliver secure containerized applications faster. This tutorial includes easy-to-follow code examples.

Container technology, which creates consistent environments and streamlines deployment processes, is incredibly beneficial for software development. Containers contribute to faster development cycles, more efficient resource utilization, and greater flexibility in application management. Some of that efficiency can be lost, though, if organizations reinvent the wheel with each software development project. Instead, a base image should serve as the starting point for building other container images. These base images contain a bare minimum OS, essential tools, ensured compatibility, reduced image size, and other advantages. While base images provide a lot of value, they do have risks. It’s easy for your application to be compromised due to:
Chainguard Images offer several key benefits that make them essential for organizations prioritizing security:
The Chainguard directory provides hardened, minimal container images to help developers build software from the onset. With 97.6% fewer vulnerabilities than the average image, Chainguard Images help organizations swiftly reach container security compliance goals like NIST 800-53, FedRAMP, or PCI-DSS.

unit-tests: image: cgr.dev/chainguard/go:latest stage: test before_script: - go mod download script: - go test -coverprofile=coverage.out artifacts: paths: - coverage.out
### Using Chainguard images in a Dockerfile
To use a Chainguard image within a Dockerfile, simply create a Dockerfile in the root directory of your GitLab project. Then set the base image of the Dockerfile to the Chainguard image you wish to use, and add any other required commands:
```dockerfile
FROM cgr.dev/chainguard/go:latest
WORKDIR /app
COPY . .
RUN go mod download
RUN go build -o /main .
CMD [“/main”]
Then, you can create a job in the .gitlab-ci.yml to log in to the built-in GitLab Container Registry and push the image:
build-app-image:
stage: build
image: docker:latest
services:
- docker:dind
variables:
IMAGE: $CI_REGISTRY_IMAGE/$CI_DEFAULT_BRANCH:latest
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE .
- docker push $IMAGE
Once the job completes, you can see the pushed images in GitLab Container Registry by selecting Deploy > Container Registry from your project’s side tab.

include:
Once you've enabled the scanners, whenever you create a merge request to commit code from a feature branch into another branch, [scanner results will display directly within the MR](https://docs.gitlab.com/ee/user/application_security/index.html#view-security-scan-information):

<center><i>GitLab security scanner findings displayed in MR</i></center>
<p></p>
These results allow developers to quickly assess, prioritize, and mitigate or remediate vulnerabilities by providing the following information:
- description
- severity
- location
- links and identifiers
- training
- solutions

<center><i>GitLab security scanner vulnerability details</i></center>
<p></p>
Additional actions can be taken on a vulnerability, such as:
- dismissing the vulnerability and providing a reason to allow quicker review from the security team
- creating an issue to collaborate later on a resolution
**Note:** Scanners can also be configured and/or extended using variables and pipeline directives, just like any other GitLab job.
### Security guardrails
The scanners mentioned above can be used along with [security policies](https://docs.gitlab.com/ee/user/application_security/policies/) to prevent insecure code from being merged into production and to ensure that the scanners are run on every pipeline. GitLab provides the following security policy types:
- __Merge request approval policy:__ Create rules that check for security vulnerabilities and license compliance before merging a merge request.
- __Scan execution policy:__ Create rules that enforce security scans for particular branches at a certain time.
- __Pipeline execution policy:__ Enforce a custom CI/CD configuration to run in project pipelines.
Implementing these policies ensures that when creating an MR, security scans and custom compliance jobs will be run, and that approval will be required if vulnerabilities or incompatible licenses are detected:

<center><i>Merge request approval required due to vulnerabilities and incompatible licenses</i></center>
## Vulnerability reports
Detecting vulnerabilities before they make it to production is important, but it is equally important to determine and manage vulnerabilities that make their way into production, so that they can be mitigated accordingly.
[GitLab Vulnerability Report](https://docs.gitlab.com/ee/user/application_security/vulnerability_report/) provides information on all the detected vulnerabilities from scans of the default branch (which may be your staging or production branch):

<center><i>Vulnerability report with filters applied</i></center>
<p></p>
If you select a vulnerability, you’ll be taken to its vulnerability page, which displays the same vulnerability details as you would see in the MR view. You can use this view to quickly assess, prioritize, and mitigate or remediate vulnerabilities:

<center><i>Vulnerability page for improper authorization vulnerability</i></center>
<p></p>
The security team can manage vulnerabilities by setting their status to one of the following:
- Detected: The default state for a newly discovered vulnerability.
- Confirmed: A user has seen this vulnerability and confirmed it is accurate.
- Dismissed: A user has seen this vulnerability and dismissed it because it is inaccurate or otherwise not to be resolved. Dismissed vulnerabilities are ignored if detected in subsequent scans.
- Resolved: The vulnerability has been fixed or is no longer present. If a resolved vulnerability is reintroduced and detected again, its record is reinstated and its status set to detected.
## Software bill of materials
A software bill of materials (SBOM) is a comprehensive inventory that lists all the components, dependencies, and associated metadata of a software application. SBOMs are vital for organizations to effectively manage software security, compliance, and supply chain risks.
Chainguard provides high-quality, [out-of-the-box SBOMs](https://images.chainguard.dev/directory/image/go/sbom) for their container images in SPDX format. The SBOM can be converted into CycloneDX format and loaded into or compared with the results of GitLab’s dependency list. The [dependency list](https://docs.gitlab.com/ee/user/application_security/dependency_list/) is an SBOM generated from an artifact or the results of the dependency, container, and license scanners:

<center><i>Dependency List with some components expanded</i></center>
<p></p>
Chainguard images meet [SLSA Level 2 requirements](https://slsa.dev/spec/v0.1/levels?ref=fossa.com) and are verified, signed, and attested with signatures. Furthermore, GitLab CI can [generate and produce attestation/provenance metadata](https://docs.gitlab.com/ee/ci/runners/configure_runners.html#artifact-provenance-metadata) for all build artifacts. By using Chainguard with GitLab, you can prevent tampering and provide additional build integrity guarantees.
## Learn more
To learn more about GitLab and Chainguard, and how we can help enhance your security posture, check out the following resources:
- [GitLab Security and Compliance Solutions](https://about.gitlab.com/solutions/application-security-testing/)
- [GitLab Application Security Documentation](https://docs.gitlab.com/ee/user/application_security/get-started-security.html)
- [GitLab pricing](https://about.gitlab.com/pricing/)
- [Chainguard Images](https://www.chainguard.dev/chainguard-images)
- [Chainguard Compliance and Risk Mitigation](https://www.chainguard.dev/solutions/compliance-and-risk-mitigation)
- [Chainguard Sales](https://www.chainguard.dev/contact?utm_source=blog&utm_medium=partner&utm_campaign=GitLab_announcement_blog&utm_content=article)