Policy as Code: Automatizzare le Regole di Sicurezza
Policy as Code (PaC) e la pratica di definire le regole di sicurezza e compliance come codice versionabile, testabile e applicabile automaticamente. Invece di documentare le policy in PDF che nessuno legge, PaC le trasforma in codice eseguibile che viene applicato automaticamente nella pipeline e nell'infrastruttura.
Con PaC, le regole come "ogni container deve girare come non-root" o "i bucket S3 non devono essere pubblici" diventano controlli automatici che bloccano i deploy non conformi. Questo elimina l'errore umano e garantisce conformità continua.
Cosa Imparerai
- I principi di Policy as Code e i vantaggi rispetto alle policy tradizionali
- OPA (Open Policy Agent) e il linguaggio Rego
- Kyverno per Kubernetes policy enforcement
- Sentinel di HashiCorp per Terraform
- Conftest per validare configurazioni
- Testing e deployment delle policy
OPA: Open Policy Agent
OPA (Open Policy Agent) e il motore di policy più diffuso nell'ecosistema cloud-native. Sviluppato dalla CNCF, OPA utilizza il linguaggio dichiarativo Rego per definire policy che possono essere applicate a qualsiasi tipo di dato strutturato: richieste API, configurazioni Kubernetes, configurazioni Terraform, pipeline CI/CD.
Scrivere Policy in Rego
# policy/kubernetes/pod-security.rego
package kubernetes.admission
# Nega i container che girano come root
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.securityContext.runAsNonRoot
msg := sprintf(
"Container '%s' deve avere runAsNonRoot: true",
[container.name]
)
}
# Nega immagini con tag :latest
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf(
"Container '%s' usa :latest. Specificare un tag esplicito.",
[container.name]
)
}
# Richiedi resource limits
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.resources.limits
msg := sprintf(
"Container '%s' deve definire resource limits (CPU e memory)",
[container.name]
)
}
Testare le Policy OPA
# policy/kubernetes/pod-security_test.rego
package kubernetes.admission
test_deny_root_container {
count(deny) > 0 with input as {
"request": {
"kind": {"kind": "Pod"},
"object": {
"spec": {
"containers": [{
"name": "app",
"image": "myapp:v1",
"securityContext": {}
}]
}
}
}
}
}
test_allow_nonroot_container {
count(deny) == 0 with input as {
"request": {
"kind": {"kind": "Pod"},
"object": {
"spec": {
"containers": [{
"name": "app",
"image": "myapp:v1",
"securityContext": {"runAsNonRoot": true},
"resources": {"limits": {"cpu": "500m", "memory": "256Mi"}}
}]
}
}
}
}
}
Kyverno: Policy Nativo Kubernetes
Kyverno e un policy engine progettato specificamente per Kubernetes. A differenza di OPA che usa Rego, Kyverno definisce le policy come risorse Kubernetes native in YAML, rendendo l'adozione più semplice per i team che hanno già familiarita con Kubernetes.
# kyverno-policies/require-nonroot.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-run-as-nonroot
annotations:
policies.kyverno.io/title: Require runAsNonRoot
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: high
spec:
validationFailureAction: Enforce
background: true
rules:
- name: check-containers
match:
any:
- resources:
kinds:
- Pod
validate:
message: >-
Container deve girare come non-root.
Impostare securityContext.runAsNonRoot a true.
pattern:
spec:
containers:
- securityContext:
runAsNonRoot: true
---
# Richiedi registry approvati
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-image-registries
spec:
validationFailureAction: Enforce
rules:
- name: validate-registries
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Immagini devono provenire da registry approvati."
pattern:
spec:
containers:
- image: "ghcr.io/myorg/* | registry.internal.company.com/*"
Conftest: Validare Configurazioni
Conftest utilizza OPA/Rego per validare qualsiasi tipo di file di configurazione: Dockerfile, Kubernetes manifest, Terraform files, pipeline CI/CD. E particolarmente utile come step nella pipeline CI per validare le configurazioni prima del deploy.
# Installare Conftest
brew install conftest
# Validare un Dockerfile
conftest test Dockerfile --policy policy/docker/
# Validare manifest Kubernetes
conftest test k8s/ --policy policy/kubernetes/
# Validare con output strutturato
conftest test --output json terraform/ --policy policy/terraform/
# policy/docker/dockerfile.rego
package docker
# Nega Dockerfile senza USER
deny[msg] {
input[i].Cmd == "from"
not any_user_after(i)
msg := "Dockerfile deve includere l'istruzione USER per evitare l'esecuzione come root"
}
any_user_after(from_idx) {
input[j].Cmd == "user"
j > from_idx
}
# Nega immagini base :latest
deny[msg] {
input[i].Cmd == "from"
val := input[i].Value[0]
endswith(val, ":latest")
msg := sprintf("Evitare :latest nell'istruzione FROM. Usare un tag specifico: %s", [val])
}
Sentinel: Policy per Terraform
Sentinel e il framework di policy di HashiCorp, integrato nativamente in Terraform Cloud e Enterprise. Permette di definire policy che validano i piani Terraform prima dell'applicazione, prevenendo la creazione di risorse non conformi.
Confronto Policy Engines
| Caratteristica | OPA/Rego | Kyverno | Sentinel |
|---|---|---|---|
| Ambito | Universale | Kubernetes | HashiCorp ecosystem |
| Linguaggio | Rego (dichiarativo) | YAML nativo K8s | Sentinel (imperativo) |
| Curva apprendimento | Media-alta | Bassa | Media |
| Licenza | Open source (Apache 2.0) | Open source (Apache 2.0) | Commerciale (Terraform Cloud) |
Policy nella Pipeline CI/CD
# .github/workflows/policy-check.yml
name: Policy Validation
on:
pull_request:
jobs:
validate-policies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Conftest
run: |
wget -q https://github.com/open-policy-agent/conftest/releases/download/v0.46.0/conftest_0.46.0_Linux_x86_64.tar.gz
tar xzf conftest_0.46.0_Linux_x86_64.tar.gz
sudo mv conftest /usr/local/bin/
- name: Test OPA policies
run: opa test policy/ -v
- name: Validate Dockerfiles
run: conftest test Dockerfile --policy policy/docker/
- name: Validate K8s manifests
run: conftest test k8s/ --policy policy/kubernetes/
- name: Validate Terraform
run: conftest test terraform/ --policy policy/terraform/
Best Practice per Policy as Code
- Versionare le policy: trattare le policy come codice, con review, test e release
- Testare le policy: scrivere unit test per ogni policy per evitare regressioni
- Gradualità: iniziare in modalità audit (warning) prima di passare a enforce (bloccante)
- Documentare: ogni policy deve avere una descrizione chiara del perchè esiste
- Feedback rapido: integrare la validazione nella PR per feedback immediato
- Eccezioni gestite: prevedere un processo per le eccezioni temporanee con scadenza
Conclusioni
Policy as Code trasforma le regole di sicurezza da documenti statici a codice eseguibile e automatizzato. Con OPA, Kyverno e Conftest, le organizzazioni possono garantire conformità continua senza rallentare il processo di sviluppo.
Nel prossimo articolo esploreremo CI/CD Security Pipeline, analizzando come proteggere il processo di build e deploy stesso: pipeline hardening, OIDC, least privilege e signed commits.







