Deployment

Kubernetes deployment guide — S3 ingestion, Helm configuration, license governance, theming, and operations.

This guide covers deploying SeeBOM to a Kubernetes cluster using Helm.

Prerequisites

  • Kubernetes cluster (1.27+)
  • ClickHouse Operator installed
  • Helm 3.x
  • Container images pushed to a registry (e.g. ghcr.io/seebom-labs/seebom/*)

1. SBOMs – Getting Data Into the Cluster

SeeBOM supports multiple SBOM ingestion methods. S3 bucket ingestion is the default and recommended approach — it requires no PVCs, no volume scheduling, and scales to any number of SBOMs.

Ingest SBOMs directly from S3-compatible buckets (AWS S3, MinIO, GCS). The Ingestion Watcher streams object listings with pagination and the Parsing Workers fetch objects on-demand.

Single public bucket:

s3:
  buckets: '[{"name":"cncf-subproject-sboms","region":"us-east-1"}]'

Multiple buckets:

s3:
  buckets: '[{"name":"cncf-subproject-sboms","region":"us-east-1"},{"name":"cncf-project-sboms","region":"us-east-1"}]'

Private buckets with credentials:

s3:
  buckets: '[{"name":"my-private-bucket","region":"eu-west-1"}]'
  accessKey: ""   # pass via --set or K8s Secret
  secretKey: ""   # pass via --set or K8s Secret
helm install seebom deploy/helm/seebom/ -n seebom -f my-values.yaml \
  --set s3.accessKey="AKIA..." \
  --set s3.secretKey="..."

Private buckets with an existing Kubernetes Secret (recommended for production):

Instead of passing credentials as plain Helm values, you can reference a pre-existing Kubernetes Secret — the same pattern used for ClickHouse and GitHub credentials:

s3:
  buckets: '[{"name":"my-private-bucket","region":"eu-west-1"}]'
  credentialsSecret:
    enabled: true
    secretName: "my-s3-credentials"
    accessKeyKey: "S3_ACCESS_KEY"   # key inside the Secret
    secretKeyKey: "S3_SECRET_KEY"   # key inside the Secret

Create the Secret first:

kubectl create secret generic my-s3-credentials \
  --from-literal=S3_ACCESS_KEY="AKIA..." \
  --from-literal=S3_SECRET_KEY="..." \
  -n seebom

This avoids storing credentials in Helm values files or command history.

MinIO (local S3-compatible):

s3:
  buckets: '[{"name":"sboms","endpoint":"minio.minio.svc:9000","usePathStyle":true,"useSSL":false}]'
  accessKey: "minioadmin"
  secretKey: "minioadmin"

Advantages:

  • No PVC, no volume scheduling, no pod affinity constraints
  • Streams object listings — handles 100k+ SBOMs without memory issues
  • Works with any S3-compatible storage (AWS, GCS, MinIO, Ceph, DigitalOcean Spaces)

Option B: Seed Job

s3:
  buckets: ""

gitSync:
  enabled: false

seedJob:
  sbomRepo: "https://github.com/cncf/sbom.git"
  sbomBranch: main

Option C: git-sync (small repos < 1 GB)

s3:
  buckets: ""

gitSync:
  enabled: true
  repo: "https://github.com/your-org/sbom-repo.git"
  branch: main

⚠️ git-sync struggles with large repos (multi-GB). Use S3 or the seed job instead.

Option D: Pre-populated PVC

s3:
  buckets: ""
gitSync:
  enabled: false

sbomSource:
  pvcName: my-preloaded-sbom-pvc

2. License Exceptions

License exceptions suppress specific license violations. They are stored in a ConfigMap that is mounted read-only into the API Gateway and Workers.

kubectl edit configmap seebom-license-exceptions
kubectl rollout restart deployment seebom-api-gateway

3. License Policy

The license policy defines which SPDX IDs are classified as permissive, copyleft, or unknown.

kubectl edit configmap seebom-license-policy
kubectl rollout restart deployment seebom-api-gateway seebom-parsing-worker

4. Custom Theme

ui:
  customTheme:
    enabled: true
kubectl create configmap seebom-custom-theme \
  --from-file=custom-theme.css=./my-theme.css \
  --dry-run=client -o yaml | kubectl apply -f -
kubectl rollout restart deployment seebom-ui

5. Site Configuration

ui:
  siteConfig:
    enabled: true
    content:
      brandName: "My Platform"
      pageTitle: "My Platform"
      dashboard:
        title: "Overview"
        subtitle: "Software Supply Chain Governance"

6. GitHub Token (License Resolution)

SeeBOM resolves unknown package licenses (NOASSERTION) by querying the GitHub API. Without a token, you are limited to 60 requests per hour. With a token, the limit increases to 5,000 req/h.

We strongly recommend setting a GitHub token for any production deployment.

Create a Personal Access Token (classic) with no scopes required.

github:
  token: "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Or pass it securely via --set:

helm install seebom deploy/helm/seebom/ -n seebom -f values.yaml \
  --set github.token="ghp_..."

See FAQ: Should I use a GitHub token? for more details and how to re-ingest after adding a token.


7. Full Deployment Example

helm install seebom ./deploy/helm/seebom \
  -f values-production.yaml \
  --set image.tag=0.1.3 \
  --set 's3.buckets=[{"name":"cncf-subproject-sboms","region":"us-east-1"}]' \
  --set s3.accessKey="AKIA..." \
  --set s3.secretKey="..." \
  --set parsingWorker.replicas=10

8. Verifying the Deployment

kubectl get pods -l app.kubernetes.io/name=seebom

kubectl exec -it $(kubectl get pod -l app.kubernetes.io/component=api-gateway -o name | head -1) \
  -- wget -qO- http://localhost:8080/api/v1/stats/dashboard

Summary

WhatWhereHow to Change
SBOMs (S3)S3-compatible bucketsConfigure s3.buckets in Helm values
SBOMs (volume)PVC via seed job or git-syncPush to Git, seed job clones
VEX filesSame S3 bucket or directoryPlace *.openvex.json alongside SBOMs
License ExceptionsConfigMapkubectl edit configmap → restart API
License PolicyConfigMapkubectl edit configmap → restart API + Workers
Custom ThemeConfigMapkubectl create configmap → restart UI
Site ConfigConfigMapHelm values ui.siteConfig.content.* → restart UI
S3 credentialsSecret--set s3.accessKey=... or s3.credentialsSecret (existing K8s Secret)