Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions grype-operator/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM python:3.11-slim
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \
chmod +x kubectl && \
mv kubectl /usr/local/bin/kubectl
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY operator.py .
CMD ["kopf", "run", "/app/operator.py", "--verbose", "--standalone", "--liveness=http://0.0.0.0:8080/healthz"]
149 changes: 149 additions & 0 deletions grype-operator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
## Pre-Requisites

- A Kubernetes Cluster (cloud managed or on-prem [eg. minikube,Kind,etc] )
- kubectl cli install
- Basic understanding of kubernetes

### Installation

Although the namespace is already inside `grype-operator/manifests`.

```bash
kubectl create ns grype-operator-system
```

Now we have to install crd,rbac,cm,etc in short all manifests from `grype-operator/manifests`.

```bash
cd grype-operator
kubectl apply -f manifests/
```

You should see operator pod running in ns : `grype-operator-system`, like below :

```bash
kubectl get pods -n grype-operator-system

NAME READY STATUS RESTARTS AGE
grype-operator-5645fcf69d-2mxf8 1/1 Running 0 46m
```

## Now Comes the interesting part, Testing the operator running 😘😎

```bash
kubectl run test-nginx --image=nginx:alpine
```

- Now as per our application or operator, grype operator will get triggered and create a job to scan the image used for above pod.
- When the job work is done , it will generate the vulnerability report for the scanned container/image and that can be checked with our custom resource and job pod is terminated.

```bash
kubectl get vr or kubectl get vulnerabilityreport

Output :

NAME POD CRITICAL HIGH MEDIUM LOW AGE
test-nginx-74ccbdf4-report test-nginx 0 1 2 6 52m
```

### For In-Depth Vulnerability Report for the Image :

```bash
kubectl describe vr test-nginx-74ccbdf4-report
```

Output :

```bash
Name: test-nginx-74ccbdf4-report
Namespace: default
Labels: grype-operator.security.io/container=test-nginx
grype-operator.security.io/pod=test-nginx
Annotations: <none>
API Version: security.grype.io/v1alpha1
Kind: VulnerabilityReport
Metadata:
Creation Timestamp: 2025-11-10T11:37:52Z
Generation: 1
Resource Version: 377766
UID: 8d034f77-ae8d-4582-87be-6d92a7fe3978
Spec:
Container Reports:
Container: test-nginx
Image: nginx:alpine
Summary:
Critical: 0
High: 1
Low: 6
Medium: 2
Negligible: 0
Total: 9
Unknown: 0
Vulnerabilities:
Description: An out-of-memory flaw was found in libtiff. Passing a crafted tiff file to TIFFOpen() API may allow a remote attacker to cause a denial of service via a craft input with size smaller than 379 KB.
Id: CVE-2023-6277
Package: tiff
Severity: Medium
Version: 4.7.1-r0
Description: A segment fault (SEGV) flaw was found in libtiff that could be triggered by passing a crafted tiff file to the TIFFReadRGBATileExt() API. This flaw allows a remote attacker to cause a heap-buffer over
Id: CVE-2023-52356
Package: tiff
Severity: High
Version: 4.7.1-r0
Description: An issue was found in the tiffcp utility distributed by the libtiff package where a crafted TIFF file on processing may cause a heap-based buffer overflow leads to an application crash.
Id: CVE-2023-6228
Package: tiff
Severity: Medium
Version: 4.7.1-r0
Description: In tar in BusyBox through 1.37.0, a TAR archive can have filenames hidden from a listing through the use of terminal escape sequences.
Id: CVE-2025-46394
Package: busybox
Severity: Low
Version: 1.37.0-r19
Description: In tar in BusyBox through 1.37.0, a TAR archive can have filenames hidden from a listing through the use of terminal escape sequences.
Id: CVE-2025-46394
Package: busybox-binsh
Severity: Low
Version: 1.37.0-r19
Description: In tar in BusyBox through 1.37.0, a TAR archive can have filenames hidden from a listing through the use of terminal escape sequences.
Id: CVE-2025-46394
Package: ssl_client
Severity: Low
Version: 1.37.0-r19
Description: In netstat in BusyBox through 1.37.0, local users can launch of network application with an argv[0] containing an ANSI terminal escape sequence, leading to a denial of service (terminal locked up) whe
Id: CVE-2024-58251
Package: busybox
Severity: Low
Version: 1.37.0-r19
Description: In netstat in BusyBox through 1.37.0, local users can launch of network application with an argv[0] containing an ANSI terminal escape sequence, leading to a denial of service (terminal locked up) whe
Id: CVE-2024-58251
Package: busybox-binsh
Severity: Low
Version: 1.37.0-r19
Description: In netstat in BusyBox through 1.37.0, local users can launch of network application with an argv[0] containing an ANSI terminal escape sequence, leading to a denial of service (terminal locked up) whe
Id: CVE-2024-58251
Package: ssl_client
Severity: Low
Version: 1.37.0-r19
Pod: test-nginx
Scan Time: 2025-11-10T11:37:52.206036Z
Scanner:
Name: Grype
Vendor: Anchore
Summary:
Critical: 0
High: 1
Low: 6
Medium: 2
Negligible: 0
Total: 9
Unknown: 0
Events: <none>
```


## Full Demo Video for Grype Operator for Kubernetes Clusters


https://github.com/user-attachments/assets/2dd85c3b-b30c-42c5-b589-efecd4423ab1

23 changes: 23 additions & 0 deletions grype-operator/manifests/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: grype-operator-config
namespace: grype-operator-system
data:
# Operator behavior
scan-on-create: "true"
scan-on-update: "true"

# Scanner configuration
scanner-image: "anchore/grype:latest"
scanner-cpu-request: "100m"
scanner-memory-request: "256Mi"
scanner-cpu-limit: "500m"
scanner-memory-limit: "512Mi"

# Job settings
job-ttl-seconds: "3600"
job-backoff-limit: "2"

# Excluded namespaces (comma-separated)
excluded-namespaces: "kube-system,kube-public,kube-node-lease,grype-operator-system"
136 changes: 136 additions & 0 deletions grype-operator/manifests/crd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: vulnerabilityreports.security.grype.io
spec:
group: security.grype.io
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
pod:
type: string
description: Name of the scanned pod
scanTime:
type: string
description: Timestamp of the scan
scanner:
type: object
properties:
name:
type: string
vendor:
type: string
summary:
type: object
properties:
critical:
type: integer
high:
type: integer
medium:
type: integer
low:
type: integer
negligible:
type: integer
unknown:
type: integer
total:
type: integer
containerReports:
type: array
items:
type: object
properties:
container:
type: string
image:
type: string
error:
type: string
summary:
type: object
properties:
critical:
type: integer
high:
type: integer
medium:
type: integer
low:
type: integer
negligible:
type: integer
unknown:
type: integer
total:
type: integer
vulnerabilities:
type: array
items:
type: object
properties:
id:
type: string
severity:
type: string
package:
type: string
version:
type: string
fixedVersion:
type: array
items:
type: string
description:
type: string
urls:
type: array
items:
type: string
cvss:
type: array
items:
type: object
properties:
version:
type: string
vector:
type: string
score:
type: number
additionalPrinterColumns:
- name: Pod
type: string
jsonPath: .spec.pod
- name: Critical
type: integer
jsonPath: .spec.summary.critical
- name: High
type: integer
jsonPath: .spec.summary.high
- name: Medium
type: integer
jsonPath: .spec.summary.medium
- name: Low
type: integer
jsonPath: .spec.summary.low
- name: Age
type: date
jsonPath: .metadata.creationTimestamp
scope: Namespaced
names:
plural: vulnerabilityreports
singular: vulnerabilityreport
kind: VulnerabilityReport
shortNames:
- vulnreport
- vr
Loading