Skip to content

Add IPMI sidecar for Home Assistant server power management#1010

Draft
Copilot wants to merge 5 commits intomainfrom
copilot/add-ipmi-sidecar-container
Draft

Add IPMI sidecar for Home Assistant server power management#1010
Copilot wants to merge 5 commits intomainfrom
copilot/add-ipmi-sidecar-container

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 30, 2026

Enables IPMI-based server power control from Home Assistant without requiring ipmitool in the HA container. Implements a lightweight sidecar that exposes IPMI operations via HTTP API.

Implementation

Sidecar Container (kubernetes/apps/base/home-assistant/ipmi-sidecar/)

  • Alpine-based Flask API (Python 3.12 + ipmitool)
  • RESTful endpoints: /power/{on,off,force-off,status,cycle,reset}
  • Non-root execution (UID 1000), 64Mi memory footprint
  • Docker build/test scripts and docker-compose for local validation

Kubernetes Integration

  • Added ipmi-sidecar container to Home Assistant StatefulSet
  • ClusterIP service on port 8080 (pod-local only)
  • SOPS-encrypted secret for BMC credentials and API key
  • Environment-based configuration (BMC_HOST, BMC_USER, BMC_PASSWORD, API_KEY)

Security

  • Constant-time API key comparison (secrets.compare_digest)
  • Command allowlist validation prevents injection attacks
  • Credentials redacted from logs
  • Exits on missing required environment variables

Usage

API accessible from HA container via localhost:

# Home Assistant configuration.yaml
rest_command:
  server_power_on:
    url: http://localhost:8080/power/on
    method: POST
    headers:
      X-API-Key: !secret ipmi_api_key

sensor:
  - platform: rest
    name: "Server Power Status"
    resource: http://localhost:8080/power/status
    headers:
      X-API-Key: !secret ipmi_api_key
    value_template: "{{ value_json.power_state }}"

Documentation

  • docs/ipmi-sidecar.md: Setup guide with HA configuration examples
  • kubernetes/apps/base/home-assistant/ipmi-sidecar/README.md: Component documentation
  • IMPLEMENTATION_SUMMARY.md: Architecture and deployment workflow

Deployment

  1. Build and push Docker image to registry
  2. Update release.yaml image repository reference
  3. Configure SOPS secret with BMC credentials
  4. Flux syncs changes automatically
Original prompt

Implement an "IPMI sidecar" approach alongside the existing Home Assistant (HASS) container deployment defined in the bancey/lab-ops repository.

Goals:

  • Add a lightweight sidecar container/service that contains ipmitool and can be used to power on/off/query a SuperMicro server via IPMI.
  • Ensure the sidecar can be triggered from Home Assistant running as a container (without needing to install ipmitool inside the HASS container).
  • The sidecar should expose a simple interface Home Assistant can call (preferably HTTP endpoint(s), or alternately a simple CLI entrypoint invoked via docker exec/ssh). Prefer an HTTP API that HA can call with rest_command / command_line.
  • Include secure handling of IPMI credentials (use environment variables and/or Docker secrets; do not hardcode credentials).
  • Update the repo’s deployment definitions to wire the sidecar to the existing HASS container (e.g., docker compose, k8s manifests, or whatever deployment mechanism the repo uses).
  • Provide example Home Assistant configuration snippets (e.g., rest_command, switch, automations) in repository docs so users can integrate the sidecar.

Implementation details:

  • Add a new service definition (e.g., ipmi-sidecar) in the same deployment stack as HASS.
  • The sidecar image can be built from a small base (alpine/debian slim) and include ipmitool.
  • Provide endpoints such as:
    • POST /power/on
    • POST /power/off
    • GET /power/status
    • Optionally POST /power/cycle
  • Authentication for the sidecar API: at minimum a shared token via header (e.g., X-API-Key) stored as a secret/environment variable.
  • Validate inputs (BMC host, user, password, optional cipher suite/lanplus) and return clear JSON responses.
  • Add healthcheck.

Repository notes:

  • All changes must be made in bancey/lab-ops.
  • Discover how HASS is currently deployed in this repo and integrate accordingly.

Deliverables:

  • New sidecar Dockerfile and source (if needed).
  • Updated deployment config to run sidecar and connect it to HASS.
  • Documentation updates describing setup and Home Assistant config examples.

No images provided.

This pull request was created from Copilot chat.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits January 30, 2026 12:12
Co-authored-by: bancey <23360105+bancey@users.noreply.github.com>
Co-authored-by: bancey <23360105+bancey@users.noreply.github.com>
@autonomous-bancey
Copy link
Copy Markdown
Contributor

Plan Result (prod_twingate)

No changes. Your infrastructure matches the configuration.

@autonomous-bancey
Copy link
Copy Markdown
Contributor

Plan Result (generate_ansible_inventory)

No changes. Your infrastructure matches the configuration.

@autonomous-bancey
Copy link
Copy Markdown
Contributor

Plan Result (test_vpn_gateway)

No changes. Your infrastructure matches the configuration.

@autonomous-bancey
Copy link
Copy Markdown
Contributor

Plan Result (prod_vpn_gateway)

No changes. Your infrastructure matches the configuration.

@autonomous-bancey
Copy link
Copy Markdown
Contributor

Plan Result (test_gameserver)

No changes. Your infrastructure matches the configuration.

@autonomous-bancey
Copy link
Copy Markdown
Contributor

Plan Result (prod_gameserver)

No changes. Your infrastructure matches the configuration.

Copilot AI and others added 2 commits January 30, 2026 12:18
Co-authored-by: bancey <23360105+bancey@users.noreply.github.com>
Co-authored-by: bancey <23360105+bancey@users.noreply.github.com>
Copilot AI changed the title [WIP] Add IPMI sidecar with lightweight service for Home Assistant Add IPMI sidecar for Home Assistant server power management Jan 30, 2026
Copilot AI requested a review from bancey January 30, 2026 12:22
@autonomous-bancey
Copy link
Copy Markdown
Contributor

Plan Result (tiny_virtual_machines)

No changes. Your infrastructure matches the configuration.

@autonomous-bancey
Copy link
Copy Markdown
Contributor

Plan Result (prod_dns)

Plan: 0 to add, 2 to change, 0 to destroy.
  • Update
    • module.adguard_gamora.adguard_config.config
    • module.adguard_thanos.adguard_config.config
Change Result (Click me)
  # module.adguard_gamora.adguard_config.config will be updated in-place
  ~ resource "adguard_config" "config" {
      ~ dns                             = {
          - allowed_clients            = [] -> null
          - disallowed_clients         = [] -> null
            # (26 unchanged attributes hidden)
        }
        id                              = "1"
      ~ last_updated                    = "Monday, 26-Jan-26 16:05:42 UTC" -> (known after apply)
      ~ tls                             = {
          ~ dns_names          = [] -> (known after apply)
          ~ issuer             = null -> (known after apply)
          ~ key_type           = null -> (known after apply)
          ~ not_after          = null -> (known after apply)
          ~ not_before         = null -> (known after apply)
          ~ private_key_saved  = false -> (known after apply)
          ~ subject            = null -> (known after apply)
          ~ valid_cert         = false -> (known after apply)
          ~ valid_chain        = false -> (known after apply)
          ~ valid_key          = false -> (known after apply)
          ~ valid_pair         = false -> (known after apply)
          ~ warning_validation = null -> (known after apply)
            # (9 unchanged attributes hidden)
        }
        # (8 unchanged attributes hidden)
    }

  # module.adguard_thanos.adguard_config.config will be updated in-place
  ~ resource "adguard_config" "config" {
      ~ dns                             = {
          - allowed_clients            = [] -> null
          - disallowed_clients         = [] -> null
            # (26 unchanged attributes hidden)
        }
        id                              = "1"
      ~ last_updated                    = "Monday, 26-Jan-26 16:05:39 UTC" -> (known after apply)
      ~ tls                             = {
          ~ dns_names          = [] -> (known after apply)
          ~ issuer             = null -> (known after apply)
          ~ key_type           = null -> (known after apply)
          ~ not_after          = null -> (known after apply)
          ~ not_before         = null -> (known after apply)
          ~ private_key_saved  = false -> (known after apply)
          ~ subject            = null -> (known after apply)
          ~ valid_cert         = false -> (known after apply)
          ~ valid_chain        = false -> (known after apply)
          ~ valid_key          = false -> (known after apply)
          ~ valid_pair         = false -> (known after apply)
          ~ warning_validation = null -> (known after apply)
            # (9 unchanged attributes hidden)
        }
        # (8 unchanged attributes hidden)
    }

Plan: 0 to add, 2 to change, 0 to destroy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants