6 Commits

Author SHA1 Message Date
benvin 8e655c26af Merge pull request 'Harden kea socket dir to 0750 (fix remaining CrashLoopBackOff)' (#4) from benvin/fix-socket-dir-perms into main
ci/woodpecker/tag/docker Pipeline was successful
Reviewed-on: #4
2026-08-08 22:13:30 +10:00
unkinben e95e5437a2 Harden kea socket dir to 0750 in the rendered entrypoints
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
After v0.1.1 moved the socket dir to /var/run/kea, kea-dhcp4 and
kea-ctrl-agent still crash-loop:

  DHCP4_PARSER_COMMIT_FAIL ... 'socket-name' is invalid: socket path:/var/run/kea
  does not exist or has more relaxed permissions than 750

Kea 2.6+ refuses a unix-socket directory whose mode is more relaxed than
0750. The shared emptyDir is mounted at /var/run/kea with the default 0777,
so kea rejects it. The kea containers run as root, so the entrypoints can
tighten it.

- chmod 0750 the RunDir in both rendered entrypoints after mkdir.
- Assert both entrypoints chmod the socket dir to 0750.

Needs a v0.1.2 release so argocd-apps can bump the operator image.

Claude-Session: https://claude.ai/code/session_01JUoARVdmhxKQHyyyp1pxeT
2026-08-08 20:12:17 +10:00
benvin a6feed2840 Merge pull request 'Fix kea CrashLoopBackOff: render socket paths under /var/run/kea' (#3) from benvin/fix-runstatedir-path into main
ci/woodpecker/tag/docker Pipeline was successful
Reviewed-on: #3
2026-08-08 18:15:06 +10:00
unkinben 1b8be63d05 Render kea unix socket paths under /var/run/kea
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
Kea 2.6.5 restricts control/HA unix socket paths to its compiled
runstatedir and rejects any other path by exact string match
("invalid path specified: '/run/kea', supported path is '/var/run/kea'"),
even though /var/run is a symlink to /run. The operator rendered sockets
under /run/kea, so kea-dhcp4 and kea-ctrl-agent crash-looped on startup.

- Point RunDir at /var/run/kea so all derived config/socket paths match.
- Pre-create /var/run/kea in the kea image.
- Assert rendered socket paths live under /var/run/kea.

Claude-Session: https://claude.ai/code/session_01JUoARVdmhxKQHyyyp1pxeT
2026-08-06 23:38:55 +10:00
benvin 34783c51fd Merge pull request 'Fix DHCP sample gateways and lowercase PXE client-class names' (#2) from benvin/fix-samples into main
Reviewed-on: #2
2026-08-02 21:51:30 +10:00
unkinben 23922649b6 Fix DHCP sample gateways and lowercase PXE client-class names
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
Two sample bugs surfaced while authoring the argocd deployment.

- set subnet gateways to match the authoritative puppet hieradata: 198.18.13-16
  routers are .254 (not .1); 198.18.17 stays .1
- rename KeaClientClass samples Legacy/UEFI-64 to legacy/uefi-64 so they are
  valid RFC1123 object names (the operator renders the kea class name from
  metadata.name, which k8s forces to lowercase); align the README

Claude-Session: https://claude.ai/code/session_01JUoARVdmhxKQHyyyp1pxeT
2026-08-02 21:47:48 +10:00
7 changed files with 46 additions and 11 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ RUN dnf -y install epel-release \
&& dnf -y install kea kea-hooks \
&& dnf clean all \
&& rm -rf /var/cache/dnf \
&& mkdir -p /run/kea
&& mkdir -p /var/run/kea
EXPOSE 67/udp 8000/tcp
# Command is supplied by the operator (per-container entrypoint scripts).
+1 -1
View File
@@ -12,7 +12,7 @@ Namespace: `dhcp-system`. API group: `kea.unkin.net/v1alpha1`.
|------|---------|
| **KeaCluster** | Spawns a StatefulSet of `kea-dhcp4` + `kea-ctrl-agent` pods, an HA control channel, and an anycast DHCP `Service`. Holds global config (domain, lease times, NTP, PXE option-defs). |
| **KeaSubnet** | One DHCPv4 subnet referenced to a KeaCluster (`clusterRef`). CIDR, optional pools, routers, DNS, domain, next-server. Pool-less subnets are declared so relayed requests are still serviced. |
| **KeaClientClass** | PXE boot class matched on client architecture (option 93), e.g. `Legacy``/undionly.kpxe`, `UEFI-64``/ipxe.efi`. |
| **KeaClientClass** | PXE boot class matched on client architecture (option 93), e.g. `legacy``/undionly.kpxe`, `uefi-64``/ipxe.efi`. |
| **KeaAPI** | Spawns the Terraform-friendly REST API service (see below). |
The **KeaCluster** controller lists the matching subnets and client classes,
+4 -4
View File
@@ -10,7 +10,7 @@ spec:
subnet: 198.18.13.0/24
pools:
- 198.18.13.200 - 198.18.13.220
routers: [198.18.13.1]
routers: [198.18.13.254]
dnsServers: [198.18.19.15]
domainName: main.unkin.net
nextServer: 198.18.19.19
@@ -25,7 +25,7 @@ spec:
subnet: 198.18.14.0/24
pools:
- 198.18.14.200 - 198.18.14.220
routers: [198.18.14.1]
routers: [198.18.14.254]
dnsServers: [198.18.19.15]
domainName: main.unkin.net
nextServer: 198.18.19.19
@@ -40,7 +40,7 @@ spec:
subnet: 198.18.15.0/24
pools:
- 198.18.15.200 - 198.18.15.220
routers: [198.18.15.1]
routers: [198.18.15.254]
dnsServers: [198.18.19.15]
domainName: main.unkin.net
nextServer: 198.18.19.19
@@ -55,7 +55,7 @@ spec:
subnet: 198.18.16.0/24
pools:
- 198.18.16.200 - 198.18.16.220
routers: [198.18.16.1]
routers: [198.18.16.254]
dnsServers: [198.18.19.15]
domainName: main.unkin.net
nextServer: 198.18.19.19
+4 -3
View File
@@ -1,9 +1,10 @@
# PXE boot classes matching the client architecture option (code 93), replacing
# the legacy dhcpd "Legacy" and "UEFI-64" classes.
# the legacy dhcpd "Legacy" and "UEFI-64" classes. Object names must be RFC1123
# (lowercase); the operator renders the kea client-class name from metadata.name.
apiVersion: kea.unkin.net/v1alpha1
kind: KeaClientClass
metadata:
name: Legacy
name: legacy
namespace: dhcp-system
spec:
clusterRef: pxe
@@ -13,7 +14,7 @@ spec:
apiVersion: kea.unkin.net/v1alpha1
kind: KeaClientClass
metadata:
name: UEFI-64
name: uefi-64
namespace: dhcp-system
spec:
clusterRef: pxe
+2
View File
@@ -35,6 +35,7 @@ func EntrypointDHCP4() string {
set -e
ORD="${HOSTNAME##*-}"
mkdir -p %[1]s
chmod 0750 %[1]s
sed "s/%[2]s/server${ORD}/g" %[3]s/kea-dhcp4.conf > %[4]s
exec %[5]s -c %[4]s
`, RunDir, ThisServerPlaceholder, ConfigDir, DHCP4ConfPath, DHCP4Bin)
@@ -45,6 +46,7 @@ func EntrypointCtrlAgent() string {
return fmt.Sprintf(`#!/bin/sh
set -e
mkdir -p %[1]s
chmod 0750 %[1]s
cp %[2]s/kea-ctrl-agent.conf %[3]s
exec %[4]s -c %[3]s
`, RunDir, ConfigDir, CtrlAgentConfPath, CtrlAgentBin)
+29
View File
@@ -231,4 +231,33 @@ func TestRenderCtrlAgent(t *testing.T) {
t.Errorf("ctrl-agent config missing %q", m)
}
}
// Kea 2.6+ only accepts unix socket paths under /var/run/kea (exact string).
if !strings.Contains(out, `"socket-name": "/var/run/kea/`) {
t.Errorf("ctrl-agent socket-name must be under /var/run/kea, got: %s", out)
}
}
func TestEntrypointsHardenSocketDir(t *testing.T) {
// Kea 2.6+ rejects a socket dir "more relaxed than 750"; the emptyDir mount
// defaults to 0777, so the entrypoints must chmod it before exec'ing kea.
want := "chmod 0750 " + RunDir
if ep := EntrypointDHCP4(); !strings.Contains(ep, want) {
t.Errorf("dhcp4 entrypoint must %q, got:\n%s", want, ep)
}
if ep := EntrypointCtrlAgent(); !strings.Contains(ep, want) {
t.Errorf("ctrl-agent entrypoint must %q, got:\n%s", want, ep)
}
}
func TestControlSocketPathAllowedByKea(t *testing.T) {
if !strings.HasPrefix(CtrlSocketPath, "/var/run/kea/") {
t.Errorf("CtrlSocketPath %q must live under /var/run/kea (kea 2.6+ restriction)", CtrlSocketPath)
}
out, err := RenderDHCP4(referenceInput())
if err != nil {
t.Fatal(err)
}
if !strings.Contains(out, `"socket-name": "/var/run/kea/`) {
t.Errorf("dhcp4 control-socket must be under /var/run/kea, got: %s", out)
}
}
+5 -2
View File
@@ -10,8 +10,11 @@ const (
// ConfigDir is where projected config is mounted read-only.
ConfigDir = "/etc/kea-operator"
// RunDir is a shared emptyDir for the config copy and control socket.
RunDir = "/run/kea"
// RunDir is a shared emptyDir for the config copy and control socket. Kea
// 2.6+ restricts unix socket paths to its compiled runstatedir and rejects
// anything else by exact string ("supported path is '/var/run/kea'"), even
// though /var/run symlinks to /run, so this must be the literal /var/run/kea.
RunDir = "/var/run/kea"
// DHCP4ConfPath is the runtime kea-dhcp4 config.
DHCP4ConfPath = RunDir + "/kea-dhcp4.conf"