# Threshold Threshold provides simple and secure access to hosts and services. It is a community-maintained fork of HashiCorp Boundary Community Edition (CE). ## About this fork Threshold is a community fork of [HashiCorp Boundary Community Edition](https://github.com/hashicorp/boundary). HashiCorp (an IBM company) archived the upstream Boundary CE repository on 2026-10-09 and announced that no further CE releases, maintenance updates, bug fixes or security patches are planned. Threshold continues maintenance of the Community Edition code base so that existing self-managed deployments can keep receiving fixes. - Threshold is licensed under the [Business Source License 1.1](LICENSE), the same license as the upstream code. The original license text and all copyright headers are preserved. See [NOTICE](NOTICE) for attribution. - **Threshold is not affiliated with, endorsed by, or sponsored by HashiCorp or IBM.** "Boundary", "HashiCorp" and "HCP Boundary" are trademarks of their respective owners and are used here only to describe the origin of this project. - Upstream project: - This repository: ### Compatibility with Boundary CE This is the first phase of the rebrand and is designed to keep existing Boundary CE deployments working: - The command-line binary is now `threshold` (built from `cmd/threshold`). - The wire protocol, HTTP API paths (`/v1`), database schema, plugin protocol and configuration file format are unchanged. - The Go module path is `repo.anhonesthost.net/CyberCoveLLC/threshold` (with `/api` and `/sdk` submodules); protobuf code has been regenerated for it. - Release versions are still reported on the wire with the upstream `Boundary v` prefix so mixed clusters keep working. `Threshold v` is also accepted when parsing. ### Environment variable and path fallbacks Threshold prefers `THRESHOLD_*` environment variables, and transparently falls back to the legacy `BOUNDARY_*` name when the `THRESHOLD_*` variable is not set. For example `THRESHOLD_ADDR`, `THRESHOLD_TOKEN`, `THRESHOLD_SCOPE_ID`, `THRESHOLD_KEYRING_TYPE`, `THRESHOLD_TOKEN_NAME`, `THRESHOLD_CONNECT_*`, `THRESHOLD_SKIP_CACHE_DAEMON` and the other CLI and server variables are read first, then `BOUNDARY_ADDR`, `BOUNDARY_TOKEN`, and so on. A `THRESHOLD_*` variable that is set to a non-empty value always wins. Existing scripts and deployments that only set `BOUNDARY_*` variables do not need to change. Notes: - `env://VAR` references inside configuration files and flags (for example `url = "env://BOUNDARY_POSTGRES_URL"` or `url = "env://THRESHOLD_POSTGRES_URL"` as used by the bundled container config) name an environment variable literally and are not rewritten; keep using whichever variable name you export. - `threshold connect -exec` exports both `THRESHOLD_PROXIED_{PORT,IP,ADDR}` and the legacy `BOUNDARY_PROXIED_{PORT,IP,ADDR}` variables to the child process. - The container image entrypoint mirrors any `BOUNDARY_*` variables to the matching `THRESHOLD_*` variable when it is unset. Other fallbacks: | Item | New | Legacy fallback | |------|-----|-----------------| | Client cache directory | `~/.threshold` | `~/.boundary` is used if it exists and `~/.threshold` does not | | Keyring entry (macOS Keychain / Windows Credential Manager) | `Threshold Auth Token` | `HashiCorp Boundary Auth Token` is read if the new entry is not found, and removed on `threshold logout` | | Keyring prefix (`pass`, libsecret) | `Threshold` | `HashiCorp_Boundary` is read if the new entry is not found, and removed on `threshold logout` | Tokens are always written using the new names. ## Upgrading from Boundary Threshold is designed as an in-place replacement for HashiCorp Boundary CE: the same database, the same configuration files, and a binary that can still be invoked as `boundary`. ### Compatibility guarantees These are unchanged from upstream Boundary CE, so a mixed fleet of Boundary and Threshold controllers and workers interoperates, and you can upgrade (and roll back) one node at a time: - **Database schema**: the schema migrations are untouched and the `boundary_schema_version` table keeps its name. Threshold runs against an existing Boundary database as-is (`threshold database migrate` applies the same migrations Boundary would). - **Wire protocol**: protobuf packages, gRPC service names and the `/v1` HTTP API paths are unchanged (only Go import paths were renamed). Versions are still reported to peers with the `Boundary v` prefix. - **Plugin protocol**: the plugin magic cookie (`HASHICORP_BOUNDARY_PLUGIN` / `boundary-plugin`) is unchanged, so existing `boundary-plugin-*` binaries keep working. - **Configuration file format** (HCL) is unchanged. Do not run `database migrate` from a newer Threshold than your other nodes understand; as with Boundary, upgrade controllers before workers and follow the usual rolling-upgrade guidance for schema migrations. ### Linux packages (deb/rpm) 1. Back up `/etc/boundary.d` and take a database backup. 2. Install the Threshold package. Do not `purge` the old `boundary` package (removal is fine); purging runs its scripts, which may delete the `boundary` user that Threshold will reuse. Installing Threshold while the old package is still installed is supported. 3. The package scripts then, automatically: - **copy** `/etc/boundary.d` to `/etc/threshold.d` (`boundary.hcl` becomes `threshold.hcl`, `boundary.env` becomes `threshold.env`; subdirectories such as TLS material are copied as-is). Existing files in `/etc/threshold.d` are never overwritten and the originals are never modified or deleted; - keep reading `/etc/boundary.d/boundary.env` as a fallback environment file (`threshold.env` takes precedence), so `BOUNDARY_*` variables keep working; - reuse the existing `boundary` service user and group instead of creating a `threshold` user (through a managed systemd drop-in, `/etc/systemd/system/threshold.service.d/10-legacy-boundary-user.conf`), so ownership of your data, log and key directories keeps working; - if `boundary.service` was enabled and/or running, stop and disable it, enable `threshold.service`, and start it if the old service was running. If `threshold.service` fails to start, the old service is restored; - make `systemctl restart boundary` (and `status`, `stop`, ...) address `threshold.service` via a `boundary.service` alias symlink in `/etc/systemd/system`, and provide `/usr/bin/boundary` as a symlink to `threshold` if no such file exists. The `boundary` command prints a one-line deprecation notice to **stderr** only (silence it with `THRESHOLD_NO_DEPRECATION_NOTICE=1`); stdout, flags and exit codes are identical to `threshold`. 4. Verify: `systemctl status threshold`, `threshold version`. What is **not** migrated automatically: - Paths *inside* your configuration files are not rewritten. A config that refers to `/etc/boundary.d/...` or `/var/lib/boundary` keeps working because those locations are left in place; update them at your own pace. - A custom `/etc/systemd/system/boundary.service` unit (a regular file) is left alone and the legacy service is not touched; migrate it by hand. - If `/usr/bin/boundary` is still the old binary from the Boundary package, it is left alone. After removing the old package: `ln -s threshold /usr/bin/boundary`. - Distribution-specific package-manager behavior such as `--force-confnew` (dpkg) can replace `/etc/threshold.d` defaults; your originals remain in `/etc/boundary.d`. - Data directories, the database, KMS keys and the client cache are not moved (the client cache directory is covered by the table above). Rollback: stop `threshold.service`, remove the `boundary.service` alias symlink (`/etc/systemd/system/boundary.service`) and the drop-in, reinstall the old Boundary package, and `systemctl enable --now boundary`. Because the database schema is unchanged and `/etc/boundary.d` was never modified, nothing else needs to be restored. If you ran a Threshold release that applied schema migrations newer than your Boundary version, restore the database backup instead. ### Container image The image's configuration directory moved from `/boundary` to `/threshold` (default command: `threshold server -config /threshold/config.hcl`). For compatibility the image: - contains `/boundary` as a symlink to `/threshold`, so existing `-v "$(pwd)":/boundary/` mounts land in the right place; - falls back to `/boundary/config.hcl` (printing a deprecation warning) when `-config /boundary/config.hcl` is requested, or when the stock demo config is still in place and a config exists at `/boundary/config.hcl`; - accepts `boundary ...` as the command and `BOUNDARY_*` environment variables (mirrored to `THRESHOLD_*`). Plan to switch your mounts, `-config` arguments and environment variables to the `/threshold` and `THRESHOLD_*` names; the compatibility paths print warnings and may be removed in a future major release. ### Other installs (binary / zip) Replace the `boundary` binary with `threshold` (or keep the file name `boundary`, which behaves identically). Existing `BOUNDARY_*` variables, `~/.boundary` and stored credentials are picked up as described above. ### Development mode `threshold dev` creates the `ssh.threshold.dev` and `postgres.threshold.dev` aliases and, for compatibility, the legacy `ssh.boundary.dev` and `postgres.boundary.dev` aliases pointing at the same targets. ## Building ``` make build # builds bin/threshold (requires the embedded UI, see Makefile) make build-no-ui # builds bin/threshold without the embedded admin UI ``` The embedded admin UI is built from the upstream `boundary-ui` project and is not part of this repository. ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md).