Skip to content

Software Bill of Behaviour: A vendor-supplied profile of runtime behaviors for software, designed to be distributed directly within OCI artifacts.

License

Notifications You must be signed in to change notification settings

k8sstormcenter/bob

Repository files navigation

Software Bill of Behavior SBoB

WARNING: REPO HAS BEEN RENAMED

BoBLogoRegistered

We introduce the “Bill of Behavior” (BoB): a vendor-supplied profile detailing known benign runtime behaviors for software, designed to be distributed directly within OCI artifacts. Generated using eBPF, a BoB codifies expected syscalls, file access patterns, network communications, and capabilities. This empowers two things:

  • for the supply chain at deploy-time (possibly in a staging env): we can use a detailed and highly specific such profile to verify an installer at client side to exclude tampering (see the npm incident from sept 8)
  • for continuous anomaly detection at runtime: allowing end-users to infer malicious activity, to shrink their false positive noise and to have a vendor-supplied behavioural baseline, the generalized and more lightweight profile is used.

We foresee a massive scale benefit for the end-user, who does not have in-depth knowledge of the software by shifting authoring and maintaining custom security policies to the vendor, who knows their own software, has the test cases and can judge what part of the policies should be generalized.

Imagine a software vendor (like a pharmaceutical company) distills all their knowledge of their own testing into a standard file and ship it with each update . Just like a Container Beipackzettel 🌡️📦📃🩻 <img BoBverticalboth_registered

That means the user receives a secure default runtime profile. They can customize it, or directly apply it for runtime detection. And which each update of the software, get an uptodate runtimeprofile

Trademark: Bill of Behavior is a registered trademark by Constanze Roedig, all rights reserved


Table of Contents

  1. Introduction
  2. Bill of Behavior (BoB) Overview
  3. A generalized ApplicationProfile
  4. FAQ
  5. Example Comparison: Seccomp vs BoB
  6. BoB as a Transport and Enforcement Mechanism
  7. Origin Story
  8. Understanding the Use Cases
  9. Try it Out in a Live Lab
  10. Demo: Deploy an Application
  11. Generate Traffic of Benign Behaviour
  12. Create a Repeatable Positive Test
  13. Generate Runtime Attack
  14. Generate Supply Chain Attack (WIP)
  15. License

DISCLAIMER:
The scripts are currently for rapid prototyping to iterate on a design the community will accept.
The regex is not stable—do not rely on AI for these profiles. If you want to use them for your software:
Run the scripts, then use your eyes to fix what the regex messed up. Once the code is stable, (and if there is expressed interest/acceptance/funding etc) I ll create proper tooling


What it looks like (in Kubescape format)

🚨 New Design Kubescape 4.0 will support user-defined-profiles, here an example using the kubescape CRDs 🚨

apiVersion: spdx.softwarecomposition.kubescape.io/v1beta1
kind: ApplicationProfile
metadata:
  name: bob-application123
  namespace: {{ .Release.Namespace }}                                                                                                                      
spec:
  architectures:
  - amd64
  containers:
  - capabilities:  # KNOWN CAPABILITIES
    - DAC_OVERRIDE
    - SETGID
    - SETUID
    endpoints:     # KNOWN NETWORK
    - direction: inbound
      endpoint: :8080/ping.php
      headers:
        Host: # User accessible Overrides
        - {{ include "mywebapp.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}                          
      internal: false
      methods:
      - GET
    execs:       #KNOWN EXEC
    - args:
      - /usr/bin/dirname
      - /var/lock/apache2
      path: /usr/bin/dirname
    - args:
      - /bin/sh
      - -c
      - ping -c 4 172.16.0.2
      path: /bin/sh
    imageID: ghcr.io/k8sstormcenter/webapp@sha256:e323014ec9befb76bc551f8cc3bf158120150e2e277bae11844c2da6c56c0a2b  #IMAGE HASH
    opens:     #KNOWN FILE OPENS
    - flags:  
      - O_CLOEXEC
      - O_DIRECTORY
      - O_NONBLOCK
      - O_RDONLY
      path: /etc/apache2/* #globs that generalize UUIDs or well-known FS structures
    - flags:
      - O_CLOEXEC
      - O_RDONLY
      path: /etc/group
    - flags:
      - O_CLOEXEC
      - O_RDONLY
      path: /etc/ld.so.cache
    rulePolicies:  # SPECIFIC EXCEPTION RULES
      R0001:
        processAllowed:
        - ping
        - sh
      R0002: {}
      ...
    syscalls:    # KNOWN SYSCALLS
    - accept4
    - access
    - arch_prctl
    - getegid
    - geteuid
      ...

FAQ

Q: Isnt this the same as SELINUX/APPARMOR profiles?

A: Just like eBPF extends the Kernel, the above Profile are a superset of (Lists of recorded activity like incl FileAccess, Execs, ImageHashes, NetworkEndpoints, SystemCalls and Capabilities) and can work real-time with user-defined profiles, but it doesnt require loading anything into the LSM. LSMs have a totally different life-cycle and granularity than applications. Screenshot 2025-09-08 at 09 47 48

THE MOST IMPORTANT DIFFERENCE is UX, granularity and timeing and this enables transferring it between systems and making it transparent to users

Example comparison of seccomp with BoB (for redis)

Seccomp is a well-established sandboxing mechanism that filters which syscalls are allowed from an application to be made to the kernel. Kubernetes uses it since version 1.19

For the KV-database redis in its most popular Helm-Chart, we traced out the superset of benign behavior across many k8s-versions/distros. In K8s, there is a RuntimeDefault seccomp profile that is shipped by default, the SBoB allowlists 99 syscalls, meaning the resulting difference will be detected as anomaly. Generally speaking, a BoB profile will have a lower number of syscalls than a seccomp profile. There are many discussions on the internet on how seccomp is difficult across architecture

An SBoB is a generalized and customizable Application Profile that alerts on anything not allowlisted

(The following summaries are output by the github workflow script that summarizes what the profile allows if each of the workloads is annotated with said SBoB profile) WARNING: those scripts may not be fully stable.

For redis (in standalone form)

using the bitnami chart: For a DB, the user will need to supply network-ranges that are allowed.

Component Container Type Capabilities Net Opens Execs Syscalls
rs-bob-redis-master redis container DAC_OVERRIDE
DAC_READ_SEARCH
NET_ADMIN
0 17 5 99

Applications of type DB are security sensitive, as they often store juicy content. The most interesting thing to anomaly detect is which outbound network connections are happening (exfiltration attempts).

If you are interested in using eBPF to monitor querys, see this course how our friends from pixie achieve such observability.

For Tetragon (an OpenSource CNCF Security eBPF tool)

Component Container Type Capabilities Net Opens Execs Syscalls
rs-tetragon-operator tetragon-operator container NET_ADMIN 10 8 1 92
rs-tetragon export-stdout container none 0 5 2 84
rs-tetragon tetragon container BPF
DAC_OVERRIDE
DAC_READ_SEARCH
NET_ADMIN
PERFMON
SYSLOG
SYS_ADMIN
SYS_PTRACE
0 49 1 131

More elaborate Comparison of the shrinking attack surface if using NO| FULL | BAU profiles for CNCF Pixie

Profile Capabilities Network Opens (#) Execs (#) Allowed Syscalls (#)
Kubernetes Default (v1.33) unconfined CNI unconfined unconfined 363
FULL:catalogoperator CHOWN,
DAC_OVERRIDE,
DAC_READ_SEARCH,
NET_ADMIN,
SETGID,
SETPCAP,
SETUID,
SYS_ADMIN
1 23 3 96
FULL:catalogsource CHOWN,
DAC_OVERRIDE,
DAC_READ_SEARCH,
NET_ADMIN,
SETGID,
SETPCAP,
SETUID,
SYS_ADMIN
0 19 2 106
BAU :catalogsource CHOWN,
DAC_OVERRIDE,
DAC_READ_SEARCH,
NET_ADMIN,
SETGID,
SETPCAP,
SETUID,
SYS_ADMIN
0 57 2 94
FULL:certman DAC_OVERRIDE,
DAC_READ_SEARCH
0 8 1 65
FULL:initjob DAC_OVERRIDE,
DAC_READ_SEARCH
0 10 1 100
FULL:kelvin DAC_OVERRIDE,
DAC_READ_SEARCH,
NET_ADMIN
0 97 1 76
BAU :kelvin none 0 0 0 22
FULL:olmoperator DAC_OVERRIDE,
DAC_READ_SEARCH,
NET_ADMIN
1 8 1 63
FULL:pem BPF,
DAC_READ_SEARCH,
IPC_LOCK,
NET_ADMIN,
PERFMON,
SYS_ADMIN,
SYS_PTRACE,
SYSLOG
0 390 1 122
BAU :pem BPF,
DAC_READ_SEARCH,
IPC_LOCK,
NET_ADMIN,
PERFMON,
SYS_ADMIN,
SYS_PTRACE
0 197 0 44
FULL:pletcd NET_ADMIN,
NET_RAW,
SETGID,
SETPCAP,
SETUID,
SYS_ADMIN
0 39 10 92
BAU :pletcd SETGID,
SETPCAP,
SETUID,
SYS_ADMIN
0 37 2 53
FULL:plnats DAC_OVERRIDE,
DAC_READ_SEARCH,
NET_ADMIN
3 11 1 57
BAU :plnats none 1 1 0 19
FULL:querybroker DAC_OVERRIDE,
DAC_READ_SEARCH,
FOWNER,
NET_ADMIN
0 20 1 107
BAU :querybroker DAC_OVERRIDE,
FOWNER
0 0 0 22
FULL:viziercloudconnector DAC_OVERRIDE,
DAC_READ_SEARCH,
NET_ADMIN
0 18 1 70
BAU :viziercloudconnector none 0 3 0 29
FULL:viziermeta NET_ADMIN 0 16 1 65
BAU :viziermeta none 0 3 0 24
FULL:vizieroperator NET_ADMIN 1 13 1 104
BAU :vizieroperator none 1 2 0 27

Additionally to syscalls: a BoB contains fileopens, execs, capabilities and network endpoints/methods. This is reminiscent of Apparmour profiles and network-policies. It is theoretically possible to convert a BoB into an Apparmour profile, a seccomp profile and a set of network-policies.

Which way the community will go in terms of using the information contained in a bob, such that it can be enforced at runtime, remains to be seen.

A BoB, is first of all a vehicle to transport the information of the runtime behavior. And only secondly, the runtime-anomaly generation method. The fact, that kubescape can rather straightforwardly consume them is a huge plus.

Origin Story

.. over coffee at London KubeCon EU 2025

animation

Understanding the Use Cases

A Bill of Behaviour helps us detect unexpected or malicious activity. We'll focus on two primary scenarios:

1. Runtime Anomalies

This scenario covers situations where a CVE is present in the app, or it gets exploited.

2. Supply Chain Anomalies

This scenario covers threats originating from a compromised supply chain. For example:

  • The artefact is not the one from the vendor.
  • The vendor's supply chain got compromised.
  • A typosquatting attack has occurred.
  • The artefact contains a beacon, a backdoor, a cryptominer, or something else malicious.

Try it out in a live lab

give us feedback , report issues , raise PRs (contributing guidelines will follow)

https://labs.iximiuz.com/courses/bill-of-behaviour-c070da3a

License is Apache 2.0

Demo: Deploy a Application

Using a well-known demo** app, we deploy a ping utility called webapp that has:

  • a) Desired functionality: it pings things.
  • b) Undesired functionality: it is vulnerable to injection (runtime is compromised).
    • This is to mimic a CVE in your app.
  • c) Tampering with the artefact: In module 2, we will additionally tamper with the artifact and make it create a backdoor (supply chain is compromised).
    • This is to mimic a SupplyChain corruption between vendor and you.
cd ~/bobctl
git checkout https://github.com/k8sstormcenter/bobctl
# maybe you need storage, then `make storage`
make kubescape
sleep 30 # TODO proper wait command goes here
make helm-install

Generate Traffic of Benign Behaviour

Benign (adjective) [bi-ˈnīn]

  • Benignity (noun) [bi-ˈnig-nə-tē]
  • Benignly (adverb) [bi-ˈnīn-lē]

Definitions/SYNONYMS:

  1. Of a mild type or character that does not threaten health or life. HARMLESS.
  2. Of a gentle disposition: GRACIOUS.
  3. Showing kindness and gentleness. FAVORABLE, WHOLESOME.

In shell 1:

kubectl logs -n honey -l app=node-agent -c node-agent -f

In shell 2

make fwd
curl localhost:8080/ping.php?ip=172.16.0.2

This will be recorded into the above profile reflected by the stanza:

  endpoint:
    - direction: inbound
      endpoint: :8080/ping.php
      headers:
        Host:
        - localhost:8080  # vendor needs to template possible benign endpoints e.g via k8s-dns                         
      internal: false
      methods:
      - GET
  exec:
  ...
    - args:
      - /bin/sh
      - -c
      - ping -c 4 172.16.0.2 #vendor needs to template possible benign IP CIDR
      path: /bin/sh

Create a repeatable Positive Test

Vendor Encode the benign behavior into a test, like a helm hook

apiVersion: v1
kind: Pod
metadata:
  labels:
    {{- include "mywebapp.labels" . | nindent 4 }}
    kubescape.io/ignore: "true"
  annotations:
    "helm.sh/hook": test
    "helm.sh/hook-delete-policy": hook-succeeded,hook-failed
spec:
  containers:
    - image: curlimages/curl:8.7.1
      command:
          URL=\"${SERVICE}.${NAMESPACE}.svc.cluster.local:${PORT}/ping.php?ip=${TARGET_IP}\"
          RESPONSE=$(curl -s \"$URL\")
          echo \"$RESPONSE\"
          echo \"$RESPONSE\" | grep -q \"Ping results for ${TARGET_IP}\"
          echo \"$RESPONSE\" | grep -q \"${TARGET_IP} ping statistics\"

User If I now pull the helm-chart and execute helm test -> I can test that I do not see any anomalies.

make helm-test
kubectl logs -n honey -l app=node-agent -c node-agent -f | grep "Unexpected"  # You should not see anything 

*** Known exceptions: There are expected syscall deviations, those are small. Making those transparent to the user is WIP. Currently you need a superset Bob

Generate Runtime Attack (normal attack that abuses CVE)

In shell 1:

kubectl logs -n honey -l app=node-agent -c node-agent -f

In shell 2

make attack
{"BaseRuntimeMetadata":{"alertName":"Unexpected process launched","arguments":{"args":["/bin/ls"],"exec":"/bin/ls","retval":0},"infectedPID":6972,"severity":5,"size":"4.1 kB","timestamp":"2025-05-22T17:16:24Z"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected file access","arguments":{"flags":["O_RDONLY","O_NONBLOCK","O_DIRECTORY","O_CLOEXEC"],"path":"/var/www/html"},"infectedPID":6972,"severity":1,"timestamp":"2025-05-22T17:16:24Z"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected system call","arguments":{"syscall":"sendmmsg"},"infectedPID":15899,"md5Hash":"4e79f11b07df8f72e945e0e3b3587177","sha1Hash":"b361a04dcb3086d0ecf960dbb6e0f6f1d9b7ebf3b"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected system call","arguments":{"syscall":"socketpair"},"infectedPID":15899,"md5Hash":"4e79f11b07df8f72e945e0e3b3587177","sha1Hash":"b361a04dcb3086d0ecf960dbb6e0f6f1d9b7ebf3b"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected domain request","arguments":{"addresses":["216.58.210.174"],"domain":"google.com.","port":50015,"protocol":"UDP"},"infectedPID":20611,"severity":5,"size":"4.1 kB","timestamp":"2025-05-22T17:16:24Z"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected system call","arguments":{"syscall":"getpeername"},"infectedPID":15899,"md5Hash":"4e79f11b07df8f72e945e0e3b3587177","sha1Hash":"b361a04dcb3086d0ecf960dbb6e0f6f1d9b7ebf3b"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected process launched","arguments":{"args":["/usr/bin/curl","google.com"],"exec":"/usr/bin/curl","retval":0},"infectedPID":20611,"severity":5,"size":"4.1 kB","timestamp":"2025-05-22T17:16:24Z"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected Service Account Token Access","arguments":{"flags":["O_RDONLY"],"path":"/run/secrets/kubernetes.io/serviceaccount/..2025_07_07_21_05_56.676258237/token"},"infectedPID":20611,"severity":5,"timestamp":"2025-05-22T17:16:24Z"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected file access","arguments":{"flags":["O_RDONLY"],"path":"/run/secrets/kubernetes.io/serviceaccount/..2025_07_07_21_05_56.676258237/token"},"infectedPID":20611,"severity":5,"timestamp":"2025-05-22T17:16:24Z"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected system call","arguments":{"syscall":"fadvise64"},"infectedPID":15899,"md5Hash":"4e79f11b07df8f72e945e0e3b3587177","sha1Hash":"b361a04dcb3086d0ecf960dbb6e0f6f1d9b7ebf3b"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected file access","arguments":{"flags":["O_RDONLY"],"path":"/var/www/html/index.html"},"infectedPID":20581,"severity":1,"timestamp":"2025-07-07T21:22:04"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected file access","arguments":{"flags":["O_RDONLY","O_NONBLOCK","O_DIRECTORY","O_CLOEXEC"],"path":"/var/www/html"},"infectedPID":20503,"severity":1,"timestamp":"2025-07-07T21:21:53"}}
{"BaseRuntimeMetadata":{"alertName":"Unexpected process launched","arguments":{"args":["/bin/cat","/proc/self/mounts"],"exec":"/bin/cat","retval":0},"infectedPID":20527,"severity":5,"size":"4.1 kB","timestamp":"2025-07-07T21:22:08"}}

Generate Supply Chain Attack

WIP

About

Software Bill of Behaviour: A vendor-supplied profile of runtime behaviors for software, designed to be distributed directly within OCI artifacts.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages