diff --git a/charts/sourcegraph-executor/k8s/README.md b/charts/sourcegraph-executor/k8s/README.md index 936c019e..3d0c3154 100644 --- a/charts/sourcegraph-executor/k8s/README.md +++ b/charts/sourcegraph-executor/k8s/README.md @@ -53,6 +53,12 @@ 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 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) | | 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..e765a474 --- /dev/null +++ b/charts/sourcegraph-executor/k8s/templates/executor.CiliumNetworkPolicy.yaml @@ -0,0 +1,94 @@ +{{- 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 }} + +{{- 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 +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 }} + egress: +{{ include "executor.ciliumNetworkPolicy.egressAllow" $egressAllowContext | indent 4 }} + 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 + 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 84c0aceb..46707041 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,86 @@ 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: spec.egress[0].toServices[0].k8sService + value: + namespace: sourcegraph + serviceName: sourcegraph-frontend + 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.egress[0].toServices[0].k8sService + value: + namespace: sourcegraph + serviceName: sourcegraph-frontend + 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..b37bfa0b 100644 --- a/charts/sourcegraph-executor/k8s/values.yaml +++ b/charts/sourcegraph-executor/k8s/values.yaml @@ -99,6 +99,23 @@ executor: storageSize: 10Gi # -- The namespace in which jobs are generated by the executor. namespace: "default" + ciliumNetworkPolicy: + # -- 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. + 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.