Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,14 @@ e2e-cluster: ## Create the kind cluster used by the e2e tests.
.PHONY: e2e-deploy
e2e-deploy: docker-build ## Build the image, load it into kind and install the chart.
kind load docker-image $(IMG) --name $(KIND_CLUSTER)
API_SERVER_IP="$$(kubectl get service kubernetes --namespace default -o jsonpath='{.spec.clusterIP}')"; \
helm upgrade --install crashloop-operator charts/crashloop-operator \
--namespace $(NAMESPACE) --create-namespace \
--set image.repository=$(firstword $(subst :, ,$(IMG))) \
--set image.tag=$(lastword $(subst :, ,$(IMG))) \
--set image.pullPolicy=Never \
--set networkPolicy.enabled=true \
--set networkPolicy.apiServer.ipBlock.cidr="$$API_SERVER_IP/32" \
--wait

.PHONY: e2e-run
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,25 @@ workload names are not, and a series for a workload that is later deleted would
never go away. Use `status.activeScaledDown` or the `scaled-down-by` annotation
to identify individual workloads.

## NetworkPolicy

The chart can isolate the operator pod with an ingress and egress NetworkPolicy.
Supply the CIDR for your cluster's Kubernetes API endpoint when enabling it:

```bash
helm upgrade --install crashloop-operator \
oci://ghcr.io/slauger/charts/crashloop-operator \
--namespace crashloop-system --create-namespace \
--set networkPolicy.enabled=true \
--set networkPolicy.apiServer.ipBlock.cidr=10.96.0.1/32
```

The policy allows egress only to that API endpoint and to the selected cluster
DNS pods. It denies ingress unless `metrics.service.enabled` is true, in which
case it allows TCP traffic to the metrics container port. Adjust the DNS
namespace and pod selectors for clusters that do not label DNS as `kube-dns` in
`kube-system`. The cluster's network plugin must enforce NetworkPolicy objects.

Two alerts worth having:

```yaml
Expand Down
6 changes: 6 additions & 0 deletions charts/crashloop-operator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ Kubernetes: `>=1.29.0-0`
| metrics.serviceMonitor.interval | string | `"30s"` | Scrape interval. |
| metrics.serviceMonitor.labels | object | `{}` | Extra labels for the ServiceMonitor, for Prometheus selector matching. |
| nameOverride | string | `""` | Override the chart name used in resource names. |
| networkPolicy.apiServer.ipBlock.cidr | string | `""` | CIDR containing the Kubernetes API server endpoint. Required when the policy is enabled. |
| networkPolicy.apiServer.ipBlock.except | list | `[]` | CIDRs to exclude from the API server CIDR. |
| networkPolicy.apiServer.port | int | `443` | Kubernetes API server port. |
| networkPolicy.dns.namespaceSelector | object | `{"matchLabels":{"kubernetes.io/metadata.name":"kube-system"}}` | Namespace selector for the cluster DNS pods. |
| networkPolicy.dns.podSelector | object | `{"matchLabels":{"k8s-app":"kube-dns"}}` | Pod selector for the cluster DNS pods. |
| networkPolicy.enabled | bool | `false` | Create a NetworkPolicy for the operator pod. Requires an API server CIDR. |
| nodeSelector | object | `{}` | Node selector for the operator pod. |
| podAnnotations | object | `{}` | Annotations to add to the operator pod. |
| podDisruptionBudget.enabled | bool | `false` | Create a PodDisruptionBudget. Only meaningful with replicaCount above 1, since leader election already keeps a single replica from being active twice. |
Expand Down
46 changes: 46 additions & 0 deletions charts/crashloop-operator/templates/networkpolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{{- if .Values.networkPolicy.enabled }}
{{- $apiServerCIDR := required "networkPolicy.apiServer.ipBlock.cidr is required when networkPolicy.enabled is true" .Values.networkPolicy.apiServer.ipBlock.cidr }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "crashloop-operator.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "crashloop-operator.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "crashloop-operator.selectorLabels" . | nindent 6 }}
policyTypes:
- Ingress
- Egress
{{- if .Values.metrics.service.enabled }}
ingress:
- ports:
- protocol: TCP
port: 8080
{{- else }}
ingress: []
{{- end }}
egress:
- to:
- ipBlock:
cidr: {{ $apiServerCIDR }}
{{- with .Values.networkPolicy.apiServer.ipBlock.except }}
except:
{{- toYaml . | nindent 14 }}
{{- end }}
ports:
- protocol: TCP
port: {{ .Values.networkPolicy.apiServer.port }}
- to:
- namespaceSelector:
{{- toYaml .Values.networkPolicy.dns.namespaceSelector | nindent 12 }}
podSelector:
{{- toYaml .Values.networkPolicy.dns.podSelector | nindent 12 }}
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
{{- end }}
85 changes: 85 additions & 0 deletions charts/crashloop-operator/tests/networkpolicy_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
suite: NetworkPolicy tests
templates:
- templates/networkpolicy.yaml
tests:
- it: should not create a NetworkPolicy by default
asserts:
- hasDocuments:
count: 0

- it: should require an API server CIDR when enabled
set:
networkPolicy:
enabled: true
asserts:
- failedTemplate:
errorMessage: "networkPolicy.apiServer.ipBlock.cidr is required when networkPolicy.enabled is true"

- it: should allow only API server and DNS egress with ingress denied
set:
networkPolicy:
enabled: true
apiServer:
ipBlock:
cidr: 10.96.0.0/24
except:
- 10.96.0.2/32
port: 6443
asserts:
- isKind:
of: NetworkPolicy
- equal:
path: spec.podSelector.matchLabels
value:
app.kubernetes.io/name: crashloop-operator
app.kubernetes.io/instance: RELEASE-NAME
- equal:
path: spec.policyTypes
value:
- Ingress
- Egress
- equal:
path: spec.ingress
value: []
- equal:
path: spec.egress
value:
- to:
- ipBlock:
cidr: 10.96.0.0/24
except:
- 10.96.0.2/32
ports:
- protocol: TCP
port: 6443
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53

- it: should allow metrics ingress only when the metrics Service is enabled
set:
networkPolicy:
enabled: true
apiServer:
ipBlock:
cidr: 10.96.0.1/32
metrics:
service:
enabled: true
port: 9090
asserts:
- equal:
path: spec.ingress
value:
- ports:
- protocol: TCP
port: 8080
64 changes: 64 additions & 0 deletions charts/crashloop-operator/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,70 @@
"description": "Override the chart name used in resource names.",
"type": "string"
},
"networkPolicy": {
"type": "object",
"properties": {
"apiServer": {
"type": "object",
"properties": {
"ipBlock": {
"type": "object",
"properties": {
"cidr": {
"description": "CIDR containing the Kubernetes API server endpoint. Required when the policy is enabled.",
"type": "string"
},
"except": {
"description": "CIDRs to exclude from the API server CIDR.",
"type": "array"
}
}
},
"port": {
"description": "Kubernetes API server port.",
"type": "integer"
}
}
},
"dns": {
"type": "object",
"properties": {
"namespaceSelector": {
"description": "Namespace selector for the cluster DNS pods.",
"type": "object",
"properties": {
"matchLabels": {
"type": "object",
"properties": {
"kubernetes.io/metadata.name": {
"type": "string"
}
}
}
}
},
"podSelector": {
"description": "Pod selector for the cluster DNS pods.",
"type": "object",
"properties": {
"matchLabels": {
"type": "object",
"properties": {
"k8s-app": {
"type": "string"
}
}
}
}
}
}
},
"enabled": {
"description": "Create a NetworkPolicy for the operator pod. Requires an API server CIDR.",
"type": "boolean"
}
}
},
"nodeSelector": {
"description": "Node selector for the operator pod.",
"type": "object"
Expand Down
21 changes: 21 additions & 0 deletions charts/crashloop-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,27 @@ metrics:
# -- Extra labels for the ServiceMonitor, for Prometheus selector matching.
labels: {}

networkPolicy:
# -- Create a NetworkPolicy for the operator pod. Requires an API server CIDR.
enabled: false
apiServer:
ipBlock:
# -- CIDR containing the Kubernetes API server endpoint. Required when the policy is enabled.
cidr: ""
# -- CIDRs to exclude from the API server CIDR.
except: []
# -- Kubernetes API server port.
port: 443
dns:
# -- Namespace selector for the cluster DNS pods.
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
# -- Pod selector for the cluster DNS pods.
podSelector:
matchLabels:
k8s-app: kube-dns

# -- Resource requests and limits for the operator container.
resources:
limits:
Expand Down