Pular para o conteúdo principal

Trivy: Um canivete suiço para segurança

trivy

Documentação

Github

É um scanner de segurança muito poderoso e versávil desenvolvido pela Aqua Security. Extremamente fácil de usar, um command line All In One que gera relatórios de CVEs para os seguintes recursos:

  • Imagens de Container
  • Filesystem
  • Repositórios Git
  • Imagens de VMs
  • Kubernetes
  • AWS

Suporta as principais linguagens, como:

  • Golang
  • .Net
  • Java
  • NodeJs
  • Rust
  • Python

Além de tudo isso podemos analisar o arquivos de declarações de IaC em Terraforms, Helm, manifestos do kubernetes e vulnerabilidades do cluster e Dockerfiles. Claro que existem ferramentas mais específicas para esse assunto, mas de forma básica faz um ótimo trabalho tornando o Trivy um dos canivetes suiço no mundo da segurança.

Como veremos mais abaixo usando o Trivy podemos scannear várias coisas. Cada comando irá atuar de forma diferente.

alt text

Instalação

Podemos instalar a cli ou rodar direto de um container.

Não adianta reinventar a roda. Podemo instalar usando o gerenciador de pacote das principais distros, baixando o binário, usando o asdf, usando o script e clonando o repositório. Confira aqui como instalar.

Já que é somente uma CLI podemos usar o docker. A imagem já possui o entrypoint trivy preparado para receber os parâmetros da CLI.

Só é necessário mapear os volumes -v /var/run/docker.sock:/var/run/docker.sock -v $HOME/Library/Caches:/root/.cache se for fazer scan de imagens.

# docker run  aquasec/trivy também funciona

root@master:~# docker run -v /var/run/docker.sock:/var/run/docker.sock -v $HOME/Library/Caches:/root/.cache/ aquasec/trivy:0.55.0
Usage:
trivy [global flags] command [flags] target
trivy [command]

Examples:
# Scan a container image
$ trivy image python:3.4-alpine

# Scan a container image from a tar archive
$ trivy image --input ruby-3.1.tar

# Scan local filesystem
$ trivy fs .

# Run in server mode
$ trivy server


########### SEPARAÇÃO DAS FUNCIONALIDADE ##################
Scanning Commands
config Scan config files for misconfigurations
filesystem Scan local filesystem
image Scan a container image
kubernetes [EXPERIMENTAL] Scan kubernetes cluster
repository Scan a repository
rootfs Scan rootfs
sbom Scan SBOM for vulnerabilities and licenses
vm [EXPERIMENTAL] Scan a virtual machine image
###########################################################

Management Commands
module Manage modules
plugin Manage plugins
vex [EXPERIMENTAL] VEX utilities

Utility Commands
clean Remove cached files
completion Generate the autocompletion script for the specified shell
convert Convert Trivy JSON report into a different format
help Help about any command
server Server mode
version Print the version

Flags:
--cache-dir string cache directory (default "/root/.cache/trivy")
-c, --config string config path (default "trivy.yaml")
-d, --debug debug mode
-f, --format string version format (json)
--generate-default-config write the default config to trivy-default.yaml
-h, --help help for trivy
--insecure allow insecure server connections
-q, --quiet suppress progress bar and log output
--timeout duration timeout (default 5m0s)
-v, --version show version

Use "trivy [command] --help" for more information about a command.

Habilite o completion para verificar vários possíveis parâmetros.

Análise de Containers

Vamos começar logo pelo básico scan de vulnerabilidades em imagens. Podemos fazer a análise de uma imagem que já temos ou ele irá baixar.

trivy image <parametros> é o subcomando usado para ativar scan de imagens images.

# Usando a ultima versão do trivy:latest scaneando a ultima versão do alpine.

# Toda vez que ele irá baixar o database logo, vamo remover um pouco de saída para melhorar a leitura
root@master:~# docker run aquasec/trivy image alpine
2024-09-04T01:14:19Z INFO [db] Need to update DB
2024-09-04T01:14:19Z INFO [db] Downloading DB... repository="ghcr.io/aquasecurity/trivy-db:2"
16.98 MiB / 52.71 MiB [------------------->_________________________________________] 32.21% ? p/s ?34.67 MiB / 52.71 MiB s ETA 0s52.71 MiB / 52.71 MiB [-------------------------------------------------] 100.00% 13.57 MiB p/s 4.1s2024-09-04T01:14:23Z INFO [vuln] Vulnerability scanning is enabled
2024-09-04T01:14:23Z INFO [secret] Secret scanning is enabled
2024-09-04T01:14:23Z INFO [secret] If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2024-09-04T01:14:23Z INFO [secret] Please see also https://aquasecurity.github.io/trivy/v0.55/docs/scanner/secret#recommendation for faster secret detection
2024-09-04T01:14:25Z INFO Detected OS family="alpine" version="3.20.2"
2024-09-04T01:14:25Z INFO [alpine] Detecting vulnerabilities... os_version="3.20" repository="3.20" pkg_num=14
2024-09-04T01:14:25Z INFO Number of language-specific files num=0

alpine (alpine 3.20.2)
======================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
# Alpine é top mesmo!

Faça um teste em outras imagens como por exemplo o Ubuntu.

Vamos para o kubernetes scanear o apiserver 1.30.4

root@cks-master:~# docker run  aquasec/trivy image registry.k8s.io/kube-apiserver:v1.30.4
2024-09-04T01:20:19Z INFO [db] Need to update DB
2024-09-04T01:20:19Z INFO [db] Downloading DB... repository="ghcr.io/aquasecurity/trivy-db:2"
15.68 MiB / 52.71 MiB [------------------>__________________________________________] 29.74% ? p/s ?37.33 MiB / 52.71 MiB [-------------------------------------------------] 100.00% 16.18 MiB p/s 3.5s2024-09-04T01:20:23Z INFO [vuln] Vulnerability scanning is enabled
2024-09-04T01:20:23Z INFO [secret] Secret scanning is enabled
2024-09-04T01:20:23Z INFO [secret] If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2024-09-04T01:20:23Z INFO [secret] Please see also https://aquasecurity.github.io/trivy/v0.55/docs/scanner/secret#recommendation for faster secret detection
2024-09-04T01:20:26Z INFO Detected OS family="debian" version="12.5"
2024-09-04T01:20:26Z INFO [debian] Detecting vulnerabilities... os_version="12" pkg_num=3
2024-09-04T01:20:26Z INFO Number of language-specific files num=2
2024-09-04T01:20:26Z INFO [gobinary] Detecting vulnerabilities...

registry.k8s.io/kube-apiserver:v1.30.4 (debian 12.5)
====================================================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)


usr/local/bin/kube-apiserver (gobinary)
=======================================
Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)

┌──────────────────────────────────────────────────────────────┬────────────────┬──────────┬──────────┬───────────────────┬───────────────┬─────────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├──────────────────────────────────────────────────────────────┼────────────────┼──────────┼──────────┼───────────────────┼───────────────┼─────────────────────────────────────────────────────────────┤
│ go.opentelemetry.io/contrib/instrumentation/google.golang.o- │ CVE-2023-47108 │ HIGH │ fixed │ v0.42.0 │ 0.46.0 │ opentelemetry-go-contrib: DoS vulnerability in otelgrpc due │
│ rg/grpc/otelgrpc │ │ │ │ │ │ to unbound cardinality metrics │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2023-47108 │
├──────────────────────────────────────────────────────────────┼────────────────┼──────────┼──────────┼───────────────────┼───────────────┼─────────────────────────────────────────────────────────────┤
│ gopkg.in/square/go-jose.v2 │ CVE-2024-28180 │ MEDIUM │ affected │ v2.6.0 │ │ jose-go: improper handling of highly compressed data │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-28180 │
└──────────────────────────────────────────────────────────────┴────────────────┴──────────┴──────────┴───────────────────┴───────────────┴─────────────────────────────────────────────────────────────┘
# Opa encontramos coisinhas...

Bom é isso, ali já é mostrado as CVEs para encontrados, se é possível corrigir ou não. Se quiser ignorar os que não é possível corrigir só passar a flag -ignore-unfixed.

Se quer ver bastante CVEs faz um test ai no nginx. Dessa vez vou rodar usando o cli do trivy.

# --ignore-unfixed irá diminuir a saída somente para cves conhecidas e reparáveis.
trivy image nginx --ignore-unfixed
2024-09-03T22:32:41-03:00 INFO [vuln] Vulnerability scanning is enabled
2024-09-03T22:32:41-03:00 INFO [secret] Secret scanning is enabled
2024-09-03T22:32:41-03:00 INFO [secret] If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2024-09-03T22:32:41-03:00 INFO [secret] Please see also https://aquasecurity.github.io/trivy/v0.54/docs/scanner/secret#recommendation for faster secret detection
2024-09-03T22:32:43-03:00 INFO Detected OS family="debian" version="12.6"
2024-09-03T22:32:43-03:00 INFO [debian] Detecting vulnerabilities... os_version="12" pkg_num=149
2024-09-03T22:32:43-03:00 INFO Number of language-specific files num=0
2024-09-03T22:32:43-03:00 WARN Using severities from other vendors for some vulnerabilities. Read https://aquasecurity.github.io/trivy/v0.54/docs/scanner/vulnerability#severity-selection for details.

nginx (debian 12.6)

Total: 9 (UNKNOWN: 0, LOW: 2, MEDIUM: 6, HIGH: 0, CRITICAL: 1)

┌──────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────────┬───────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├──────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────────┼───────────────────────────────────────────────────────────┤
curl │ CVE-2024-7264 │ MEDIUM │ fixed │ 7.88.1-10+deb12u6 │ 7.88.1-10+deb12u7 │ curl: libcurl: ASN.1 date parser overread │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-7264 │
├──────────┼───────────────┼──────────┤ ├───────────────────┼───────────────────┼───────────────────────────────────────────────────────────┤
│ libaom3 │ CVE-2024-5171 │ CRITICAL │ │ 3.6.0-1 │ 3.6.0-1+deb12u1 │ libaom: Integer overflow in internal │
│ │ │ │ │ │ │ function img_alloc_helper │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-5171 │
├──────────┼───────────────┼──────────┤ ├───────────────────┼───────────────────┼───────────────────────────────────────────────────────────┤
│ libcurl4 │ CVE-2024-7264 │ MEDIUM │ │ 7.88.1-10+deb12u6 │ 7.88.1-10+deb12u7 │ curl: libcurl: ASN.1 date parser overread │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-7264 │
├──────────┼───────────────┤ │ ├───────────────────┼───────────────────┼───────────────────────────────────────────────────────────┤
│ libssl3 │ CVE-2024-4603 │ │ │ 3.0.13-1~deb12u1 │ 3.0.14-1~deb12u1 │ openssl: Excessive time spent checking DSA keys and │
│ │ │ │ │ │ │ parameters │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-4603 │
│ ├───────────────┤ │ │ │ ├───────────────────────────────────────────────────────────┤
│ │ CVE-2024-4741 │ │ │ │ │ openssl: Use After Free with SSL_free_buffers │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-4741 │
│ ├───────────────┼──────────┤ │ │ ├───────────────────────────────────────────────────────────┤
│ │ CVE-2024-2511 │ LOW │ │ │ │ openssl: Unbounded memory growth with session handling in
│ │ │ │ │ │ │ TLSv1.3 │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-2511 │
├──────────┼───────────────┼──────────┤ │ │ ├───────────────────────────────────────────────────────────┤
│ openssl │ CVE-2024-4603 │ MEDIUM │ │ │ │ openssl: Excessive time spent checking DSA keys and │
│ │ │ │ │ │ │ parameters │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-4603 │
│ ├───────────────┤ │ │ │ ├───────────────────────────────────────────────────────────┤
│ │ CVE-2024-4741 │ │ │ │ │ openssl: Use After Free with SSL_free_buffers │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-4741 │
│ ├───────────────┼──────────┤ │ │ ├───────────────────────────────────────────────────────────┤
│ │ CVE-2024-2511 │ LOW │ │ │ │ openssl: Unbounded memory growth with session handling in
│ │ │ │ │ │ │ TLSv1.3 │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-2511 │
└──────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────────┴───────────────────────────────────────────────────────────┘

Analisando IaC

Dentro do diretório um Dockerfile simples e um deployment.yaml

cat Dockerfile
FROM alpine
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y golang-go
COPY app.go .
RUN go build app.go
CMD ["./app"]

#Criando o deployment.yaml
❯ kubectl create deployment nginx --image=nginx -oyaml --dry-run=client > deployment.yaml

cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}

Vamos analisar a pasta corrente que estamos. Vou comentar essa saída.

❯ trivy config .  
2024-09-03T23:31:25-03:00 INFO [misconfig] Misconfiguration scanning is enabled
2024-09-03T23:31:26-03:00 INFO Detected config files num=2

# Encontrou um dockerfile
Dockerfile (dockerfile)

Tests: 27 (SUCCESSES: 23, FAILURES: 4, EXCEPTIONS: 0)
Failures: 4 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 2, CRITICAL: 0)

MEDIUM: Specify a tag in the 'FROM' statement for image 'alpine' # Legal, por que não definimos nenhuma versão específica
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
When using a 'FROM' statement you should use a specific tag to avoid uncontrolled behavior when the image is updated.

See https://avd.aquasec.com/misconfig/ds001
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Dockerfile:1
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 [ FROM alpine
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Legal, por que não definimos nenhum USER
HIGH: Specify at least 1 USER command in Dockerfile with non-root user as argument
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile.

See https://avd.aquasec.com/misconfig/ds002
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Boa por que não é boa prática ter o HEALTHCHECK do container.
LOW: Add HEALTHCHECK instruction in your Dockerfile
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
You should add HEALTHCHECK instruction in your docker container images to perform the health check on running containers.

See https://avd.aquasec.com/misconfig/ds026
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Muito bom....
HIGH: '--no-install-recommends' flag is missed: 'apt-get update && apt-get install -y golang-go'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
'apt-get' install should use '--no-install-recommends' to minimize image size.

See https://avd.aquasec.com/misconfig/ds029
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Dockerfile:3
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
3 [ RUN apt-get update && apt-get install -y golang-go
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Agora analisando o outro arquivo...

deployment.yaml (kubernetes)

Tests: 94 (SUCCESSES: 80, FAILURES: 14, EXCEPTIONS: 0)
Failures: 14 (UNKNOWN: 0, LOW: 9, MEDIUM: 4, HIGH: 1, CRITICAL: 0)

# Muito bom, o kubebench ia acusar a mesma coisa
MEDIUM: Container 'nginx' of Deployment 'nginx' should set 'securityContext.allowPrivilegeEscalation' to false
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.

See https://avd.aquasec.com/misconfig/ksv001
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Ótimo kube bench também ia acusar isso.
LOW: Container 'nginx' of Deployment 'nginx' should add 'ALL' to 'securityContext.capabilities.drop'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
The container should drop all default capabilities and add only those that are needed for its execution.

See https://avd.aquasec.com/misconfig/ksv003
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Realmente esta faltando limites nesse container
LOW: Container 'nginx' of Deployment 'nginx' should set 'resources.limits.cpu'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Enforcing CPU limits prevents DoS via resource exhaustion.

See https://avd.aquasec.com/misconfig/ksv011
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Também seria acusado pelo kube bench
MEDIUM: Container 'nginx' of Deployment 'nginx' should set 'securityContext.runAsNonRoot' to true
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Force the running image to run as a non-root user to ensure least privileges.

See https://avd.aquasec.com/misconfig/ksv012
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Perfeito, pois não devemos rodar com a tag latest
MEDIUM: Container 'nginx' of Deployment 'nginx' should specify an image tag
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
It is best to avoid using the ':latest' image tag when deploying containers in production. Doing so makes it hard to track which version of the image is running, and hard to roll back the version.

See https://avd.aquasec.com/misconfig/ksv013
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Ia acusar também no kube bench
HIGH: Container 'nginx' of Deployment 'nginx' should set 'securityContext.readOnlyRootFilesystem' to true
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
An immutable root file system prevents applications from writing to their local disk. This can limit intrusions, as attackers will not be able to tamper with the file system or write foreign executables to disk.

See https://avd.aquasec.com/misconfig/ksv014
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Mesma situação dos limites acima, mas para requests de cpu e memoria
LOW: Container 'nginx' of Deployment 'nginx' should set 'resources.requests.cpu'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
When containers have resource requests specified, the scheduler can make better decisions about which nodes to place pods on, and how to deal with resource contention.

See https://avd.aquasec.com/misconfig/ksv015
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: Container 'nginx' of Deployment 'nginx' should set 'resources.requests.memory'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
When containers have memory requests specified, the scheduler can make better decisions about which nodes to place pods on, and how to deal with resource contention.

See https://avd.aquasec.com/misconfig/ksv016
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: Container 'nginx' of Deployment 'nginx' should set 'resources.limits.memory'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Enforcing memory limits prevents DoS via resource exhaustion.

See https://avd.aquasec.com/misconfig/ksv018
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Mesma coisa do kube-bench, que também pede para colocar user e group acima de 10000. Já estou començando a achar que o trivy tem o kube bench embutido.
LOW: Container 'nginx' of Deployment 'nginx' should set 'securityContext.runAsUser' > 10000
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Force the container to run with user ID > 10000 to avoid conflicts with the host’s user table.

See https://avd.aquasec.com/misconfig/ksv020
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: Container 'nginx' of Deployment 'nginx' should set 'securityContext.runAsGroup' > 10000
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Force the container to run with group ID > 10000 to avoid conflicts with the host’s user table.

See https://avd.aquasec.com/misconfig/ksv021
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: Either Pod or Container should set 'securityContext.seccompProfile.type' to 'RuntimeDefault'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
According to pod security standard 'Seccomp', the RuntimeDefault seccomp profile must be required, or allow specific additional profiles.

See https://avd.aquasec.com/misconfig/ksv030
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


MEDIUM: container "nginx" of deployment "nginx" in "default" namespace should specify a seccomp profile
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
A program inside the container can bypass Seccomp protection policies.

See https://avd.aquasec.com/misconfig/ksv104
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: container should drop all
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Containers must drop ALL capabilities, and are only permitted to add back the NET_BIND_SERVICE capability.

See https://avd.aquasec.com/misconfig/ksv106
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.yaml:21-23
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
21 ┌ - image: nginx
22 │ name: nginx
23 └ resources: {}
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Bom, e vimos que o trivy também traz um bom trabalho com arquivos declarativos de IaC. E um helm será que dá certo?

helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm pull aqua/trivy --untar

trivy config trivy
2024-09-03T23:45:45-03:00 INFO [misconfig] Misconfiguration scanning is enabled
2024-09-03T23:45:46-03:00 INFO Detected config files num=7

# Arquivos encontrados...
templates/statefulset.yaml (helm)

Tests: 94 (SUCCESSES: 87, FAILURES: 7, EXCEPTIONS: 0)
Failures: 7 (UNKNOWN: 0, LOW: 5, MEDIUM: 2, HIGH: 0, CRITICAL: 0)

MEDIUM: Container 'main' of StatefulSet 'trivy' should set 'securityContext.allowPrivilegeEscalation' to false
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node.

See https://avd.aquasec.com/misconfig/ksv001
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
templates/statefulset.yaml:45-92
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
45 ┌ - name: main
46 │ image: docker.io/aquasec/trivy:0.37.2
47 │ imagePullPolicy: "IfNotPresent"
48 │ securityContext:
49 │ privileged: false
50 │ readOnlyRootFilesystem: true
51 │ args:
52 │ - server
53 └ envFrom:
..
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: Container 'main' of StatefulSet 'trivy' should add 'ALL' to 'securityContext.capabilities.drop'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
The container should drop all default capabilities and add only those that are needed for its execution.

See https://avd.aquasec.com/misconfig/ksv003
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
templates/statefulset.yaml:45-92
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
45 ┌ - name: main
46 │ image: docker.io/aquasec/trivy:0.37.2
47 │ imagePullPolicy: "IfNotPresent"
48 │ securityContext:
49 │ privileged: false
50 │ readOnlyRootFilesystem: true
51 │ args:
52 │ - server
53 └ envFrom:
..
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: Container 'main' of StatefulSet 'trivy' should set 'securityContext.runAsUser' > 10000
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Force the container to run with user ID > 10000 to avoid conflicts with the host’s user table.

See https://avd.aquasec.com/misconfig/ksv020
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
templates/statefulset.yaml:45-92
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
45 ┌ - name: main
46 │ image: docker.io/aquasec/trivy:0.37.2
47 │ imagePullPolicy: "IfNotPresent"
48 │ securityContext:
49 │ privileged: false
50 │ readOnlyRootFilesystem: true
51 │ args:
52 │ - server
53 └ envFrom:
..
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: Container 'main' of StatefulSet 'trivy' should set 'securityContext.runAsGroup' > 10000
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Force the container to run with group ID > 10000 to avoid conflicts with the host’s user table.

See https://avd.aquasec.com/misconfig/ksv021
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
templates/statefulset.yaml:45-92
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
45 ┌ - name: main
46 │ image: docker.io/aquasec/trivy:0.37.2
47 │ imagePullPolicy: "IfNotPresent"
48 │ securityContext:
49 │ privileged: false
50 │ readOnlyRootFilesystem: true
51 │ args:
52 │ - server
53 └ envFrom:
..
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: Either Pod or Container should set 'securityContext.seccompProfile.type' to 'RuntimeDefault'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
According to pod security standard 'Seccomp', the RuntimeDefault seccomp profile must be required, or allow specific additional profiles.

See https://avd.aquasec.com/misconfig/ksv030
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
templates/statefulset.yaml:45-92
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
45 ┌ - name: main
46 │ image: docker.io/aquasec/trivy:0.37.2
47 │ imagePullPolicy: "IfNotPresent"
48 │ securityContext:
49 │ privileged: false
50 │ readOnlyRootFilesystem: true
51 │ args:
52 │ - server
53 └ envFrom:
..
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


MEDIUM: container "main" of statefulset "trivy" in "default" namespace should specify a seccomp profile
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
A program inside the container can bypass Seccomp protection policies.

See https://avd.aquasec.com/misconfig/ksv104
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: container should drop all
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Containers must drop ALL capabilities, and are only permitted to add back the NET_BIND_SERVICE capability.

See https://avd.aquasec.com/misconfig/ksv106
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
templates/statefulset.yaml:45-92
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
45 ┌ - name: main
46 │ image: docker.io/aquasec/trivy:0.37.2
47 │ imagePullPolicy: "IfNotPresent"
48 │ securityContext:
49 │ privileged: false
50 │ readOnlyRootFilesystem: true
51 │ args:
52 │ - server
53 └ envFrom:
..

Analise do FS

Não é necessário criar a imagem da aplicação para conferir o projeto em que se está trabalhando. Obviamente depois que montarmos a imagem teremos uma herança da base escolhida, mas podemos somente conferir o próprio projeto.

trivy fs <path para o diretório do projeto>

Nesse exemplo vou scannear o próprio projeto do docusaurus, este mesmo que estou escrevendo.

# Passei somente o que eu quero scannear para não pegar secrets que estão no projeto que são de exemplos.

❯ trivy fs . --scanners vuln,misconfig
2024-09-04T09:36:23-03:00 INFO [vuln] Vulnerability scanning is enabled
2024-09-04T09:36:23-03:00 INFO [misconfig] Misconfiguration scanning is enabled
2024-09-04T09:36:26-03:00 INFO Number of language-specific files num=1
2024-09-04T09:36:26-03:00 INFO [npm] Detecting vulnerabilities...
2024-09-04T09:36:26-03:00 INFO Detected config files num=3

node_modules/@surma/rollup-plugin-off-main-thread/Dockerfile (dockerfile)

Tests: 27 (SUCCESSES: 23, FAILURES: 4, EXCEPTIONS: 0)
Failures: 4 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 2, CRITICAL: 0)

MEDIUM: Specify a tag in the 'FROM' statement for image 'selenium/node-chrome'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
When using a 'FROM' statement you should use a specific tag to avoid uncontrolled behavior when the image is updated.

See https://avd.aquasec.com/misconfig/ds001
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
node_modules/@surma/rollup-plugin-off-main-thread/Dockerfile:1
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 [ FROM selenium/node-chrome:latest
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


HIGH: Last USER command in Dockerfile should not be 'root'
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile.

See https://avd.aquasec.com/misconfig/ds002
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
node_modules/@surma/rollup-plugin-off-main-thread/Dockerfile:3
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
3 [ USER root
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


HIGH: The instruction 'RUN <package-manager> update' should always be followed by '<package-manager> install' in the same RUN statement.
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
The instruction 'RUN <package-manager> update' should always be followed by '<package-manager> install' in the same RUN statement.

See https://avd.aquasec.com/misconfig/ds017
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
node_modules/@surma/rollup-plugin-off-main-thread/Dockerfile:5-8
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
5 ┌ RUN apt-get update -qqy \
6&& rm -rf /var/lib/apt/lists/* /var/cache/apt/* \
7&& rm /bin/sh && ln -s /bin/bash /bin/sh \
8&& chown seluser /usr/local
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────


LOW: Add HEALTHCHECK instruction in your Dockerfile
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
You should add HEALTHCHECK instruction in your docker container images to perform the health check on running containers.

See https://avd.aquasec.com/misconfig/ds026
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

# Também podemos conferir licenças
trivy fs . --scanners license

O scaneamento local permite avaliar os módulos que estão instalados enquanto estiver buildando o projeto. Diferentemente se fizemos o scan para um repositório em que ignoramos usando o .gitignore vários arquivos do build.

Também é util para entrar em um container e fazer a análise interna.

Analise de Repositório

Se fizemos a mesma análise acima, podemos observar que não teremos node_modules, pois não estará no repositório.

Observe que as análises estão olhando as versões dos pacotes e não os binários.

❯ trivy repository https://gitlab.com/davidpuziol/devsecops.git --scanners vulnerability,misconfig
2024-09-04T09:47:14-03:00 INFO [vuln] Vulnerability scanning is enabled
2024-09-04T09:47:14-03:00 INFO [misconfig] Misconfiguration scanning is enabled
Enumerating objects: 1371, done.
Counting objects: 100% (1371/1371), done.
Compressing objects: 100% (1281/1281), done.
Total 1371 (delta 32), reused 1166 (delta 28), pack-reused 0 (from 0)
2024-09-04T09:47:21-03:00 INFO [npm] To collect the license information of packages, "npm install" needs to be performed beforehand dir="node_modules"
2024-09-04T09:47:22-03:00 INFO Number of language-specific files num=1
2024-09-04T09:47:22-03:00 INFO [npm] Detecting vulnerabilities...
2024-09-04T09:47:22-03:00 INFO Detected config files num=2

package-lock.json (npm)

Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 2, HIGH: 0, CRITICAL: 0)

┌────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼────────────────────────────────────────────────────────┤
│ micromatch │ CVE-2024-4067 │ MEDIUM │ fixed │ 4.0.5 │ 4.0.8 │ micromatch: vulnerable to Regular Expression Denial of │
│ │ │ │ │ │ │ Service │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-4067 │
├────────────┼────────────────┤ │ ├───────────────────┼───────────────┼────────────────────────────────────────────────────────┤
│ webpack │ CVE-2024-43788 │ │ │ 5.91.0 │ 5.94.0 │ webpack: DOM Clobbering vulnerability in
│ │ │ │ │ │ │ AutoPublicPathRuntimeModule │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-43788 │
└────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴────────────────────────────────────────────────────────┘