Integration¶
La sécurité runtime ne fonctionne pas en silo. Son efficacité depend de son integration avec les autres services de la plateforme.
Integration avec l'observabilité¶
Falco vers Loki¶
Les alertes Falco sont collectees par Alloy et poussees vers Loki pour centralisation et requetage.
graph LR
Falco["Falco<br/>(stdout JSON)"] --> Alloy["Alloy<br/>(collecte)"] --> Loki["Loki<br/>(stockage)"] --> Grafana["Grafana<br/>(dashboard alertes)"] Configuration du pipeline :
# Labels Loki ajoutes aux alertes Falco
# (via la configuration Alloy)
loki.process "falco_enrich" {
stage.json {
expressions = {
priority = "priority",
rule = "rule",
source = "output_fields.container.name",
image = "output_fields.container.image.repository",
}
}
stage.labels {
values = {
priority = "",
rule = "",
source = "",
}
}
forward_to = [loki.write.default.receiver]
}
Dashboards Grafana sécurité¶
Créer un dossier Securite dans Grafana avec les dashboards suivants :
| Dashboard | Contenu | Requête principale |
|---|---|---|
| Vue d'ensemble sécurité | Nombre d'alertes par priorité, tendance 24h | sum by (priority) (count_over_time({job="falco"}[1h])) |
| Alertes critiques | Liste des alertes Critical/Error en temps reel | {job="falco"} \| json \| priority =~ "Critical\|Error" |
| Violations OPA | Contraintes violees, namespaces concernes | gatekeeper_violations (Prometheus) |
| Vulnerabilites Trivy | CVE critiques et hautes par namespace | trivy_image_vulnerabilities{severity=~"Critical\|High"} |
| Performance sécurité | Événements/s Falco, latence OPA, drops | rate(falco_events_total[5m]), gatekeeper_request_duration |
Alertes Grafana¶
# Alerte Grafana : Falco Critical
apiVersion: 1
groups:
- name: security-runtime
folder: Securite
interval: 1m
rules:
- alert: FalcoCriticalAlert
expr: |
count_over_time({job="falco"} | json | priority = "Critical" [5m]) > 0
for: 0m
labels:
severity: critical
team: security
annotations:
summary: "Alerte Falco critique detectee"
description: "{{ $labels.rule }} sur {{ $labels.source }}"
- alert: GatekeeperViolationsHigh
expr: |
sum(gatekeeper_violations) > 10
for: 5m
labels:
severity: warning
team: security
annotations:
summary: "Nombre eleve de violations OPA/Gatekeeper"
- alert: TrivyCriticalCVE
expr: |
sum(trivy_image_vulnerabilities{severity="Critical"}) > 0
for: 15m
labels:
severity: warning
team: security
annotations:
summary: "CVE critiques detectees dans des images deployees"
Integration avec le CI/CD¶
Trivy dans le pipeline¶
Trivy s'integre dans le pipeline CI/CD comme gate de sécurité avant le déploiement :
# .gitea/workflows/security-scan.yaml
name: Security Scan
on:
push:
branches: [main]
pull_request:
jobs:
trivy-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t ${{ github.repository }}:${{ github.sha }} .
- name: Trivy vulnerability scan
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ github.repository }}:${{ github.sha }}
format: table
exit-code: 1 # Echouer si des CVE critiques
severity: CRITICAL,HIGH
ignore-unfixed: true
- name: Trivy config scan
uses: aquasecurity/trivy-action@master
with:
scan-type: config
scan-ref: ./k8s/
format: table
exit-code: 1
severity: CRITICAL,HIGH
OPA/Conftest pour validation pre-déploiement¶
Avant de soumettre les manifestes au cluster, validez-les localement avec Conftest (OPA en mode CLI) :
# .gitea/workflows/policy-check.yaml
name: Policy Check
on:
pull_request:
paths:
- 'k8s/**'
jobs:
conftest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install conftest
run: |
curl -L -o conftest.tar.gz \
https://github.com/open-policy-agent/conftest/releases/download/v0.52.0/conftest_0.52.0_Linux_x86_64.tar.gz
tar xzf conftest.tar.gz
sudo mv conftest /usr/local/bin/
- name: Validate Kubernetes manifests
run: conftest test k8s/ --policy policy/ --all-namespaces
# policy/security.rego
package main
# Interdire les images sans tag ou avec :latest
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("Image avec tag :latest interdite : %s", [container.image])
}
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
not contains(container.image, ":")
msg := sprintf("Image sans tag interdite : %s", [container.image])
}
# Exiger un securityContext
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
not container.securityContext.runAsNonRoot
msg := sprintf("runAsNonRoot requis pour : %s", [container.name])
}
Integration avec l'IAM¶
RBAC Kubernetes aligne sur Keycloak¶
Les groupes Keycloak sont mappes sur des ClusterRoles Kubernetes pour controler l'accès aux ressources de sécurité :
| Groupe Keycloak | ClusterRole Kubernetes | Accès sécurité |
|---|---|---|
security-admins | security-admin | Lecture/écriture des regles Falco, contraintes OPA, rapports Trivy |
platform-engineers | security-viewer | Lecture des alertes et rapports, pas de modification des regles |
developers | security-none | Aucun accès direct aux composants de sécurité |
# clusterrole-security-admin.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: security-admin
rules:
# Gatekeeper
- apiGroups: ["templates.gatekeeper.sh"]
resources: ["constrainttemplates"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: ["constraints.gatekeeper.sh"]
resources: ["*"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
# Trivy reports
- apiGroups: ["aquasecurity.github.io"]
resources: ["vulnerabilityreports", "configauditreports", "exposedsecretreports"]
verbs: ["get", "list", "watch", "delete"]
# Falco namespace
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
# Restreint au namespace falco-system via RoleBinding
# clusterrole-security-viewer.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: security-viewer
rules:
- apiGroups: ["constraints.gatekeeper.sh"]
resources: ["*"]
verbs: ["get", "list", "watch"]
- apiGroups: ["aquasecurity.github.io"]
resources: ["vulnerabilityreports", "configauditreports"]
verbs: ["get", "list", "watch"]
Accès aux dashboards Grafana¶
Les dashboards de sécurité dans Grafana sont proteges par RBAC :
# Grafana provisioning : permissions du dossier Securite
apiVersion: 1
providers:
- name: security-dashboards
folder: Securite
folderUid: security-folder
permissions:
- role: Admin
permission: Edit
- teamId: security-team # Equipe securite
permission: View
# Pas d'acces pour les autres equipes
Integration avec la politique de classification¶
Regles Falco par niveau de classification¶
Les regles Falco sont differenciees selon le niveau de classification du namespace :
# Regles strictes pour les namespaces Restreint
- rule: Any Process Execution in Restricted Namespace
desc: Detect any new process in a namespace classified as Restricted
condition: >
spawned_process and container and
k8s.ns.name in (vault-system, pki-system, secrets-management)
output: >
Execution de processus dans un namespace Restreint
(namespace=%k8s.ns.name process=%proc.name user=%user.name
container=%container.name image=%container.image.repository)
priority: NOTICE
tags: [classification_restricted]
# Regles standard pour les namespaces Confidentiel
- rule: Shell in Confidential Namespace
desc: Detect shell spawned in a namespace classified as Confidential
condition: >
spawned_process and container and
proc.name in (bash, sh, zsh) and
k8s.ns.name in (production, staging, cicd)
output: >
Shell dans un namespace Confidentiel
(namespace=%k8s.ns.name shell=%proc.name user=%user.name
container=%container.name)
priority: WARNING
tags: [classification_confidential]
Contraintes OPA par classification de namespace¶
# Contrainte OPA : les namespaces Restreint n'acceptent que des images signees
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: restricted-ns-signed-images-only
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces:
- vault-system
- pki-system
parameters:
repos:
- "registry.internal.company.io/signed/"
Classification et sécurité runtime
La politique de classification (voir Classification et zones de confiance) définit les niveaux de protection requis. La sécurité runtime implemente ces niveaux via des regles Falco et des contraintes OPA adaptées à chaque classification. Les namespaces Restreint ont les regles les plus strictes, les namespaces Interne les plus permissives.