diff --git a/README.md b/README.md index b2003bf..3eab1be 100644 --- a/README.md +++ b/README.md @@ -16,91 +16,8 @@ It's still very early in it's development, however these are some of the feature ## Deployment > The docker image is not available yet. For now you can build it locally with `docker build -t ghcr.io/tale/headplane:latest .` -In order to use Headplane, you need to be running the Headscale 0.23 alpha or later. -Currently I'd only recommend deploying this with Docker because environment variables are required. -Here's a very basic `docker-compose.yaml` file that utilizes each configuration variable. - -```yaml -version: '3.8' -services: - headscale: - image: 'headscale/headscale:0.23.0-alpha5' - container_name: 'headscale' - restart: 'unless-stopped' - command: 'serve' - volumes: - - './data:/var/lib/headscale' - - './configs:/etc/headscale' - ports: - - '8080:8080' - environment: - TZ: 'America/New_York' - headplane: - container_name: headplane - image: ghcr.io/tale/headplane:latest - restart: unless-stopped - volumes: - - './data:/var/lib/headscale' - - './configs:/etc/headscale' - ports: - - '3000:3000' - environment: - HEADSCALE_URL: 'http://headscale:8080' - API_KEY: 'abcdefghijklmnopqrstuvwxyz' - COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz' - HEADSCALE_CONTAINER: 'headscale' - OIDC_CLIENT_ID: 'headscale' - OIDC_ISSUER: 'https://sso.example.com' - OIDC_CLIENT_SECRET: 'super_secret_client_secret' - DISABLE_API_KEY_LOGIN: 'true' - HOST: '0.0.0.0' - PORT: '3000' -``` - -#### Required Variables - -- **`HEADSCALE_URL`**: The public URL of your Headscale server. -- **`API_KEY`**: An API key used to issue new ones for sessions (keep expiry fairly long). -- **`COOKIE_SECRET`**: A secret used to sign cookies (use a relatively long and random string). - -#### Optional Variables - -- **`HOST`**: The host to bind the server to (default: `0.0.0.0`). -- **`PORT`**: The port to bind the server to (default: `3000`). -- **`CONFIG_FILE`**: The path to the Headscale `config.yaml` (default: `/etc/headscale/config.yaml`). -- **`HEADSCALE_CONTAINER`**: The name of the Headscale container (for Docker integration). - -### SSO/OpenID Connect -If you want to use OpenID Connect for SSO, you'll need to provide these variables. -Headplane will utilize the expiry of your tokens to determine the expiry of the session. - -- **`OIDC_ISSUER`**: The issuer URL of your OIDC provider. -- **`OIDC_CLIENT_ID`**: The client ID of your OIDC provider. -- **`OIDC_CLIENT_SECRET`**: The client secret of your OIDC provider. -- **`DISABLE_API_KEY_LOGIN`**: If you want to disable API key login, set this to `true`. - -Here's what an example with Authelia would look like if you used the same client for both Headscale and Headplane. -Keep in mind that the recommended deployment would be putting Headplane behind /admin on a reverse proxy. -If you use a different domain than the Headscale server, you'll need to make sure that Headscale responds with CORS headers. - -```yaml -- client_id: 'headscale' - client_name: 'Headscale and Headplane' - public: false - authorization_policy: 'two_factor' - redirect_uris: - - 'https://headscale.example.com/oidc/callback' - - 'https://headscale.example.com/admin/oidc/callback' - scopes: - - 'openid' - - 'profile' - - 'email' - userinfo_signed_response_alg: 'none' - client_secret: 'my_super_secret_client_secret' -``` - -Instructions for deploying this will come soon. It will utilize Docker to support advanced features. -If you do want to fight with the environment variables right now, the image is `ghcr.io/tale/headplane:latest` +- If you run Headscale in a Docker container, see the [Advanced Deployment](./docs/Advanced-Integration.md) guide. +- If you run Headscale natively, see the [Basic Deployment](./docs/Basic-Integration.md) guide. ## Contributing If you would like to contribute, please install a relatively modern version of Node.js and PNPM. diff --git a/assets/advanced-preview.png b/assets/advanced-preview.png new file mode 100644 index 0000000..42985cc Binary files /dev/null and b/assets/advanced-preview.png differ diff --git a/docs/Advanced-Integration.md b/docs/Advanced-Integration.md new file mode 100644 index 0000000..ebd61d2 --- /dev/null +++ b/docs/Advanced-Integration.md @@ -0,0 +1,120 @@ +# Advanced Integration + +![Integration Preview](./assets/advanced-preview.png) + +With the advanced integration it's possible to control Access Control Lists (ACLs) and the Headscale configuration via the Headplane UI. +Every single aspect of this integration is optional, meaning you can only use what you want. +If you want to use this integration, you do not need Docker and you can make it work with Headscale and Headplane running natively. + +### Configuration Editing + +When the configuration file is available to Headplane, the `DNS` and `Settings` tabs will become functional. +Similar to the Tailscale UI, you'll be able to edit the configuration without needing to manually edit the file. +Headscale will read the file from the path given in the `CONFIG_FILE` environment variable. +By default this is set to `/etc/headscale/config.yaml`. + +> One important think to note is that environment variables always take priority over the configuration file. +> The `HEADSCALE_URL`, `OIDC_CLIENT_ID`, `OIDFC_ISSUER`, and `OIDC_CLIENT_SECRET` will be preferred over the configuration file if available. + +### Access Control Lists (ACLs) + +Headplane will enable the `Access Controls` tab if it is able to read an ACL file from Headscale.
+The ACL file path is read from the following sources in order of priority: + +- **Environment Variable**: If you set the `ACL_FILE` environment variable, Headplane will read the file from that path. +- **Configuration Integration**: If you've set this up, then Headplane will read the `acl_policy_path` key from the configuration file. + +### Docker Integration + +The Docker integration can be used to automatically reload the configuration or ACLs when they are changed. +In order for this to work, you'll need to pass in the `HEADSCALE_CONTAINER` environment variable. +You'll also need to ensure that `/var/run/docker.sock` is mounted if Headplane is running in a container. +This should be either the name or ID of the Headscale container (you can retrieve this using `docker ps`). +If the other integrations aren't setup, then Headplane will automatically disable the Docker integration. + +## Deployment + +Requirements: +- Headscale 0.23 alpha or later +- Headscale and Headplane need a Reverse Proxy (NGINX, Traefik, Caddy, etc) +- Headscale needs to be running in a docker container + +Here's a good Docker Compose example: +```yaml +version: '3.8' +services: + headscale: + image: 'headscale/headscale:0.23.0-alpha5' + container_name: 'headscale' + restart: 'unless-stopped' + command: 'serve' + volumes: + - './data:/var/lib/headscale' + - './configs:/etc/headscale' + ports: + - '8080:8080' + environment: + TZ: 'America/New_York' + headplane: + container_name: headplane + image: ghcr.io/tale/headplane:latest + restart: unless-stopped + volumes: + - './data:/var/lib/headscale' + - './configs:/etc/headscale' + - '/var/run/docker.sock:/var/run/docker.sock:ro' + ports: + - '3000:3000' + environment: + # These are always required for Headplane to work + COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz' + API_KEY: 'abcdefghijklmnopqrstuvwxyz' + + HEADSCALE_CONTAINER: 'headscale' + DISABLE_API_KEY_LOGIN: 'true' + HOST: '0.0.0.0' + PORT: '3000' + + # Overrides the configuration file values if they are set in config.yaml + # If you want to share the same OIDC configuration you do not need this + OIDC_CLIENT_ID: 'headscale' + OIDC_ISSUER: 'https://sso.example.com' + OIDC_CLIENT_SECRET: 'super_secret_client_secret' +``` + +> For a breakdown of each configuration variable, please refer to the [Configuration](./docs/Configuration.md) guide. +> It explains what each variable does, how to configure them, and what the default values are. + +You may also choose to run it natively with the distributed binaries on the releases page. +You'll need to manage running this yourself, and I would recommend making a `systemd` unit. + +## Configuration Scenarios + +Since the configuration is fairly modular you can have a variety of different setups.
+Here are a few examples to inspire you and show you what can work and what can't: + +#### Full Integration +Headscale runs in a container, Headplane can run in either a container or natively. +Headplane is able to manage the configuration file and ACLs that Headscale uses. +When changes happen, the Docker integration will automatically reload the configuration and ACLs. + +> Note that the full integration currently isn't possible if Headscale isn't running in a container. + +#### Configuration Only +Headscale and Headplane can either run in containers or natively. +Headplane is able to manage the configuration file and ACLs that Headscale uses. +When changes are made, Headscale will need to be manually restarted to apply the changes. + +#### ACL Only +Headscale and Headplane can either run in containers or natively. +Headplane is able to manage the ACLs that Headscale uses. +When changes are made, Headscale will need to be sent a `SIGHUP` to reload the ACLs. +In this scenario, Headplane does not have access to the configuration file. + +#### Read-Only Configuration or ACLs +If the configuration or ACLs are read-only, Headplane will not be able to manage them. +Instead you'll only be able to view the configurations on the UI and need to edit them manually. + +#### No Integration +If no integration is setup, Headplane will not be able to manage the configuration or ACLs. +This is the simplest setup by far, however it also heavily reduces the capabilities of Headplane. diff --git a/docs/Basic-Integration.md b/docs/Basic-Integration.md new file mode 100644 index 0000000..1908d20 --- /dev/null +++ b/docs/Basic-Integration.md @@ -0,0 +1,46 @@ +# Basic Integration + +The basic integration is not able to offer advanced features such as: +- Automatic management of Access Control Lists (ACLs) +- Management of DNS settings for your tailnet +- Management of the Headscale configuration + +In order to support these features please refer to the [Advanced Integration](./docs/Advanced-Integration.md) guide. +Note that in order to use this deployment strategy you need to run Headscale in a Docker container. + +## Deployment + +Requirements: +- Headscale 0.23 alpha or later +- Headscale and Headplane need a Reverse Proxy (NGINX, Traefik, Caddy, etc) + +Headplane is currently best run in a Docker container due to the easy configuration. +Here's a very basic `docker-compose.yaml` file that utilizes each configuration variable. + +```yaml +version: '3.8' +services: + headplane: + container_name: headplane + image: ghcr.io/tale/headplane:latest + restart: unless-stopped + ports: + - '3000:3000' + environment: + HEADSCALE_URL: 'http://headscale:8080' + API_KEY: 'abcdefghijklmnopqrstuvwxyz' + COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz' + HEADSCALE_CONTAINER: 'headscale' + OIDC_CLIENT_ID: 'headscale' + OIDC_ISSUER: 'https://sso.example.com' + OIDC_CLIENT_SECRET: 'super_secret_client_secret' + DISABLE_API_KEY_LOGIN: 'true' + HOST: '0.0.0.0' + PORT: '3000' +``` + +> For a breakdown of each configuration variable, please refer to the [Configuration](./docs/Configuration.md) guide. +> It explains what each variable does, how to configure them, and what the default values are. + +You may also choose to run it natively with the distributed binaries on the releases page. +You'll need to manage running this yourself, and I would recommend making a `systemd` unit. diff --git a/docs/Configuration.md b/docs/Configuration.md new file mode 100644 index 0000000..a9c0eee --- /dev/null +++ b/docs/Configuration.md @@ -0,0 +1,47 @@ +# Configuration + +You can configure Headplane using environment variables. + +#### Required Variables + +- **`HEADSCALE_URL`**: The public URL of your Headscale server. +- **`API_KEY`**: An API key used to issue new ones for sessions (keep expiry fairly long). +- **`COOKIE_SECRET`**: A secret used to sign cookies (use a relatively long and random string). + +#### Optional Variables + +- **`HOST`**: The host to bind the server to (default: `0.0.0.0`). +- **`PORT`**: The port to bind the server to (default: `3000`). +- **`CONFIG_FILE`**: The path to the Headscale `config.yaml` (default: `/etc/headscale/config.yaml`). +- **`ACL_FILE`**: The path to the ACL file (default: `/etc/headscale/acl_policy.json`). +- **`HEADSCALE_CONTAINER`**: The name of the Headscale container (required for Docker integration). + +### SSO/OpenID Connect +If you want to use OpenID Connect for SSO, you'll need to provide these variables. +Headplane will utilize the expiry of your tokens to determine the expiry of the session. +If you use the Headscale configuration integration, these are not required. + +- **`OIDC_ISSUER`**: The issuer URL of your OIDC provider. +- **`OIDC_CLIENT_ID`**: The client ID of your OIDC provider. +- **`OIDC_CLIENT_SECRET`**: The client secret of your OIDC provider. +- **`DISABLE_API_KEY_LOGIN`**: If you want to disable API key login, set this to `true`. + +Here's what an example with Authelia would look like if you used the same client for both Headscale and Headplane. +Keep in mind that the recommended deployment would be putting Headplane behind /admin on a reverse proxy. +If you use a different domain than the Headscale server, you'll need to make sure that Headscale responds with CORS headers. + +```yaml +- client_id: 'headscale' + client_name: 'Headscale and Headplane' + public: false + authorization_policy: 'two_factor' + redirect_uris: + - 'https://headscale.example.com/oidc/callback' + - 'https://headscale.example.com/admin/oidc/callback' + scopes: + - 'openid' + - 'profile' + - 'email' + userinfo_signed_response_alg: 'none' + client_secret: 'my_super_secret_client_secret' +```