.png)
Runtime Enforcement
Até agora, na jornada do eBPF aplicada às cargas de trabalho InterSystems, temos sido praticamente somente leitura quando se trata de chamadas de sistema, execução binária e monitoramento de arquivos.
Mas, assim como as políticas de segurança de rede que estavam em jogo com o último post que impõem conectividade, e se pudermos impor chamadas de sistema, acesso a arquivos e processos da mesma maneira em todo um cluster?
Apresentando Tetragon, uma ferramenta flexível de observabilidade e imposição de segurança sensível ao Kubernetes que aplica política e filtragem diretamente com eBPF, permitindo uma redução de sobrecarga de observação, rastreamento de qualquer processo e imposição em tempo real de políticas.
Imposição quando seu aplicativo não pode fornecê-la.
Onde ele Roda
Observabilidade e Imposição em Todo o Cluster
.png)
De pé e rodando
Os passos obrigatórios parra levantar e rodar se você optar por isso, realizados no estilo de um Isovalent Lab.
Cluster
Cluster Kind, 3 nós de trabalho, sem um CNI padrão.
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
networking:
disableDefaultCNI: true
EOF
Cilium
Instale Cilium, se não for outra coisa, um CNI.
cilium install version 1.16.2
Tetragon
Aqui instalamos a estrela do nosso show, Tetragon, como um conjunto daemon.
EXTRA_HELM_FLAGS=(--set tetragon.hostProcPath=/proc)
helm repo add cilium https://helm.cilium.io
helm repo update
helm install tetragon ${EXTRA_HELM_FLAGS[@]} cilium/tetragon -n kube-system
kubectl rollout status -n kube-system ds/tetragon -w
Cargas de trabalho IRIS
Pod IRIS rápido, não privilegiado, mas facilmente modificado para ser. Este é o pod que executaremos coisas para explicar algo do comportamento da política de rastreamento.
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: iris-nopriv
labels:
app: iris
spec:
imagePullSecrets:
- name: isc-pull
containers:
- name: iris-priv
image: containers.intersystems.com/intersystems/iris-community:2024.2
ports:
- containerPort: 80
EOF
Políticas de rastreamento
Políticas de Rastreamento são recursos personalizados que facilitam a configuração de filtros em tempo real para eventos do kernel. Uma Política de Rastreamento combina e filtra chamadas de sistema para observabilidade e também aciona uma ação sobre essas correspondências.
Logo de cara, porém, process_exec e process_exit sem precisar carregar nenhuma política de rastreamento.
Em um terminal, execute seu ZF, no outro, examine os eventos Tetragon:
kubectl exec -ti -n kube-system tetragon-sw9k4 -c tetragon -- tetra getevents -o compact --pods iris-nopriv
Se dermos uma olhada na execução do processo em Tetragon para a seguinte chamada que imprime o diretório de trabalho atual.

Isso pode ser óbvio para você, mas executar ZF com o argumento "/SHELL" invoca o bash e, em seguida, chama o comando, enquanto quando ele é omitido, ele chama diretamente o binário. Agora usamos a saída compacta acima, mas se você observar os eventos no formato json, pode ver como eles são chamados de forma diferente, com a opção /shell tendo um processo pai.
ie:
"cwd": "/usr/irissys/bin",
"binary": "/usr/irissys/bin/irisdb",
"arguments": "-w /home/irisowner -s /usr/irissys/mgr",
"flags": "execve",
{
"process_exec": {
"process": {
"exec_id": "a2luZC13b3JrZXIyOjI3OTI5NDExNjY1NzMzMzozMDA4MzAw",
"pid": 3008300,
"uid": 51773,
"cwd": "/usr/irissys/mgr/user",
"binary": "/usr/bin/pwd",
"flags": "execve clone",
"start_time": "2024-10-01T02:39:42.761250745Z",
"auid": 4294967295,
"pod": {
"namespace": "default",
"name": "iris-priv",
"container": {
"id": "containerd://5f5df2f9ff01fc737c88f83254ca37c0c214ff7a648c9eabd5f01edcc0804e56",
"name": "iris-priv",
"image": {
"id": "containers.intersystems.com/intersystems/iris-community@sha256:493c073cc968f1053511e6cf56301767ab304f21a60afdf65543e56ef1217cb4",
"name": "containers.intersystems.com/intersystems/iris-community:2024.2"
},
"start_time": "2024-10-01T02:12:16Z",
"pid": 68242
},
"pod_labels": {
"app": "iris"
},
"workload": "iris-priv",
"workload_kind": "Pod"
},
"docker": "5f5df2f9ff01fc737c88f83254ca37c",
"parent_exec_id": "a2luZC13b3JrZXIyOjI3NzgzMjYyNzQ1NzA1ODoyOTc4MzQ0",
"tid": 3008300
},
"parent": {
"exec_id": "a2luZC13b3JrZXIyOjI3NzgzMjYyNzQ1NzA1ODoyOTc4MzQ0",
"pid": 2978344,
"uid": 51773,
"cwd": "/usr/irissys/bin",
"binary": "/usr/irissys/bin/irisdb",
"arguments": "-w /home/irisowner -s /usr/irissys/mgr",
"flags": "execve",
"start_time": "2024-10-01T02:15:21.272075833Z",
"auid": 4294967295,
"pod": {
"namespace": "default",
"name": "iris-priv",
"container": {
"id": "containerd://5f5df2f9ff01fc737c88f83254ca37c0c214ff7a648c9eabd5f01edcc0804e56",
"name": "iris-priv",
"image": {
"id": "containers.intersystems.com/intersystems/iris-community@sha256:493c073cc968f1053511e6cf56301767ab304f21a60afdf65543e56ef1217cb4",
"name": "containers.intersystems.com/intersystems/iris-community:2024.2"
},
"start_time": "2024-10-01T02:12:16Z",
"pid": 67506
},
"pod_labels": {
"app": "iris"
},
"workload": "iris-priv",
"workload_kind": "Pod"
},
"docker": "5f5df2f9ff01fc737c88f83254ca37c",
"parent_exec_id": "a2luZC13b3JrZXIyOjI3NzgzMjYyNjUzMzA5NzoyOTc4MzQ0",
"tid": 2978344
}
},
"node_name": "kind-worker2",
"time": "2024-10-01T02:39:42.761250372Z"
}
{
"process_exec": {
"process": {
"exec_id": "a2luZC13b3JrZXIyOjI3OTAxMjk3OTY2NTcxMTozMDA1Mzcy",
"pid": 3005372,
"uid": 51773,
"cwd": "/usr/irissys/mgr/user",
"binary": "/bin/bash",
"arguments": "-p -c pwd",
"flags": "execve clone",
"start_time": "2024-10-01T02:35:01.624258293Z",
"auid": 4294967295,
"pod": {
"namespace": "default",
"name": "iris-priv",
"container": {
"id": "containerd://5f5df2f9ff01fc737c88f83254ca37c0c214ff7a648c9eabd5f01edcc0804e56",
"name": "iris-priv",
"image": {
"id": "containers.intersystems.com/intersystems/iris-community@sha256:493c073cc968f1053511e6cf56301767ab304f21a60afdf65543e56ef1217cb4",
"name": "containers.intersystems.com/intersystems/iris-community:2024.2"
},
"start_time": "2024-10-01T02:12:16Z",
"pid": 68097
},
"pod_labels": {
"app": "iris"
},
"workload": "iris-priv",
"workload_kind": "Pod"
},
"docker": "5f5df2f9ff01fc737c88f83254ca37c",
"parent_exec_id": "a2luZC13b3JrZXIyOjI3NzgzMjYyNzQ1NzA1ODoyOTc4MzQ0",
"tid": 3005372
},
"parent": {
"exec_id": "a2luZC13b3JrZXIyOjI3NzgzMjYyNzQ1NzA1ODoyOTc4MzQ0",
"pid": 2978344,
"uid": 51773,
"cwd": "/usr/irissys/bin",
"binary": "/usr/irissys/bin/irisdb",
"arguments": "-w /home/irisowner -s /usr/irissys/mgr",
"flags": "execve",
"start_time": "2024-10-01T02:15:21.272075833Z",
"auid": 4294967295,
"pod": {
"namespace": "default",
"name": "iris-priv",
"container": {
"id": "containerd://5f5df2f9ff01fc737c88f83254ca37c0c214ff7a648c9eabd5f01edcc0804e56",
"name": "iris-priv",
"image": {
"id": "containers.intersystems.com/intersystems/iris-community@sha256:493c073cc968f1053511e6cf56301767ab304f21a60afdf65543e56ef1217cb4",
"name": "containers.intersystems.com/intersystems/iris-community:2024.2"
},
"start_time": "2024-10-01T02:12:16Z",
"pid": 67506
},
"pod_labels": {
"app": "iris"
},
"workload": "iris-priv",
"workload_kind": "Pod"
},
"docker": "5f5df2f9ff01fc737c88f83254ca37c",
"parent_exec_id": "a2luZC13b3JrZXIyOjI3NzgzMjYyNjUzMzA5NzoyOTc4MzQ0",
"tid": 2978344
}
},
"node_name": "kind-worker2",
"time": "2024-10-01T02:35:01.624257883Z"
}
Os eventos JSON são enviados para o log do Tetragon e podem ser enviados para um sistema SIEM ou observabilidade para insights acionáveis
Imposição em Tempo de Execução
Isso pode ser um pouco falto de imaginação para um caso de uso, mas e se quiséssemos proibir qualquer pessoa de chamar e ler o arquivo de licença?
Para isso, precisamos aplicar uma Política de Rastreamento que impõe um matchAction. Essas políticas são um pouco envolvidas, mas esta é a maneira longa de dizer "Ei, se você executar cat /usr/irissys/mgr/iris.key, vou matá-lo (SIGKILL você).
kubectl apply -f - <<EOF
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: "iris-read-file-sigkill"
spec:
kprobes:
- call: "fd_install"
syscall: false
return: false
args:
- index: 0
type: int
- index: 1
type: "file"
selectors:
- matchPIDs:
- operator: NotIn
followForks: true
isNamespacePID: true
values:
- 1
matchArgs:
- index: 1
operator: "Prefix"
values:
- "/usr/irissys/secrets/"
- "/usr/irissys/mgr/iris.key"
matchActions:
- action: FollowFD
argFd: 0
argName: 1
- call: "__x64_sys_close"
syscall: true
args:
- index: 0
type: "int"
selectors:
- matchActions:
- action: UnfollowFD
argFd: 0
argName: 0
- call: "__x64_sys_read"
syscall: true
args:
- index: 0
type: "fd"
- index: 1
type: "char_buf"
returnCopy: true
- index: 2
type: "size_t"
selectors:
- matchActions:
- action: Sigkill
EOF
Uma vez implantado, você deve vê-lo carregado como um recurso TracingPolicy:

Vamos vê-lo impor a política:
.png)
O -1 nos conta que algo está errado, e o comando não teve sucesso.
Mas desconhecido pelo colega brogrammer, nós o bloqueamos administrativamente e enviamos um SIGKILL para o processo!
.png)
Essa será uma longa chamada para o WRC para o usuário final desavisado (ou especialista do WRC).
Experimentos
Eu encontrei alguns que eram interessantes nos centenas que eu roubei, apliquei e brinquei, notável foi um que deu as chamadas de sistema por binário. Se você realmente quisesse ser nerd, você poderia literalmente bloquear por syscall.

Outro que foi fascinante foi a Política de Rastreamento de acesso a arquivos, que mostrava todos os processos acessando todos os arquivos.

Essas e outros políticas podem ser encontrados no repositório de examplos @ tetragon:
-
Chamadas de sistema
-
Atributos de processo
-
Argumentos de linha de comando
-
Atividade de rede
-
Operações do sistema de arquivos