# One CiliumNetworkPolicy, applied to all three clients alike (the Nitro sandbox pod and the
# ordinary neighbor and control pods), proving L3/L4, L7 HTTP and FQDN enforcement crosses the
# Nitro guest boundary exactly as it does for an ordinary container.
#
# It selects every pod labelled role=client and turns on egress enforcement for them. With
# egress enforcement on, a client may make ONLY the connections an egress rule below allows,
# and nothing else is reachable. Cilium enforces this at the pod's network interface on the
# Ubuntu host, so it applies to the Nitro pod's guest VM exactly as to an ordinary container.
#
# The rules, with their positive and negative controls (test.sh proves each both ways):
#
#   L3/L4  -- ALLOW: reach the "server" pods on TCP 8080. DENY (negative control): the "other"
#             pod, an identical server the selector does not name, is DROPPED. The unselected
#             "server" pod can still reach "other", which proves the deny is the policy and not
#             an unavailable destination.
#
#   L7     -- ALLOW: GET "/" on "api":8080. DENY (negative control): GET "/admin" is rejected
#             by the node-local Envoy proxy with an HTTP 403 (verdict Denied), not dropped.
#             "api" is a SEPARATE toEndpoints target from "server": an L7 HTTP rule on the SAME
#             toEndpoints/port as an existing L4-only rule would widen that rule to allow-all
#             (Cilium only drops the L7 portion when it duplicates a plain L4 rule for the
#             identical selector and port), so the L7 check needs its own target or the deny
#             would never show. test.sh reads the Request verdict from the proxy, not just the
#             client's HTTP status, so an app-issued 403 cannot masquerade as a policy deny.
#
#   FQDN   -- ALLOW: reach checkip.amazonaws.com on TCP 80, wherever it currently resolves.
#             DENY (negative control): a resolved name no rule names (example.net) is DROPPED
#             while it still RESOLVES, which proves the deny is the egress policy and not a
#             broken lookup. The unselected "server" pod still reaches example.net, which
#             proves it is not the NAT gateway or the name being down. test.sh reads the Cilium
#             agent's own fqdn cache as evidence the DNS proxy saw the allowed lookup.
#
#   DNS    -- reach CoreDNS (kube-dns) on 53. Cilium's DNS proxy only sees a lookup when a
#             toEndpoints rule with an L7 DNS rule covers the client's DNS traffic, so the
#             kube-dns rule carries rules.dns with matchPattern "*": every lookup is visible to
#             the proxy (and so can seed the toFQDNs allowlist), while the policy still
#             constrains where the answer may be used.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: clients-egress
  namespace: cilium-ubuntu-demo
spec:
  endpointSelector:
    matchLabels:
      role: client
  egress:
    - toEndpoints:
        - matchLabels:
            app: server
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
    - toEndpoints:
        - matchLabels:
            app: api
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
          rules:
            http:
              - method: "GET"
                path: "/"
    - toFQDNs:
        - matchName: "checkip.amazonaws.com"
      toPorts:
        - ports:
            - port: "80"
              protocol: TCP
    - toEndpoints:
        - matchLabels:
            k8s:io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: ANY
          rules:
            dns:
              - matchPattern: "*"
