Skip to main content

Pregunta 17 | Política de Registro de Auditoría

Usar contexto: kubectl config use-context infra-prod

El Registro de Auditoría ha sido habilitado en el clúster con una Política de Auditoría ubicada en /etc/kubernetes/audit/policy.yaml en cluster2-controlplane1.

Cambia la configuración para que solo se almacene una copia de seguridad de los registros.

Altera la Política de manera que solo almacene registros:

De recursos Secret, nivel Metadata

De userGroups "system:nodes", nivel RequestResponse

Después de alterar la Política asegúrate de vaciar el archivo de registro para que solo contenga entradas según tus cambios, como usando truncate -s 0 /etc/kubernetes/audit/logs/audit.log.

NOTA: Puedes usar jq para renderizar json más legible. cat data.json | jq


Respuesta:

Primero verificamos la configuración del apiserver y cambiamos según lo solicitado:

ssh cluster2-controlplane1

➜ root@cluster2-controlplane1:~# cp /etc/kubernetes/manifests/kube-apiserver.yaml ~/17_kube-apiserver.yaml # copia de seguridad

➜ root@cluster2-controlplane1:~# vim /etc/kubernetes/manifests/kube-apiserver.yaml
# /etc/kubernetes/manifests/kube-apiserver.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
- --audit-policy-file=/etc/kubernetes/audit/policy.yaml
- --audit-log-path=/etc/kubernetes/audit/logs/audit.log
- --audit-log-maxsize=5
- --audit-log-maxbackup=1 # CAMBIAR
- --advertise-address=192.168.100.21
- --allow-privileged=true
...

NOTA: Deberías saber cómo habilitar el Registro de Auditoría completamente por ti mismo como se describe en la documentación. Siéntete libre de probarlo en otro clúster en este entorno.

Ahora miramos la Política existente:

➜ root@cluster2-controlplane1:~# vim /etc/kubernetes/audit/policy.yaml
# /etc/kubernetes/audit/policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

Podemos ver que esta Política simple registra todo en nivel Metadata. Así que la cambiamos según los requisitos:

# /etc/kubernetes/audit/policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:

# registrar auditorías de recursos Secret, nivel Metadata
- level: Metadata
resources:
- group: ""
resources: ["secrets"]

# registrar auditorías relacionadas con nodos, nivel RequestResponse
- level: RequestResponse
userGroups: ["system:nodes"]

# para todo lo demás no registrar nada
- level: None

Después de guardar los cambios tenemos que reiniciar el apiserver:

➜ root@cluster2-controlplane1:~# cd /etc/kubernetes/manifests/

➜ root@cluster2-controlplane1:/etc/kubernetes/manifests# mv kube-apiserver.yaml ..

➜ root@cluster2-controlplane1:/etc/kubernetes/manifests# watch crictl ps # esperar a que se detenga apiserver

➜ root@cluster2-controlplane1:/etc/kubernetes/manifests# truncate -s 0 /etc/kubernetes/audit/logs/audit.log

➜ root@cluster2-controlplane1:/etc/kubernetes/manifests# mv ../kube-apiserver.yaml .

Una vez que el apiserver esté ejecutándose nuevamente podemos verificar los nuevos registros y desplazarnos por algunas entradas:

cat audit.log | tail | jq
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "e598dc9e-fc8b-4213-aee3-0719499ab1bd",
"stage": "RequestReceived",
"requestURI": "...",
"verb": "watch",
"user": {
"username": "system:serviceaccount:gatekeeper-system:gatekeeper-admin",
"uid": "79870838-75a8-479b-ad42-4b7b75bd17a3",
"groups": [
"system:serviceaccounts",
"system:serviceaccounts:gatekeeper-system",
"system:authenticated"
]
},
"sourceIPs": [
"192.168.102.21"
],
"userAgent": "manager/v0.0.0 (linux/amd64) kubernetes/$Format",
"objectRef": {
"resource": "secrets",
"apiVersion": "v1"
},
"requestReceivedTimestamp": "2020-09-27T20:01:36.238911Z",
"stageTimestamp": "2020-09-27T20:01:36.238911Z",
"annotations": {
"authentication.k8s.io/legacy-token": "..."
}
}
# Arriba registramos una acción watch por OPA Gatekeeper para Secrets, nivel Metadata.

{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"auditID": "c90e53ed-b0cf-4cc4-889a-f1204dd39267",
"stage": "ResponseComplete",
"requestURI": "...",
"verb": "list",
"user": {
"username": "system:node:cluster2-controlplane1",
"groups": [
"system:nodes",
"system:authenticated"
]
},
"sourceIPs": [
"192.168.100.21"
],
"userAgent": "kubelet/v1.19.1 (linux/amd64) kubernetes/206bcad",
"objectRef": {
"resource": "configmaps",
"namespace": "kube-system",
"name": "kube-proxy",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"responseObject": {
"kind": "ConfigMapList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/namespaces/kube-system/configmaps",
"resourceVersion": "83409"
},
"items": [
{
"metadata": {
"name": "kube-proxy",
"namespace": "kube-system",
"selfLink": "/api/v1/namespaces/kube-system/configmaps/kube-proxy",
"uid": "0f1c3950-430a-4543-83e4-3f9c87a478b8",
"resourceVersion": "232",
"creationTimestamp": "2020-09-26T20:59:50Z",
"labels": {
"app": "kube-proxy"
},
"annotations": {
"kubeadm.kubernetes.io/component-config.hash": "..."
},
"managedFields": [
{
...
}
]
},
...
}
]
},
"requestReceivedTimestamp": "2020-09-27T20:01:36.223781Z",
"stageTimestamp": "2020-09-27T20:01:36.225470Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": ""
}
}

Y en el de arriba registramos una acción list por system:nodes para un ConfigMaps, nivel RequestResponse.

Porque todas las entradas JSON están escritas en una sola línea en el archivo también podríamos ejecutar algunas verificaciones simples en nuestra Política:

# muestra entradas de Secret
cat audit.log | grep '"resource":"secrets"' | wc -l

# confirma que las entradas de Secret son solo de nivel Metadata
cat audit.log | grep '"resource":"secrets"' | grep -v '"level":"Metadata"' | wc -l

# muestra entradas de nivel RequestResponse
cat audit.log | grep -v '"level":"RequestResponse"' | wc -l

# muestra que las entradas de nivel RequestResponse son solo para system:nodes
cat audit.log | grep '"level":"RequestResponse"' | grep -v "system:nodes" | wc -l