fix: API_KEY is no longer required for login to work

This commit is contained in:
Aarnav Tale 2024-05-01 02:43:44 -04:00
parent a57e777a6b
commit a63f4e4d52
No known key found for this signature in database
8 changed files with 39 additions and 18 deletions

9
CHANGELOG.md Normal file
View File

@ -0,0 +1,9 @@
### 0.1.2 (May 1, 2024)
- Added support for renaming, expiring, removing, and managing the routes of a machine.
- Implemented an expiry check for machines which now reflect on the machine table.
- Fixed an issue where `HEADSCALE_CONTAINER` was needed to start even without the Docker integration.
- Removed the requirement for the root `API_KEY` unless OIDC was being used for authentication.
- Switched to [React Aria](https://react-spectrum.adobe.com/react-aria/) for better accessibility support.
- Cleaned up various different UI inconsistencies and copied components that could've been abstracted.
- Added a changelog for any new versions going forward.

View File

@ -33,14 +33,6 @@ export async function loader() {
throw new Error('The COOKIE_SECRET environment variable is required') throw new Error('The COOKIE_SECRET environment variable is required')
} }
if (!process.env.API_KEY) {
throw new Error('The API_KEY environment variable is required')
}
if (!process.env.HEADSCALE_CONTAINER) {
throw new Error('The HEADSCALE_CONTAINER environment variable is required')
}
// eslint-disable-next-line unicorn/no-null // eslint-disable-next-line unicorn/no-null
return null return null
} }

View File

@ -233,6 +233,7 @@ async function getOidcConfig() {
let issuer = process.env.OIDC_ISSUER let issuer = process.env.OIDC_ISSUER
let client = process.env.OIDC_CLIENT_ID let client = process.env.OIDC_CLIENT_ID
let secret = process.env.OIDC_CLIENT_SECRET let secret = process.env.OIDC_CLIENT_SECRET
const rootKey = process.env.API_KEY
if (!issuer || !client || !secret) { if (!issuer || !client || !secret) {
const config = await getConfig() const config = await getConfig()
@ -250,6 +251,10 @@ async function getOidcConfig() {
return return
} }
if (!rootKey) {
throw new Error('Cannot use OIDC without the root API_KEY variable set')
}
return { issuer, client, secret } return { issuer, client, secret }
} }

View File

@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
/* eslint-disable no-constant-condition */ /* eslint-disable no-constant-condition */
import { setTimeout } from 'node:timers/promises' import { setTimeout } from 'node:timers/promises'
@ -6,7 +6,7 @@ import { setTimeout } from 'node:timers/promises'
import { Client } from 'undici' import { Client } from 'undici'
import { getContext } from './config' import { getContext } from './config'
import { pull } from './headscale' import { HeadscaleError, pull } from './headscale'
export async function sighupHeadscale() { export async function sighupHeadscale() {
const context = await getContext() const context = await getContext()
@ -61,9 +61,16 @@ export async function restartHeadscale() {
let attempts = 0 let attempts = 0
while (true) { while (true) {
try { try {
await pull('v1/apikey', process.env.API_KEY!) // Acceptable blank because API_KEY is not required
await pull('v1/apikey', process.env.API_KEY ?? '')
return return
} catch { } 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
if (error instanceof HeadscaleError && error.status === 401) {
break
}
if (attempts > 10) { if (attempts > 10) {
throw new Error('Headscale did not restart in time') throw new Error('Headscale did not restart in time')
} }

View File

@ -12,7 +12,7 @@ export class HeadscaleError extends Error {
export class FatalError extends Error { export class FatalError extends Error {
constructor() { constructor() {
super('The Headscale server is not accessible or the API_KEY is invalid.') super('The Headscale server is not accessible or the supplied API key is invalid')
this.name = 'FatalError' this.name = 'FatalError'
} }
} }

View File

@ -68,9 +68,8 @@ services:
ports: ports:
- '3000:3000' - '3000:3000'
environment: environment:
# These are always required for Headplane to work # This is always required for Headplane to work
COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz' COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz'
API_KEY: 'abcdefghijklmnopqrstuvwxyz'
HEADSCALE_CONTAINER: 'headscale' HEADSCALE_CONTAINER: 'headscale'
DISABLE_API_KEY_LOGIN: 'true' DISABLE_API_KEY_LOGIN: 'true'
@ -82,6 +81,11 @@ services:
OIDC_CLIENT_ID: 'headscale' OIDC_CLIENT_ID: 'headscale'
OIDC_ISSUER: 'https://sso.example.com' OIDC_ISSUER: 'https://sso.example.com'
OIDC_CLIENT_SECRET: 'super_secret_client_secret' 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
API_KEY: 'abcdefghijklmnopqrstuvwxyz'
``` ```
> For a breakdown of each configuration variable, please refer to the [Configuration](/docs/Configuration.md) guide. > For a breakdown of each configuration variable, please refer to the [Configuration](/docs/Configuration.md) guide.

View File

@ -28,13 +28,17 @@ services:
- '3000:3000' - '3000:3000'
environment: environment:
HEADSCALE_URL: 'http://headscale:8080' HEADSCALE_URL: 'http://headscale:8080'
API_KEY: 'abcdefghijklmnopqrstuvwxyz'
COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz' COOKIE_SECRET: 'abcdefghijklmnopqrstuvwxyz'
# These are all optional!
HEADSCALE_CONTAINER: 'headscale' HEADSCALE_CONTAINER: 'headscale'
API_KEY: 'abcdefghijklmnopqrstuvwxyz'
OIDC_CLIENT_ID: 'headscale' OIDC_CLIENT_ID: 'headscale'
OIDC_ISSUER: 'https://sso.example.com' OIDC_ISSUER: 'https://sso.example.com'
OIDC_CLIENT_SECRET: 'super_secret_client_secret' OIDC_CLIENT_SECRET: 'super_secret_client_secret'
DISABLE_API_KEY_LOGIN: 'true' DISABLE_API_KEY_LOGIN: 'true'
# These are the default values
HOST: '0.0.0.0' HOST: '0.0.0.0'
PORT: '3000' PORT: '3000'
``` ```

View File

@ -4,9 +4,8 @@ You can configure Headplane using environment variables.
#### Required 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). - **`COOKIE_SECRET`**: A secret used to sign cookies (use a relatively long and random string).
- **`HEADSCALE_URL`**: The public URL of your Headscale server (not required if using the configuration file).
#### Optional Variables #### Optional Variables
@ -24,6 +23,7 @@ If you use the Headscale configuration integration, these are not required.
- **`OIDC_ISSUER`**: The issuer URL of your OIDC provider. - **`OIDC_ISSUER`**: The issuer URL of your OIDC provider.
- **`OIDC_CLIENT_ID`**: The client ID of your OIDC provider. - **`OIDC_CLIENT_ID`**: The client ID of your OIDC provider.
- **`OIDC_CLIENT_SECRET`**: The client secret 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).
- **`DISABLE_API_KEY_LOGIN`**: If you want to disable API key login, set this to `true`. - **`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. Here's what an example with Authelia would look like if you used the same client for both Headscale and Headplane.