@kustodian/plugin-authentik 1.0.0 → 2.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/src/generator.ts DELETED
@@ -1,319 +0,0 @@
1
- import { type ResultType, failure, success } from '@kustodian/core';
2
- import type { KustodianErrorType } from '@kustodian/core';
3
- import * as yaml from 'js-yaml';
4
-
5
- import type {
6
- AuthConfigType,
7
- AuthentikApplicationType,
8
- AuthentikBlueprintType,
9
- AuthentikOAuth2ProviderType,
10
- AuthentikPluginOptionsType,
11
- AuthentikProxyProviderType,
12
- AuthentikSAMLProviderType,
13
- } from './types.js';
14
-
15
- /**
16
- * Generate a random secret for OAuth2 clients.
17
- */
18
- export function generate_client_secret(length = 64): string {
19
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
20
- let result = '';
21
- const randomArray = new Uint8Array(length);
22
- crypto.getRandomValues(randomArray);
23
- for (const value of randomArray) {
24
- result += chars[value % chars.length];
25
- }
26
- return result;
27
- }
28
-
29
- /**
30
- * Generate OAuth2 provider blueprint entry.
31
- */
32
- export function generate_oauth2_provider(
33
- auth_config: AuthConfigType,
34
- options: AuthentikPluginOptionsType,
35
- ): ResultType<AuthentikOAuth2ProviderType, KustodianErrorType> {
36
- if (auth_config.provider !== 'oauth2') {
37
- return failure({
38
- code: 'INVALID_CONFIG',
39
- message: 'Auth config provider must be "oauth2"',
40
- });
41
- }
42
-
43
- const oauth2_config = auth_config.oauth2 ?? {};
44
- const provider_name = `${auth_config.app_name}-oauth2`;
45
-
46
- const provider: AuthentikOAuth2ProviderType = {
47
- identifiers: {
48
- name: provider_name,
49
- },
50
- model: 'authentik_providers_oauth2.oauth2provider',
51
- attrs: {
52
- name: provider_name,
53
- client_id: oauth2_config.client_id ?? auth_config.app_name,
54
- client_type: oauth2_config.client_type ?? 'confidential',
55
- redirect_uris: oauth2_config.redirect_uris?.join('\n') ?? '',
56
- authorization_flow: oauth2_config.authorization_flow ?? options.default_authorization_flow,
57
- include_claims_in_id_token: oauth2_config.include_claims_in_id_token ?? true,
58
- access_token_validity: oauth2_config.access_token_validity ?? 'minutes=10',
59
- refresh_token_validity: oauth2_config.refresh_token_validity ?? 'days=30',
60
- sub_mode: oauth2_config.sub_mode ?? 'hashed_user_identifier',
61
- issue_refresh_tokens: oauth2_config.issue_refresh_tokens ?? true,
62
- },
63
- };
64
-
65
- // Add client secret if confidential and auto-generate is enabled
66
- if (
67
- provider.attrs.client_type === 'confidential' &&
68
- options.auto_generate_secrets &&
69
- !oauth2_config.client_secret
70
- ) {
71
- provider.attrs.client_secret = generate_client_secret();
72
- } else if (oauth2_config.client_secret) {
73
- provider.attrs.client_secret = oauth2_config.client_secret;
74
- }
75
-
76
- // Add optional signing key
77
- if (oauth2_config.signing_key) {
78
- provider.attrs.signing_key = oauth2_config.signing_key;
79
- }
80
-
81
- return success(provider);
82
- }
83
-
84
- /**
85
- * Generate SAML provider blueprint entry.
86
- */
87
- export function generate_saml_provider(
88
- auth_config: AuthConfigType,
89
- options: AuthentikPluginOptionsType,
90
- ): ResultType<AuthentikSAMLProviderType, KustodianErrorType> {
91
- if (auth_config.provider !== 'saml') {
92
- return failure({
93
- code: 'INVALID_CONFIG',
94
- message: 'Auth config provider must be "saml"',
95
- });
96
- }
97
-
98
- const saml_config = auth_config.saml;
99
- if (!saml_config?.acs_url || !saml_config?.issuer) {
100
- return failure({
101
- code: 'INVALID_CONFIG',
102
- message: 'SAML provider requires acs_url and issuer',
103
- });
104
- }
105
-
106
- const provider_name = `${auth_config.app_name}-saml`;
107
-
108
- const provider: AuthentikSAMLProviderType = {
109
- identifiers: {
110
- name: provider_name,
111
- },
112
- model: 'authentik_providers_saml.samlprovider',
113
- attrs: {
114
- name: provider_name,
115
- acs_url: saml_config.acs_url,
116
- issuer: saml_config.issuer,
117
- sp_binding: saml_config.sp_binding ?? 'post',
118
- authorization_flow: saml_config.authorization_flow ?? options.default_authorization_flow,
119
- assertion_valid_not_before: saml_config.assertion_valid_not_before ?? 'minutes=5',
120
- assertion_valid_not_on_or_after: saml_config.assertion_valid_not_on_or_after ?? 'minutes=5',
121
- session_valid_not_on_or_after: saml_config.session_valid_not_on_or_after ?? 'minutes=86400',
122
- },
123
- };
124
-
125
- // Add optional fields
126
- if (saml_config.audience) {
127
- provider.attrs.audience = saml_config.audience;
128
- }
129
- if (saml_config.signing_kp) {
130
- provider.attrs.signing_kp = saml_config.signing_kp;
131
- }
132
-
133
- return success(provider);
134
- }
135
-
136
- /**
137
- * Generate Proxy provider blueprint entry.
138
- */
139
- export function generate_proxy_provider(
140
- auth_config: AuthConfigType,
141
- options: AuthentikPluginOptionsType,
142
- ): ResultType<AuthentikProxyProviderType, KustodianErrorType> {
143
- if (auth_config.provider !== 'proxy') {
144
- return failure({
145
- code: 'INVALID_CONFIG',
146
- message: 'Auth config provider must be "proxy"',
147
- });
148
- }
149
-
150
- const proxy_config = auth_config.proxy;
151
- if (!proxy_config?.external_host) {
152
- return failure({
153
- code: 'INVALID_CONFIG',
154
- message: 'Proxy provider requires external_host',
155
- });
156
- }
157
-
158
- const provider_name = `${auth_config.app_name}-proxy`;
159
-
160
- const provider: AuthentikProxyProviderType = {
161
- identifiers: {
162
- name: provider_name,
163
- },
164
- model: 'authentik_providers_proxy.proxyprovider',
165
- attrs: {
166
- name: provider_name,
167
- external_host: proxy_config.external_host,
168
- internal_host_ssl_validation: proxy_config.internal_host_ssl_validation ?? true,
169
- basic_auth_enabled: proxy_config.basic_auth_enabled ?? false,
170
- mode: proxy_config.mode ?? 'forward_single',
171
- authorization_flow: proxy_config.authorization_flow ?? options.default_authorization_flow,
172
- access_token_validity: proxy_config.access_token_validity ?? 'minutes=10',
173
- intercept_header_auth: proxy_config.intercept_header_auth ?? true,
174
- },
175
- };
176
-
177
- // Add optional fields
178
- if (proxy_config.internal_host) {
179
- provider.attrs.internal_host = proxy_config.internal_host;
180
- }
181
- if (proxy_config.certificate) {
182
- provider.attrs.certificate = proxy_config.certificate;
183
- }
184
- if (proxy_config.skip_path_regex) {
185
- provider.attrs.skip_path_regex = proxy_config.skip_path_regex;
186
- }
187
- if (proxy_config.basic_auth_password_attribute) {
188
- provider.attrs.basic_auth_password_attribute = proxy_config.basic_auth_password_attribute;
189
- }
190
- if (proxy_config.basic_auth_user_attribute) {
191
- provider.attrs.basic_auth_user_attribute = proxy_config.basic_auth_user_attribute;
192
- }
193
-
194
- return success(provider);
195
- }
196
-
197
- /**
198
- * Generate application blueprint entry.
199
- */
200
- export function generate_application(
201
- auth_config: AuthConfigType,
202
- provider_name: string,
203
- ): AuthentikApplicationType {
204
- const attrs: AuthentikApplicationType['attrs'] = {
205
- name: auth_config.app_display_name ?? auth_config.app_name,
206
- slug: auth_config.app_name,
207
- provider: provider_name,
208
- policy_engine_mode: 'any',
209
- };
210
-
211
- // Add optional fields only if defined
212
- if (auth_config.app_description) {
213
- attrs.meta_description = auth_config.app_description;
214
- }
215
- if (auth_config.app_icon) {
216
- attrs.meta_icon = auth_config.app_icon;
217
- }
218
- if (auth_config.app_group) {
219
- attrs.group = auth_config.app_group;
220
- }
221
- if (auth_config.app_launch_url) {
222
- attrs.meta_launch_url = auth_config.app_launch_url;
223
- }
224
-
225
- return {
226
- identifiers: {
227
- slug: auth_config.app_name,
228
- },
229
- model: 'authentik_core.application',
230
- attrs,
231
- };
232
- }
233
-
234
- /**
235
- * Generate complete Authentik blueprint from auth configuration.
236
- */
237
- export function generate_authentik_blueprint(
238
- auth_config: AuthConfigType,
239
- options: AuthentikPluginOptionsType,
240
- ): ResultType<AuthentikBlueprintType, KustodianErrorType> {
241
- const entries: AuthentikBlueprintType['entries'] = [];
242
-
243
- // Generate provider based on type
244
- let provider_result:
245
- | ResultType<AuthentikOAuth2ProviderType, KustodianErrorType>
246
- | ResultType<AuthentikSAMLProviderType, KustodianErrorType>
247
- | ResultType<AuthentikProxyProviderType, KustodianErrorType>;
248
-
249
- switch (auth_config.provider) {
250
- case 'oauth2':
251
- provider_result = generate_oauth2_provider(auth_config, options);
252
- break;
253
- case 'saml':
254
- provider_result = generate_saml_provider(auth_config, options);
255
- break;
256
- case 'proxy':
257
- provider_result = generate_proxy_provider(auth_config, options);
258
- break;
259
- default:
260
- return failure({
261
- code: 'INVALID_CONFIG',
262
- message: `Unknown provider type: ${auth_config.provider}`,
263
- });
264
- }
265
-
266
- if (!provider_result.success) {
267
- return provider_result;
268
- }
269
-
270
- const provider = provider_result.value;
271
- entries.push(provider);
272
-
273
- // Generate application
274
- const application = generate_application(auth_config, provider.identifiers.name);
275
- entries.push(application);
276
-
277
- const blueprint: AuthentikBlueprintType = {
278
- version: options.blueprint_version,
279
- metadata: {
280
- name: `${auth_config.app_name}-blueprint`,
281
- labels: {
282
- 'app.kubernetes.io/name': auth_config.app_name,
283
- 'app.kubernetes.io/managed-by': 'kustodian',
284
- },
285
- },
286
- entries,
287
- };
288
-
289
- return success(blueprint);
290
- }
291
-
292
- /**
293
- * Convert blueprint to YAML string.
294
- */
295
- export function blueprint_to_yaml(blueprint: AuthentikBlueprintType): string {
296
- return yaml.dump(blueprint, {
297
- indent: 2,
298
- lineWidth: -1,
299
- noRefs: true,
300
- sortKeys: false,
301
- });
302
- }
303
-
304
- /**
305
- * Parse YAML string to blueprint.
306
- */
307
- export function yaml_to_blueprint(
308
- yaml_string: string,
309
- ): ResultType<AuthentikBlueprintType, KustodianErrorType> {
310
- try {
311
- const blueprint = yaml.load(yaml_string) as AuthentikBlueprintType;
312
- return success(blueprint);
313
- } catch (error) {
314
- return failure({
315
- code: 'PARSE_ERROR',
316
- message: `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`,
317
- });
318
- }
319
- }
package/src/index.ts DELETED
@@ -1,44 +0,0 @@
1
- /**
2
- * Authentik authentication provider plugin for Kustodian
3
- *
4
- * This plugin enables integration with Authentik for authentication and authorization.
5
- * It can generate OAuth2, SAML, and Proxy provider configurations, create Authentik
6
- * blueprints, and manage authentication requirements for deployed applications.
7
- *
8
- * @packageDocumentation
9
- */
10
-
11
- export { create_authentik_plugin, plugin as default } from './plugin.js';
12
- export type {
13
- AuthConfigType,
14
- AuthProviderType,
15
- AuthentikPluginOptionsType,
16
- OAuth2ProviderConfigType,
17
- SAMLProviderConfigType,
18
- ProxyProviderConfigType,
19
- AuthentikBlueprintType,
20
- AuthentikApplicationType,
21
- AuthentikOAuth2ProviderType,
22
- AuthentikSAMLProviderType,
23
- AuthentikProxyProviderType,
24
- ClientTypeType,
25
- ProxyModeType,
26
- SAMLBindingType,
27
- SAMLNameIDPolicyType,
28
- AuthentikFlowType,
29
- } from './types.js';
30
- export {
31
- generate_authentik_blueprint,
32
- generate_oauth2_provider,
33
- generate_saml_provider,
34
- generate_proxy_provider,
35
- generate_application,
36
- generate_client_secret,
37
- blueprint_to_yaml,
38
- yaml_to_blueprint,
39
- } from './generator.js';
40
- export {
41
- check_authentik_available,
42
- validate_blueprint,
43
- generate_random_secret,
44
- } from './executor.js';
package/src/plugin.ts DELETED
@@ -1,238 +0,0 @@
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_authentik_available,
14
- generate_random_secret,
15
- validate_blueprint,
16
- } from './executor.js';
17
- import { blueprint_to_yaml, generate_authentik_blueprint } from './generator.js';
18
- import type { AuthConfigType } from './types.js';
19
- import { authentik_plugin_options_schema } from './types.js';
20
-
21
- /**
22
- * Authentik plugin manifest.
23
- */
24
- const manifest: PluginManifestType = {
25
- name: '@kustodian/plugin-authentik',
26
- version: '1.0.0',
27
- description: 'Authentik authentication provider plugin for Kustodian',
28
- capabilities: ['commands', 'hooks'],
29
- };
30
-
31
- /**
32
- * Creates the Authentik plugin.
33
- */
34
- export function create_authentik_plugin(
35
- options: Record<string, unknown> = {},
36
- ): KustodianPluginType {
37
- // Parse options through schema to apply defaults
38
- const plugin_options = authentik_plugin_options_schema.parse(options);
39
-
40
- return {
41
- manifest,
42
-
43
- async activate() {
44
- // Verify CLI availability on activation (warning only)
45
- const check_result = await check_authentik_available();
46
- if (!check_result.success) {
47
- console.warn('Authentik CLI not found - some features may be unavailable');
48
- console.warn('Install from: https://goauthentik.io/docs/installation/');
49
- }
50
- return success(undefined);
51
- },
52
-
53
- async deactivate() {
54
- return success(undefined);
55
- },
56
-
57
- get_commands(): PluginCommandContributionType[] {
58
- const authentik_command: CommandType = {
59
- name: 'authentik',
60
- description: 'Authentik authentication provider commands',
61
- subcommands: [
62
- {
63
- name: 'check',
64
- description: 'Check Authentik CLI availability',
65
- handler: async () => {
66
- const result = await check_authentik_available();
67
- if (result.success) {
68
- console.log(`Authentik CLI: ${result.value}`);
69
- return success(undefined);
70
- }
71
- console.error('Authentik CLI not available');
72
- return result;
73
- },
74
- },
75
- {
76
- name: 'generate-secret',
77
- description: 'Generate random secret for OAuth2 client',
78
- arguments: [
79
- {
80
- name: 'length',
81
- description: 'Secret length (default: 64)',
82
- required: false,
83
- },
84
- ],
85
- handler: async (ctx: {
86
- args: string[];
87
- options: Record<string, unknown>;
88
- data: Record<string, unknown>;
89
- }) => {
90
- const length = ctx.args[0] ? Number.parseInt(ctx.args[0], 10) : 64;
91
-
92
- const result = await generate_random_secret(length);
93
- if (result.success) {
94
- console.log('Generated secret:');
95
- console.log(result.value);
96
- return success(undefined);
97
- }
98
-
99
- console.error(`Failed to generate secret: ${result.error.message}`);
100
- return result;
101
- },
102
- },
103
- {
104
- name: 'generate-blueprint',
105
- description: 'Generate Authentik blueprint from auth configuration',
106
- arguments: [
107
- {
108
- name: 'app-name',
109
- description: 'Application name',
110
- required: true,
111
- },
112
- {
113
- name: 'provider',
114
- description: 'Provider type (oauth2, saml, proxy)',
115
- required: true,
116
- },
117
- {
118
- name: 'config-json',
119
- description: 'JSON configuration for the provider',
120
- required: true,
121
- },
122
- ],
123
- handler: async (ctx: {
124
- args: string[];
125
- options: Record<string, unknown>;
126
- data: Record<string, unknown>;
127
- }) => {
128
- const app_name = ctx.args[0];
129
- const provider = ctx.args[1] as 'oauth2' | 'saml' | 'proxy';
130
- const config_json = ctx.args[2];
131
-
132
- if (!app_name || !provider || !config_json) {
133
- console.error('App name, provider, and config JSON are required');
134
- return success(undefined);
135
- }
136
-
137
- try {
138
- const provider_config = JSON.parse(config_json);
139
- const auth_config: AuthConfigType = {
140
- provider,
141
- app_name,
142
- [provider]: provider_config,
143
- };
144
-
145
- const result = generate_authentik_blueprint(auth_config, plugin_options);
146
- if (result.success) {
147
- console.log('Generated blueprint:');
148
- console.log(blueprint_to_yaml(result.value));
149
- return success(undefined);
150
- }
151
-
152
- console.error(`Failed to generate blueprint: ${result.error.message}`);
153
- return result;
154
- } catch (error) {
155
- console.error(
156
- `Failed to parse config JSON: ${error instanceof Error ? error.message : String(error)}`,
157
- );
158
- return success(undefined);
159
- }
160
- },
161
- },
162
- {
163
- name: 'validate-blueprint',
164
- description: 'Validate Authentik blueprint file',
165
- arguments: [
166
- {
167
- name: 'blueprint-path',
168
- description: 'Path to blueprint file',
169
- required: true,
170
- },
171
- ],
172
- handler: async (ctx: {
173
- args: string[];
174
- options: Record<string, unknown>;
175
- data: Record<string, unknown>;
176
- }) => {
177
- const blueprint_path = ctx.args[0];
178
-
179
- if (!blueprint_path) {
180
- console.error('Blueprint path is required');
181
- return success(undefined);
182
- }
183
-
184
- const result = await validate_blueprint(blueprint_path);
185
- if (result.success) {
186
- console.log('✓ Blueprint is valid');
187
- return success(undefined);
188
- }
189
-
190
- console.error(`✗ Blueprint validation failed: ${result.error.message}`);
191
- return result;
192
- },
193
- },
194
- ],
195
- };
196
- return [{ command: authentik_command }];
197
- },
198
-
199
- get_hooks(): PluginHookContributionType[] {
200
- return [
201
- {
202
- event: 'generator:after_resolve',
203
- priority: 40, // Run before secret providers to allow auth configs to be processed
204
- handler: async (_event: HookEventType, ctx: HookContextType) => {
205
- // TODO: Implement auth config extraction from templates
206
- // This will:
207
- // 1. Extract auth configs from kustomizations
208
- // 2. Generate Authentik blueprints
209
- // 3. Write blueprints to output directory
210
- // 4. Generate Kubernetes ConfigMaps with blueprints
211
-
212
- // For now, just pass through
213
- return success(ctx);
214
- },
215
- },
216
- {
217
- event: 'generator:before',
218
- priority: 50,
219
- handler: async (_event: HookEventType, ctx: HookContextType) => {
220
- // TODO: This hook could be used to:
221
- // 1. Inject generated Authentik blueprints as ConfigMaps
222
- // 2. Generate documentation for configured applications
223
- // 3. Validate auth configuration consistency
224
-
225
- return success(ctx);
226
- },
227
- },
228
- ];
229
- },
230
- };
231
- }
232
-
233
- /**
234
- * Default plugin export.
235
- */
236
- export const plugin = create_authentik_plugin();
237
-
238
- export default plugin;