@kustodian/plugin-authelia 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +306 -0
- package/package.json +42 -0
- package/src/executor.ts +114 -0
- package/src/generator.ts +236 -0
- package/src/index.ts +36 -0
- package/src/plugin.ts +249 -0
- package/src/types.ts +181 -0
package/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# @kustodian/plugin-authelia
|
|
2
|
+
|
|
3
|
+
Authelia authentication provider plugin for Kustodian. This plugin enables integration with Authelia for authentication and authorization in your Kubernetes applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔐 **OIDC Client Generation** - Automatically generate Authelia OIDC client configurations
|
|
8
|
+
- 🛡️ **Access Control Rules** - Define access control rules for your applications
|
|
9
|
+
- 🔑 **Secret Management** - Generate and hash secrets for OIDC clients
|
|
10
|
+
- ✅ **Configuration Validation** - Validate Authelia configurations using the CLI
|
|
11
|
+
- 📝 **YAML Export** - Export configurations as Authelia-compatible YAML
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @kustodian/plugin-authelia
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
For full functionality, install the Authelia CLI:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# macOS
|
|
25
|
+
brew install authelia
|
|
26
|
+
|
|
27
|
+
# Linux
|
|
28
|
+
# See: https://www.authelia.com/integration/deployment/installation/
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Basic Plugin Setup
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { create_authelia_plugin } from '@kustodian/plugin-authelia';
|
|
37
|
+
|
|
38
|
+
const authelia_plugin = create_authelia_plugin({
|
|
39
|
+
domain: 'auth.example.com',
|
|
40
|
+
default_policy: 'two_factor',
|
|
41
|
+
auto_generate_secrets: true,
|
|
42
|
+
output_dir: './authelia-config',
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### CLI Commands
|
|
47
|
+
|
|
48
|
+
The plugin provides several CLI commands:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Check Authelia CLI availability
|
|
52
|
+
kustodian authelia check
|
|
53
|
+
|
|
54
|
+
# Generate a hashed password
|
|
55
|
+
kustodian authelia hash-password <password> [algorithm]
|
|
56
|
+
|
|
57
|
+
# Generate a random secret
|
|
58
|
+
kustodian authelia generate-secret [length]
|
|
59
|
+
|
|
60
|
+
# Generate OIDC client configuration
|
|
61
|
+
kustodian authelia generate-client <app-name> <redirect-uri>
|
|
62
|
+
|
|
63
|
+
# Validate Authelia configuration file
|
|
64
|
+
kustodian authelia validate-config <config-path>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Programmatic Usage
|
|
68
|
+
|
|
69
|
+
#### Generate OIDC Client Configuration
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { generate_oidc_client } from '@kustodian/plugin-authelia';
|
|
73
|
+
|
|
74
|
+
const auth_config = {
|
|
75
|
+
provider: 'oidc' as const,
|
|
76
|
+
app_name: 'grafana',
|
|
77
|
+
app_display_name: 'Grafana',
|
|
78
|
+
external_host: 'https://grafana.example.com',
|
|
79
|
+
oidc: {
|
|
80
|
+
client_id: 'grafana',
|
|
81
|
+
redirect_uris: ['https://grafana.example.com/login/generic_oauth'],
|
|
82
|
+
scopes: ['openid', 'profile', 'email', 'groups'],
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const options = {
|
|
87
|
+
domain: 'auth.example.com',
|
|
88
|
+
default_policy: 'two_factor' as const,
|
|
89
|
+
hash_algorithm: 'pbkdf2' as const,
|
|
90
|
+
auto_generate_secrets: true,
|
|
91
|
+
output_dir: './authelia-config',
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const result = generate_oidc_client(auth_config, options);
|
|
95
|
+
|
|
96
|
+
if (result.success) {
|
|
97
|
+
console.log('Generated client:', result.value);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### Generate Access Control Rules
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { generate_access_control_rules } from '@kustodian/plugin-authelia';
|
|
105
|
+
|
|
106
|
+
const auth_config = {
|
|
107
|
+
provider: 'proxy' as const,
|
|
108
|
+
app_name: 'my-app',
|
|
109
|
+
external_host: 'https://app.example.com',
|
|
110
|
+
proxy: {
|
|
111
|
+
external_host: 'https://app.example.com',
|
|
112
|
+
internal_host: 'http://app.svc.cluster.local:8080',
|
|
113
|
+
policy: 'two_factor' as const,
|
|
114
|
+
skip_path_regex: '^/api/health.*',
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const result = generate_access_control_rules(auth_config, options);
|
|
119
|
+
|
|
120
|
+
if (result.success) {
|
|
121
|
+
console.log('Generated rules:', result.value);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Generate Complete Authelia Configuration
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import {
|
|
129
|
+
generate_authelia_config,
|
|
130
|
+
config_to_yaml,
|
|
131
|
+
} from '@kustodian/plugin-authelia';
|
|
132
|
+
|
|
133
|
+
const auth_configs = [
|
|
134
|
+
{
|
|
135
|
+
provider: 'oidc' as const,
|
|
136
|
+
app_name: 'app1',
|
|
137
|
+
external_host: 'https://app1.example.com',
|
|
138
|
+
oidc: {
|
|
139
|
+
client_id: 'app1',
|
|
140
|
+
redirect_uris: ['https://app1.example.com/callback'],
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
provider: 'oidc' as const,
|
|
145
|
+
app_name: 'app2',
|
|
146
|
+
external_host: 'https://app2.example.com',
|
|
147
|
+
oidc: {
|
|
148
|
+
client_id: 'app2',
|
|
149
|
+
redirect_uris: ['https://app2.example.com/callback'],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
const config_result = generate_authelia_config(auth_configs, options);
|
|
155
|
+
|
|
156
|
+
if (config_result.success) {
|
|
157
|
+
const yaml_result = config_to_yaml(config_result.value);
|
|
158
|
+
if (yaml_result.success) {
|
|
159
|
+
console.log(yaml_result.value);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Configuration
|
|
165
|
+
|
|
166
|
+
### Plugin Options
|
|
167
|
+
|
|
168
|
+
| Option | Type | Default | Description |
|
|
169
|
+
| ----------------------- | --------------------------- | --------------------- | ---------------------------------------------- |
|
|
170
|
+
| `domain` | `string` | `undefined` | Authelia domain (e.g., auth.example.com) |
|
|
171
|
+
| `default_policy` | `AutheliaPolicyType` | `'two_factor'` | Default authorization policy |
|
|
172
|
+
| `hash_algorithm` | `'pbkdf2' \| 'argon2'` | `'pbkdf2'` | Secret hashing algorithm |
|
|
173
|
+
| `auto_generate_secrets` | `boolean` | `true` | Auto-generate client secrets |
|
|
174
|
+
| `output_dir` | `string` | `'./authelia-config'` | Output directory for generated configurations |
|
|
175
|
+
|
|
176
|
+
### Auth Provider Types
|
|
177
|
+
|
|
178
|
+
- **`oidc`** - OpenID Connect provider
|
|
179
|
+
- **`proxy`** - Forward authentication/proxy mode
|
|
180
|
+
- **`header`** - Header-based authentication
|
|
181
|
+
|
|
182
|
+
### Authorization Policies
|
|
183
|
+
|
|
184
|
+
- **`bypass`** - No authentication required
|
|
185
|
+
- **`one_factor`** - Single-factor authentication (username + password)
|
|
186
|
+
- **`two_factor`** - Two-factor authentication (MFA required)
|
|
187
|
+
- **`deny`** - Deny all access
|
|
188
|
+
|
|
189
|
+
## Examples
|
|
190
|
+
|
|
191
|
+
### Example 1: Grafana with OIDC
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
const grafana_config = {
|
|
195
|
+
provider: 'oidc' as const,
|
|
196
|
+
app_name: 'grafana',
|
|
197
|
+
app_display_name: 'Grafana',
|
|
198
|
+
app_description: 'Monitoring and observability platform',
|
|
199
|
+
app_launch_url: 'https://grafana.example.com',
|
|
200
|
+
external_host: 'https://grafana.example.com',
|
|
201
|
+
oidc: {
|
|
202
|
+
client_id: 'grafana',
|
|
203
|
+
redirect_uris: ['https://grafana.example.com/login/generic_oauth'],
|
|
204
|
+
scopes: ['openid', 'profile', 'email', 'groups'],
|
|
205
|
+
authorization_policy: 'two_factor' as const,
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Example 2: Forward Auth for Internal App
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const internal_app_config = {
|
|
214
|
+
provider: 'proxy' as const,
|
|
215
|
+
app_name: 'internal-tool',
|
|
216
|
+
app_display_name: 'Internal Tool',
|
|
217
|
+
external_host: 'https://internal.example.com',
|
|
218
|
+
proxy: {
|
|
219
|
+
external_host: 'https://internal.example.com',
|
|
220
|
+
internal_host: 'http://internal-tool.default.svc.cluster.local:80',
|
|
221
|
+
policy: 'two_factor' as const,
|
|
222
|
+
skip_path_regex: '^/(health|metrics)$',
|
|
223
|
+
networks: ['10.0.0.0/8'], // Only allow from internal network
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Example 3: Public App with Bypass
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const public_app_config = {
|
|
232
|
+
provider: 'proxy' as const,
|
|
233
|
+
app_name: 'public-site',
|
|
234
|
+
external_host: 'https://public.example.com',
|
|
235
|
+
proxy: {
|
|
236
|
+
external_host: 'https://public.example.com',
|
|
237
|
+
internal_host: 'http://public-site.default.svc.cluster.local:80',
|
|
238
|
+
policy: 'bypass' as const, // No authentication required
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Integration with Kustodian
|
|
244
|
+
|
|
245
|
+
The plugin integrates with Kustodian's template system through hooks:
|
|
246
|
+
|
|
247
|
+
1. **`generator:after_resolve`** - Extracts auth configurations from templates
|
|
248
|
+
2. **`generator:before`** - Injects generated Authelia configurations
|
|
249
|
+
|
|
250
|
+
### Template Integration (Future)
|
|
251
|
+
|
|
252
|
+
```yaml
|
|
253
|
+
# Future feature - not yet implemented
|
|
254
|
+
apiVersion: kustodian.io/v1
|
|
255
|
+
kind: Template
|
|
256
|
+
metadata:
|
|
257
|
+
name: grafana
|
|
258
|
+
spec:
|
|
259
|
+
kustomizations:
|
|
260
|
+
- name: grafana
|
|
261
|
+
path: grafana
|
|
262
|
+
auth:
|
|
263
|
+
provider: oidc
|
|
264
|
+
app_name: grafana
|
|
265
|
+
app_display_name: Grafana
|
|
266
|
+
oidc:
|
|
267
|
+
redirect_uris:
|
|
268
|
+
- https://grafana.${cluster_domain}/login/generic_oauth
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Development
|
|
272
|
+
|
|
273
|
+
### Running Tests
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
cd plugins/authelia
|
|
277
|
+
bun test
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Type Checking
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
pnpm run typecheck
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## API Reference
|
|
287
|
+
|
|
288
|
+
See the [TypeScript types](./src/types.ts) for complete API documentation.
|
|
289
|
+
|
|
290
|
+
## Related Documentation
|
|
291
|
+
|
|
292
|
+
- [Authelia Documentation](https://www.authelia.com/)
|
|
293
|
+
- [Authelia Access Control](https://www.authelia.com/configuration/security/access-control/)
|
|
294
|
+
- [Authelia OIDC](https://www.authelia.com/configuration/identity-providers/openid-connect/)
|
|
295
|
+
|
|
296
|
+
## License
|
|
297
|
+
|
|
298
|
+
MIT
|
|
299
|
+
|
|
300
|
+
## Sources
|
|
301
|
+
|
|
302
|
+
This plugin was implemented using the official Authelia documentation:
|
|
303
|
+
|
|
304
|
+
- [Access Control Configuration](https://www.authelia.com/configuration/security/access-control/)
|
|
305
|
+
- [OIDC Clients Configuration](https://www.authelia.com/configuration/identity-providers/openid-connect/clients.md)
|
|
306
|
+
- [Authelia GitHub Repository](https://github.com/authelia/authelia)
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kustodian/plugin-authelia",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Authelia authentication provider plugin for Kustodian",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./src/index.ts",
|
|
11
|
+
"import": "./src/index.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": ["src"],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "bun test",
|
|
17
|
+
"test:watch": "bun test --watch",
|
|
18
|
+
"typecheck": "bun run tsc --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"keywords": ["kustodian", "plugin", "authelia", "authentication", "oidc", "kubernetes"],
|
|
21
|
+
"author": "Luca Silverentand <luca@onezero.company>",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/lucasilverentand/kustodian.git",
|
|
26
|
+
"directory": "plugins/authelia"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"registry": "https://npm.pkg.github.com"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@kustodian/core": "^1.1.0",
|
|
33
|
+
"@kustodian/plugins": "^1.0.1",
|
|
34
|
+
"@kustodian/schema": "^1.2.0",
|
|
35
|
+
"js-yaml": "^4.1.1",
|
|
36
|
+
"zod": "^4.3.5"
|
|
37
|
+
},
|
|
38
|
+
"packageManager": "pnpm@10.19.0",
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/js-yaml": "^4.0.9"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/executor.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { exec } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { type KustodianErrorType, type ResultType, create_error, success } from '@kustodian/core';
|
|
4
|
+
|
|
5
|
+
const exec_async = promisify(exec);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Check if authelia CLI is available
|
|
9
|
+
*/
|
|
10
|
+
export async function check_authelia_available(): Promise<ResultType<string, KustodianErrorType>> {
|
|
11
|
+
try {
|
|
12
|
+
const { stdout } = await exec_async('authelia --version', { timeout: 5000 });
|
|
13
|
+
const version = stdout.trim();
|
|
14
|
+
return success(version);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
return {
|
|
17
|
+
success: false,
|
|
18
|
+
error: create_error(
|
|
19
|
+
'AUTHELIA_CLI_NOT_FOUND',
|
|
20
|
+
'Authelia CLI not found. Install from: https://www.authelia.com/integration/deployment/installation/',
|
|
21
|
+
error,
|
|
22
|
+
),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generate a hashed password using Authelia CLI
|
|
29
|
+
* @param password - Plain text password to hash
|
|
30
|
+
* @param algorithm - Hashing algorithm (pbkdf2 or argon2)
|
|
31
|
+
*/
|
|
32
|
+
export async function hash_password(
|
|
33
|
+
password: string,
|
|
34
|
+
algorithm: 'pbkdf2' | 'argon2' = 'pbkdf2',
|
|
35
|
+
): Promise<ResultType<string, KustodianErrorType>> {
|
|
36
|
+
try {
|
|
37
|
+
const cmd =
|
|
38
|
+
algorithm === 'argon2'
|
|
39
|
+
? `authelia crypto hash generate argon2 --password '${password}'`
|
|
40
|
+
: `authelia crypto hash generate pbkdf2 --password '${password}'`;
|
|
41
|
+
|
|
42
|
+
const { stdout } = await exec_async(cmd, { timeout: 10000 });
|
|
43
|
+
|
|
44
|
+
// Extract the hash from output (format: "Digest: $hash...")
|
|
45
|
+
const hash_match = stdout.match(/Digest: (.+)/);
|
|
46
|
+
if (!hash_match?.[1]) {
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
error: create_error(
|
|
50
|
+
'AUTHELIA_HASH_GENERATION_FAILED',
|
|
51
|
+
'Failed to extract hash from authelia output',
|
|
52
|
+
),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return success(hash_match[1].trim());
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
error: create_error(
|
|
61
|
+
'AUTHELIA_HASH_GENERATION_FAILED',
|
|
62
|
+
`Failed to hash password: ${error instanceof Error ? error.message : String(error)}`,
|
|
63
|
+
error,
|
|
64
|
+
),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Generate a random secret suitable for OIDC client secrets
|
|
71
|
+
*/
|
|
72
|
+
export async function generate_random_secret(
|
|
73
|
+
length = 64,
|
|
74
|
+
): Promise<ResultType<string, KustodianErrorType>> {
|
|
75
|
+
try {
|
|
76
|
+
const { stdout } = await exec_async(
|
|
77
|
+
`authelia crypto rand --length ${length} --charset alphanumeric`,
|
|
78
|
+
{
|
|
79
|
+
timeout: 5000,
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
return success(stdout.trim());
|
|
83
|
+
} catch (error) {
|
|
84
|
+
return {
|
|
85
|
+
success: false,
|
|
86
|
+
error: create_error(
|
|
87
|
+
'AUTHELIA_SECRET_GENERATION_FAILED',
|
|
88
|
+
`Failed to generate random secret: ${error instanceof Error ? error.message : String(error)}`,
|
|
89
|
+
error,
|
|
90
|
+
),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Validate access control configuration using Authelia CLI
|
|
97
|
+
*/
|
|
98
|
+
export async function validate_access_control(
|
|
99
|
+
config_path: string,
|
|
100
|
+
): Promise<ResultType<boolean, KustodianErrorType>> {
|
|
101
|
+
try {
|
|
102
|
+
await exec_async(`authelia validate-config ${config_path}`, { timeout: 10000 });
|
|
103
|
+
return success(true);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
error: create_error(
|
|
108
|
+
'AUTHELIA_CONFIG_VALIDATION_FAILED',
|
|
109
|
+
`Configuration validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
110
|
+
error,
|
|
111
|
+
),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
package/src/generator.ts
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type KustodianErrorType,
|
|
3
|
+
type ResultType,
|
|
4
|
+
create_error,
|
|
5
|
+
failure,
|
|
6
|
+
success,
|
|
7
|
+
} from '@kustodian/core';
|
|
8
|
+
import * as yaml from 'js-yaml';
|
|
9
|
+
import type {
|
|
10
|
+
AccessControlRuleType,
|
|
11
|
+
AuthConfigType,
|
|
12
|
+
AutheliaConfigType,
|
|
13
|
+
AutheliaPluginOptionsType,
|
|
14
|
+
OIDCClientConfigType,
|
|
15
|
+
} from './types.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Generates an OIDC client configuration from auth config
|
|
19
|
+
*/
|
|
20
|
+
export function generate_oidc_client(
|
|
21
|
+
auth_config: AuthConfigType,
|
|
22
|
+
options: AutheliaPluginOptionsType,
|
|
23
|
+
): ResultType<OIDCClientConfigType, KustodianErrorType> {
|
|
24
|
+
try {
|
|
25
|
+
const client_id = auth_config.app_name;
|
|
26
|
+
|
|
27
|
+
// Build base client config
|
|
28
|
+
const client: OIDCClientConfigType = {
|
|
29
|
+
client_id,
|
|
30
|
+
client_name: auth_config.app_display_name ?? auth_config.app_name,
|
|
31
|
+
public: auth_config.oidc?.public ?? false,
|
|
32
|
+
authorization_policy: auth_config.oidc?.authorization_policy ?? options.default_policy,
|
|
33
|
+
require_pkce: auth_config.oidc?.require_pkce ?? true,
|
|
34
|
+
pkce_challenge_method: auth_config.oidc?.pkce_challenge_method ?? 'S256',
|
|
35
|
+
redirect_uris: auth_config.oidc?.redirect_uris ?? [],
|
|
36
|
+
scopes: auth_config.oidc?.scopes ?? ['openid', 'profile', 'email', 'groups'],
|
|
37
|
+
response_types: auth_config.oidc?.response_types ?? ['code'],
|
|
38
|
+
grant_types: auth_config.oidc?.grant_types ?? ['authorization_code'],
|
|
39
|
+
token_endpoint_auth_method:
|
|
40
|
+
auth_config.oidc?.token_endpoint_auth_method ?? 'client_secret_basic',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Add client secret if not public and auto-generation is enabled
|
|
44
|
+
if (!client.public && options.auto_generate_secrets) {
|
|
45
|
+
// In production, this should generate a proper hashed secret
|
|
46
|
+
// For now, we'll add a placeholder that users must replace
|
|
47
|
+
client.client_secret = `\${${client_id.toUpperCase().replace(/-/g, '_')}_CLIENT_SECRET}`;
|
|
48
|
+
} else if (auth_config.oidc?.client_secret) {
|
|
49
|
+
client.client_secret = auth_config.oidc.client_secret;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Add optional fields
|
|
53
|
+
if (auth_config.oidc?.consent_mode) {
|
|
54
|
+
client.consent_mode = auth_config.oidc.consent_mode;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (auth_config.oidc?.pre_configured_consent_duration) {
|
|
58
|
+
client.pre_configured_consent_duration = auth_config.oidc.pre_configured_consent_duration;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (auth_config.oidc?.audience) {
|
|
62
|
+
client.audience = auth_config.oidc.audience;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Merge additional options
|
|
66
|
+
if (auth_config.oidc?.additional_options) {
|
|
67
|
+
Object.assign(client, auth_config.oidc.additional_options);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return success(client);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
return failure(
|
|
73
|
+
create_error(
|
|
74
|
+
'AUTHELIA_CLIENT_GENERATION_FAILED',
|
|
75
|
+
`Failed to generate OIDC client: ${error instanceof Error ? error.message : String(error)}`,
|
|
76
|
+
),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Generates access control rules from auth config
|
|
83
|
+
*/
|
|
84
|
+
export function generate_access_control_rules(
|
|
85
|
+
auth_config: AuthConfigType,
|
|
86
|
+
_options: AutheliaPluginOptionsType,
|
|
87
|
+
): ResultType<AccessControlRuleType[], KustodianErrorType> {
|
|
88
|
+
try {
|
|
89
|
+
const rules: AccessControlRuleType[] = [];
|
|
90
|
+
|
|
91
|
+
// Add custom access control rules if provided
|
|
92
|
+
if (auth_config.access_control) {
|
|
93
|
+
rules.push(...auth_config.access_control);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Generate proxy/forward auth rules
|
|
97
|
+
if (auth_config.provider === 'proxy' && auth_config.external_host) {
|
|
98
|
+
const domain = new URL(auth_config.external_host).hostname;
|
|
99
|
+
const rule: AccessControlRuleType = {
|
|
100
|
+
domain,
|
|
101
|
+
policy: auth_config.proxy?.policy ?? 'two_factor',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Add networks if specified
|
|
105
|
+
if (auth_config.proxy?.networks) {
|
|
106
|
+
rule.networks = auth_config.proxy.networks;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Add subject if specified
|
|
110
|
+
if (auth_config.proxy?.subject) {
|
|
111
|
+
rule.subject = auth_config.proxy.subject;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Add resource patterns if skip_path_regex is specified
|
|
115
|
+
if (auth_config.proxy?.skip_path_regex) {
|
|
116
|
+
// Create a bypass rule for skipped paths
|
|
117
|
+
rules.push({
|
|
118
|
+
domain,
|
|
119
|
+
policy: 'bypass',
|
|
120
|
+
resources: [auth_config.proxy.skip_path_regex],
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
rules.push(rule);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Generate OIDC access control rules
|
|
128
|
+
if (auth_config.provider === 'oidc' && auth_config.external_host) {
|
|
129
|
+
const domain = new URL(auth_config.external_host).hostname;
|
|
130
|
+
rules.push({
|
|
131
|
+
domain,
|
|
132
|
+
policy: auth_config.oidc?.authorization_policy ?? 'two_factor',
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return success(rules);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
return failure(
|
|
139
|
+
create_error(
|
|
140
|
+
'AUTHELIA_ACCESS_CONTROL_GENERATION_FAILED',
|
|
141
|
+
`Failed to generate access control rules: ${error instanceof Error ? error.message : String(error)}`,
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Generates complete Authelia configuration from multiple auth configs
|
|
149
|
+
*/
|
|
150
|
+
export function generate_authelia_config(
|
|
151
|
+
auth_configs: AuthConfigType[],
|
|
152
|
+
options: AutheliaPluginOptionsType,
|
|
153
|
+
): ResultType<AutheliaConfigType, KustodianErrorType> {
|
|
154
|
+
try {
|
|
155
|
+
const config: AutheliaConfigType = {
|
|
156
|
+
identity_providers: {
|
|
157
|
+
oidc: {
|
|
158
|
+
clients: [],
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
access_control: {
|
|
162
|
+
default_policy: options.default_policy,
|
|
163
|
+
rules: [],
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// Generate OIDC clients and access control rules
|
|
168
|
+
for (const auth_config of auth_configs) {
|
|
169
|
+
// Generate OIDC client if provider is OIDC
|
|
170
|
+
if (auth_config.provider === 'oidc') {
|
|
171
|
+
const client_result = generate_oidc_client(auth_config, options);
|
|
172
|
+
if (!client_result.success) {
|
|
173
|
+
return client_result;
|
|
174
|
+
}
|
|
175
|
+
config.identity_providers?.oidc?.clients?.push(client_result.value);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Generate access control rules
|
|
179
|
+
const rules_result = generate_access_control_rules(auth_config, options);
|
|
180
|
+
if (!rules_result.success) {
|
|
181
|
+
return rules_result;
|
|
182
|
+
}
|
|
183
|
+
config.access_control?.rules?.push(...rules_result.value);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return success(config);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
return failure(
|
|
189
|
+
create_error(
|
|
190
|
+
'AUTHELIA_CONFIG_GENERATION_FAILED',
|
|
191
|
+
`Failed to generate Authelia configuration: ${error instanceof Error ? error.message : String(error)}`,
|
|
192
|
+
),
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Converts Authelia configuration to YAML string
|
|
199
|
+
*/
|
|
200
|
+
export function config_to_yaml(config: AutheliaConfigType): ResultType<string, KustodianErrorType> {
|
|
201
|
+
try {
|
|
202
|
+
const yaml_output = yaml.dump(config, {
|
|
203
|
+
indent: 2,
|
|
204
|
+
lineWidth: 120,
|
|
205
|
+
noRefs: true,
|
|
206
|
+
sortKeys: false,
|
|
207
|
+
});
|
|
208
|
+
return success(yaml_output);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
return failure(
|
|
211
|
+
create_error(
|
|
212
|
+
'AUTHELIA_YAML_SERIALIZATION_FAILED',
|
|
213
|
+
`Failed to convert config to YAML: ${error instanceof Error ? error.message : String(error)}`,
|
|
214
|
+
),
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Parses YAML string to Authelia configuration
|
|
221
|
+
*/
|
|
222
|
+
export function yaml_to_config(
|
|
223
|
+
yaml_string: string,
|
|
224
|
+
): ResultType<AutheliaConfigType, KustodianErrorType> {
|
|
225
|
+
try {
|
|
226
|
+
const config = yaml.load(yaml_string) as AutheliaConfigType;
|
|
227
|
+
return success(config);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
return failure(
|
|
230
|
+
create_error(
|
|
231
|
+
'AUTHELIA_YAML_PARSING_FAILED',
|
|
232
|
+
`Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`,
|
|
233
|
+
),
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authelia authentication provider plugin for Kustodian
|
|
3
|
+
*
|
|
4
|
+
* This plugin enables integration with Authelia for authentication and authorization.
|
|
5
|
+
* It can generate OIDC client configurations, access control rules, and manage
|
|
6
|
+
* authentication requirements for deployed applications.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export { create_authelia_plugin, plugin as default } from './plugin.js';
|
|
12
|
+
export type {
|
|
13
|
+
AuthConfigType,
|
|
14
|
+
AuthProviderType,
|
|
15
|
+
AutheliaPolicyType,
|
|
16
|
+
AutheliaPluginOptionsType,
|
|
17
|
+
OIDCClientConfigType,
|
|
18
|
+
AccessControlRuleType,
|
|
19
|
+
ProxyAuthConfigType,
|
|
20
|
+
ConsentModeType,
|
|
21
|
+
PKCEChallengeMethodType,
|
|
22
|
+
TokenEndpointAuthMethodType,
|
|
23
|
+
} from './types.js';
|
|
24
|
+
export {
|
|
25
|
+
generate_oidc_client,
|
|
26
|
+
generate_access_control_rules,
|
|
27
|
+
generate_authelia_config,
|
|
28
|
+
config_to_yaml,
|
|
29
|
+
yaml_to_config,
|
|
30
|
+
} from './generator.js';
|
|
31
|
+
export {
|
|
32
|
+
check_authelia_available,
|
|
33
|
+
hash_password,
|
|
34
|
+
generate_random_secret,
|
|
35
|
+
validate_access_control,
|
|
36
|
+
} from './executor.js';
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { success } from '@kustodian/core';
|
|
2
|
+
import type {
|
|
3
|
+
CommandType,
|
|
4
|
+
HookContextType,
|
|
5
|
+
HookEventType,
|
|
6
|
+
KustodianPluginType,
|
|
7
|
+
PluginCommandContributionType,
|
|
8
|
+
PluginHookContributionType,
|
|
9
|
+
PluginManifestType,
|
|
10
|
+
} from '@kustodian/plugins';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
check_authelia_available,
|
|
14
|
+
generate_random_secret,
|
|
15
|
+
hash_password,
|
|
16
|
+
validate_access_control,
|
|
17
|
+
} from './executor.js';
|
|
18
|
+
import { generate_oidc_client } from './generator.js';
|
|
19
|
+
import type { AuthConfigType } from './types.js';
|
|
20
|
+
import { authelia_plugin_options_schema } from './types.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Authelia plugin manifest.
|
|
24
|
+
*/
|
|
25
|
+
const manifest: PluginManifestType = {
|
|
26
|
+
name: '@kustodian/plugin-authelia',
|
|
27
|
+
version: '1.0.0',
|
|
28
|
+
description: 'Authelia authentication provider plugin for Kustodian',
|
|
29
|
+
capabilities: ['commands', 'hooks'],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Creates the Authelia plugin.
|
|
34
|
+
*/
|
|
35
|
+
export function create_authelia_plugin(options: Record<string, unknown> = {}): KustodianPluginType {
|
|
36
|
+
// Parse options through schema to apply defaults
|
|
37
|
+
const plugin_options = authelia_plugin_options_schema.parse(options);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
manifest,
|
|
41
|
+
|
|
42
|
+
async activate() {
|
|
43
|
+
// Verify CLI availability on activation (warning only)
|
|
44
|
+
const check_result = await check_authelia_available();
|
|
45
|
+
if (!check_result.success) {
|
|
46
|
+
console.warn('Authelia CLI not found - some features may be unavailable');
|
|
47
|
+
console.warn('Install from: https://www.authelia.com/integration/deployment/installation/');
|
|
48
|
+
}
|
|
49
|
+
return success(undefined);
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
async deactivate() {
|
|
53
|
+
return success(undefined);
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
get_commands(): PluginCommandContributionType[] {
|
|
57
|
+
const authelia_command: CommandType = {
|
|
58
|
+
name: 'authelia',
|
|
59
|
+
description: 'Authelia authentication provider commands',
|
|
60
|
+
subcommands: [
|
|
61
|
+
{
|
|
62
|
+
name: 'check',
|
|
63
|
+
description: 'Check Authelia CLI availability',
|
|
64
|
+
handler: async () => {
|
|
65
|
+
const result = await check_authelia_available();
|
|
66
|
+
if (result.success) {
|
|
67
|
+
console.log(`Authelia CLI: ${result.value}`);
|
|
68
|
+
return success(undefined);
|
|
69
|
+
}
|
|
70
|
+
console.error('Authelia CLI not available');
|
|
71
|
+
return result;
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'hash-password',
|
|
76
|
+
description: 'Generate hashed password for Authelia',
|
|
77
|
+
arguments: [
|
|
78
|
+
{
|
|
79
|
+
name: 'password',
|
|
80
|
+
description: 'Password to hash',
|
|
81
|
+
required: true,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'algorithm',
|
|
85
|
+
description: 'Hashing algorithm (pbkdf2 or argon2)',
|
|
86
|
+
required: false,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
handler: async (ctx) => {
|
|
90
|
+
const password = ctx.args[0];
|
|
91
|
+
const algorithm = (ctx.args[1] as 'pbkdf2' | 'argon2') ?? 'pbkdf2';
|
|
92
|
+
|
|
93
|
+
if (!password) {
|
|
94
|
+
console.error('Password is required');
|
|
95
|
+
return success(undefined);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const result = await hash_password(password, algorithm);
|
|
99
|
+
if (result.success) {
|
|
100
|
+
console.log('Hashed password:');
|
|
101
|
+
console.log(result.value);
|
|
102
|
+
return success(undefined);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
console.error(`Failed to hash password: ${result.error.message}`);
|
|
106
|
+
return result;
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: 'generate-secret',
|
|
111
|
+
description: 'Generate random secret for OIDC client',
|
|
112
|
+
arguments: [
|
|
113
|
+
{
|
|
114
|
+
name: 'length',
|
|
115
|
+
description: 'Secret length (default: 64)',
|
|
116
|
+
required: false,
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
handler: async (ctx) => {
|
|
120
|
+
const length = ctx.args[0] ? Number.parseInt(ctx.args[0], 10) : 64;
|
|
121
|
+
|
|
122
|
+
const result = await generate_random_secret(length);
|
|
123
|
+
if (result.success) {
|
|
124
|
+
console.log('Generated secret:');
|
|
125
|
+
console.log(result.value);
|
|
126
|
+
return success(undefined);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.error(`Failed to generate secret: ${result.error.message}`);
|
|
130
|
+
return result;
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'generate-client',
|
|
135
|
+
description: 'Generate OIDC client configuration',
|
|
136
|
+
arguments: [
|
|
137
|
+
{
|
|
138
|
+
name: 'app-name',
|
|
139
|
+
description: 'Application name',
|
|
140
|
+
required: true,
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'redirect-uri',
|
|
144
|
+
description: 'OAuth redirect URI',
|
|
145
|
+
required: true,
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
handler: async (ctx) => {
|
|
149
|
+
const app_name = ctx.args[0];
|
|
150
|
+
const redirect_uri = ctx.args[1];
|
|
151
|
+
|
|
152
|
+
if (!app_name || !redirect_uri) {
|
|
153
|
+
console.error('App name and redirect URI are required');
|
|
154
|
+
return success(undefined);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const auth_config: AuthConfigType = {
|
|
158
|
+
provider: 'oidc',
|
|
159
|
+
app_name,
|
|
160
|
+
oidc: {
|
|
161
|
+
client_id: app_name,
|
|
162
|
+
redirect_uris: [redirect_uri],
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const result = generate_oidc_client(auth_config, plugin_options);
|
|
167
|
+
if (result.success) {
|
|
168
|
+
console.log('Generated OIDC client configuration:');
|
|
169
|
+
console.log(JSON.stringify(result.value, null, 2));
|
|
170
|
+
return success(undefined);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
console.error(`Failed to generate client: ${result.error.message}`);
|
|
174
|
+
return result;
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: 'validate-config',
|
|
179
|
+
description: 'Validate Authelia configuration file',
|
|
180
|
+
arguments: [
|
|
181
|
+
{
|
|
182
|
+
name: 'config-path',
|
|
183
|
+
description: 'Path to Authelia configuration file',
|
|
184
|
+
required: true,
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
handler: async (ctx) => {
|
|
188
|
+
const config_path = ctx.args[0];
|
|
189
|
+
|
|
190
|
+
if (!config_path) {
|
|
191
|
+
console.error('Configuration path is required');
|
|
192
|
+
return success(undefined);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const result = await validate_access_control(config_path);
|
|
196
|
+
if (result.success) {
|
|
197
|
+
console.log('✓ Configuration is valid');
|
|
198
|
+
return success(undefined);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
console.error(`✗ Configuration validation failed: ${result.error.message}`);
|
|
202
|
+
return result;
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
};
|
|
207
|
+
return [{ command: authelia_command }];
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
get_hooks(): PluginHookContributionType[] {
|
|
211
|
+
return [
|
|
212
|
+
{
|
|
213
|
+
event: 'generator:after_resolve',
|
|
214
|
+
priority: 40, // Run before secret providers to allow auth configs to be processed
|
|
215
|
+
handler: async (_event: HookEventType, ctx: HookContextType) => {
|
|
216
|
+
// TODO: Implement auth config extraction from templates
|
|
217
|
+
// This will:
|
|
218
|
+
// 1. Extract auth configs from kustomizations
|
|
219
|
+
// 2. Generate Authelia OIDC clients and access control rules
|
|
220
|
+
// 3. Write configuration to output directory
|
|
221
|
+
// 4. Generate Kubernetes secrets for client credentials
|
|
222
|
+
|
|
223
|
+
// For now, just pass through
|
|
224
|
+
return success(ctx);
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
event: 'generator:before',
|
|
229
|
+
priority: 50,
|
|
230
|
+
handler: async (_event: HookEventType, ctx: HookContextType) => {
|
|
231
|
+
// TODO: This hook could be used to:
|
|
232
|
+
// 1. Inject generated Authelia configurations as additional kustomizations
|
|
233
|
+
// 2. Add ConfigMaps with Authelia config fragments
|
|
234
|
+
// 3. Generate documentation for configured auth apps
|
|
235
|
+
|
|
236
|
+
return success(ctx);
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
];
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Default plugin export.
|
|
246
|
+
*/
|
|
247
|
+
export const plugin = create_authelia_plugin();
|
|
248
|
+
|
|
249
|
+
export default plugin;
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Authelia access control policy types
|
|
5
|
+
*/
|
|
6
|
+
export const authelia_policy_schema = z.enum(['bypass', 'one_factor', 'two_factor', 'deny']);
|
|
7
|
+
export type AutheliaPolicyType = z.infer<typeof authelia_policy_schema>;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Authelia PKCE challenge method
|
|
11
|
+
*/
|
|
12
|
+
export const pkce_challenge_method_schema = z.enum(['plain', 'S256']);
|
|
13
|
+
export type PKCEChallengeMethodType = z.infer<typeof pkce_challenge_method_schema>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Authelia token endpoint auth method
|
|
17
|
+
*/
|
|
18
|
+
export const token_endpoint_auth_method_schema = z.enum([
|
|
19
|
+
'client_secret_basic',
|
|
20
|
+
'client_secret_post',
|
|
21
|
+
'client_secret_jwt',
|
|
22
|
+
'private_key_jwt',
|
|
23
|
+
'none',
|
|
24
|
+
]);
|
|
25
|
+
export type TokenEndpointAuthMethodType = z.infer<typeof token_endpoint_auth_method_schema>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Authelia consent mode
|
|
29
|
+
*/
|
|
30
|
+
export const consent_mode_schema = z.enum(['explicit', 'implicit', 'pre-configured']);
|
|
31
|
+
export type ConsentModeType = z.infer<typeof consent_mode_schema>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Authentication provider types supported by the plugin
|
|
35
|
+
*/
|
|
36
|
+
export const auth_provider_schema = z.enum(['oidc', 'proxy', 'header']);
|
|
37
|
+
export type AuthProviderType = z.infer<typeof auth_provider_schema>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* OIDC client configuration for Authelia
|
|
41
|
+
*/
|
|
42
|
+
export const oidc_client_config_schema = z.object({
|
|
43
|
+
/** Unique client identifier */
|
|
44
|
+
client_id: z.string(),
|
|
45
|
+
/** Display name for the client */
|
|
46
|
+
client_name: z.string().optional(),
|
|
47
|
+
/** Client secret (will be hashed) */
|
|
48
|
+
client_secret: z.string().optional(),
|
|
49
|
+
/** Whether this is a public client (no secret) */
|
|
50
|
+
public: z.boolean().default(false),
|
|
51
|
+
/** Authorization policy (default: two_factor) */
|
|
52
|
+
authorization_policy: authelia_policy_schema.default('two_factor'),
|
|
53
|
+
/** Require PKCE for authorization code flow */
|
|
54
|
+
require_pkce: z.boolean().default(true),
|
|
55
|
+
/** PKCE challenge method */
|
|
56
|
+
pkce_challenge_method: pkce_challenge_method_schema.default('S256'),
|
|
57
|
+
/** Redirect URIs for OAuth callbacks */
|
|
58
|
+
redirect_uris: z.array(z.string()),
|
|
59
|
+
/** Scopes to grant (default: openid, profile, email, groups) */
|
|
60
|
+
scopes: z.array(z.string()).default(['openid', 'profile', 'email', 'groups']),
|
|
61
|
+
/** Response types (default: code) */
|
|
62
|
+
response_types: z.array(z.string()).default(['code']),
|
|
63
|
+
/** Grant types (default: authorization_code) */
|
|
64
|
+
grant_types: z.array(z.string()).default(['authorization_code']),
|
|
65
|
+
/** Token endpoint authentication method */
|
|
66
|
+
token_endpoint_auth_method: token_endpoint_auth_method_schema.default('client_secret_basic'),
|
|
67
|
+
/** Consent mode */
|
|
68
|
+
consent_mode: consent_mode_schema.optional(),
|
|
69
|
+
/** Pre-configured consent duration (e.g., '1 week') */
|
|
70
|
+
pre_configured_consent_duration: z.string().optional(),
|
|
71
|
+
/** Audience for the client */
|
|
72
|
+
audience: z.array(z.string()).optional(),
|
|
73
|
+
/** Additional Authelia client options */
|
|
74
|
+
additional_options: z.record(z.string(), z.unknown()).optional(),
|
|
75
|
+
});
|
|
76
|
+
export type OIDCClientConfigType = z.infer<typeof oidc_client_config_schema>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Access control rule configuration for Authelia
|
|
80
|
+
*/
|
|
81
|
+
export const access_control_rule_schema = z.object({
|
|
82
|
+
/** Domain(s) to match */
|
|
83
|
+
domain: z.union([z.string(), z.array(z.string())]),
|
|
84
|
+
/** Domain regex pattern (alternative to domain) */
|
|
85
|
+
domain_regex: z.string().optional(),
|
|
86
|
+
/** Policy to apply */
|
|
87
|
+
policy: authelia_policy_schema,
|
|
88
|
+
/** Networks to match */
|
|
89
|
+
networks: z.array(z.string()).optional(),
|
|
90
|
+
/** Subject(s) to match (users/groups) */
|
|
91
|
+
subject: z.union([z.string(), z.array(z.string()), z.array(z.array(z.string()))]).optional(),
|
|
92
|
+
/** HTTP methods to match */
|
|
93
|
+
methods: z.array(z.string()).optional(),
|
|
94
|
+
/** Resource patterns to match */
|
|
95
|
+
resources: z.array(z.string()).optional(),
|
|
96
|
+
/** Query parameter conditions */
|
|
97
|
+
query: z.array(z.array(z.record(z.string(), z.unknown()))).optional(),
|
|
98
|
+
});
|
|
99
|
+
export type AccessControlRuleType = z.infer<typeof access_control_rule_schema>;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Proxy/Forward Auth configuration
|
|
103
|
+
*/
|
|
104
|
+
export const proxy_auth_config_schema = z.object({
|
|
105
|
+
/** External host for the application */
|
|
106
|
+
external_host: z.string(),
|
|
107
|
+
/** Internal service host */
|
|
108
|
+
internal_host: z.string(),
|
|
109
|
+
/** Paths to skip authentication */
|
|
110
|
+
skip_path_regex: z.string().optional(),
|
|
111
|
+
/** Access control policy */
|
|
112
|
+
policy: authelia_policy_schema.default('two_factor'),
|
|
113
|
+
/** Allowed networks */
|
|
114
|
+
networks: z.array(z.string()).optional(),
|
|
115
|
+
/** Allowed subjects (users/groups) */
|
|
116
|
+
subject: z.union([z.string(), z.array(z.string())]).optional(),
|
|
117
|
+
});
|
|
118
|
+
export type ProxyAuthConfigType = z.infer<typeof proxy_auth_config_schema>;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Authentication configuration in template kustomizations
|
|
122
|
+
*/
|
|
123
|
+
export const auth_config_schema = z.object({
|
|
124
|
+
/** Authentication provider type */
|
|
125
|
+
provider: auth_provider_schema,
|
|
126
|
+
/** Application name (used as client_id for OIDC) */
|
|
127
|
+
app_name: z.string(),
|
|
128
|
+
/** Display name for the application */
|
|
129
|
+
app_display_name: z.string().optional(),
|
|
130
|
+
/** Application description */
|
|
131
|
+
app_description: z.string().optional(),
|
|
132
|
+
/** Application icon URL */
|
|
133
|
+
app_icon: z.string().optional(),
|
|
134
|
+
/** Application group/category */
|
|
135
|
+
app_group: z.string().optional(),
|
|
136
|
+
/** Application launch URL */
|
|
137
|
+
app_launch_url: z.string().optional(),
|
|
138
|
+
/** External host (for proxy/access control) */
|
|
139
|
+
external_host: z.string().optional(),
|
|
140
|
+
/** Internal service host (for proxy) */
|
|
141
|
+
internal_host: z.string().optional(),
|
|
142
|
+
/** OIDC-specific configuration */
|
|
143
|
+
oidc: oidc_client_config_schema.partial().optional(),
|
|
144
|
+
/** Proxy-specific configuration */
|
|
145
|
+
proxy: proxy_auth_config_schema.partial().optional(),
|
|
146
|
+
/** Custom access control rules */
|
|
147
|
+
access_control: z.array(access_control_rule_schema).optional(),
|
|
148
|
+
});
|
|
149
|
+
export type AuthConfigType = z.infer<typeof auth_config_schema>;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Authelia plugin options
|
|
153
|
+
*/
|
|
154
|
+
export const authelia_plugin_options_schema = z.object({
|
|
155
|
+
/** Authelia domain (e.g., auth.example.com) */
|
|
156
|
+
domain: z.string().optional(),
|
|
157
|
+
/** Default authorization policy */
|
|
158
|
+
default_policy: authelia_policy_schema.default('two_factor'),
|
|
159
|
+
/** Secret hashing algorithm (for client secrets) */
|
|
160
|
+
hash_algorithm: z.enum(['pbkdf2', 'argon2']).default('pbkdf2'),
|
|
161
|
+
/** Whether to generate client secrets automatically */
|
|
162
|
+
auto_generate_secrets: z.boolean().default(true),
|
|
163
|
+
/** Output directory for generated configurations */
|
|
164
|
+
output_dir: z.string().default('./authelia-config'),
|
|
165
|
+
});
|
|
166
|
+
export type AutheliaPluginOptionsType = z.infer<typeof authelia_plugin_options_schema>;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Generated Authelia configuration
|
|
170
|
+
*/
|
|
171
|
+
export interface AutheliaConfigType {
|
|
172
|
+
identity_providers?: {
|
|
173
|
+
oidc?: {
|
|
174
|
+
clients?: OIDCClientConfigType[];
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
access_control?: {
|
|
178
|
+
default_policy?: AutheliaPolicyType;
|
|
179
|
+
rules?: AccessControlRuleType[];
|
|
180
|
+
};
|
|
181
|
+
}
|