feat(shelly-manager): ServiceAccount + RBAC for ESPHome firmware pipeline

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 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 11:54:04 +02:00
co-authored by Claude Opus 4.8
parent 07c93e4aa3
commit 33283754ba
4 changed files with 65 additions and 4 deletions
+5 -4
View File
@@ -27,13 +27,14 @@ esp32:
framework: framework:
type: esp-idf # required for a stable bluetooth_proxy type: esp-idf # required for a stable bluetooth_proxy
# DEBUG globally, with the BLE stack turned up to VERBOSE so a GATT connection # Lean steady-state logging: DEBUG globally is enough to see a GATT connection
# attempt logs its progress and failure reason (esp32_ble_client) — the detail # attempt's outcome without the per-packet VERBOSE firehose that fills the PVC.
# shelly-manager needs to diagnose why provisioning a Shelly over BLE fails. # Bump esp32_ble_client back to VERBOSE temporarily (via the flash pipeline)
# only when actively diagnosing a failed BLE provisioning.
logger: logger:
level: DEBUG level: DEBUG
logs: logs:
esp32_ble_client: VERBOSE esp32_ble_client: DEBUG
esp32_ble_tracker: DEBUG esp32_ble_tracker: DEBUG
bluetooth_proxy: DEBUG bluetooth_proxy: DEBUG
@@ -21,6 +21,7 @@ resources:
- mosquitto-evcc-credentials-externalsecret.yaml - mosquitto-evcc-credentials-externalsecret.yaml
- shelly-manager-pvc.yaml - shelly-manager-pvc.yaml
- shelly-manager-network-attachment.yaml - shelly-manager-network-attachment.yaml
- shelly-manager-firmware-rbac.yaml
- shelly-ble-proxy-key-externalsecret.yaml - shelly-ble-proxy-key-externalsecret.yaml
- shelly-manager-deployment.yaml - shelly-manager-deployment.yaml
- shelly-manager-service.yaml - shelly-manager-service.yaml
@@ -43,6 +43,10 @@ spec:
# keeps this pod off there (we never tolerate it), and the NAD's # 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. # `master: eth2` lines up with v30iot on every k8s-{1,2,3} worker.
enableServiceLinks: false 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: securityContext:
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
@@ -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 <name>.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