The goal: introduction into configuration-management
Disclaimer: the following section give only a brief introduction into the topics and propose a few low-hanging fruits to get started.
-
(Almost) all the software has issues (intentional or not).
- Likely, we are not eager to run application with known issues inside.
- When an issue is discovered, engineers try to fix it and release a fix/patch.
- When a patch is released, we have to apply it to get rid of the issue.
-
Common Vulnerabilities and Exposures system provides a standard to describe vulnerable software: ID, description, severity, references.
-
There are tools that helps to compare your software with CVE database to find if your software has any known issue. You can scan your OS, application codebase, container images
-
One of popular scanners is trivy. You can install it to your machine or run inside a container, for example:
docker run --rm -v ~/.trivy:/root/.cache/ aquasec/trivy:0.50.1 image python:3.12
Discalimer: there are a lot of other free and commercial scanners: Clair, anchore/grype, snyk to name a few.
NOTE:
trivy
does not actually dive into packages content, but trusts reported version number. For example, you can update java pom file manually to trick the tool. Thus it's not a reliable runtime protection, but an assistant to understand your software. -
You can include image-scanning as gate before pushing an image to Container Registry. thus, if container has a known vulnerability - image is not released:
docker run --rm -v ~/.trivy:/root/.cache/ aquasec/trivy:0.50.1 image --exit-code 1 --no-progress python:3.12 # get exit-code of last command echo $? docker run --rm -v ~/.trivy:/root/.cache/ aquasec/trivy:0.50.1 image --exit-code 1 --no-progress alpine:latest echo $?
You can fail only on critical issues
--severity HIGH,CRITICAL
, ignore unfixed--ignore-unfixed
or particular CVEs--ignorefile ~/.trivyignore
. -
Often, you do not have to fix all the CVEs manually, but change your base image:
### buster docker run --rm -v ~/.trivy:/root/.cache/ aquasec/trivy:0.50.1 image --exit-code 1 --no-progress python:3.12 python:3.12 (debian 12.5) ========================= Total: 988 (UNKNOWN: 5, LOW: 525, MEDIUM: 350, HIGH: 103, CRITICAL: 5)
### buster-slim docker run --rm -v ~/.trivy:/root/.cache/ aquasec/trivy:0.50.1 image --exit-code 1 --no-progress python:3.12-slim python:3.12-slim (debian 12.5) ============================== Total: 116 (UNKNOWN: 0, LOW: 71, MEDIUM: 33, HIGH: 11, CRITICAL: 1)
### alpine docker run --rm -v ~/.trivy:/root/.cache/ aquasec/trivy:0.50.1 image --exit-code 1 --no-progress python:3.12-alpine python:3.12-alpine (alpine 3.19.1) ================================== Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
The difference in base images is also amount of used tools: more tools - more issues. For example, compare
python
image sizes:$ docker images python REPOSITORY TAG IMAGE ID CREATED SIZE python 3.12 099bf23b94d9 6 days ago 1.02GB python 3.12-slim 0e42464fe231 6 days ago 130MB python 3.12-alpine f44387b48281 6 days ago 57.1MB
-
Software supply chain (e.g. code delivery process): write code, build, test, deploy, run, monitor.
-
Build your solution only on top of trusted sources. For example, do not use no-name pip/npm packages or base docker-images. Consider pulling used dependencies to your local package registry instead of pulling from public sources.
-
During writing code you can use Static Code Analysis tools to catch issues earlier. To find a tool for your language, search
static code analysis {your programming language}
. Maybe, the most popular one is Sonarqube. -
Regularly patch your dependencies and run scanners, like
trivy
above. -
Sign your commits, container images (or with cosign).
-
Verify signatures. For example:
- Github can require signed commits;
- Container Runtime can trust only particular keys;
- or you can verify signed container images localy: https://docs.sigstore.dev/cosign/verify/
-
Protect access to your build tools.
-
Use immutable versions whenever is possible.
For example, container images has immutable id:
# run image using mutable tag: docker run -it --rm python:3.12 # find image immutable digest: docker inspect --format='{{index .RepoDigests 0}}' python:3.12 # or docker images --digests # run image by digest instaed of tag: # NOTE: likely, at the moment the hash is different, e.g. someone pushed a new image with the same 3.9 tag docker run -it --rm python@sha256:e0e2713ebf0f7b114b8bf9fbcaba9a69ef80e996b9bb3fa5837e42c779dcdc0f
- Start from trusted code
- Scan and sign your code and container images
- Regularly patch your software
- Less CVEs - less issues
- Smaller image -> less tools -> less CVEs
- Use immutable versions