docs: solidify DOCKER_SOCK and ROOT_API_KEY usage

This commit is contained in:
Aarnav Tale 2024-05-22 12:43:42 -04:00
parent 694b22f205
commit c7e59b137c
No known key found for this signature in database
7 changed files with 68 additions and 23 deletions

View File

@ -1,4 +1,4 @@
API_KEY=abcdefghijklmnopqrstuvwxyz
ROOT_API_KEY=abcdefghijklmnopqrstuvwxyz
COOKIE_SECRET=abcdefghijklmnopqrstuvwxyz
DISABLE_API_KEY_LOGIN=true
HEADSCALE_CONTAINER=headscale

View File

@ -25,7 +25,8 @@ export interface HeadplaneContext {
}
docker?: {
sock: string
url: string
sock: boolean
container: string
}
@ -163,19 +164,48 @@ async function checkAcl(config?: HeadscaleConfig) {
}
async function checkDocker() {
const path = process.env.DOCKER_SOCK ?? '/var/run/docker.sock'
const path = process.env.DOCKER_SOCK ?? 'unix:///var/run/docker.sock'
let url: URL | undefined
try {
await access(path, constants.R_OK)
url = new URL(path)
} catch {
return
}
// The API is available as an HTTP endpoint
if (url.protocol === 'tcp:') {
url.protocol = 'http:'
}
// Check if the socket is accessible
if (url.protocol === 'unix:') {
try {
await access(path, constants.R_OK)
} catch {
return
}
}
if (url.protocol === 'http:') {
try {
await fetch(new URL('/v1.30/version', url).href)
} catch {
return
}
}
if (url.protocol !== 'http:' && url.protocol !== 'unix:') {
return
}
if (!process.env.HEADSCALE_CONTAINER) {
return
}
return {
sock: path,
url: url.href,
sock: url.protocol === 'unix:',
container: process.env.HEADSCALE_CONTAINER,
}
}

View File

@ -1,5 +1,3 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable no-constant-condition */
import { setTimeout } from 'node:timers/promises'
import { Client } from 'undici'
@ -13,9 +11,12 @@ export async function sighupHeadscale() {
return
}
const client = new Client('http://localhost', {
socketPath: context.docker.sock,
})
// Supports the DOCKER_SOCK environment variable
const client = context.docker.sock
? new Client('http://localhost', {
socketPath: context.docker.url,
})
: new Client(context.docker.url)
const response = await client.request({
method: 'POST',
@ -33,9 +34,12 @@ export async function restartHeadscale() {
return
}
const client = new Client('http://localhost', {
socketPath: context.docker.sock,
})
// Supports the DOCKER_SOCK environment variable
const client = context.docker.sock
? new Client('http://localhost', {
socketPath: context.docker.url,
})
: new Client(context.docker.url)
const response = await client.request({
method: 'POST',
@ -48,14 +52,15 @@ export async function restartHeadscale() {
// Wait for Headscale to restart before continuing
let attempts = 0
// eslint-disable-next-line
while (true) {
try {
// Acceptable blank because API_KEY is not required
await pull('v1/apikey', process.env.API_KEY ?? '')
// Acceptable blank because ROOT_API_KEY is not required
await pull('v1/apikey', context.oidc?.rootKey ?? '')
return
} catch (error) {
// This means the server is up but the API key is invalid
// This can happen if the user only uses API_KEY via cookies
// This can happen if the user only uses ROOT_API_KEY via cookies
if (error instanceof HeadscaleError && error.status === 401) {
break
}

View File

@ -151,8 +151,7 @@ export async function finishOidc(oidc: OidcConfig, req: Request) {
const keyResponse = await post<{ apiKey: string }>(
'v1/apikey',
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
process.env.API_KEY!,
oidc.rootKey,
{
expiration: expDate,
},

View File

@ -30,10 +30,14 @@ The ACL file path is read from the following sources in order of priority:
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.
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.
## Deployment
Requirements:
@ -85,7 +89,7 @@ services:
# 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
API_KEY: 'abcdefghijklmnopqrstuvwxyz'
ROOT_API_KEY: 'abcdefghijklmnopqrstuvwxyz'
```
> For a breakdown of each configuration variable, please refer to the [Configuration](/docs/Configuration.md) guide.

View File

@ -31,8 +31,7 @@ services:
COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz'
# These are all optional!
HEADSCALE_CONTAINER: 'headscale'
API_KEY: 'abcdefghijklmnopqrstuvwxyz'
ROOT_API_KEY: 'abcdefghijklmnopqrstuvwxyz'
OIDC_CLIENT_ID: 'headscale'
OIDC_ISSUER: 'https://sso.example.com'
OIDC_CLIENT_SECRET: 'super_secret_client_secret'

View File

@ -13,6 +13,14 @@ You can configure Headplane using environment variables.
- **`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`, not needed if you have `acl_policy_path` in your config).
#### Docker Integration
The Docker integration allows Headplane to manage the Headscale docker container.
You'll need to provide these variables if you want to use this feature.
Keep in mind that `DOCKER_SOCK` must start with a protocol (e.g., `unix://`).
Secure API is currently not supported.
- **`DOCKER_SOCK`**: The protocol and path to the Docker socket (default: `unix:///var/run/docker.sock`).
- **`HEADSCALE_CONTAINER`**: The name of the Headscale container (required for Docker integration).
### SSO/OpenID Connect
@ -23,7 +31,7 @@ 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.
- **`API_KEY`**: An API key used to issue new ones for sessions (keep expiry fairly long).
- **`ROOT_API_KEY`**: An API key used to issue new ones for sessions (keep expiry fairly long).
- **`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.