timonel 3.1.1 → 3.1.2
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/CHANGELOG.md +7 -0
- package/README.md +323 -695
- package/dist/cli.js +275 -15
- package/dist/index.d.ts +5 -1
- package/dist/index.js +12 -0
- package/dist/lib/helm.d.ts +471 -0
- package/dist/lib/helm.js +483 -0
- package/dist/lib/helmChartWriter.d.ts +157 -0
- package/dist/lib/helmChartWriter.js +171 -1
- package/dist/lib/policy/configurationLoader.d.ts +132 -0
- package/dist/lib/policy/configurationLoader.js +132 -0
- package/dist/lib/policy/errorContextGenerator.d.ts +89 -0
- package/dist/lib/policy/errorContextGenerator.js +99 -2
- package/dist/lib/policy/errors.d.ts +35 -0
- package/dist/lib/policy/errors.js +36 -0
- package/dist/lib/policy/index.d.ts +9 -0
- package/dist/lib/policy/index.js +16 -0
- package/dist/lib/policy/parallelExecutor.d.ts +90 -0
- package/dist/lib/policy/parallelExecutor.js +86 -3
- package/dist/lib/policy/pluginLoader.d.ts +92 -0
- package/dist/lib/policy/pluginLoader.js +92 -1
- package/dist/lib/policy/pluginRegistry.d.ts +54 -0
- package/dist/lib/policy/pluginRegistry.js +56 -0
- package/dist/lib/policy/policyEngine.d.ts +137 -0
- package/dist/lib/policy/policyEngine.js +191 -5
- package/dist/lib/policy/resultAggregator.d.ts +46 -0
- package/dist/lib/policy/resultAggregator.js +69 -1
- package/dist/lib/policy/resultFormatter.d.ts +88 -0
- package/dist/lib/policy/resultFormatter.js +101 -0
- package/dist/lib/policy/types.d.ts +136 -0
- package/dist/lib/policy/types.js +8 -0
- package/dist/lib/policy/validationCache.d.ts +146 -0
- package/dist/lib/policy/validationCache.js +142 -6
- package/dist/lib/resources/baseResourceProvider.d.ts +45 -0
- package/dist/lib/resources/baseResourceProvider.js +48 -1
- package/dist/lib/resources/cloud/aws/awsResources.d.ts +192 -0
- package/dist/lib/resources/cloud/aws/awsResources.js +163 -1
- package/dist/lib/resources/cloud/aws/karpenterResources.d.ts +131 -0
- package/dist/lib/resources/cloud/aws/karpenterResources.js +77 -0
- package/dist/lib/rutter.d.ts +381 -3
- package/dist/lib/rutter.js +439 -28
- package/dist/lib/security.d.ts +123 -0
- package/dist/lib/security.js +162 -4
- package/dist/lib/templates/flexible-subchart.d.ts +52 -0
- package/dist/lib/templates/flexible-subchart.js +70 -0
- package/dist/lib/templates/umbrella-chart.d.ts +27 -0
- package/dist/lib/templates/umbrella-chart.js +89 -0
- package/dist/lib/types.d.ts +26 -0
- package/dist/lib/umbrella.d.ts +23 -0
- package/dist/lib/umbrella.js +23 -0
- package/dist/lib/umbrellaRutter.d.ts +75 -0
- package/dist/lib/umbrellaRutter.js +82 -2
- package/dist/lib/utils/envVarsLoader.d.ts +49 -0
- package/dist/lib/utils/envVarsLoader.js +53 -0
- package/dist/lib/utils/helmConstructSerializer.d.ts +17 -0
- package/dist/lib/utils/helmConstructSerializer.js +22 -0
- package/dist/lib/utils/helmControlStructures.d.ts +194 -0
- package/dist/lib/utils/helmControlStructures.js +180 -0
- package/dist/lib/utils/helmHelpers/envHelpers.d.ts +13 -0
- package/dist/lib/utils/helmHelpers/envHelpers.js +13 -0
- package/dist/lib/utils/helmHelpers/gitopsHelpers.d.ts +13 -0
- package/dist/lib/utils/helmHelpers/gitopsHelpers.js +13 -0
- package/dist/lib/utils/helmHelpers/index.d.ts +74 -0
- package/dist/lib/utils/helmHelpers/index.js +85 -1
- package/dist/lib/utils/helmHelpers/observabilityHelpers.d.ts +13 -0
- package/dist/lib/utils/helmHelpers/observabilityHelpers.js +13 -0
- package/dist/lib/utils/helmHelpers/types.d.ts +23 -0
- package/dist/lib/utils/helmHelpers/types.js +4 -0
- package/dist/lib/utils/helmHelpers/validationHelpers.d.ts +13 -0
- package/dist/lib/utils/helmHelpers/validationHelpers.js +13 -0
- package/dist/lib/utils/helmHelpers.d.ts +62 -0
- package/dist/lib/utils/helmHelpers.js +77 -0
- package/dist/lib/utils/helmYamlSerializer.d.ts +77 -0
- package/dist/lib/utils/helmYamlSerializer.js +398 -21
- package/dist/lib/utils/logger.d.ts +153 -0
- package/dist/lib/utils/logger.js +170 -2
- package/dist/lib/utils/valuesRef.d.ts +181 -50
- package/dist/lib/utils/valuesRef.js +168 -170
- package/dist/lib/validation/inputValidator.d.ts +45 -0
- package/dist/lib/validation/inputValidator.js +67 -2
- package/dist/types/index.d.ts +34 -0
- package/dist/types/index.js +3 -0
- package/package.json +31 -38
|
@@ -1,70 +1,253 @@
|
|
|
1
1
|
import type { ApiObject } from 'cdk8s';
|
|
2
2
|
import * as kplus from 'cdk8s-plus-33';
|
|
3
3
|
import { BaseResourceProvider } from '../../baseResourceProvider.js';
|
|
4
|
+
/**
|
|
5
|
+
* AWS-specific Kubernetes resources provider
|
|
6
|
+
* Handles AWS integrations like EBS, EFS, ALB, IRSA, and other AWS services
|
|
7
|
+
*
|
|
8
|
+
* @since 2.8.0+
|
|
9
|
+
*/
|
|
4
10
|
export declare class AWSResources extends BaseResourceProvider {
|
|
5
11
|
private static readonly STORAGE_API_VERSION;
|
|
12
|
+
/**
|
|
13
|
+
* Creates an AWS EBS StorageClass
|
|
14
|
+
* @param spec - EBS StorageClass specification
|
|
15
|
+
* @returns Created StorageClass ApiObject
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* awsResources.addEBSStorageClass({
|
|
20
|
+
* name: 'fast-ebs',
|
|
21
|
+
* volumeType: 'gp3',
|
|
22
|
+
* encrypted: true,
|
|
23
|
+
* allowVolumeExpansion: true
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @since 2.8.0+
|
|
28
|
+
*/
|
|
6
29
|
addEBSStorageClass(spec: AWSEBSStorageClassSpec): ApiObject;
|
|
30
|
+
/**
|
|
31
|
+
* Creates an AWS EFS StorageClass
|
|
32
|
+
* @param spec - EFS StorageClass specification
|
|
33
|
+
* @returns Created StorageClass ApiObject
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* awsResources.addEFSStorageClass({
|
|
38
|
+
* name: 'efs-storage',
|
|
39
|
+
* fileSystemId: 'fs-12345678',
|
|
40
|
+
* directoryPerms: '0755'
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @since 2.8.0+
|
|
45
|
+
*/
|
|
7
46
|
addEFSStorageClass(spec: AWSEFSStorageClassSpec): ApiObject;
|
|
47
|
+
/**
|
|
48
|
+
* Creates an AWS IRSA (IAM Roles for Service Accounts) ServiceAccount
|
|
49
|
+
* @param spec - IRSA ServiceAccount specification
|
|
50
|
+
* @returns Created ServiceAccount ApiObject
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* awsResources.addIRSAServiceAccount({
|
|
55
|
+
* name: 'aws-service-account',
|
|
56
|
+
* roleArn: 'arn:aws:iam::123456789012:role/MyRole'
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @since 2.8.0+
|
|
61
|
+
*/
|
|
8
62
|
addIRSAServiceAccount(spec: AWSIRSAServiceAccountSpec): kplus.ServiceAccount;
|
|
63
|
+
/**
|
|
64
|
+
* Creates an AWS ALB Ingress
|
|
65
|
+
* @param spec - ALB Ingress specification
|
|
66
|
+
* @returns Created Ingress ApiObject
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* awsResources.addALBIngress({
|
|
71
|
+
* name: 'web-ingress',
|
|
72
|
+
* rules: [{
|
|
73
|
+
* paths: [{
|
|
74
|
+
* path: '/',
|
|
75
|
+
* pathType: 'Prefix',
|
|
76
|
+
* backend: { service: { name: 'web-service', port: { number: 80 } } }
|
|
77
|
+
* }]
|
|
78
|
+
* }],
|
|
79
|
+
* scheme: 'internet-facing'
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @since 2.8.0+
|
|
84
|
+
*/
|
|
9
85
|
addALBIngress(spec: AWSALBIngressSpec): kplus.Ingress;
|
|
86
|
+
/**
|
|
87
|
+
* Validates Ingress paths format according to Kubernetes specification
|
|
88
|
+
* @param rules - Ingress rules to validate
|
|
89
|
+
* @private
|
|
90
|
+
* @since 2.8.0+
|
|
91
|
+
*/
|
|
10
92
|
private validateIngressPaths;
|
|
93
|
+
/**
|
|
94
|
+
* Validates a single Ingress rule
|
|
95
|
+
* @param rule - Ingress rule to validate
|
|
96
|
+
* @private
|
|
97
|
+
* @since 2.8.0+
|
|
98
|
+
*/
|
|
11
99
|
private validateIngressRule;
|
|
100
|
+
/**
|
|
101
|
+
* Validates a single Ingress path
|
|
102
|
+
* @param pathRule - Path rule to validate
|
|
103
|
+
* @private
|
|
104
|
+
* @since 2.8.0+
|
|
105
|
+
*/
|
|
12
106
|
private validateIngressPath;
|
|
107
|
+
/**
|
|
108
|
+
* Validates path format
|
|
109
|
+
* @param path - Path to validate
|
|
110
|
+
* @private
|
|
111
|
+
* @since 2.5.0
|
|
112
|
+
*/
|
|
13
113
|
private validatePathFormat;
|
|
114
|
+
/**
|
|
115
|
+
* Validates path type
|
|
116
|
+
* @param pathType - Path type to validate
|
|
117
|
+
* @private
|
|
118
|
+
* @since 2.5.0
|
|
119
|
+
*/
|
|
14
120
|
private validatePathType;
|
|
121
|
+
/**
|
|
122
|
+
* Validates backend configuration
|
|
123
|
+
* @param backend - Backend to validate
|
|
124
|
+
* @private
|
|
125
|
+
* @since 2.5.0
|
|
126
|
+
*/
|
|
15
127
|
private validateBackend;
|
|
128
|
+
/**
|
|
129
|
+
* Validates StorageClass provisioner is present and valid
|
|
130
|
+
* @param provisioner - Provisioner string to validate
|
|
131
|
+
* @param storageType - Type of storage (for error messages)
|
|
132
|
+
* @private
|
|
133
|
+
* @since 2.5.0
|
|
134
|
+
*/
|
|
16
135
|
private validateStorageClassProvisioner;
|
|
136
|
+
/**
|
|
137
|
+
* Validates AWS IAM Role ARN format
|
|
138
|
+
* @param roleArn - Role ARN to validate
|
|
139
|
+
*/
|
|
17
140
|
private validateRoleArn;
|
|
141
|
+
/**
|
|
142
|
+
* Builds ALB-specific annotations
|
|
143
|
+
* @param spec - ALB Ingress specification
|
|
144
|
+
* @returns ALB annotations
|
|
145
|
+
*/
|
|
18
146
|
private buildALBAnnotations;
|
|
147
|
+
/**
|
|
148
|
+
* Creates a ServiceAccount with ECR access annotations
|
|
149
|
+
* @param spec - ECR ServiceAccount specification
|
|
150
|
+
* @returns Created ServiceAccount ApiObject
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* awsResources.addECRServiceAccount({
|
|
155
|
+
* name: 'ecr-service-account',
|
|
156
|
+
* roleArn: 'arn:aws:iam::123456789012:role/ECRAccessRole'
|
|
157
|
+
* });
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @since 2.8.0+
|
|
161
|
+
*/
|
|
19
162
|
addECRServiceAccount(spec: AWSECRServiceAccountSpec): kplus.ServiceAccount;
|
|
20
163
|
}
|
|
164
|
+
/** Configuration for an AWS EBS CSI StorageClass. */
|
|
21
165
|
export interface AWSEBSStorageClassSpec {
|
|
166
|
+
/** Kubernetes StorageClass name. */
|
|
22
167
|
name: string;
|
|
168
|
+
/** EBS volume type. Defaults to `gp3`. */
|
|
23
169
|
volumeType?: 'gp2' | 'gp3' | 'io1' | 'io2' | 'sc1' | 'st1';
|
|
170
|
+
/** Whether dynamically provisioned volumes should be encrypted. */
|
|
24
171
|
encrypted?: boolean;
|
|
172
|
+
/** Requested IOPS for volume types that support explicit IOPS. */
|
|
25
173
|
iops?: number;
|
|
174
|
+
/** Requested throughput in MiB/s for volume types that support it. */
|
|
26
175
|
throughput?: number;
|
|
176
|
+
/** Filesystem type passed to the CSI provisioner. */
|
|
27
177
|
fsType?: string;
|
|
178
|
+
/** Kubernetes reclaim policy. */
|
|
28
179
|
reclaimPolicy?: 'Delete' | 'Retain';
|
|
180
|
+
/** Whether PVCs may expand the provisioned volume. */
|
|
29
181
|
allowVolumeExpansion?: boolean;
|
|
182
|
+
/** StorageClass volume binding mode. */
|
|
30
183
|
volumeBindingMode?: 'Immediate' | 'WaitForFirstConsumer';
|
|
184
|
+
/** Optional Kubernetes labels. */
|
|
31
185
|
labels?: Record<string, string>;
|
|
186
|
+
/** Optional Kubernetes annotations. */
|
|
32
187
|
annotations?: Record<string, string>;
|
|
33
188
|
}
|
|
189
|
+
/** Configuration for an AWS EFS CSI StorageClass. */
|
|
34
190
|
export interface AWSEFSStorageClassSpec {
|
|
191
|
+
/** Kubernetes StorageClass name. */
|
|
35
192
|
name: string;
|
|
193
|
+
/** EFS filesystem identifier used by the CSI provisioner. */
|
|
36
194
|
fileSystemId?: string;
|
|
195
|
+
/** Permissions applied to dynamically created access-point directories. */
|
|
37
196
|
directoryPerms?: string;
|
|
197
|
+
/** Start of the POSIX group ID allocation range. */
|
|
38
198
|
gidRangeStart?: number;
|
|
199
|
+
/** End of the POSIX group ID allocation range. */
|
|
39
200
|
gidRangeEnd?: number;
|
|
201
|
+
/** Base path for dynamically provisioned directories. */
|
|
40
202
|
basePath?: string;
|
|
203
|
+
/** Kubernetes reclaim policy. */
|
|
41
204
|
reclaimPolicy?: 'Delete' | 'Retain';
|
|
205
|
+
/** StorageClass volume binding mode. */
|
|
42
206
|
volumeBindingMode?: 'Immediate' | 'WaitForFirstConsumer';
|
|
207
|
+
/** Optional Kubernetes labels. */
|
|
43
208
|
labels?: Record<string, string>;
|
|
209
|
+
/** Optional Kubernetes annotations. */
|
|
44
210
|
annotations?: Record<string, string>;
|
|
45
211
|
}
|
|
212
|
+
/** Configuration for an IRSA-enabled cdk8s-plus ServiceAccount. */
|
|
46
213
|
export interface AWSIRSAServiceAccountSpec {
|
|
214
|
+
/** Kubernetes ServiceAccount name. */
|
|
47
215
|
name: string;
|
|
216
|
+
/** IAM role ARN written to the IRSA annotation. */
|
|
48
217
|
roleArn: string;
|
|
218
|
+
/** Whether Kubernetes should automount the service-account token. */
|
|
49
219
|
automountServiceAccountToken?: boolean;
|
|
220
|
+
/** Existing image pull secrets referenced by name. */
|
|
50
221
|
imagePullSecrets?: Array<{
|
|
51
222
|
name: string;
|
|
52
223
|
}>;
|
|
224
|
+
/** Optional Kubernetes labels. */
|
|
53
225
|
labels?: Record<string, string>;
|
|
226
|
+
/** Additional annotations merged with the IRSA role annotation. */
|
|
54
227
|
annotations?: Record<string, string>;
|
|
55
228
|
}
|
|
229
|
+
/** Configuration for an ECR-oriented IRSA ServiceAccount. */
|
|
56
230
|
export interface AWSECRServiceAccountSpec {
|
|
231
|
+
/** Kubernetes ServiceAccount name. */
|
|
57
232
|
name: string;
|
|
233
|
+
/** IAM role ARN written to the IRSA annotation. */
|
|
58
234
|
roleArn: string;
|
|
235
|
+
/** Whether Kubernetes should automount the service-account token. */
|
|
59
236
|
automountServiceAccountToken?: boolean;
|
|
237
|
+
/** Existing image pull secrets referenced by name. */
|
|
60
238
|
imagePullSecrets?: Array<{
|
|
61
239
|
name: string;
|
|
62
240
|
}>;
|
|
241
|
+
/** Optional Kubernetes labels. */
|
|
63
242
|
labels?: Record<string, string>;
|
|
243
|
+
/** Additional Kubernetes annotations. */
|
|
64
244
|
annotations?: Record<string, string>;
|
|
65
245
|
}
|
|
246
|
+
/** Configuration for an AWS Load Balancer Controller-backed Ingress. */
|
|
66
247
|
export interface AWSALBIngressSpec {
|
|
248
|
+
/** Kubernetes Ingress name. */
|
|
67
249
|
name: string;
|
|
250
|
+
/** Host/path routing rules added to the Ingress. */
|
|
68
251
|
rules: Array<{
|
|
69
252
|
host?: string;
|
|
70
253
|
paths: Array<{
|
|
@@ -81,16 +264,25 @@ export interface AWSALBIngressSpec {
|
|
|
81
264
|
};
|
|
82
265
|
}>;
|
|
83
266
|
}>;
|
|
267
|
+
/** Optional TLS secret references and host lists. */
|
|
84
268
|
tls?: Array<{
|
|
85
269
|
hosts?: string[];
|
|
86
270
|
secretName?: string;
|
|
87
271
|
}>;
|
|
272
|
+
/** ALB exposure scheme. */
|
|
88
273
|
scheme?: 'internet-facing' | 'internal';
|
|
274
|
+
/** ALB target registration mode. */
|
|
89
275
|
targetType?: 'ip' | 'instance';
|
|
276
|
+
/** ACM certificate ARN added to the controller annotations. */
|
|
90
277
|
certificateArn?: string;
|
|
278
|
+
/** Whether to request HTTP-to-HTTPS redirection on port 443. */
|
|
91
279
|
sslRedirect?: boolean;
|
|
280
|
+
/** ALB health check path. */
|
|
92
281
|
healthCheckPath?: string;
|
|
282
|
+
/** Kubernetes IngressClass name. Defaults to `alb`. */
|
|
93
283
|
ingressClassName?: string;
|
|
284
|
+
/** Optional Kubernetes labels. */
|
|
94
285
|
labels?: Record<string, string>;
|
|
286
|
+
/** Additional controller or Kubernetes annotations. */
|
|
95
287
|
annotations?: Record<string, string>;
|
|
96
288
|
}
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
import * as kplus from 'cdk8s-plus-33';
|
|
2
2
|
import { BaseResourceProvider } from '../../baseResourceProvider.js';
|
|
3
|
+
/**
|
|
4
|
+
* AWS-specific Kubernetes resources provider
|
|
5
|
+
* Handles AWS integrations like EBS, EFS, ALB, IRSA, and other AWS services
|
|
6
|
+
*
|
|
7
|
+
* @since 2.8.0+
|
|
8
|
+
*/
|
|
3
9
|
export class AWSResources extends BaseResourceProvider {
|
|
10
|
+
/**
|
|
11
|
+
* Creates an AWS EBS StorageClass
|
|
12
|
+
* @param spec - EBS StorageClass specification
|
|
13
|
+
* @returns Created StorageClass ApiObject
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* awsResources.addEBSStorageClass({
|
|
18
|
+
* name: 'fast-ebs',
|
|
19
|
+
* volumeType: 'gp3',
|
|
20
|
+
* encrypted: true,
|
|
21
|
+
* allowVolumeExpansion: true
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @since 2.8.0+
|
|
26
|
+
*/
|
|
4
27
|
addEBSStorageClass(spec) {
|
|
5
28
|
const parameters = {
|
|
6
29
|
type: spec.volumeType ?? 'gp3',
|
|
@@ -17,9 +40,26 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
17
40
|
allowVolumeExpansion: spec.allowVolumeExpansion ?? true,
|
|
18
41
|
volumeBindingMode: spec.volumeBindingMode ?? 'WaitForFirstConsumer',
|
|
19
42
|
};
|
|
43
|
+
// Validate EBS-specific provisioner
|
|
20
44
|
this.validateStorageClassProvisioner(provisioner, 'EBS');
|
|
21
45
|
return this.createRootLevelApiObject(spec.name, AWSResources.STORAGE_API_VERSION, 'StorageClass', fields, spec.labels, spec.annotations);
|
|
22
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates an AWS EFS StorageClass
|
|
49
|
+
* @param spec - EFS StorageClass specification
|
|
50
|
+
* @returns Created StorageClass ApiObject
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* awsResources.addEFSStorageClass({
|
|
55
|
+
* name: 'efs-storage',
|
|
56
|
+
* fileSystemId: 'fs-12345678',
|
|
57
|
+
* directoryPerms: '0755'
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @since 2.8.0+
|
|
62
|
+
*/
|
|
23
63
|
addEFSStorageClass(spec) {
|
|
24
64
|
const parameters = {
|
|
25
65
|
...(spec.fileSystemId ? { fileSystemId: spec.fileSystemId } : {}),
|
|
@@ -35,9 +75,25 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
35
75
|
reclaimPolicy: spec.reclaimPolicy ?? 'Delete',
|
|
36
76
|
volumeBindingMode: spec.volumeBindingMode ?? 'Immediate',
|
|
37
77
|
};
|
|
78
|
+
// Validate EFS-specific provisioner
|
|
38
79
|
this.validateStorageClassProvisioner(provisioner, 'EFS');
|
|
39
80
|
return this.createRootLevelApiObject(spec.name, AWSResources.STORAGE_API_VERSION, 'StorageClass', fields, spec.labels, spec.annotations);
|
|
40
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Creates an AWS IRSA (IAM Roles for Service Accounts) ServiceAccount
|
|
84
|
+
* @param spec - IRSA ServiceAccount specification
|
|
85
|
+
* @returns Created ServiceAccount ApiObject
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* awsResources.addIRSAServiceAccount({
|
|
90
|
+
* name: 'aws-service-account',
|
|
91
|
+
* roleArn: 'arn:aws:iam::123456789012:role/MyRole'
|
|
92
|
+
* });
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @since 2.8.0+
|
|
96
|
+
*/
|
|
41
97
|
addIRSAServiceAccount(spec) {
|
|
42
98
|
this.validateRoleArn(spec.roleArn);
|
|
43
99
|
const annotations = {
|
|
@@ -52,6 +108,7 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
52
108
|
},
|
|
53
109
|
automountToken: spec.automountServiceAccountToken ?? true,
|
|
54
110
|
});
|
|
111
|
+
// Add image pull secrets if specified
|
|
55
112
|
if (spec.imagePullSecrets) {
|
|
56
113
|
spec.imagePullSecrets.forEach((secret) => {
|
|
57
114
|
serviceAccount.addSecret(kplus.Secret.fromSecretName(this.chart, `${spec.name}-secret-${secret.name}`, secret.name));
|
|
@@ -59,7 +116,30 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
59
116
|
}
|
|
60
117
|
return serviceAccount;
|
|
61
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Creates an AWS ALB Ingress
|
|
121
|
+
* @param spec - ALB Ingress specification
|
|
122
|
+
* @returns Created Ingress ApiObject
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* awsResources.addALBIngress({
|
|
127
|
+
* name: 'web-ingress',
|
|
128
|
+
* rules: [{
|
|
129
|
+
* paths: [{
|
|
130
|
+
* path: '/',
|
|
131
|
+
* pathType: 'Prefix',
|
|
132
|
+
* backend: { service: { name: 'web-service', port: { number: 80 } } }
|
|
133
|
+
* }]
|
|
134
|
+
* }],
|
|
135
|
+
* scheme: 'internet-facing'
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* @since 2.8.0+
|
|
140
|
+
*/
|
|
62
141
|
addALBIngress(spec) {
|
|
142
|
+
// Validate ingress paths format
|
|
63
143
|
this.validateIngressPaths(spec.rules);
|
|
64
144
|
const annotations = this.buildALBAnnotations(spec);
|
|
65
145
|
const ingress = new kplus.Ingress(this.chart, spec.name, {
|
|
@@ -70,15 +150,21 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
70
150
|
},
|
|
71
151
|
className: spec.ingressClassName ?? 'alb',
|
|
72
152
|
});
|
|
153
|
+
// Add rules to the ingress
|
|
73
154
|
spec.rules.forEach((rule) => {
|
|
74
155
|
rule.paths.forEach((path) => {
|
|
75
|
-
|
|
156
|
+
// Create a service reference for the backend - we need to create a Service instance that references the existing service
|
|
157
|
+
const service = new kplus.Service(this.chart, `${spec.name}-service-ref-${path.backend.service.name}`, {
|
|
158
|
+
// This creates a reference to an existing service by name
|
|
159
|
+
// The service should already exist in the cluster
|
|
160
|
+
});
|
|
76
161
|
const backend = kplus.IngressBackend.fromService(service, {
|
|
77
162
|
port: path.backend.service.port.number || parseInt(path.backend.service.port.name || '80'),
|
|
78
163
|
});
|
|
79
164
|
ingress.addRule(path.path, backend, path.pathType);
|
|
80
165
|
});
|
|
81
166
|
});
|
|
167
|
+
// Add TLS configuration if specified
|
|
82
168
|
if (spec.tls) {
|
|
83
169
|
spec.tls.forEach((tlsConfig) => {
|
|
84
170
|
if (tlsConfig.secretName && tlsConfig.hosts) {
|
|
@@ -93,11 +179,23 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
93
179
|
}
|
|
94
180
|
return ingress;
|
|
95
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Validates Ingress paths format according to Kubernetes specification
|
|
184
|
+
* @param rules - Ingress rules to validate
|
|
185
|
+
* @private
|
|
186
|
+
* @since 2.8.0+
|
|
187
|
+
*/
|
|
96
188
|
validateIngressPaths(rules) {
|
|
97
189
|
for (const rule of rules) {
|
|
98
190
|
this.validateIngressRule(rule);
|
|
99
191
|
}
|
|
100
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Validates a single Ingress rule
|
|
195
|
+
* @param rule - Ingress rule to validate
|
|
196
|
+
* @private
|
|
197
|
+
* @since 2.8.0+
|
|
198
|
+
*/
|
|
101
199
|
validateIngressRule(rule) {
|
|
102
200
|
if (!rule.paths || !Array.isArray(rule.paths)) {
|
|
103
201
|
throw new Error('Ingress rule must have a paths array');
|
|
@@ -106,30 +204,58 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
106
204
|
this.validateIngressPath(pathRule);
|
|
107
205
|
}
|
|
108
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* Validates a single Ingress path
|
|
209
|
+
* @param pathRule - Path rule to validate
|
|
210
|
+
* @private
|
|
211
|
+
* @since 2.8.0+
|
|
212
|
+
*/
|
|
109
213
|
validateIngressPath(pathRule) {
|
|
110
214
|
this.validatePathFormat(pathRule.path);
|
|
111
215
|
this.validatePathType(pathRule.pathType);
|
|
112
216
|
this.validateBackend(pathRule.backend);
|
|
113
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Validates path format
|
|
220
|
+
* @param path - Path to validate
|
|
221
|
+
* @private
|
|
222
|
+
* @since 2.5.0
|
|
223
|
+
*/
|
|
114
224
|
validatePathFormat(path) {
|
|
115
225
|
if (!path || typeof path !== 'string') {
|
|
116
226
|
throw new Error('Ingress path must be a non-empty string');
|
|
117
227
|
}
|
|
228
|
+
// Normalize path and check for traversal attempts
|
|
118
229
|
const normalizedPath = path.replace(/\/+/g, '/');
|
|
119
230
|
if (!normalizedPath.startsWith('/')) {
|
|
120
231
|
throw new Error(`Ingress path "${path}" must start with /`);
|
|
121
232
|
}
|
|
233
|
+
// For Kubernetes Ingress paths, we allow URL patterns but warn about suspicious ones
|
|
122
234
|
if (normalizedPath.includes('../') || normalizedPath.includes('./')) {
|
|
235
|
+
// Note: These could be valid URL patterns in some cases, but are suspicious
|
|
236
|
+
// Sanitize path for logging to prevent log injection
|
|
123
237
|
const sanitizedPath = path.replace(/[\r\n]/g, '');
|
|
124
238
|
console.warn(`Warning: Ingress path "${sanitizedPath}" contains path traversal-like sequences`);
|
|
125
239
|
}
|
|
126
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Validates path type
|
|
243
|
+
* @param pathType - Path type to validate
|
|
244
|
+
* @private
|
|
245
|
+
* @since 2.5.0
|
|
246
|
+
*/
|
|
127
247
|
validatePathType(pathType) {
|
|
128
248
|
const validPathTypes = ['Exact', 'Prefix', 'ImplementationSpecific'];
|
|
129
249
|
if (!validPathTypes.includes(pathType)) {
|
|
130
250
|
throw new Error(`Invalid pathType "${pathType}". Must be one of: ${validPathTypes.join(', ')}`);
|
|
131
251
|
}
|
|
132
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Validates backend configuration
|
|
255
|
+
* @param backend - Backend to validate
|
|
256
|
+
* @private
|
|
257
|
+
* @since 2.5.0
|
|
258
|
+
*/
|
|
133
259
|
validateBackend(backend) {
|
|
134
260
|
if (!backend?.service?.name) {
|
|
135
261
|
throw new Error('Ingress path backend must specify service name');
|
|
@@ -143,6 +269,13 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
143
269
|
throw new Error(`Invalid port number ${port.number}. Must be between 1 and 65535`);
|
|
144
270
|
}
|
|
145
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Validates StorageClass provisioner is present and valid
|
|
274
|
+
* @param provisioner - Provisioner string to validate
|
|
275
|
+
* @param storageType - Type of storage (for error messages)
|
|
276
|
+
* @private
|
|
277
|
+
* @since 2.5.0
|
|
278
|
+
*/
|
|
146
279
|
validateStorageClassProvisioner(provisioner, storageType) {
|
|
147
280
|
if (!provisioner || typeof provisioner !== 'string' || provisioner.trim() === '') {
|
|
148
281
|
throw new Error(`${storageType} StorageClass must have a valid provisioner`);
|
|
@@ -151,6 +284,7 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
151
284
|
EBS: 'ebs.csi.aws.com',
|
|
152
285
|
EFS: 'efs.csi.aws.com',
|
|
153
286
|
};
|
|
287
|
+
// Validate provisioner matches storage type
|
|
154
288
|
const expectedProvisioner = validProvisioners[storageType];
|
|
155
289
|
if (!expectedProvisioner) {
|
|
156
290
|
throw new Error(`Invalid storage type: ${storageType}`);
|
|
@@ -159,7 +293,12 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
159
293
|
throw new Error(`Invalid AWS ${storageType} provisioner "${provisioner}". Must be: ${expectedProvisioner}`);
|
|
160
294
|
}
|
|
161
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Validates AWS IAM Role ARN format
|
|
298
|
+
* @param roleArn - Role ARN to validate
|
|
299
|
+
*/
|
|
162
300
|
validateRoleArn(roleArn) {
|
|
301
|
+
// Skip validation for Helm template values
|
|
163
302
|
if (roleArn.includes('{{') && roleArn.includes('}}')) {
|
|
164
303
|
return;
|
|
165
304
|
}
|
|
@@ -168,8 +307,15 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
168
307
|
throw new Error(`Invalid AWS IAM Role ARN format: ${roleArn}`);
|
|
169
308
|
}
|
|
170
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Builds ALB-specific annotations
|
|
312
|
+
* @param spec - ALB Ingress specification
|
|
313
|
+
* @returns ALB annotations
|
|
314
|
+
*/
|
|
171
315
|
buildALBAnnotations(spec) {
|
|
172
316
|
const annotations = {
|
|
317
|
+
// Remove deprecated kubernetes.io/ingress.class annotation
|
|
318
|
+
// Use spec.ingressClassName instead
|
|
173
319
|
...(spec.annotations ?? {}),
|
|
174
320
|
};
|
|
175
321
|
if (spec.scheme) {
|
|
@@ -189,6 +335,21 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
189
335
|
}
|
|
190
336
|
return annotations;
|
|
191
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* Creates a ServiceAccount with ECR access annotations
|
|
340
|
+
* @param spec - ECR ServiceAccount specification
|
|
341
|
+
* @returns Created ServiceAccount ApiObject
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```typescript
|
|
345
|
+
* awsResources.addECRServiceAccount({
|
|
346
|
+
* name: 'ecr-service-account',
|
|
347
|
+
* roleArn: 'arn:aws:iam::123456789012:role/ECRAccessRole'
|
|
348
|
+
* });
|
|
349
|
+
* ```
|
|
350
|
+
*
|
|
351
|
+
* @since 2.8.0+
|
|
352
|
+
*/
|
|
192
353
|
addECRServiceAccount(spec) {
|
|
193
354
|
const annotations = {
|
|
194
355
|
'eks.amazonaws.com/role-arn': spec.roleArn,
|
|
@@ -202,6 +363,7 @@ export class AWSResources extends BaseResourceProvider {
|
|
|
202
363
|
},
|
|
203
364
|
automountToken: spec.automountServiceAccountToken ?? true,
|
|
204
365
|
});
|
|
366
|
+
// Add image pull secrets if specified
|
|
205
367
|
if (spec.imagePullSecrets) {
|
|
206
368
|
spec.imagePullSecrets.forEach((secret) => {
|
|
207
369
|
serviceAccount.addSecret(kplus.Secret.fromSecretName(this.chart, `${spec.name}-ecr-secret-${secret.name}`, secret.name));
|