From 33283754bab508b37a8994fd9132243d8fe34aeb Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Tue, 14 Jul 2026 11:54:04 +0200 Subject: [PATCH] feat(shelly-manager): ServiceAccount + RBAC for ESPHome firmware pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit shelly-manager will build+flash BLE proxies by spawning short-lived esphome Jobs (on the shelly-manager-iot macvlan → mDNS → OTA:3232) and streaming their logs. Give it a namespace-scoped identity to do so: - ServiceAccount shelly-manager + Role shelly-manager-firmware (jobs: create/get/list/watch/delete; pods: get/list/watch; pods/log: get) + RoleBinding. No cluster-wide, secret, or exec rights. - Wire serviceAccountName into the Deployment. - Sync esphome/shelly-ble-proxy.yaml logger to the lean level already OTA'd to the device (esp32_ble_client DEBUG, not VERBOSE) so the PVC stops filling; VERBOSE is now an on-demand diagnostic via the pipeline. Co-Authored-By: Claude Opus 4.8 --- esphome/shelly-ble-proxy.yaml | 9 +-- .../apps/home-assistant/kustomization.yaml | 1 + .../shelly-manager-deployment.yaml | 4 ++ .../shelly-manager-firmware-rbac.yaml | 55 +++++++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 kubernetes/apps/home-assistant/shelly-manager-firmware-rbac.yaml diff --git a/esphome/shelly-ble-proxy.yaml b/esphome/shelly-ble-proxy.yaml index 3a551b9d..e84c8923 100644 --- a/esphome/shelly-ble-proxy.yaml +++ b/esphome/shelly-ble-proxy.yaml @@ -27,13 +27,14 @@ esp32: framework: type: esp-idf # required for a stable bluetooth_proxy -# DEBUG globally, with the BLE stack turned up to VERBOSE so a GATT connection -# attempt logs its progress and failure reason (esp32_ble_client) — the detail -# shelly-manager needs to diagnose why provisioning a Shelly over BLE fails. +# Lean steady-state logging: DEBUG globally is enough to see a GATT connection +# attempt's outcome without the per-packet VERBOSE firehose that fills the PVC. +# Bump esp32_ble_client back to VERBOSE temporarily (via the flash pipeline) +# only when actively diagnosing a failed BLE provisioning. logger: level: DEBUG logs: - esp32_ble_client: VERBOSE + esp32_ble_client: DEBUG esp32_ble_tracker: DEBUG bluetooth_proxy: DEBUG diff --git a/kubernetes/apps/home-assistant/kustomization.yaml b/kubernetes/apps/home-assistant/kustomization.yaml index b860d591..ea26db67 100644 --- a/kubernetes/apps/home-assistant/kustomization.yaml +++ b/kubernetes/apps/home-assistant/kustomization.yaml @@ -21,6 +21,7 @@ resources: - mosquitto-evcc-credentials-externalsecret.yaml - shelly-manager-pvc.yaml - shelly-manager-network-attachment.yaml + - shelly-manager-firmware-rbac.yaml - shelly-ble-proxy-key-externalsecret.yaml - shelly-manager-deployment.yaml - shelly-manager-service.yaml diff --git a/kubernetes/apps/home-assistant/shelly-manager-deployment.yaml b/kubernetes/apps/home-assistant/shelly-manager-deployment.yaml index b98a0704..8dafaeda 100644 --- a/kubernetes/apps/home-assistant/shelly-manager-deployment.yaml +++ b/kubernetes/apps/home-assistant/shelly-manager-deployment.yaml @@ -43,6 +43,10 @@ spec: # keeps this pod off there (we never tolerate it), and the NAD's # `master: eth2` lines up with v30iot on every k8s-{1,2,3} worker. enableServiceLinks: false + # Grants shelly-manager the in-cluster identity used by the firmware + # pipeline to create esphome flash Jobs and stream their logs. RBAC is + # namespace-scoped to home-assistant (shelly-manager-firmware-rbac.yaml). + serviceAccountName: shelly-manager securityContext: seccompProfile: type: RuntimeDefault diff --git a/kubernetes/apps/home-assistant/shelly-manager-firmware-rbac.yaml b/kubernetes/apps/home-assistant/shelly-manager-firmware-rbac.yaml new file mode 100644 index 00000000..c08fc246 --- /dev/null +++ b/kubernetes/apps/home-assistant/shelly-manager-firmware-rbac.yaml @@ -0,0 +1,55 @@ +--- +# Identity + least-privilege RBAC for shelly-manager's ESPHome firmware +# pipeline. The app builds+flashes a BLE proxy by creating a short-lived +# esphome Job (attached to the shelly-manager-iot macvlan so it can mDNS- +# resolve .local and OTA over port 3232), then streams that Job's pod +# logs back to the UI. It also reads the esphome dashboard pod to co-locate +# the flash Job on the node holding the RWO esphome-data PVC. +# +# Scope is deliberately the home-assistant namespace only — no cluster-wide +# rights, no secret access, no exec. +apiVersion: v1 +kind: ServiceAccount +metadata: + name: shelly-manager + namespace: home-assistant + labels: + app.kubernetes.io/name: shelly-manager +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: shelly-manager-firmware + namespace: home-assistant + labels: + app.kubernetes.io/name: shelly-manager +rules: + # Create and manage the esphome flash Jobs the pipeline spawns. + - apiGroups: ["batch"] + resources: ["jobs"] + verbs: ["create", "get", "list", "watch", "delete"] + # Find the flash Job's pod (and the esphome dashboard pod, to pin the Job + # to the node that mounts the RWO esphome-data PVC). + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] + # Stream the flash Job's build+OTA output back to the UI. + - apiGroups: [""] + resources: ["pods/log"] + verbs: ["get"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: shelly-manager-firmware + namespace: home-assistant + labels: + app.kubernetes.io/name: shelly-manager +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: shelly-manager-firmware +subjects: + - kind: ServiceAccount + name: shelly-manager + namespace: home-assistant