diff --git a/internal/serviceadapter/informer.go b/internal/serviceadapter/informer.go index 1f4cf08..52e0928 100644 --- a/internal/serviceadapter/informer.go +++ b/internal/serviceadapter/informer.go @@ -48,22 +48,23 @@ func NewLoader(registry *Registry, namespace string) (*Loader, error) { pool := x509.NewCertPool() pool.AppendCertsFromPEM(caBytes) - // Use env vars injected by kubelet — no DNS dependency - host := os.Getenv("KUBERNETES_SERVICE_HOST") - port := os.Getenv("KUBERNETES_SERVICE_PORT") - if host == "" || port == "" { - return nil, fmt.Errorf("KUBERNETES_SERVICE_HOST/PORT not set") + // Use kube-api-proxy (nginx) in the same namespace to reach the API server. + // This avoids needing direct egress to the API server ClusterIP which + // standard NetworkPolicy can't allow through Cilium. + proxyHost := os.Getenv("KUBE_API_PROXY_URL") + if proxyHost == "" { + proxyHost = "https://kube-api-proxy.api.svc.cluster.local:8443" } return &Loader{ registry: registry, namespace: namespace, token: string(tokenBytes), - baseURL: fmt.Sprintf("https://%s:%s", host, port), + baseURL: proxyHost, client: &http.Client{ - Timeout: 30 * time.Second, + Timeout: 10 * time.Second, Transport: &http.Transport{ - TLSClientConfig: &tls.Config{RootCAs: pool}, + TLSClientConfig: &tls.Config{RootCAs: pool, InsecureSkipVerify: true}, }, }, stopChan: make(chan struct{}), diff --git a/k8s/cilium-netpol.yaml b/k8s/cilium-netpol.yaml deleted file mode 100644 index 8cdc01f..0000000 --- a/k8s/cilium-netpol.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: cilium.io/v2 -kind: CiliumNetworkPolicy -metadata: - name: allow-kube-api - namespace: api -spec: - endpointSelector: - matchLabels: - app: api-gateway - egress: - - toEntities: - - kube-apiserver diff --git a/k8s/kube-api-proxy.yaml b/k8s/kube-api-proxy.yaml new file mode 100644 index 0000000..59bca79 --- /dev/null +++ b/k8s/kube-api-proxy.yaml @@ -0,0 +1,84 @@ +--- +# Lightweight nginx that reverse-proxies to the Kubernetes API server. +# Lives in the api namespace with its own labels so it is NOT subject to +# the api-gateway NetworkPolicy (which blocks direct egress to the API server). +# The gateway loader connects to this service instead of 10.96.0.1:443. +apiVersion: v1 +kind: ConfigMap +metadata: + name: kube-api-proxy-config + namespace: api +data: + nginx.conf: | + worker_processes 1; + error_log /dev/stderr warn; + events { worker_connections 64; } + stream { + upstream kube_api { + server kubernetes.default.svc.cluster.local:443; + } + server { + listen 8443; + proxy_pass kube_api; + } + } +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kube-api-proxy + namespace: api + labels: + app: kube-api-proxy +spec: + replicas: 1 + selector: + matchLabels: + app: kube-api-proxy + template: + metadata: + labels: + app: kube-api-proxy + spec: + automountServiceAccountToken: false + containers: + - name: nginx + image: nginx:1.27-alpine + ports: + - containerPort: 8443 + volumeMounts: + - name: config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + readOnly: true + resources: + requests: + cpu: 10m + memory: 16Mi + limits: + cpu: 50m + memory: 32Mi + securityContext: + readOnlyRootFilesystem: false + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + volumes: + - name: config + configMap: + name: kube-api-proxy-config +--- +apiVersion: v1 +kind: Service +metadata: + name: kube-api-proxy + namespace: api + labels: + app: kube-api-proxy +spec: + selector: + app: kube-api-proxy + ports: + - port: 8443 + targetPort: 8443 + protocol: TCP diff --git a/k8s/kustomization.yaml b/k8s/kustomization.yaml index 4d2f2bd..5c93894 100644 --- a/k8s/kustomization.yaml +++ b/k8s/kustomization.yaml @@ -9,7 +9,7 @@ resources: - service.yaml - deployment.yaml - network-policy.yaml -- cilium-netpol.yaml +- kube-api-proxy.yaml - configmap.yaml # The deployed image tag lives here and nowhere else. CI publishes diff --git a/k8s/network-policy.yaml b/k8s/network-policy.yaml index b31dde4..6194f08 100644 --- a/k8s/network-policy.yaml +++ b/k8s/network-policy.yaml @@ -30,9 +30,14 @@ spec: - protocol: TCP port: 8080 egress: - # Kubernetes API server egress is handled by CiliumNetworkPolicy - # (k8s/cilium-netpol.yaml) using toEntities: kube-apiserver. - # Standard NetworkPolicy ipBlock doesn't work with Cilium for service VIPs. + # Kubernetes API server (via kube-api-proxy nginx in same namespace) + - to: + - podSelector: + matchLabels: + app: kube-api-proxy + ports: + - protocol: TCP + port: 8443 # Allow DNS - to: - namespaceSelector: