Skip to content

runlore runs without a CiliumNetworkPolicy (zero-trust gap) #1589

Description

@Smana

What

The runlore workload has no CiliumNetworkPolicy at all:

$ kubectl get cnp -n runlore
No resources found in runlore namespace.

Every other pod-running workload on the platform ships one. The constitution mandates default-deny + explicit allow for anything that runs a pod, so this is a straight compliance gap: runlore's egress is currently unrestricted.

How it surfaced

While chasing a suspected AWS authorization problem with runlore — there wasn't one. The EPI is Ready, the PodIdentityAssociation is Ready, the IAM policy is attached and correctly scoped read-only (ec2:Describe*, eks:Describe*, autoscaling:Describe*, cloudtrail:LookupEvents), and there are no AccessDenied errors in its logs.

The irony is worth writing down: runlore's AWS access works because nothing is restricting its egress. The moment a policy is added it will break unless the rules below are right — so this needs writing carefully, not copy-pasting.

What the policy has to allow

Egress, at minimum:

  • kube-dns — and the L7 DNS rule (toPorts.rules.dns.matchPattern: "*") is mandatory. Without it Cilium proxies the query but never sees the response IPs, so any toFQDNs allowlist has no IPs to match: DNS keeps working while every follow-up TCP connection is silently dropped (trap refacto: split network and eks tofu states #1 in .claude/rules/cilium-network-policies.md).
  • EKS Pod Identity agent at 169.254.170.23:80 — the one that will bite. The agent runs on the node's host network, so Cilium classifies the destination as the host entity: toCIDR: 169.254.170.23/32 alone silently fails, and toEntities: world does not cover link-local. It needs toEntities: ["host"] scoped to TCP 80 (trap chore(terraform): use the subnet router module v1.0.3 #3). Symptom if wrong: Connect timeout on endpoint URL: 'http://169.254.170.23/v1/credentials' — i.e. precisely the "runlore isn't authorized in AWS" failure this issue was mistaken for.
  • Hubble Relay (kube-system) — runlore dials it for network flows (chore(deps): update helm release prometheus-operator-crds to v13.0.1 #321 pinned its TLS floor to 1.2).
  • Kubernetes API — its read-only cluster tooling.
  • world:443 — LLM provider, Slack, GitHub (the KB repo). toFQDNs is a maintenance chase here because matchPattern: "*" does not span dots (trap feat(tofu): use the tailscale provider #2), so scope this deliberately rather than by reflex.

Ingress: the Cilium Gateway data-plane pods terminating the Tailscale-fronted HTTPRoute are the ingress entity, not a pod selector.

Acceptance

  • CiliumNetworkPolicy in observability/base/runlore/, default-deny + explicit allow
  • After it applies, runlore still reaches AWS (pod identity), Hubble, the API server, the LLM and Slack — verified with hubble observe --pod runlore/runlore-0 --verdict DROPPED, not by "the Kustomization reconciled"
  • An investigation runs end to end with the policy in place

Found during a platform validation session on feat/flux-schema-validation.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions