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
7 changes: 7 additions & 0 deletions changelog/unreleased/930-detect-apiserver-endpoint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Agent heartbeats reach a public API server endpoint

The chart's `allow-agent-to-apiserver` and `allow-sentinel-to-apiserver` policies only allowed
private ranges by default, so on a k3s node with a public IP every agent heartbeat timed out
and servers stayed "Starting" with no CPU, memory or disk figures. When
`networkPolicies.apiServerCIDRs` is unset, the chart now also allows the `kubernetes` Service
addresses it detects at install or upgrade time. [PR #930](https://github.com/GameplanePanel/Gameplane/pull/930)
44 changes: 44 additions & 0 deletions charts/gameplane/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,47 @@ mergeOverwrite preserves explicit zero/empty values so validation can reject the
{{- end -}}
{{- uniq $namespaces | toJson -}}
{{- end -}}

{{- /*
gameplane.apiServerEgressPeers renders the NetworkPolicy `to:` peers of the
agent and sentinel apiserver egress rules. An explicit
networkPolicies.apiServerCIDRs list wins. Otherwise it renders the RFC1918 +
link-local fallback plus every address the live cluster reports for the
`kubernetes` Service: its ClusterIPs and its EndpointSlice endpoint addresses.
On k3s and kubeadm single-node installs that endpoint is the node's own IP,
which is often public and outside the fallback; without it heartbeats time
out and every server stays "Starting". Offline renders (helm template, client
dry-run) get empty lookups and keep the plain fallback. Addresses are read at
install/upgrade time, so re-run helm upgrade if the API endpoint moves.
*/}}
{{- define "gameplane.apiServerEgressPeers" -}}
{{- $cidrs := .Values.networkPolicies.apiServerCIDRs | default (list) -}}
{{- if not $cidrs -}}
{{- $cidrs = list "10.0.0.0/8" "172.16.0.0/12" "192.168.0.0/16" "169.254.0.0/16" -}}
{{- $addrs := list -}}
{{- $svc := lookup "v1" "Service" "default" "kubernetes" -}}
{{- range (dig "spec" "clusterIPs" (list) $svc) -}}
{{- $addrs = append $addrs . -}}
{{- end -}}
{{- $slices := lookup "discovery.k8s.io/v1" "EndpointSlice" "default" "" -}}
{{- range (dig "items" (list) $slices) -}}
{{- if eq (dig "metadata" "labels" "kubernetes.io/service-name" "" .) "kubernetes" -}}
{{- range (dig "endpoints" (list) .) -}}
{{- range (dig "addresses" (list) .) -}}
{{- $addrs = append $addrs . -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- range $addrs -}}
{{- if contains ":" . -}}
{{- $cidrs = append $cidrs (printf "%s/128" .) -}}
{{- else -}}
{{- $cidrs = append $cidrs (printf "%s/32" .) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- range (uniq $cidrs) }}
- ipBlock: { cidr: {{ . | quote }} }
{{- end -}}
{{- end -}}
31 changes: 6 additions & 25 deletions charts/gameplane/templates/networkpolicies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ spec:
# Allow the agent sidecar to reach the kube-apiserver for its status
# heartbeat (gameservers/status patches). Service VIP traffic is DNATed
# to the apiserver endpoint before policy evaluation on most CNIs, so an
# ipBlock toward the endpoint address is required; like the kubelet
# probes policy below, default to RFC1918 + link-local and let operators
# narrow it via networkPolicies.apiServerCIDRs.
# ipBlock toward the endpoint address is required. Unset
# networkPolicies.apiServerCIDRs means RFC1918 + link-local plus the
# kubernetes Service endpoints detected at install time (a k3s node's
# public IP, for example); set the list to narrow it.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
Expand All @@ -56,17 +57,7 @@ spec:
policyTypes: [Egress]
egress:
- to:
{{- $apiCidrs := (.Values.networkPolicies.apiServerCIDRs | default (list)) }}
{{- if $apiCidrs }}
{{- range $apiCidrs }}
- ipBlock: { cidr: {{ . | quote }} }
{{- end }}
{{- else }}
- ipBlock: { cidr: 10.0.0.0/8 }
- ipBlock: { cidr: 172.16.0.0/12 }
- ipBlock: { cidr: 192.168.0.0/16 }
- ipBlock: { cidr: 169.254.0.0/16 }
{{- end }}
{{- include "gameplane.apiServerEgressPeers" . | trim | nindent 8 }}
ports:
- { protocol: TCP, port: 443 }
- { protocol: TCP, port: 6443 }
Expand Down Expand Up @@ -341,17 +332,7 @@ spec:
policyTypes: [Egress]
egress:
- to:
{{- $apiCidrs := (.Values.networkPolicies.apiServerCIDRs | default (list)) }}
{{- if $apiCidrs }}
{{- range $apiCidrs }}
- ipBlock: { cidr: {{ . | quote }} }
{{- end }}
{{- else }}
- ipBlock: { cidr: 10.0.0.0/8 }
- ipBlock: { cidr: 172.16.0.0/12 }
- ipBlock: { cidr: 192.168.0.0/16 }
- ipBlock: { cidr: 169.254.0.0/16 }
{{- end }}
{{- include "gameplane.apiServerEgressPeers" . | trim | nindent 8 }}
ports:
- { protocol: TCP, port: 443 }
- { protocol: TCP, port: 6443 }
Expand Down
8 changes: 6 additions & 2 deletions charts/gameplane/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -599,8 +599,12 @@ networkPolicies:
# probe ports, e.g. [{ protocol: TCP, port: 25565 }].
probePorts: []
# CIDRs that hold the kube-apiserver endpoint(s) the agent sidecar
# patches its status heartbeat through. Same fallback semantics as
# kubeletCIDRs: unset means RFC1918 + link-local on TCP 443/6443.
# patches its status heartbeat through. Unset means RFC1918 + link-local
# plus the kubernetes Service endpoint addresses detected at install or
# upgrade time (e.g. a k3s node's public IP), on TCP 443/6443. Offline
# renders (helm template, Argo CD) cannot detect them: set the list
# explicitly there when the endpoint is public. Re-run helm upgrade if
# the API server endpoint changes.
apiServerCIDRs: []
# Egress allowance for game pods to reach the public internet. Game
# servers download their binaries, assets, and mods on first start
Expand Down
2 changes: 1 addition & 1 deletion docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ Top-level knobs (see `values.yaml` for the full list):
- `networkPolicies.gameIngress` — control ingress to game pods from external sources (players)
- `gameIngress.enabled` — toggle player-ingress allowance (default `true`)
- `gameIngress.fromCIDRs` — CIDRs from which player traffic is allowed (default `[0.0.0.0/0]`)
- `networkPolicies.apiServerCIDRs` — CIDRs allowed for agent heartbeat to kube-apiserver (defaults to all RFC1918 and link-local addresses on TCP 443/6443; customize to narrow to specific API endpoint(s))
- `networkPolicies.apiServerCIDRs` — CIDRs allowed for agent heartbeat to kube-apiserver (defaults to all RFC1918 and link-local addresses plus the `kubernetes` Service endpoints detected at install/upgrade time, on TCP 443/6443; offline renders such as `helm template` or Argo CD cannot detect endpoints, so set this when the API endpoint is public; customize to narrow to specific API endpoint(s))
- `networkPolicies.gameEgress` — control public-internet egress for game pods (downloads, mod registries)
- `gameEgress.enabled` — toggle public-egress allowance (default `true`)
- `gameEgress.ports` — TCP ports for downloads (default 80, 443)
Expand Down
5 changes: 3 additions & 2 deletions docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,9 @@ When `networkPolicies.enabled=true` (default) the chart applies:
for status heartbeat (GameServer status patches). By default permits TCP 443
and 6443 to all addresses in RFC1918 and link-local ranges (10.0.0.0/8,
172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16), not limited to the apiserver
endpoint. Customize via `networkPolicies.apiServerCIDRs` to narrow to specific
API server addresses.
endpoint, plus the `kubernetes` Service ClusterIPs and endpoint addresses
the chart detects at install/upgrade time (as /32 or /128). Customize via
`networkPolicies.apiServerCIDRs` to narrow to specific API server addresses.
- `allow-api-to-agent` — allows the API and operator pods (in the
control-plane namespace) to reach every game pod's agent on TCP port 8090.
The API proxies console/files/logs/players; the operator calls `/quiesce`
Expand Down
Loading