-
Notifications
You must be signed in to change notification settings - Fork 16
HYPERFLEET-1483 - feat: Network policies to enforce access to API via Envoy proxy #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -84,13 +84,35 @@ get-credentials: check-terraform ## Configure kubectl credentials from Terraform | |
|
|
||
|
|
||
| # ==== Kind Targets ==== | ||
| KIND_CONFIG ?= scripts/kind-config.yaml | ||
|
|
||
| # kind's default CNI (kindnet) has no NetworkPolicy enforcement, so it's | ||
| # disabled (see scripts/kind-config.yaml) and install-kind-cilium installs | ||
| # Cilium as the sole CNI, providing both pod networking and policy enforcement. | ||
| # GKE gets equivalent enforcement via Dataplane V2 (see terraform/modules/cluster/gke), | ||
| # though its managed Cilium build may differ in version/config from this pinned chart. | ||
| CILIUM_VERSION ?= 1.20.1 | ||
| CILIUM_NAMESPACE ?= kube-system | ||
|
|
||
| .PHONY: create-kind-cluster | ||
| create-kind-cluster: check-kind ## Create a new kind cluster or export kubeconfig if exists | ||
| @test -n "$(KIND_CLUSTER_NAME)" || { echo "ERROR: KIND_CLUSTER_NAME is empty. HELMFILE_ENV=$(HELMFILE_ENV) does not include env.kind (only HELMFILE_ENV values without 'gcp' do) - run with HELMFILE_ENV=kind or e2e-kind."; exit 1; } | ||
| @if kind get clusters 2>/dev/null | grep -q "^$(KIND_CLUSTER_NAME)$$"; then \ | ||
| echo "kind cluster '$(KIND_CLUSTER_NAME)' already exists ..."; \ | ||
| _kindnet_check_kubeconfig=$$(mktemp); \ | ||
| kind get kubeconfig --name $(KIND_CLUSTER_NAME) > $$_kindnet_check_kubeconfig; \ | ||
| _has_kindnet=0; \ | ||
| kubectl --kubeconfig $$_kindnet_check_kubeconfig get daemonset -n kube-system kindnet >/dev/null 2>&1 && _has_kindnet=1; \ | ||
| rm -f $$_kindnet_check_kubeconfig; \ | ||
| if [ "$$_has_kindnet" = "1" ]; then \ | ||
| echo "ERROR: existing kind cluster '$(KIND_CLUSTER_NAME)' still runs the default CNI (kindnet)."; \ | ||
| echo "It predates disableDefaultCNI, so Cilium NetworkPolicy enforcement will not be effective."; \ | ||
| echo "Delete and recreate it: make delete-kind-cluster KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) && make create-kind-cluster KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME)"; \ | ||
| exit 1; \ | ||
| fi; \ | ||
| else \ | ||
| echo "Creating new kind cluster '$(KIND_CLUSTER_NAME)'..."; \ | ||
| kind create cluster --name $(KIND_CLUSTER_NAME); \ | ||
| kind create cluster --name $(KIND_CLUSTER_NAME) --config $(KIND_CONFIG); \ | ||
|
coderabbitai[bot] marked this conversation as resolved.
Comment on lines
+102
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Validate and safely expand Kind inputs. Line 103 and Line 115 expand Validate Proposed fix create-kind-cluster: check-kind ## Create a new kind cluster or export kubeconfig if exists
+ $(call check-dns-label,KIND_CLUSTER_NAME)
`@test` -n "$(KIND_CLUSTER_NAME)" || { echo "ERROR: KIND_CLUSTER_NAME is empty. HELMFILE_ENV=$(HELMFILE_ENV) does not include env.kind (only HELMFILE_ENV values without 'gcp' do) - run with HELMFILE_ENV=kind or e2e-kind."; exit 1; }
- `@if` kind get clusters 2>/dev/null | grep -q "^$(KIND_CLUSTER_NAME)$$"; then \
+ `@if` kind get clusters 2>/dev/null | grep -Fxq -- "$$KIND_CLUSTER_NAME"; then \
echo "kind cluster '$(KIND_CLUSTER_NAME)' already exists ..."; \
_kindnet_check_kubeconfig=$$(mktemp); \
- kind get kubeconfig --name $(KIND_CLUSTER_NAME) > $$_kindnet_check_kubeconfig; \
+ kind get kubeconfig --name "$$KIND_CLUSTER_NAME" > "$$_kindnet_check_kubeconfig"; \
...
else \
echo "Creating new kind cluster '$(KIND_CLUSTER_NAME)'..."; \
- kind create cluster --name $(KIND_CLUSTER_NAME) --config $(KIND_CONFIG); \
+ kind create cluster --name "$$KIND_CLUSTER_NAME" --config "$$KIND_CONFIG"; \
fi🤖 Prompt for AI AgentsSource: Path instructions |
||
| fi | ||
| @kind export kubeconfig --name $(KIND_CLUSTER_NAME) --kubeconfig $(KUBECONFIG) | ||
| @kubectl config use-context kind-$(KIND_CLUSTER_NAME) --kubeconfig $(KUBECONFIG) | ||
|
|
@@ -111,6 +133,28 @@ else | |
| @echo "To enable kind image builds set BUILD_IMAGES=true in env.kind" | ||
| endif | ||
|
|
||
| # macOS + podman: the podman machine must run rootful (podman machine set | ||
| # --rootful <name>) or Cilium's bpf-mount init container crash-loops - | ||
| # rootless podman can't mount bpffs. | ||
| .PHONY: install-kind-cilium | ||
| install-kind-cilium: check-helm check-kubectl-context ## Install Cilium CNI on the kind cluster (GKE uses Dataplane V2 instead) | ||
| @echo "Installing Cilium $(CILIUM_VERSION)..." | ||
| @helm repo add cilium https://helm.cilium.io/ >/dev/null | ||
| @helm repo update cilium >/dev/null | ||
| helm upgrade --install $(DRY_RUN_FLAG) cilium cilium/cilium \ | ||
| --version $(CILIUM_VERSION) \ | ||
| --namespace $(CILIUM_NAMESPACE) \ | ||
| --set ipam.mode=kubernetes \ | ||
| --set operator.replicas=1 \ | ||
| --wait --timeout 5m | ||
|
Comment on lines
+142
to
+149
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Verify the Cilium chart artifact before installation.
As per path instructions, “Verify targets don't execute untrusted scripts from network.” 🤖 Prompt for AI AgentsSource: Path instructions |
||
| @kubectl wait --for=condition=Ready pod -l k8s-app=cilium --namespace $(CILIUM_NAMESPACE) --timeout=180s | ||
| @echo "OK: Cilium is ready" | ||
|
|
||
| .PHONY: uninstall-kind-cilium | ||
| uninstall-kind-cilium: check-helm check-kubectl-context ## Uninstall Cilium CNI from the kind cluster | ||
| @helm uninstall cilium --namespace $(CILIUM_NAMESPACE) || true | ||
| @echo "OK: Cilium uninstalled (cluster networking is broken until Cilium is reinstalled or the cluster is deleted)" | ||
|
|
||
| # ==== Helmfile Targets ==== | ||
| .PHONY: template-helmfile | ||
| template-helmfile: check-helmfile ## Template the helmfile for the current environment | ||
|
|
@@ -682,13 +726,25 @@ validate-authorino: check-helm ## Validate gateway auth templates | |
| || { echo "ERROR: configured authorino.hosts entry not rendered"; exit 1; } | ||
| @echo "OK: Authorino gateway templates valid (ext_authz before router, fail-closed, when-gated optional header, model guard, additive AUTHORINO_HOSTS)" | ||
|
|
||
| .PHONY: validate-network-policies | ||
| validate-network-policies: check-helm ## Validate network-policies Helm chart rendering | ||
| @echo "Validating network-policies chart..." | ||
| @out=$$(helm template netpol $(HELM_DIR)/network-policies --set namespace=hyperfleet-local) \ | ||
| || { echo "ERROR: network-policies chart failed to render"; exit 1; }; \ | ||
| echo "$$out" | grep -q "name: hyperfleet-api-ingress" \ | ||
| || { echo "ERROR: hyperfleet-api-ingress NetworkPolicy not rendered"; exit 1; }; \ | ||
| echo "$$out" | grep -q "name: hyperfleet-api-postgres-ingress" \ | ||
| || { echo "ERROR: hyperfleet-api-postgres-ingress NetworkPolicy not rendered"; exit 1; } | ||
| @echo "OK: network-policies chart rendered successfully" | ||
|
|
||
| .PHONY: ci-validate | ||
| ci-validate: validate-terraform lint-helm lint-shellcheck ## Ci validate: validate terraform + lint helm + lint shellcheck | ||
|
|
||
| .PHONY: ci-dry-run | ||
| ci-dry-run: ci-validate ## Ci dry-run: ci-validate + validate maestro + validate authorino | ||
| ci-dry-run: ci-validate ## Ci dry-run: ci-validate + validate maestro + validate authorino + validate network policies | ||
| $(MAKE) validate-maestro | ||
| $(MAKE) validate-authorino | ||
| $(MAKE) validate-network-policies | ||
|
|
||
| .PHONY: health-check-maestro | ||
| health-check-maestro: check-kubectl ## Verify Maestro Components | ||
|
|
@@ -712,7 +768,7 @@ ci-cleanup: uninstall-maestro destroy-terraform ## Ci cleanup: uninstall maestro | |
| # Kind targets | ||
|
|
||
| .PHONY: local-up-kind | ||
| local-up-kind: create-kind-cluster kind-build-images install-priority-classes install-maestro-all generate-rabbitmq-values maybe-install-grafana maybe-install-tracing install-hyperfleet ## Full local kind setup | ||
| local-up-kind: create-kind-cluster install-kind-cilium kind-build-images install-priority-classes install-maestro-all generate-rabbitmq-values maybe-install-grafana maybe-install-tracing install-hyperfleet ## Full local kind setup | ||
|
|
||
| .PHONY: local-down-kind | ||
| local-down-kind: uninstall-hyperfleet uninstall-tracing uninstall-grafana uninstall-maestro delete-kind-cluster ## Tear down kind stack and delete cluster | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| apiVersion: v2 | ||
| name: network-policies | ||
| description: NetworkPolicy objects enforcing the HyperFleet app-namespace trust boundary | ||
| type: application | ||
| version: 0.1.0 | ||
| appVersion: "1.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| {{/* | ||
| Expand the name of the chart. | ||
| */}} | ||
| {{- define "network-policies.name" -}} | ||
| {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} | ||
| {{- end }} | ||
|
|
||
| {{/* | ||
| Create a default fully qualified app name. | ||
| */}} | ||
| {{- define "network-policies.fullname" -}} | ||
| {{- if .Values.fullnameOverride }} | ||
| {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} | ||
| {{- else }} | ||
| {{- $name := default .Chart.Name .Values.nameOverride }} | ||
| {{- if contains $name .Release.Name }} | ||
| {{- .Release.Name | trunc 63 | trimSuffix "-" }} | ||
| {{- else }} | ||
| {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} | ||
| {{- end }} | ||
| {{- end }} | ||
| {{- end }} | ||
|
|
||
| {{/* | ||
| Create chart name and version as used by the chart label. | ||
| */}} | ||
| {{- define "network-policies.chart" -}} | ||
| {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} | ||
| {{- end }} | ||
|
|
||
| {{/* | ||
| Common labels | ||
| */}} | ||
| {{- define "network-policies.labels" -}} | ||
| helm.sh/chart: {{ include "network-policies.chart" . }} | ||
| {{ include "network-policies.selectorLabels" . }} | ||
| {{- if .Chart.AppVersion }} | ||
| app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} | ||
| {{- end }} | ||
| app.kubernetes.io/managed-by: {{ .Release.Service }} | ||
| {{- end }} | ||
|
|
||
| {{/* | ||
| Selector labels | ||
| */}} | ||
| {{- define "network-policies.selectorLabels" -}} | ||
| app.kubernetes.io/name: {{ include "network-policies.name" . }} | ||
| app.kubernetes.io/instance: {{ .Release.Name }} | ||
| {{- end }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| {{- range .Values.networkPolicies }} | ||
| --- | ||
| apiVersion: networking.k8s.io/v1 | ||
| kind: NetworkPolicy | ||
| metadata: | ||
| name: {{ .name }} | ||
| namespace: {{ $.Values.namespace }} | ||
| labels: | ||
| {{- include "network-policies.labels" $ | nindent 4 }} | ||
| spec: | ||
| podSelector: | ||
| matchLabels: | ||
| {{- tpl (toYaml .podSelector) $ | nindent 6 }} | ||
| policyTypes: | ||
| - Ingress | ||
| ingress: | ||
| {{- tpl (toYaml .ingress) $ | nindent 4 }} | ||
| {{- end }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # Default values for network-policies. | ||
| nameOverride: "" | ||
| fullnameOverride: "" | ||
|
|
||
| monitoringNamespace: monitoring | ||
|
|
||
| # Name/instance labels of the workloads this chart guards. Must match the | ||
| # `app.kubernetes.io/name` and `app.kubernetes.io/instance` labels rendered by | ||
| # the hyperfleet-api and hyperfleet-gateway releases (helmfile release names by | ||
| # default) — override these if either release is installed under a different | ||
| # name or release instance. | ||
| apiNameLabel: hyperfleet-api | ||
| apiInstanceLabel: hyperfleet-api | ||
| gatewayNameLabel: hyperfleet-gateway | ||
| gatewayInstanceLabel: hyperfleet-gateway | ||
|
|
||
| # Add or edit policies here — this is the only file that needs to change. | ||
| # `podSelector` and `ingress` are passed through `tpl`, so they can reference | ||
| # `.Values` (e.g. the labels above). | ||
| networkPolicies: | ||
| - name: hyperfleet-api-ingress | ||
| podSelector: | ||
| app.kubernetes.io/name: "{{ .Values.apiNameLabel }}" | ||
| app.kubernetes.io/instance: "{{ .Values.apiInstanceLabel }}" | ||
| app.kubernetes.io/component: api | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| ingress: | ||
| # Sole ingress source for the API's app port: the gateway. No | ||
| # sentinel/adapter exception — they reach the API through the gateway | ||
| # (baseUrl defaults to http://hyperfleet-gateway:8000). | ||
| - from: | ||
| - podSelector: | ||
| matchLabels: | ||
| app.kubernetes.io/name: "{{ .Values.gatewayNameLabel }}" | ||
| app.kubernetes.io/instance: "{{ .Values.gatewayInstanceLabel }}" | ||
| ports: | ||
| - protocol: TCP | ||
| port: 8000 | ||
| # Prometheus metrics-only exception: the actual Prometheus pods | ||
| # (not the whole monitoring namespace), scrape :9090 only. | ||
| - from: | ||
| - namespaceSelector: | ||
| matchLabels: | ||
| kubernetes.io/metadata.name: "{{ .Values.monitoringNamespace }}" | ||
| podSelector: | ||
| matchLabels: | ||
| app.kubernetes.io/name: prometheus | ||
| operator.prometheus.io/name: kube-prometheus-stack-prometheus | ||
| ports: | ||
| - protocol: TCP | ||
| port: 9090 | ||
|
|
||
| - name: hyperfleet-api-postgres-ingress | ||
| podSelector: | ||
| app.kubernetes.io/name: "{{ .Values.apiNameLabel }}" | ||
| app.kubernetes.io/instance: "{{ .Values.apiInstanceLabel }}" | ||
| app.kubernetes.io/component: postgresql | ||
| ingress: | ||
| - from: | ||
| - podSelector: | ||
| matchLabels: | ||
| app.kubernetes.io/name: "{{ .Values.apiNameLabel }}" | ||
| app.kubernetes.io/instance: "{{ .Values.apiInstanceLabel }}" | ||
| app.kubernetes.io/component: api | ||
| ports: | ||
| - protocol: TCP | ||
| port: 5432 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| namespace: {{ .Values.namespace }} | ||
| monitoringNamespace: {{ env "MONITORING_NAMESPACE" | default "monitoring" }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| kind: Cluster | ||
| apiVersion: kind.x-k8s.io/v1alpha4 | ||
| nodes: | ||
| - role: control-plane | ||
| networking: | ||
| disableDefaultCNI: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Add the required infrastructure changelog entry.
Add Keep a Changelog entries under
Unreleased → Addedfor network-policy enforcement, Cilium/kind setup, and GKE Dataplane V2. Infrastructure deploys directly frommain.As per path instructions, “Use Keep a Changelog format for this infrastructure change.”
🤖 Prompt for AI Agents
Source: Path instructions