diff --git a/.github/assets/icon.svg b/.github/assets/icon.svg new file mode 100644 index 0000000..3873b19 --- /dev/null +++ b/.github/assets/icon.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/assets/logo.svg b/.github/assets/logo.svg new file mode 100644 index 0000000..0c9f7c3 --- /dev/null +++ b/.github/assets/logo.svg @@ -0,0 +1,5 @@ + + + Unbound + for Home Assistant + diff --git a/README.md b/README.md index d30fb6d..3e94d07 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,93 @@ -# TimInTech Home Assistant Apps +

+ Unbound for Home Assistant +

-Home Assistant app repository. +

Unbound for Home Assistant

-## Apps +

+ Recursive, caching and DNSSEC-validating DNS resolver as a Home Assistant app —
+ the private upstream for Pi-hole, without any third-party DNS provider. +

-### [Unbound](./unbound) +

+ CI + Version + Architectures: amd64, aarch64 + License: MIT +

-Recursive, DNSSEC-validating DNS resolver on `127.0.0.1:5335` — a local upstream for Pi-hole running on Home Assistant. -Supports `amd64` and `aarch64`. See the [documentation](./unbound/DOCS.md). +

+ Add this repository to your Home Assistant instance +

+ +## Why Unbound? + +Pi-hole filters DNS, but it still forwards every allowed query to an upstream resolver such as your ISP, Google or +Cloudflare — which then sees your complete query history. With this app, Pi-hole forwards to Unbound on the same +host instead, and Unbound resolves each name itself, starting at the root servers. + +- **No single upstream provider** receives all of your queries. +- **DNSSEC validation** rejects forged or manipulated answers. +- **Everything stays on your Home Assistant host** — no extra device, container host or VM. + +> Queries to the root, TLD and authoritative servers are unencrypted. Unbound removes the central upstream provider, +> but it does not hide DNS traffic from someone who can observe your internet connection. + +## Features + +- Recursive, caching resolver with prefetching of popular entries +- DNSSEC validation with an automatically maintained trust anchor (RFC 5011); ships both root keys KSK-2017 and KSK-2024 +- Listens **only on `127.0.0.1:5335`**: not reachable from the LAN, no conflict with DNS on port 53 or mDNS on port 5353 +- Runs as the unprivileged user `unbound` from the first command on, without any Linux capabilities +- Protection against DNS rebinding for private IPv4 and IPv6 ranges +- Zero configuration: install, start, point Pi-hole at it +- `amd64` and `aarch64` (e.g. Home Assistant Green/Yellow, Raspberry Pi 4/5, x86 mini PCs and VMs) +- Automatic patch releases when Unbound, OpenSSL or any other Alpine package in the image receives an update + +## How it works + +```mermaid +flowchart LR + clients["LAN clients"] -- "DNS, port 53" --> pihole["Pi-hole app
filtering"] + pihole -- "127.0.0.1:5335" --> unbound["Unbound app
recursion + DNSSEC"] + unbound -- "iterative queries" --> internet["Root, TLD and
authoritative servers"] +``` ## Installation -1. *Settings → Apps → App store → ⋮ → Repositories* -2. Add `https://github.com/TimInTech/ha-addon-unbound` -3. Install **Unbound**, start it, then set `127.0.0.1#5335` as the only upstream DNS server in Pi-hole. +1. Click the button above, or open *Settings → Apps → App store → ⋮ → Repositories* and add + `https://github.com/TimInTech/ha-addon-unbound`. +2. Install **Unbound** and start it. +3. In Pi-hole open *Settings → DNS*, disable all upstream servers and set the custom upstream `127.0.0.1#5335`. + Leave *Use DNSSEC* in Pi-hole disabled — Unbound already validates. + +The Pi-hole app must use the host network, for example +[casperklein's Pi-hole app](https://github.com/casperklein/homeassistant-addons/tree/master/pi-hole). +Do not combine Unbound with the DNSCrypt option of that app: its dnscrypt-proxy also listens on `127.0.0.1:5335`. + +Details, verification and limitations: **[documentation](unbound/DOCS.md)**. + +## Quality and maintenance + +| Area | What runs | +| --- | --- | +| **CI** (`ci.yml`) | App linter, ShellCheck, `amd64`/`aarch64` builds and `tests/smoke.sh --hardened` (resolution, DNSSEC, restart, unprivileged start with `--cap-drop ALL`) on every push to `main` and every pull request | +| **Package updates** (`package-updates.yml`) | Every Monday: rebuilds the image and compares the Alpine packages with [`unbound/apk-packages.txt`](unbound/apk-packages.txt). On a change, a read-only `check` job runs the smoke test, an `aarch64` build and the linter; only then does the `release` job, which runs no third-party actions, commit a patch release with changelog | +| **Dependabot** | Weekly pull requests for the Alpine base image and the GitHub Actions, which are pinned to commit SHAs | + +GitHub pauses scheduled workflows after 60 days without repository activity; re-enable *Package updates* in the +Actions tab if that happens. + +## Security + +Please report vulnerabilities privately, see [SECURITY.md](SECURITY.md). -## Maintenance +## Credits -- **CI** (`ci.yml`): app linter, ShellCheck, amd64/aarch64 builds and `tests/smoke.sh --hardened` - (resolution, DNSSEC, restart, unprivileged start) on every push to `main` and every pull request. -- **Package updates** (`package-updates.yml`, Mondays and on demand): rebuilds the image and compares the installed - Alpine packages with `unbound/apk-packages.txt`. On a change, a read-only `check` job runs the amd64 smoke test, - an aarch64 build with config check and the app linter; only then does the `release` job, which runs no - third-party actions, commit a patch release with changelog. -- **Dependabot**: weekly pull requests for the Alpine base image and the GitHub Actions, which are pinned to commit - SHAs. A new Alpine branch changes the package set, so the next package-update run releases it. -- GitHub pauses scheduled workflows after 60 days without repository activity; re-enable *Package updates* - in the Actions tab if that happens. +[Unbound](https://github.com/NLnetLabs/unbound) is developed by [NLnet Labs](https://www.nlnetlabs.nl/) and +licensed under the BSD 3-Clause license. This project packages it for Home Assistant and is not affiliated with +NLnet Labs or the Home Assistant project. ## License -MIT +The files in this repository are licensed under the [MIT License](LICENSE). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..3530caa --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,15 @@ +# Security policy + +## Supported versions + +Only the latest release of the Unbound app receives fixes. Updated Unbound and Alpine packages are picked up by the +weekly package-update workflow and published as a new patch release; install it from Home Assistant when offered. + +## Reporting a vulnerability + +Please do **not** open a public issue for security problems. + +- **This app** (Dockerfile, entry script, configuration, workflows): report privately via + [GitHub private vulnerability reporting](https://github.com/TimInTech/ha-addon-unbound/security/advisories/new). + Reports are handled on a best-effort basis; please include the app version and steps to reproduce. +- **Unbound itself**: report to NLnet Labs as described at . diff --git a/unbound/icon.png b/unbound/icon.png new file mode 100644 index 0000000..fed2ad2 Binary files /dev/null and b/unbound/icon.png differ diff --git a/unbound/logo.png b/unbound/logo.png new file mode 100644 index 0000000..12b7a55 Binary files /dev/null and b/unbound/logo.png differ