• Talk to an expert
  • All posts

    Always know about the dependency of your Pods – here comes SBOM operator for Kubernetes

    Some months ago Christian Kotzbauer started a community project called SBOM operator that created SBOMs based on the container images used by the Pods and stored them in a Git repository. His main intentions were to have a Kubernetes-native way to generate and store Software Bill of Materials for all running container.

    Thinking about the importance of storing a tamperproof Bill of Material and having a way to automatically relate the SBOM with the unique container image ID, he decided to extend the SBOM operator to Codenotary CAS and Codenotary Cloud.

    “I am pleased to contribute to the wider adoption and use of SBOMs with the Codenotary integration in my Kubernetes operator.” said Christian, “especially the additional security, timestamp and search capabilities across the infrastructure were key to developing the extension.”

    Christian Kotzbauer, https://github.com/ckotzbauer/sbom-operator

    What do you gain as a DevOps engineer?

    For sure you still remember the last couple of months with plenty of requests, if there are any vulnerable Log4J (Log4Shell) or spring-webmvc (Spring4Shell) versions running in the infrastructure. Just checking the Git repositories source code or image scanning doesn’t really cut it. You need to know if these components are already in your environment and you need to know it immediately.

    Codenotary Cloud and CAS make it very easy to gather the SBOM information and not simply store it, but store them auditable and fully searchable.

    Example Codenotary Cloud:

    vcn authenticate --bom-what-includes --name log4j-core --version "<2.15.0"

    Based on the included in information, you can simply check what is currently using the dependency:

    vcn authenticate --hash 6bd1bad7c9c664580428c35fe354a5f92dc87d6a24db566a5421a1abdf5ed733

    or use the dashboard

    The SBOM viewer in the Codenotary Cloud dashboard allows to search and filter dependencies and immediately detect untrusted or unwanted components – Log4J-Core component in the example below.

    Installation of the Operator in Kubernetes

    Create a secret for the API Key:

    kubectl create secret generic SBOM_JOB_VCN_LC_API_KEY --from-literal=secret=<Your Codenotary Cloud API Key>

    or using CAS:

    kubectl create secret generic SBOM_JOB_CAS_API_KEY --from-literal=secret=<Your cas.Codenotary.com API Key>

    deployment.yaml for Codenotary Cloud (make sure to change SBOM_JOB_VCN_LC_HOST value):

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/name: sbom-operator
      name: sbom-operator
      namespace: default
    spec:
      selector:
        matchLabels:
          app.kubernetes.io/name: sbom-operator
      template:
        metadata:
          labels:
            app.kubernetes.io/name: sbom-operator
        spec:
          containers:
          - image: Codenotary/sbom-operator:0.10.0
            name: operator
            env:
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_UID
              valueFrom:
                fieldRef:
                  fieldPath: metadata.uid
            # Free account
            # - name: SBOM_JOB_CAS_API_KEY
            #   value: ""
            - name: SBOM_JOB_VCN_LC_HOST
              value: "YourCNC.Codenotary.com"
            - name: SBOM_JOB_VCN_LC_API_KEY
              valueFrom:
                 secretKeyRef:
                   name: cncapikey
                   key: secret
            args:
              # example values
              - --cron="0 6 * * *"
              - --job-image=Codenotary/sbom-operator:vcn-0.11.0
              #- --pod-label-selector=sbom-operator\=true
            ports:
            - containerPort: 8080
              name: http
              protocol: TCP
            securityContext:
              capabilities:
                drop:
                - ALL
              privileged: false
              readOnlyRootFilesystem: true
              runAsNonRoot: true
              runAsUser: 101
              seccompProfile:
                type: RuntimeDefault
            resources:
              limits:
                cpu: 500m
                memory: 500Mi
              requests:
                cpu: 100m
                memory: 100Mi
            livenessProbe:
              timeoutSeconds: 3
              httpGet:
                path: "/health"
                port: 8080
            readinessProbe:
              timeoutSeconds: 3
              httpGet:
                path: "/health"
                port: 8080
          securityContext:
            fsGroup: 101
          serviceAccountName: sbom-operator
    

    or deployment.yaml for CAS

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/name: sbom-operator
      name: sbom-operator
      namespace: default
    spec:
      selector:
        matchLabels:
          app.kubernetes.io/name: sbom-operator
      template:
        metadata:
          labels:
            app.kubernetes.io/name: sbom-operator
        spec:
          containers:
          - image: Codenotary/sbom-operator:0.10.0
            name: operator
            env:
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_UID
              valueFrom:
                fieldRef:
                  fieldPath: metadata.uid
            - name: SBOM_JOB_CAS_API_KEY
              valueFrom:
                 secretKeyRef:
                   name: casapikey
                   key: secret
            args:
              # example values
              - --cron="0 6 * * *"
              - --job-image=Codenotary/sbom-operator:cas-0.11.0
              #- --pod-label-selector=sbom-operator\=true
            ports:
            - containerPort: 8080
              name: http
              protocol: TCP
            securityContext:
              capabilities:
                drop:
                - ALL
              privileged: false
              readOnlyRootFilesystem: true
              runAsNonRoot: true
              runAsUser: 101
              seccompProfile:
                type: RuntimeDefault
            resources:
              limits:
                cpu: 500m
                memory: 500Mi
              requests:
                cpu: 100m
                memory: 100Mi
            livenessProbe:
              timeoutSeconds: 3
              httpGet:
                path: "/health"
                port: 8080
            readinessProbe:
              timeoutSeconds: 3
              httpGet:
                path: "/health"
                port: 8080
          securityContext:
            fsGroup: 101
          serviceAccountName: sbom-operator

    and the rbac.yaml

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: sbom-operator
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: sbom-operator
    rules:
    - apiGroups:
      - ""
      resources:
      - pods
      - namespaces
      verbs:
      - list
    - apiGroups:
      - ""
      resources:
      - secrets
      verbs:
      - get
    - apiGroups:
      - ""
      resources:
      - pods
      verbs:
      - get
      - update
    - apiGroups:
      - ""
      resources:
      - secrets
      verbs:
      - get
      - create
      - delete
    - apiGroups:
      - batch
      resources:
      - jobs
      verbs:
      - get
      - create
      - delete
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: sbom-operator
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: sbom-operator
    subjects:
    - kind: ServiceAccount
      name: sbom-operator
      namespace: default
    

    Install everything using kubectl:

    kubectl apply -f deployment.yaml rbac.yaml

    After the deployment has been completed, the cron job (based on the configuration in the deployment.yaml) will detect the running images, generate a Software Bill of Materials for each container image and notarize it in either CAS or Codenotary Cloud.

    You are all set!