From 14145bdfe2f57797c4775398e124c1641b326e49 Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Sun, 31 May 2026 22:50:45 -0600 Subject: [PATCH 1/3] Add executor Cilium network policy guard Amp-Thread-ID: https://ampcode.com/threads/T-019e7da4-9296-7370-a039-57f2e8351c24 Co-authored-by: Amp --- charts/sourcegraph-executor/k8s/README.md | 5 ++ .../executor.CiliumNetworkPolicy.yaml | 80 +++++++++++++++++++ .../k8s/tests/executor_test.yaml | 72 +++++++++++++++++ charts/sourcegraph-executor/k8s/values.yaml | 15 ++++ 4 files changed, 172 insertions(+) create mode 100644 charts/sourcegraph-executor/k8s/templates/executor.CiliumNetworkPolicy.yaml diff --git a/charts/sourcegraph-executor/k8s/README.md b/charts/sourcegraph-executor/k8s/README.md index 936c019e..3530c7a7 100644 --- a/charts/sourcegraph-executor/k8s/README.md +++ b/charts/sourcegraph-executor/k8s/README.md @@ -53,6 +53,11 @@ In addition to the documented values, the `executor` and `private-docker-registr | Key | Type | Default | Description | |-----|------|---------|-------------| | executor.affinity | object | `{}` | Affinity, learn more from the [Kubernetes documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) | +| executor.ciliumNetworkPolicy.deniedFrontendPorts | list | `["6060","3090","80"]` | Frontend pod ports to deny directly, even though the frontend pod is otherwise excluded from the broad Sourcegraph pod deny rule. | +| executor.ciliumNetworkPolicy.deniedFrontendServiceNames | list | `["sourcegraph-frontend-internal"]` | Sourcegraph services that are backed by frontend pods but should still be denied to executors. | +| executor.ciliumNetworkPolicy.enabled | bool | `false` | Create CiliumNetworkPolicy deny rules that prevent executor controller and job pods from reaching Sourcegraph pods and services other than the user-facing frontend service. This is a deny-only guard: it does not replace existing DNS, code host, package registry, or frontend allow policies. | +| executor.ciliumNetworkPolicy.frontendPodAppLabelValue | string | `"sourcegraph-frontend"` | Value of the `app` label on Sourcegraph frontend pods. | +| executor.ciliumNetworkPolicy.sourcegraphNamespace | string | `""` | Namespace where the Sourcegraph frontend and the rest of the Sourcegraph Helm chart run. Defaults to the Helm release namespace. | | executor.configureRbac | bool | `true` | Whether to configure the necessary RBAC resources. Required only once for all executor deployments. | | executor.containerSecurityContext | object | `{"privileged":false}` | Security context for the container, learn more from the [Kubernetes documentation](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) | | executor.debug.keepJobs | string | `"false"` | If true, Kubernetes jobs will not be deleted after they complete. Not recommended for production use as it can hit cluster limits. | diff --git a/charts/sourcegraph-executor/k8s/templates/executor.CiliumNetworkPolicy.yaml b/charts/sourcegraph-executor/k8s/templates/executor.CiliumNetworkPolicy.yaml new file mode 100644 index 00000000..4322e2c3 --- /dev/null +++ b/charts/sourcegraph-executor/k8s/templates/executor.CiliumNetworkPolicy.yaml @@ -0,0 +1,80 @@ +{{- define "executor.ciliumNetworkPolicy.egressDeny" -}} +{{- $policy := .policy -}} +{{- $sourcegraphNamespace := .sourcegraphNamespace -}} +- toEndpoints: + - matchExpressions: + - key: io.kubernetes.pod.namespace + operator: In + values: + - {{ $sourcegraphNamespace | quote }} + - key: deploy + operator: In + values: + - sourcegraph + - key: app + operator: NotIn + values: + - {{ $policy.frontendPodAppLabelValue | quote }} +{{- range $serviceName := $policy.deniedFrontendServiceNames }} +- toServices: + - k8sService: + namespace: {{ $sourcegraphNamespace | quote }} + serviceName: {{ $serviceName | quote }} +{{- end }} +{{- if $policy.deniedFrontendPorts }} +- toEndpoints: + - matchLabels: + io.kubernetes.pod.namespace: {{ $sourcegraphNamespace | quote }} + app: {{ $policy.frontendPodAppLabelValue | quote }} + toPorts: + - ports: +{{- range $port := $policy.deniedFrontendPorts }} + - port: {{ $port | quote }} + protocol: TCP +{{- end }} +{{- end }} +{{- end }} + +{{- if .Values.executor.ciliumNetworkPolicy.enabled }} +{{- $policy := .Values.executor.ciliumNetworkPolicy }} +{{- $sourcegraphNamespace := default .Release.Namespace $policy.sourcegraphNamespace }} +{{- $jobNamespace := default .Release.Namespace .Values.executor.namespace }} +{{- $egressDenyContext := dict "policy" $policy "sourcegraphNamespace" $sourcegraphNamespace }} +--- +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: {{ printf "%s-controller-egress-deny" (include "executor.name" .) | trunc 63 | trimSuffix "-" }} + namespace: {{ .Release.Namespace | quote }} +spec: + description: >- + Deny Sourcegraph executor controller pods from reaching Sourcegraph pods and + services other than the user-facing frontend service. + enableDefaultDeny: + egress: false + endpointSelector: + matchLabels: + app: {{ include "executor.name" . | quote }} + egressDeny: +{{ include "executor.ciliumNetworkPolicy.egressDeny" $egressDenyContext | indent 4 }} +--- +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: {{ printf "%s-jobs-egress-deny" (include "executor.name" .) | trunc 63 | trimSuffix "-" }} + namespace: {{ $jobNamespace | quote }} +spec: + description: >- + Deny Sourcegraph executor job pods from reaching Sourcegraph pods and + services other than the user-facing frontend service. + enableDefaultDeny: + egress: false + endpointSelector: + matchExpressions: + - key: sourcegraph/job-id + operator: Exists + - key: sourcegraph/run-id + operator: Exists + egressDeny: +{{ include "executor.ciliumNetworkPolicy.egressDeny" $egressDenyContext | indent 4 }} +{{- end }} diff --git a/charts/sourcegraph-executor/k8s/tests/executor_test.yaml b/charts/sourcegraph-executor/k8s/tests/executor_test.yaml index 84c0aceb..ae46a551 100644 --- a/charts/sourcegraph-executor/k8s/tests/executor_test.yaml +++ b/charts/sourcegraph-executor/k8s/tests/executor_test.yaml @@ -4,6 +4,7 @@ templates: - executor.Service.yaml - executor.ConfigMap.yaml - executor.PersistentVolumeClaim.yaml + - executor.CiliumNetworkPolicy.yaml tests: - it: should render the Deployment, Service, ConfigMap, PVC if executor is enabled set: @@ -131,3 +132,74 @@ tests: path: spec.template.spec.securityContext.runAsUser - isNull: path: spec.template.spec.securityContext.runAsGroup + + - it: should render CiliumNetworkPolicy deny guards when enabled + template: executor.CiliumNetworkPolicy.yaml + set: + executor: + queueNames: + - batches + - codeintel + namespace: executor-jobs + ciliumNetworkPolicy: + enabled: true + sourcegraphNamespace: sourcegraph + asserts: + - hasDocuments: + count: 2 + - equal: + path: apiVersion + value: cilium.io/v2 + documentIndex: 0 + - equal: + path: kind + value: CiliumNetworkPolicy + documentIndex: 0 + - equal: + path: metadata.name + value: executor-batches-codeintel-controller-egress-deny + documentIndex: 0 + - equal: + path: metadata.namespace + value: NAMESPACE + documentIndex: 0 + - equal: + path: spec.enableDefaultDeny.egress + value: false + documentIndex: 0 + - equal: + path: spec.endpointSelector.matchLabels.app + value: executor-batches-codeintel + documentIndex: 0 + - equal: + path: apiVersion + value: cilium.io/v2 + documentIndex: 1 + - equal: + path: kind + value: CiliumNetworkPolicy + documentIndex: 1 + - equal: + path: metadata.name + value: executor-batches-codeintel-jobs-egress-deny + documentIndex: 1 + - equal: + path: metadata.namespace + value: executor-jobs + documentIndex: 1 + - equal: + path: spec.endpointSelector.matchExpressions + value: + - key: sourcegraph/job-id + operator: Exists + - key: sourcegraph/run-id + operator: Exists + documentIndex: 1 + - equal: + path: spec.egressDeny[0].toEndpoints[0].matchExpressions[0] + value: + key: io.kubernetes.pod.namespace + operator: In + values: + - sourcegraph + documentIndex: 1 diff --git a/charts/sourcegraph-executor/k8s/values.yaml b/charts/sourcegraph-executor/k8s/values.yaml index 09305be1..fd1862ec 100644 --- a/charts/sourcegraph-executor/k8s/values.yaml +++ b/charts/sourcegraph-executor/k8s/values.yaml @@ -99,6 +99,21 @@ executor: storageSize: 10Gi # -- The namespace in which jobs are generated by the executor. namespace: "default" + ciliumNetworkPolicy: + # -- Create CiliumNetworkPolicy deny rules that prevent executor controller and job pods from reaching Sourcegraph pods and services other than the user-facing frontend service. This is a deny-only guard: it does not replace existing DNS, code host, package registry, or frontend allow policies. + enabled: false + # -- Namespace where the Sourcegraph frontend and the rest of the Sourcegraph Helm chart run. Defaults to the Helm release namespace. + sourcegraphNamespace: "" + # -- Value of the `app` label on Sourcegraph frontend pods. + frontendPodAppLabelValue: sourcegraph-frontend + # -- Sourcegraph services that are backed by frontend pods but should still be denied to executors. + deniedFrontendServiceNames: + - sourcegraph-frontend-internal + # -- Frontend pod ports to deny directly, even though the frontend pod is otherwise excluded from the broad Sourcegraph pod deny rule. + deniedFrontendPorts: + - "6060" + - "3090" + - "80" # -- The path to the kubeconfig file. If not specified, the in-cluster config is used. kubeconfigPath: "" # -- DEPRECATED: Use `executor.containerSecurityContext` or `executor.podSecurityContext` instead. From c2b53f901c7fe53948251c0de19bf3fb14ed3136 Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:15:49 -0600 Subject: [PATCH 2/3] Allow frontend service in executor Cilium policy Amp-Thread-ID: https://ampcode.com/threads/T-019e7da4-9296-7370-a039-57f2e8351c24 Co-authored-by: Amp --- charts/sourcegraph-executor/k8s/README.md | 3 ++- .../templates/executor.CiliumNetworkPolicy.yaml | 14 ++++++++++++++ .../k8s/tests/executor_test.yaml | 12 ++++++++++++ charts/sourcegraph-executor/k8s/values.yaml | 4 +++- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/charts/sourcegraph-executor/k8s/README.md b/charts/sourcegraph-executor/k8s/README.md index 3530c7a7..3d0c3154 100644 --- a/charts/sourcegraph-executor/k8s/README.md +++ b/charts/sourcegraph-executor/k8s/README.md @@ -55,8 +55,9 @@ In addition to the documented values, the `executor` and `private-docker-registr | executor.affinity | object | `{}` | Affinity, learn more from the [Kubernetes documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) | | executor.ciliumNetworkPolicy.deniedFrontendPorts | list | `["6060","3090","80"]` | Frontend pod ports to deny directly, even though the frontend pod is otherwise excluded from the broad Sourcegraph pod deny rule. | | executor.ciliumNetworkPolicy.deniedFrontendServiceNames | list | `["sourcegraph-frontend-internal"]` | Sourcegraph services that are backed by frontend pods but should still be denied to executors. | -| executor.ciliumNetworkPolicy.enabled | bool | `false` | Create CiliumNetworkPolicy deny rules that prevent executor controller and job pods from reaching Sourcegraph pods and services other than the user-facing frontend service. This is a deny-only guard: it does not replace existing DNS, code host, package registry, or frontend allow policies. | +| executor.ciliumNetworkPolicy.enabled | bool | `false` | Create CiliumNetworkPolicy rules that allow executor controller and job pods to reach the user-facing frontend service and deny other Sourcegraph pods and services. This does not replace existing DNS, code host, or package registry allow policies. | | executor.ciliumNetworkPolicy.frontendPodAppLabelValue | string | `"sourcegraph-frontend"` | Value of the `app` label on Sourcegraph frontend pods. | +| executor.ciliumNetworkPolicy.frontendServiceName | string | `"sourcegraph-frontend"` | Kubernetes Service name for the user-facing Sourcegraph frontend service that executor pods must be able to reach. | | executor.ciliumNetworkPolicy.sourcegraphNamespace | string | `""` | Namespace where the Sourcegraph frontend and the rest of the Sourcegraph Helm chart run. Defaults to the Helm release namespace. | | executor.configureRbac | bool | `true` | Whether to configure the necessary RBAC resources. Required only once for all executor deployments. | | executor.containerSecurityContext | object | `{"privileged":false}` | Security context for the container, learn more from the [Kubernetes documentation](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) | diff --git a/charts/sourcegraph-executor/k8s/templates/executor.CiliumNetworkPolicy.yaml b/charts/sourcegraph-executor/k8s/templates/executor.CiliumNetworkPolicy.yaml index 4322e2c3..e765a474 100644 --- a/charts/sourcegraph-executor/k8s/templates/executor.CiliumNetworkPolicy.yaml +++ b/charts/sourcegraph-executor/k8s/templates/executor.CiliumNetworkPolicy.yaml @@ -35,11 +35,21 @@ {{- end }} {{- end }} +{{- define "executor.ciliumNetworkPolicy.egressAllow" -}} +{{- $policy := .policy -}} +{{- $sourcegraphNamespace := .sourcegraphNamespace -}} +- toServices: + - k8sService: + namespace: {{ $sourcegraphNamespace | quote }} + serviceName: {{ $policy.frontendServiceName | quote }} +{{- end }} + {{- if .Values.executor.ciliumNetworkPolicy.enabled }} {{- $policy := .Values.executor.ciliumNetworkPolicy }} {{- $sourcegraphNamespace := default .Release.Namespace $policy.sourcegraphNamespace }} {{- $jobNamespace := default .Release.Namespace .Values.executor.namespace }} {{- $egressDenyContext := dict "policy" $policy "sourcegraphNamespace" $sourcegraphNamespace }} +{{- $egressAllowContext := dict "policy" $policy "sourcegraphNamespace" $sourcegraphNamespace }} --- apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy @@ -55,6 +65,8 @@ spec: endpointSelector: matchLabels: app: {{ include "executor.name" . | quote }} + egress: +{{ include "executor.ciliumNetworkPolicy.egressAllow" $egressAllowContext | indent 4 }} egressDeny: {{ include "executor.ciliumNetworkPolicy.egressDeny" $egressDenyContext | indent 4 }} --- @@ -75,6 +87,8 @@ spec: operator: Exists - key: sourcegraph/run-id operator: Exists + egress: +{{ include "executor.ciliumNetworkPolicy.egressAllow" $egressAllowContext | indent 4 }} egressDeny: {{ include "executor.ciliumNetworkPolicy.egressDeny" $egressDenyContext | indent 4 }} {{- end }} diff --git a/charts/sourcegraph-executor/k8s/tests/executor_test.yaml b/charts/sourcegraph-executor/k8s/tests/executor_test.yaml index ae46a551..46707041 100644 --- a/charts/sourcegraph-executor/k8s/tests/executor_test.yaml +++ b/charts/sourcegraph-executor/k8s/tests/executor_test.yaml @@ -171,6 +171,12 @@ tests: path: spec.endpointSelector.matchLabels.app value: executor-batches-codeintel documentIndex: 0 + - equal: + path: spec.egress[0].toServices[0].k8sService + value: + namespace: sourcegraph + serviceName: sourcegraph-frontend + documentIndex: 0 - equal: path: apiVersion value: cilium.io/v2 @@ -195,6 +201,12 @@ tests: - key: sourcegraph/run-id operator: Exists documentIndex: 1 + - equal: + path: spec.egress[0].toServices[0].k8sService + value: + namespace: sourcegraph + serviceName: sourcegraph-frontend + documentIndex: 1 - equal: path: spec.egressDeny[0].toEndpoints[0].matchExpressions[0] value: diff --git a/charts/sourcegraph-executor/k8s/values.yaml b/charts/sourcegraph-executor/k8s/values.yaml index fd1862ec..b37bfa0b 100644 --- a/charts/sourcegraph-executor/k8s/values.yaml +++ b/charts/sourcegraph-executor/k8s/values.yaml @@ -100,10 +100,12 @@ executor: # -- The namespace in which jobs are generated by the executor. namespace: "default" ciliumNetworkPolicy: - # -- Create CiliumNetworkPolicy deny rules that prevent executor controller and job pods from reaching Sourcegraph pods and services other than the user-facing frontend service. This is a deny-only guard: it does not replace existing DNS, code host, package registry, or frontend allow policies. + # -- Create CiliumNetworkPolicy rules that allow executor controller and job pods to reach the user-facing frontend service and deny other Sourcegraph pods and services. This does not replace existing DNS, code host, or package registry allow policies. enabled: false # -- Namespace where the Sourcegraph frontend and the rest of the Sourcegraph Helm chart run. Defaults to the Helm release namespace. sourcegraphNamespace: "" + # -- Kubernetes Service name for the user-facing Sourcegraph frontend service that executor pods must be able to reach. + frontendServiceName: sourcegraph-frontend # -- Value of the `app` label on Sourcegraph frontend pods. frontendPodAppLabelValue: sourcegraph-frontend # -- Sourcegraph services that are backed by frontend pods but should still be denied to executors. From ffb68347cb87aa2ef628e3eb76c98dedb7302e0c Mon Sep 17 00:00:00 2001 From: Marc LeBlanc <7050295+marcleblanc2@users.noreply.github.com> Date: Tue, 2 Jun 2026 23:46:10 -0600 Subject: [PATCH 3/3] Add network policy --- .../executor-network-policy.yaml | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 charts/sourcegraph/examples/network-policy/executor-network-policy.yaml diff --git a/charts/sourcegraph/examples/network-policy/executor-network-policy.yaml b/charts/sourcegraph/examples/network-policy/executor-network-policy.yaml new file mode 100644 index 00000000..100ac2a9 --- /dev/null +++ b/charts/sourcegraph/examples/network-policy/executor-network-policy.yaml @@ -0,0 +1,106 @@ +# Sourcegraph Executor network policies for native Kubernetes +# +# Description: +# +# - Executors must not be allowed to connect to any Sourcegraph-internal services, +# except the sourcegraph-frontend service +# +# - Many Kubernetes platforms do not block inter-namespace communication by default +# +# - Unless your instance requires external pods to be able to connect to +# Sourcegraph-internal services, ex. external Prometheus scraping pod metrics, +# then Sourcegraph-internal services should not be reachable outside of +# the instance's namespace +# +# Native Kubernetes NetworkPolicy supports allow rules only, like: +# +# - Block all ingress by default +# - Allow ingress by specified exceptions +# +# Usage: +# +# - Deploy both network policies in your Sourcegraph instance's namespace +# +# - You can still use `frontendUrl: http://sourcegraph-frontend:30080` +# in your override file for the sourcegraph-executor Helm charts, +# to avoid paying egress / ingress charges for the Executors' traffic +# +# Effect: +# +# - Executor pods can reach the frontend HTTP service +# - Executor pods cannot reach frontend internal/debug ports +# - Executor pods cannot reach other Sourcegraph pods or services +# - Executor egress to DNS, kube API, code hosts, package registries, and other +# external services is unchanged +# +# Notes: +# +# - Kubernetes NetworkPolicy rules are additive; if another policy already allows +# executor ingress to backend pods, remove or narrow that broader allow policy +# +# - This policy relies on all Sourcegraph + executor pods having at least +# the default labels from their respective Helm charts +# +# - To protect additional pods (ex. src-serve-git), either: +# - Apply the deploy=sourcegraph label to them +# - Or add an identifying label for them in the spec.podSelector.matchExpressions +# of the sourcegraph-internal-pods-block-executors policy +# +# - If you need pods from outside of your Sourcegraph instance's namespace +# to continue to be able to connect to backend pods, then uncomment the +# `namespaceSelector: {}` line + +--- + +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: sourcegraph-pods-block-executors +spec: + podSelector: + matchExpressions: + - key: deploy + operator: In + values: + - sourcegraph + - key: app.kubernetes.io/component + operator: NotIn + values: + - executor + - key: sourcegraph/job-id + operator: DoesNotExist + - key: sourcegraph/run-id + operator: DoesNotExist + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchExpressions: + - key: app.kubernetes.io/component + operator: NotIn + values: + - executor + - key: sourcegraph/job-id + operator: DoesNotExist + - key: sourcegraph/run-id + operator: DoesNotExist + # namespaceSelector: {} + +--- + +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: sourcegraph-frontend-allow-http-from-anywhere +spec: + podSelector: + matchLabels: + deploy: sourcegraph + app: sourcegraph-frontend + policyTypes: + - Ingress + ingress: + - ports: + - protocol: TCP + port: http