From bda151f4e856d68cde27b9c7742f67c9ce65e21e Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Mon, 8 Jul 2024 14:31:53 -0400 Subject: [PATCH] chore: simplify documentation --- docs/Advanced-Integration.md | 156 ++++++--------------------------- docs/Basic-Integration.md | 38 ++++---- docs/integration/Docker.md | 86 ++++++++++++++++++ docs/integration/Kubernetes.md | 123 ++++++++++++++++++++++++++ docs/integration/Native.md | 28 ++++++ 5 files changed, 285 insertions(+), 146 deletions(-) create mode 100644 docs/integration/Docker.md create mode 100644 docs/integration/Kubernetes.md create mode 100644 docs/integration/Native.md diff --git a/docs/Advanced-Integration.md b/docs/Advanced-Integration.md index 09a110a..c25eb9b 100644 --- a/docs/Advanced-Integration.md +++ b/docs/Advanced-Integration.md @@ -1,5 +1,11 @@ # Advanced Integration +The advanced integration methods unlock the full capabilities of Headplane. +This is the closest you can get to the SaaS experience if you were paying for +Tailscale. + +### Configuration Management + -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. -Additionally, with an integration provider, you can automatically reload the configuration or ACLs when they are changed. +The advanced integration allows you to manage the Headscale configuration via +the Headplane UI. When the configuration is available for editing, the `DNS` +and `Settings` tabs will become available. When using the Docker or Kubernetes +integration, changes to the configuration file will be automatically applied +to Headscale. -## Configuration Editing +> By default, the configuration file is read from `/etc/headscale/config.yaml`. +This can be overridden by setting the `CONFIG_FILE` environment variable. Any +variables including `HEADSCALE_URL`, `OIDC_CLIENT_ID`, `OIDC_ISSUER`, and +`OIDC_CLIENT_SECRET` will take priority over the configuration file. -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) +### 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: +The advanced integration allows you to manage the ACLs via the Headplane UI. +When the ACL file is available for editing, the `Access Controls` tab will +become available. All of the integrations support automatic reloading of the +ACLs when the file is changed. -- **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. +> By default, the ACL file is read from `/etc/headscale/acl_policy.json`. This +can be overridden by setting the `ACL_FILE` environment variable and is also +overriden by the `acl_policy_path` key in the configuration file if set. -## Automatic Configuration Reload - -When the configuration file is changed, Headscale will need to be restarted to apply the changes. -Similarly, when the ACL file is changed, Headscale will need to be sent a `SIGHUP` signal to reload the ACLs. -Currently there are 2 integration providers that can do this for you: - -### Docker Integration - -To enable the Docker integration, set `HEADSCALE_INTEGRATION=docker` in the environment variables. -Additionally, you'll need to pass in the `HEADSCALE_CONTAINER` environment variable. -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. - -By default the integration will check for `/var/run/docker.sock`, however you can override this by -setting the `DOCKER_SOCK` environment variable if you use a different configuration than the default. -When setting `DOCKER_SOCK`, you'll need to include the protocol (e.g., `unix://` or `tcp://`). -Headplane currently does not support the HTTPS protocol for the Docker socket. - -#### Example Docker Deployment +## 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: - # This is always required for Headplane to work - COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz' +Currently there are 3 integration providers that can do this for you: +- [Docker Integration](/docs/integration/Docker.md) +- [Kubernetes Integration](/docs/integration/Kubernetes.md) +- [Native Linux Integration](/docs/integration/Native.md) - HEADSCALE_INTEGRATION: 'docker' - 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' - - # This NEEDS to be set with OIDC, regardless of what's in the config - # This needs to be a very long-lived (999 day) API key used to create - # shorter ones for OIDC and allow the OIDC functionality to work - ROOT_API_KEY: 'abcdefghijklmnopqrstuvwxyz' -``` - -> 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. - -### Native Linux Integration (Beta) - -The native integration for Linux relies on the `/proc` directory to locate the Headscale process. -To enable it, set the `HEADSCALE_INTEGRATION=proc` value in the environment variables. -Because of the way this integration works, it only supports automatically reloading ACLs. -It's still very experimental and may not work in all environments. - -## Configuration Scenarios - -Since the configuration is fairly modular you can have a variety of different setups. -This mostly applies to the Docker integration since the native integration isn't fully featured yet. -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 index 51858eb..c07cbf0 100644 --- a/docs/Basic-Integration.md +++ b/docs/Basic-Integration.md @@ -1,12 +1,17 @@ # 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 +The basic integration is the simplest way to get started with Headplane. +It's more of a preview and is heavily limited in the features it can offer +when compared to the [Advanced Integration](/docs/Advanced-Integration.md). -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. +> Note that the Advanced integration is the recommend way to run +Headplane in a production environment. + +## Limitations +- No automatic management of Access Control Lists (ACLs) +- No management of DNS settings for your tailnet +- No capability to edit the configuration +- Limited support for OIDC authentication ## Deployment @@ -14,11 +19,13 @@ 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. +Docker heavily simplifies the deployment process, but this process can be +adopted to run natively. Follow the first section of the deployment guide +in the [Native Integration](/docs/integration/Native.md#deployment) for a +bare-metal or virtual machine deployment. +Here is a simple Docker Compose deployment: ```yaml -version: '3.8' services: headplane: container_name: headplane @@ -42,12 +49,7 @@ services: 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. - -## ACL Configuration -If you would like to get the web ACL configuration working, you'll need to pass the `ACL_FILE` environment variable. -This should point to the path of the ACL file on the Headscale server (ie. `ACL_FILE=/etc/headscale/acl_policy.json`). +> 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. diff --git a/docs/integration/Docker.md b/docs/integration/Docker.md new file mode 100644 index 0000000..d7ceaa1 --- /dev/null +++ b/docs/integration/Docker.md @@ -0,0 +1,86 @@ +## Docker Integration + +The Docker integration allows you to run Headplane and Headscale separately +in a dockerized environment. It allows you to unlock full functionality such as +automatic reloading of ACLs, DNS management, and Headscale configuration +management. + +### Deployment + +> When running with the Docker integration, it's assumed that both Headscale and +Headplane will run as containers. If you are running Headscale natively, then +refer to the [Native Integration](/docs/integration/Native.md) guide. + +To enable the Docker integration, set the `HEADSCALE_INTEGRATION` environment +variable to `docker`. You'll also need to supply `HEADSCALE_CONTAINER` with the +name or ID of the Headscale container. + +By default Headplane uses `unix:///var/run/docker.sock` to connect to Docker. +This can be overridden by setting the `DOCKER_SOCK` environment variable. For +example, a remote socket would be `tcp://:2375`. When setting +the variable, you'll need to specify the protocol (`unix://` or `tcp://`). + +> The `DOCKER_SOCK` variable does not support the HTTPS protocol. + +To enable the Docker integration, set `HEADSCALE_INTEGRATION=docker` in the environment variables. +Additionally, you'll need to pass in the `HEADSCALE_CONTAINER` environment variable. +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. + +By default the integration will check for `/var/run/docker.sock`, however you can override this by +setting the `DOCKER_SOCK` environment variable if you use a different configuration than the default. +When setting `DOCKER_SOCK`, you'll need to include the protocol (e.g., `unix://` or `tcp://`). +Headplane currently does not support the HTTPS protocol for the Docker socket. + +Here's an example deployment using Docker Compose (recommended). Keep in mind +that you'll NEED to setup a reverse proxy and this is incomplete: +```yaml +services: + headscale: + image: 'headscale/headscale:0.23.0-alpha12' + 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: + # This is always required for Headplane to work + COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz' + + HEADSCALE_INTEGRATION: 'docker' + 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' + + # This NEEDS to be set with OIDC, regardless of what's in the config + # This needs to be a very long-lived (999 day) API key used to create + # shorter ones for OIDC and allow the OIDC functionality to work + ROOT_API_KEY: 'abcdefghijklmnopqrstuvwxyz' +``` + +> 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. diff --git a/docs/integration/Kubernetes.md b/docs/integration/Kubernetes.md new file mode 100644 index 0000000..1eec3c1 --- /dev/null +++ b/docs/integration/Kubernetes.md @@ -0,0 +1,123 @@ +## Kubernetes Integration + +The Kubernetes integration allows you to run Headplane and Headscale together +in a cluster. It allows you to unlock full functionality such as automatic +reloading of ACLs, DNS management, and Headscale configuration management. + +Currently there are a few limitations to the Kubernetes integration: +- Headplane and Headscale need to run in the same Pod and share the same + process space for the integration to work correctly due to a limitation in + the Kubernetes API. + +- The only supported methods of deploying the integration are through a + `Deployment` or `Pod` (more coming soon). You can still get around this with + the `HEADSCALE_INTEGRATION_UNSTRICT` variable, but it's not recommended. + +- The integration will assume that the Headscale container will always restart + because the integration relies on a system call that will exit the container. + +### Deployment + +In order to ensure Headplane can read Kubernetes resources, you'll need to +grant additional RBAC permissions to the default `ServiceAccount` in the +namespace. This can be done with the following: +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: headplane-agent + namespace: default # Adjust namespace as needed +rules: +- apiGroups: [''] + resources: ['pods'] + verbs: ['get', 'list'] +- apiGroups: ['apps'] + resources: ['deployments'] + verbs: ['get', 'list'] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: headplane-agent + namespace: default # Adjust namespace as needed +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: headplane-agent +subjects: +- kind: ServiceAccount + name: default # If you use a different service account, change this + namespace: default # Adjust namespace as needed +``` + +Keep in mind you'll need to make `PersistentVolumeClaim`s for the data and that +they need to be either `ReadWriteOnce` or `ReadWriteMany` depending on your +topology. Additionally, you can abstract environment variables and configuration +away into a `ConfigMap` or `Secret` for easier management. + +The important parts of this deployment are the `HEADSCALE_INTEGRATION` and +`DEPLOYMENT_NAME` environment variables. The `HEADSCALE_INTEGRATION` variable +should be set to `kubernetes` and the `DEPLOYMENT_NAME` variable should be set +to the name of the deployment (done using the Downward API below). + +A basic deployment of the integration would look like this. Keep in mind that +you are responsible for setting up a reverse-proxy via an `Ingress` or `Service` +otherwise Headplane will not work: +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: headplane + namespace: default # Adjust namespace as needed + labels: + app: headplane +spec: + replicas: 1 + selector: + matchLabels: + app: headplane + template: + metadata: + labels: + app: headplane + spec: + serviceAccountName: default + containers: + - name: headplane + image: ghcr.io/tale/headplane:latest + env: + - name: COOKIE_SECRET + value: 'abcdefghijklmnopqrstuvwxyz' + - name: HEADSCALE_INTEGRATION + value: 'kubernetes' + - name: DEPLOYMENT_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + volumeMounts: + - name: headscale-config + mountPath: /etc/headscale + + - name: headscale + image: headscale/headscale:0.23.0-alpha12 + command: ['serve'] + env: + - name: TZ + value: 'America/New_York' + volumeMounts: + - name: headscale-data + mountPath: /var/lib/headscale + - name: headscale-config + mountPath: /etc/headscale + + volumes: + - name: headscale-data + persistentVolumeClaim: + claimName: headscale-data + - name: headscale-config + persistentVolumeClaim: + claimName: headscale-config +``` + +> 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. diff --git a/docs/integration/Native.md b/docs/integration/Native.md new file mode 100644 index 0000000..06ef23b --- /dev/null +++ b/docs/integration/Native.md @@ -0,0 +1,28 @@ +## Native Integration + +The Native integration allows you to run both Headplane and Headscale on +bare-metal servers or virtual machines. This integration is best suited for +environments where Docker or Kubernetes are not available or not desired. + +Currently the Native integration only supports automatic reloading of ACLs. It +cannot handle configuration changes as killing the `headscale` process can lead +to undefined behavior or the service not restarting. + +### Deployment + +Follow the instructions to install Headscale from the +[Linux Installation Guide](https://headscale.net/running-headscale-linux/). As +of now, Headplane requires Node.js 20 to be installed on the system. Once you +are ready, clone the repository (`git clone https://github.com/tale/headplane`), +install dependencies (`npm install`), build the project (`npm run build`), and +start the server (`npm start`). + +> If you'd like, you can turn this into a `systemd` unit to manage the service. +> I plan to provide packages and unit files to make this easier in the future. + +When running Headplane, you'll need to set environment variables to configure +the application. The `HEADSCALE_INTEGRATION` variable should be set to `proc`. + +> 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.