Aller au contenu
Sécurité medium

OBOM : inventorier ce qui tourne vraiment en production

34 min de lecture

Vous avez un SBOM parfait généré au build. Puis arrive une CVE critique. Vous vérifiez : "on n'utilise pas cette lib". Sauf qu'en production, un plugin chargé dynamiquement l'utilise. Le SBOM décrivait ce qui avait été assemblé, pas l'état opérationnel réellement observé.

L'OBOM (Operations Bill of Materials) cherche à capturer cet état opérationnel : librairies chargées dynamiquement, modules activés selon l'environnement, configurations runtime, services connectés. C'est un complément au SBOM, pas un remplacement.

Dans ce guide, vous apprendrez :

  • Pourquoi l'OBOM est nécessaire et ce qu'il capture de plus qu'un SBOM
  • Comment collecter les informations runtime sur Linux et dans les conteneurs
  • Comment générer un OBOM avec les outils disponibles
  • Comment corréler SBOM et OBOM pour une visibilité complète

Les deux inventaires ne sont pas produits au même moment ni à partir de la même source, et c'est précisément d'où vient l'écart. Le SBOM lit des fichiers de déclaration au moment où le logiciel est assemblé ; l'OBOM interroge des processus qui tournent. Entre les deux, il s'est passé un déploiement, des variables d'environnement, des plugins activés et des bibliothèques système fournies par l'hôte.

Lisez ce tableau ligne par ligne comme une liste de questions auxquelles un SBOM seul ne répond pas. La colonne de droite indique à chaque fois quelle information supplémentaire l'observation du runtime apporte.

AspectSBOM (build-time)OBOM (runtime)
MomentÀ la compilation/packagingEn production
SourceManifestes (package.json, go.mod, etc.)Processus en cours d'exécution
DépendancesDéclarées et transitivesEffectivement chargées
ConfigurationValeurs par défautConfiguration active
Modules optionnelsListés comme optionnelsActivés ou non
PluginsPotentielsRéellement chargés

Le code ci-dessous choisit son pilote de base de données à partir d'une variable d'environnement et charge ses plugins en parcourant un dossier. Aucun outil d'analyse statique ne peut deviner ce qui sera réellement importé : la décision est prise au démarrage, sur la machine de production.

# app.py - Application avec chargement dynamique
import os
import importlib
# Le driver de base de données dépend de l'environnement
db_driver = os.getenv("DB_DRIVER", "sqlite")
db_module = importlib.import_module(f"databases.{db_driver}")
# Les plugins sont chargés depuis un dossier
for plugin in os.listdir("plugins/enabled"):
importlib.import_module(f"plugins.{plugin}")

Ce que le SBOM voit (inventaire produit à partir du build ou de l'environnement packagé) :

flask==3.0.0
databases-sqlite==0.9.0
databases-postgres==0.9.0 # dépendance extras
plugin-analytics==1.2.0 # plugin disponible
plugin-cache==2.0.0 # plugin disponible

Note : cet exemple est simplifié à des fins pédagogiques. En réalité, les sources de divergence sont plus variées (wheels, entry points, montages runtime, etc.).

Ce qui tourne en production (runtime réel) :

flask==3.0.0
databases-postgres==0.9.0 # ← Celui-ci est activé
plugin-cache==2.0.0 # ← Seul ce plugin est activé
psycopg2==2.9.9 # ← Dépendance transitive de postgres
libpq.so.5 # ← Librairie C chargée par psycopg2

Le SBOM liste databases-sqlite (défaut) mais la production utilise databases-postgres. Si une CVE touche psycopg2, un SBOM build-time peut ne pas suffire à dire si cette dépendance est réellement active dans cet environnement. L'OBOM aide alors à distinguer présence théorique et usage effectif.

Un OBOM ne se limite pas à une liste de paquets : il décrit un état de fonctionnement. Les informations utiles se répartissent en cinq familles, dont certaines s'obtiennent en une commande et d'autres demandent un travail d'enrichissement. Savoir laquelle est facile à collecter conditionne l'ordre dans lequel vous construirez votre inventaire.

Le schéma regroupe ces familles et donne, pour chacune, le type de source à interroger.

Les 5 catégories d'informations capturées par un OBOM : librairies, modules, configuration, services, système

La colonne de droite est la plus utile : elle indique le type d'incident que chaque catégorie permet de trancher, depuis une CVE dans une bibliothèque C jusqu'à un paramètre TLS abaissé en production.

CatégorieExemplesPourquoi c'est important
Librairies chargéeslibssl.so.3, libc.so.6, libpq.so.5CVE dans les libs C/système
Modules activésPlugins WordPress, extensions PythonCode actif non visible au build
Configuration activeTLS_MIN_VERSION=1.2, DEBUG=falseParamètres de sécurité effectifs
Services connectéspostgres://db:5432, redis://cache:6379Dépendances réseau
État systèmeKernel 5.15, glibc 2.35Vulnérabilités système

Linux expose l'état d'un processus dans le pseudo-système de fichiers /proc, ce qui permet de l'interroger sans instrumenter l'application. Les quatre méthodes qui suivent vont du plus générique au plus spécifique : bibliothèques partagées, modules Python, paquets Node.js, puis variables d'environnement. Aucune ne suffit seule, elles se complètent. Toutes demandent au minimum le droit de lire /proc pour le compte propriétaire du processus.

La méthode la plus directe pour lister les librairies chargées par un processus :

Fenêtre de terminal
# Lister les librairies chargées par un processus
cat /proc/$(pgrep -x python3)/maps | grep '\.so' | awk '{print $6}' | sort -u
# Exemple de sortie :
/lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libpthread.so.0
/lib/x86_64-linux-gnu/libm.so.6
/usr/lib/x86_64-linux-gnu/libssl.so.3
/usr/lib/x86_64-linux-gnu/libcrypto.so.3
/usr/lib/python3.11/lib-dynload/_ssl.cpython-311-x86_64-linux-gnu.so
collect-runtime-libs.sh
#!/bin/bash
# Collecte les librairies chargées pour un processus
PID=${1:-}
if [ -z "$PID" ]; then
echo "Usage: $0 <PID>"
exit 1
fi
echo "=== Runtime libraries for PID $PID ==="
echo ""
# Nom du processus
PROC_NAME=$(cat "/proc/$PID/comm")
echo "Process: $PROC_NAME"
echo ""
# Librairies .so uniques
echo "Shared libraries:"
grep -E '\.so(\.[0-9]+)*$' "/proc/$PID/maps" | \
awk '{print $6}' | \
sort -u | \
while read -r lib; do
# Afficher le chemin de la librairie
if [ -f "$lib" ]; then
echo " - $lib"
fi
done
# Fichiers ouverts (fd)
echo ""
echo "Open files (non-trivial):"
for fd in "/proc/$PID/fd"/*; do
cible=$(readlink "$fd" 2>/dev/null) || continue
case "$cible" in
pipe:*|socket:*|anon_inode:*|/dev/*) continue ;;
esac
echo " $cible"
done

Pour les applications Python, listez les modules effectivement importés :

runtime_modules.py
import sys
import json
def get_loaded_modules():
"""Retourne les modules Python chargés avec leur chemin."""
modules = {}
for name, module in sys.modules.items():
if hasattr(module, '__file__') and module.__file__:
modules[name] = {
"path": module.__file__,
"version": getattr(module, '__version__', None)
}
return modules
if __name__ == "__main__":
print(json.dumps(get_loaded_modules(), indent=2))

Exemple d'exécution via kubectl exec :

Fenêtre de terminal
# Via un shell dans le conteneur
kubectl exec -it myapp-pod -- python -c "
import sys, json
mods = {k: getattr(v, '__file__', 'builtin') for k, v in sys.modules.items()}
print(json.dumps(mods, indent=2))
"

Pour les applications Node.js :

runtime-deps.js
// Ajouter en fin de votre app ou via un endpoint debug
function getLoadedModules() {
const modules = {};
for (const [path, mod] of Object.entries(require.cache)) {
if (path.includes('node_modules')) {
const parts = path.split('node_modules/');
const pkgPath = parts[parts.length - 1].split('/')[0];
if (!modules[pkgPath]) {
try {
const pkg = require(`${pkgPath}/package.json`);
modules[pkgPath] = pkg.version;
} catch {
modules[pkgPath] = 'unknown';
}
}
}
}
return modules;
}
console.log(JSON.stringify(getLoadedModules(), null, 2));

Les variables d'environnement définissent souvent le comportement runtime :

Fenêtre de terminal
# Lister les variables d'environnement d'un processus
cat /proc/$(pgrep -x python3)/environ | tr '\0' '\n' | grep -E '^(DB_|API_|FEATURE_|DEBUG|LOG_LEVEL)'
# Dans un conteneur Kubernetes
kubectl exec myapp-pod -- env | grep -E '^(DB_|API_|FEATURE_)'

Dans un conteneur, la même logique s'applique mais depuis l'extérieur : docker exec ouvre un processus dans les espaces de noms du conteneur et donne accès à son /proc. Deux angles sont possibles et ne donnent pas le même résultat : interroger les processus actifs, ou exporter le système de fichiers pour l'analyser avec un outil de composition. Le second est plus complet sur les paquets installés, le premier est le seul à voir ce qui est réellement chargé.

Ces commandes supposent que les utilitaires interrogés existent dans l'image ; sur une image distroless ou construite FROM scratch, ni ps ni netstat ne seront présents.

Fenêtre de terminal
# Lister les processus dans un conteneur
docker exec mycontainer ps aux
# Librairies chargées par le processus principal (PID 1 dans le conteneur)
docker exec mycontainer cat /proc/1/maps | grep '\.so' | awk '{print $6}' | sort -u
# Connexions réseau actives
docker exec mycontainer netstat -tuln
# Packages installés (Debian/Ubuntu)
docker exec mycontainer dpkg-query -W -f='${Package} ${Version}\n'
# Packages installés (Alpine)
docker exec mycontainer apk list --installed

Scanner le filesystem d'un conteneur en cours d'exécution

Section intitulée « Scanner le filesystem d'un conteneur en cours d'exécution »

Syft peut scanner une image Docker, mais aussi le filesystem exporté d'un conteneur :

Fenêtre de terminal
# Scanner l'image (SBOM classique)
syft myregistry/myapp:v1.0.0 -o cyclonedx-json > sbom.json
# Scanner le rootfs d'un conteneur en cours d'exécution
CONTAINER_ID=$(docker ps -qf "name=myapp")
docker export $CONTAINER_ID | syft /dev/stdin -o cyclonedx-json > runtime-sbom.json

Ce script assemble les deux sources précédentes, paquets système et bibliothèques chargées, dans un document CycloneDX 1.6 minimal. Il est volontairement simple et sert de point de départ : la propriété obom:collection-method qu'il inscrit dans les métadonnées permettra plus tard de distinguer ce document d'un SBOM classique.

collect-obom.sh
#!/bin/bash
# Prototype de collecte partielle pour un conteneur
# Utile pour démonstration ou expérimentation, insuffisant comme OBOM de production
CONTAINER=$1
OUTPUT=${2:-obom.json}
if [ -z "$CONTAINER" ]; then
echo "Usage: $0 <container_name_or_id> [output.json]"
exit 1
fi
echo "Collecting OBOM for container: $CONTAINER"
# Créer le JSON de sortie
cat > "$OUTPUT" << EOF
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"version": 1,
"metadata": {
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"component": {
"name": "$CONTAINER",
"type": "container"
},
"properties": [
{"name": "obom:collection-method", "value": "runtime-inspection"}
]
},
"components": [
EOF
# Collecter les packages système
echo " Collecting system packages..."
docker exec "$CONTAINER" sh -c '
if command -v dpkg-query >/dev/null; then
dpkg-query -W -f "${Package}\t${Version}\n" 2>/dev/null
elif command -v apk >/dev/null; then
apk list --installed 2>/dev/null | sed "s/-\([0-9]\)/ \1/"
elif command -v rpm >/dev/null; then
rpm -qa --queryformat "%{NAME}\t%{VERSION}\n" 2>/dev/null
fi
' | while IFS=$'\t' read -r name version; do
echo " {\"type\": \"library\", \"name\": \"$name\", \"version\": \"$version\", \"properties\": [{\"name\": \"source\", \"value\": \"os-package\"}]},"
done >> "$OUTPUT"
# Collecter les librairies chargées du processus principal
# Note : PID 1 n'est pas toujours le processus applicatif (peut être init/wrapper)
echo " Collecting loaded libraries..."
docker exec "$CONTAINER" cat /proc/1/maps 2>/dev/null | \
grep -E '\.so(\.[0-9]+)*$' | \
awk '{print $6}' | \
sort -u | \
while read lib; do
name=$(basename "$lib" | sed 's/\.so.*//')
echo " {\"type\": \"library\", \"name\": \"$name\", \"properties\": [{\"name\": \"source\", \"value\": \"loaded-library\"}, {\"name\": \"path\", \"value\": \"$lib\"}]},"
done >> "$OUTPUT"
# Fermer le JSON (enlever la dernière virgule et fermer)
sed -i '$ s/,$//' "$OUTPUT"
echo " ]" >> "$OUTPUT"
echo "}" >> "$OUTPUT"
echo "OBOM written to: $OUTPUT"

cdxgen est un générateur CycloneDX lié à l'écosystème OWASP/CycloneDX. Il propose des capacités utiles pour aller vers l'OBOM, notamment pour certaines images Linux et VMs via plugins, mais le support reste à valider selon le contexte.

cdxgen se distribue comme paquet npm global et nécessite donc une installation Node.js sur la machine qui lance la collecte.

Fenêtre de terminal
npm install -g @cyclonedx/cdxgen

L'option --deep est celle qui change tout : sans elle, cdxgen se contente des manifestes de dépendances et produit un SBOM ordinaire.

Fenêtre de terminal
# Pour un projet Node.js avec détection des dépendances runtime
cdxgen -t nodejs -o obom.json --deep
# Pour une image Docker avec analyse approfondie
cdxgen -t docker -o obom.json my-image:latest --deep
# Inclure les informations d'environnement
cdxgen -t nodejs -o obom.json --include-env

À l'échelle d'un cluster, la collecte se heurte à deux contraintes : kubectl exec doit être autorisé par le RBAC du compte utilisé, et chaque conteneur d'un pod doit être traité séparément. Prévoyez aussi le cas des pods sans shell : la commande échouera silencieusement et produira un fichier vide, ce qu'il faut savoir interpréter comme une absence de donnée et non comme une absence de composant.

Le script parcourt tous les pods d'un namespace et écrit trois fichiers par conteneur : paquets, bibliothèques et connexions réseau.

collect-cluster-obom.sh
#!/bin/bash
# Collecte l'inventaire runtime de tous les pods
NAMESPACE=${1:-default}
OUTPUT_DIR=${2:-./obom-collection}
mkdir -p "$OUTPUT_DIR"
echo "Collecting OBOM for namespace: $NAMESPACE"
# Lister tous les pods
kubectl get pods -n "$NAMESPACE" -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].name}{"\n"}{end}' | \
while IFS=$'\t' read -r pod containers; do
for container in $containers; do
echo "Processing: $pod / $container"
# Collecter les packages (si possible)
kubectl exec -n "$NAMESPACE" "$pod" -c "$container" -- sh -c '
if command -v dpkg-query >/dev/null; then
dpkg-query -W -f "${Package}\t${Version}\n"
elif command -v apk >/dev/null; then
apk list --installed 2>/dev/null
fi
' 2>/dev/null > "$OUTPUT_DIR/${pod}_${container}_packages.txt"
# Collecter les librairies chargées
kubectl exec -n "$NAMESPACE" "$pod" -c "$container" -- \
cat /proc/1/maps 2>/dev/null | \
grep -E '\.so' | awk '{print $6}' | sort -u \
> "$OUTPUT_DIR/${pod}_${container}_libs.txt"
# Collecter les connexions réseau
kubectl exec -n "$NAMESPACE" "$pod" -c "$container" -- \
netstat -tuln 2>/dev/null \
> "$OUTPUT_DIR/${pod}_${container}_network.txt"
done
done
echo "Collection complete. Files in: $OUTPUT_DIR"

Ces outils ont des rôles différents, ne les confondez pas :

OutilCatégorieFonction
TrivyScan de compositionAnalyse image/filesystem/k8s, pas inventaire runtime fin
SyftScan de compositionSBOM depuis images/filesystems
SysdigTélémétrie runtimeObservation runtime via agent eBPF
FalcoDétection comportementaleAlertes sur comportements anormaux, pas OBOM
KSOCVisibilité KubernetesRuntime visibility via agent

Collecter les deux inventaires n'a d'intérêt que si vous les comparez. Trois écarts méritent une investigation : un composant présent au runtime mais absent du SBOM, une version qui diffère entre les deux documents, et un composant déclaré mais jamais chargé. Le premier cas est le plus sérieux : il signale du code qui s'exécute sans être passé par votre chaîne de construction.

Le schéma résume l'enchaînement, de la production des deux documents jusqu'à l'identification des composants « fantômes ».

Workflow de corrélation SBOM et OBOM : comparaison build time vs runtime pour identifier les composants fantômes

Le script attend deux documents CycloneDX et classe les composants en quatre ensembles : présents des deux côtés, propres au SBOM, propres à l'OBOM et versions divergentes. C'est la catégorie obom_only qui doit déclencher une analyse.

#!/usr/bin/env python3
"""compare-sbom-obom.py - Compare SBOM et OBOM pour détecter les écarts."""
import json
import sys
from collections import defaultdict
def load_bom(path):
"""Charge un BOM CycloneDX et extrait les composants."""
with open(path) as f:
bom = json.load(f)
components = {}
for comp in bom.get("components", []):
name = comp.get("name", "")
version = comp.get("version", "unknown")
components[name] = version
return components
def compare(sbom_path, obom_path):
"""Compare SBOM et OBOM, retourne les écarts."""
sbom = load_bom(sbom_path)
obom = load_bom(obom_path)
sbom_names = set(sbom.keys())
obom_names = set(obom.keys())
results = {
"sbom_only": list(sbom_names - obom_names), # Déclaré, non chargé
"obom_only": list(obom_names - sbom_names), # Chargé, non déclaré
"both": list(sbom_names & obom_names), # Match
"version_mismatch": [] # Versions différentes
}
# Vérifier les versions
for name in results["both"]:
if sbom[name] != obom[name]:
results["version_mismatch"].append({
"name": name,
"sbom_version": sbom[name],
"obom_version": obom[name]
})
return results
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: compare-sbom-obom.py sbom.json obom.json")
sys.exit(1)
results = compare(sys.argv[1], sys.argv[2])
print("=== Composants SBOM-only (déclarés mais non chargés) ===")
for name in results["sbom_only"][:10]:
print(f" - {name}")
print("\n=== Composants OBOM-only (chargés mais non déclarés) ===")
for name in results["obom_only"][:10]:
print(f" ⚠️ {name}")
print(f"\n=== Résumé ===")
print(f"Match: {len(results['both'])}")
print(f"SBOM-only: {len(results['sbom_only'])}")
print(f"OBOM-only: {len(results['obom_only'])} ← À investiguer")
print(f"Version mismatch: {len(results['version_mismatch'])}")

Usage :

Fenêtre de terminal
python compare-sbom-obom.py sbom.json obom.json

GUAC (Graph for Understanding Artifact Composition) peut ingérer des documents CycloneDX et SPDX ainsi que d'autres métadonnées supply chain, ce qui en fait un bon candidat pour corréler SBOM, attestations, vulnérabilités et, potentiellement, des inventaires opérationnels modélisés de manière compatible. La profondeur réelle de cette corrélation dépend toutefois de la qualité et de la structure des documents ingérés.

guacone collect files accepte les deux documents sans distinction de nature : c'est vous qui donnez du sens à l'ensemble en les ingérant tous les deux, puis en interrogeant le graphe.

Fenêtre de terminal
# Ingérer le SBOM (build-time)
guacone collect files sbom.json
# Ingérer l'OBOM (runtime)
guacone collect files obom.json
# Maintenant GUAC peut répondre à des requêtes comme :
# "Quels composants sont en production mais pas dans le SBOM ?"
# "Ce conteneur utilise-t-il une lib vulnérable à cette CVE ?"

Un OBOM est un instantané : sa valeur dépend directement de sa fraîcheur et de la discipline avec laquelle il est produit. Deux décisions structurent la démarche : à quelle fréquence collecter, et quelles données s'interdire de capturer. La seconde n'est pas négociable, un inventaire qui contient des secrets devient lui-même un actif à protéger.

Le déclencheur le plus utile n'est pas le calendrier mais le déploiement : c'est à ce moment que l'état runtime change réellement.

EnvironnementFréquenceRaison
ProductionQuotidien ou après chaque déploiementDétection rapide des dérives
StagingÀ chaque déploiementValidation avant prod
Dev/TestOptionnelMoins critique

La règle tient en une phrase : collectez des identifiants, jamais des valeurs. Le nom d'une variable d'environnement documente la configuration, sa valeur peut être un mot de passe.

✅ Collecter❌ Ne pas collecter
Noms des packagesValeurs des secrets
VersionsDonnées utilisateur
Chemins des librairiesContenu des fichiers de config sensibles
Noms des variables d'envValeurs des variables d'env secrètes
Connexions réseau (hosts)Credentials dans les connexions

Trois déclencheurs couvrent l'essentiel des besoins et se mettent en place avec des objets Kubernetes standard : un Job après déploiement, un CronJob quotidien et une collecte manuelle en réponse à un incident.

  1. À chaque déploiement

    Générez un OBOM snapshot après le démarrage de l'application :

    # Kubernetes Job post-deploy
    apiVersion: batch/v1
    kind: Job
    metadata:
    name: collect-obom
    spec:
    template:
    spec:
    containers:
    - name: collector
    image: obom-collector:1.2.0
    command: ["./collect-obom.sh", "myapp-pod"]
  2. Quotidiennement

    Collecte planifiée pour détecter les dérives (plugins activés, libs mises à jour) :

    apiVersion: batch/v1
    kind: CronJob
    metadata:
    name: daily-obom
    spec:
    schedule: "0 2 * * *" # 2h du matin
    jobTemplate:
    # ...
  3. Sur incident de sécurité

    Collecte immédiate pour répondre à "est-ce qu'on utilise cette lib vulnérable ?"

L'OBOM est un complément précieux, mais il ne faut pas remplacer un mythe ("le SBOM suffit") par un autre ("l'OBOM règle le runtime").

Ces six limites sont structurelles : aucune amélioration de l'outillage ne les lève, parce qu'observer un système à un instant donné ne dit rien de son origine ni de son avenir.

LimitationExplication
Intégrité de la chaîne de buildL'OBOM observe, il ne prouve pas l'origine
Absence de dérive futureSnapshot à un instant T, pas surveillance continue
Couverture complèteDépend de la méthode de collecte et des privilèges
Exploitabilité d'une CVEPrésence ≠ vulnérabilité exploitable (c'est le rôle du VEX)
Conformité à lui seulUn élément parmi d'autres dans une posture de sécurité
Détection automatique de toutPlugins/comportements très dynamiques peuvent échapper

L'OBOM s'intègre dans un ensemble :

  • SBOM : ce qui a été assemblé
  • Attestations : preuves de provenance et d'intégrité
  • VEX : exploitabilité des vulnérabilités
  • Télémétrie runtime : observation continue
  • OBOM : état opérationnel observé à un instant T

Situez-vous sur cette échelle pour planifier votre progression :

Le point de départ : vous savez ce que contient l'image livrée, mais rien de ce qui se passe après son démarrage.

  • SBOM d'image finale
  • Scan de vulnérabilités
  • Inventaire packages OS

Vous prenez des instantanés du runtime et les comparez à la main : suffisant pour répondre à une question ponctuelle, trop lent pour un incident large.

  • Snapshot runtime (libs chargées, variables d'env)
  • Comparaison SBOM / snapshot manual
  • Alertes sur écarts majeurs

L'introspection descend jusqu'aux modules du langage et la comparaison est automatisée, avec un historique qui permet de dater une dérive. C'est l'objectif réaliste pour la plupart des équipes.

  • Introspection langage (Python/Node/Java)
  • Corrélation multi-source automatisée
  • Enrichissement vulnérabilités
  • Stockage historisé

L'inventaire alimente un graphe interrogeable et les décisions de risque se prennent à partir de ses réponses, sans collecte manuelle préalable. Peu d'organisations y sont, et ce niveau ne se construit pas avant le précédent.

  • OBOM structuré et normalisé
  • Corrélation continue (GUAC ou équivalent)
  • Knowledge graph interrogeable
  • Décision de risque intégrée au workflow

Les 5 points essentiels de ce guide :

  • SBOM et OBOM sont complémentaires, le SBOM décrit ce qui a été assemblé, l'OBOM observe l'état opérationnel réel
  • Plusieurs méthodes de collecte : /proc/<pid>/maps, introspection langage, scan de filesystem, chacune avec ses limites
  • La corrélation SBOM/OBOM révèle les écarts, composants "fantômes" absents du SBOM mais actifs en production
  • L'OBOM n'est pas magique, c'est un snapshot partiel, pas une surveillance continue ni une preuve d'intégrité
  • Automatisez la collecte, après chaque déploiement et quotidiennement, sans jamais collecter les secrets

XBOM : au-delà du SBOM

Comprenez l'écosystème complet des BOM (SBOM, OBOM, CBOM, etc.) Lire le guide

GUAC

Corrélez SBOM, OBOM et vulnérabilités dans un graphe de connaissances Lire le guide GUAC

VEX

Documentez l'exploitabilité des vulnérabilités détectées Lire le guide VEX

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn