@highstate/k8s 0.7.2 → 0.7.4
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/dist/{helm-wPTgVV1N.js → chunk-K4WKJ4L5.js} +89 -47
- package/dist/chunk-K4WKJ4L5.js.map +1 -0
- package/dist/{shared-Clzbl5K-.js → chunk-T5Z2M4JE.js} +21 -7
- package/dist/chunk-T5Z2M4JE.js.map +1 -0
- package/dist/highstate.manifest.json +9 -0
- package/dist/index.js +304 -154
- package/dist/index.js.map +1 -0
- package/dist/units/access-point/index.js +9 -7
- package/dist/units/access-point/index.js.map +1 -0
- package/dist/units/cert-manager/index.js +29 -29
- package/dist/units/cert-manager/index.js.map +1 -0
- package/dist/units/dns01-issuer/index.js +22 -14
- package/dist/units/dns01-issuer/index.js.map +1 -0
- package/dist/units/existing-cluster/index.js +49 -21
- package/dist/units/existing-cluster/index.js.map +1 -0
- package/package.json +15 -16
- package/src/access-point.ts +185 -0
- package/src/container.ts +271 -0
- package/src/cron-job.ts +77 -0
- package/src/deployment.ts +210 -0
- package/src/gateway/backend.ts +61 -0
- package/src/gateway/http-route.ts +139 -0
- package/src/gateway/index.ts +2 -0
- package/src/helm.ts +298 -0
- package/src/index.ts +61 -0
- package/src/job.ts +66 -0
- package/src/network-policy.ts +732 -0
- package/src/pod.ts +5 -0
- package/src/pvc.ts +178 -0
- package/src/scripting/bundle.ts +244 -0
- package/src/scripting/container.ts +44 -0
- package/src/scripting/environment.ts +79 -0
- package/src/scripting/index.ts +3 -0
- package/src/service.ts +279 -0
- package/src/shared.ts +150 -0
- package/src/stateful-set.ts +159 -0
- package/src/units/access-point/index.ts +12 -0
- package/src/units/cert-manager/index.ts +37 -0
- package/src/units/dns01-issuer/index.ts +41 -0
- package/src/units/dns01-issuer/solver.ts +23 -0
- package/src/units/existing-cluster/index.ts +107 -0
- package/src/workload.ts +150 -0
- package/assets/charts.json +0 -8
- package/dist/index.d.ts +0 -1036
@@ -0,0 +1,732 @@
|
|
1
|
+
import { networking, types, type core } from "@pulumi/kubernetes"
|
2
|
+
import {
|
3
|
+
ComponentResource,
|
4
|
+
normalize,
|
5
|
+
output,
|
6
|
+
type Input,
|
7
|
+
type InputArray,
|
8
|
+
type Output,
|
9
|
+
type Resource,
|
10
|
+
type ResourceOptions,
|
11
|
+
type Unwrap,
|
12
|
+
} from "@highstate/pulumi"
|
13
|
+
import { capitalize, flat, merge, mergeDeep } from "remeda"
|
14
|
+
import { parseDomain, ParseResultType, type ParseResultIp } from "parse-domain"
|
15
|
+
import { k8s } from "@highstate/library"
|
16
|
+
import {
|
17
|
+
mapMetadata,
|
18
|
+
mapNamespaceLikeToNamespaceName,
|
19
|
+
mapNamespaceNameToSelector,
|
20
|
+
mapSelectorLikeToSelector,
|
21
|
+
type CommonArgs,
|
22
|
+
type NamespaceLike,
|
23
|
+
type SelectorLike,
|
24
|
+
} from "./shared"
|
25
|
+
import { mapServiceToLabelSelector } from "./service"
|
26
|
+
|
27
|
+
export type NetworkPolicyPort = {
|
28
|
+
/**
|
29
|
+
* The protocol to match.
|
30
|
+
*
|
31
|
+
* If not provided, "TCP" will be used.
|
32
|
+
*/
|
33
|
+
protocol?: string
|
34
|
+
} & (
|
35
|
+
| {
|
36
|
+
/**
|
37
|
+
* The single port to match.
|
38
|
+
*/
|
39
|
+
port: number
|
40
|
+
}
|
41
|
+
| {
|
42
|
+
/**
|
43
|
+
* The range of ports to match.
|
44
|
+
*/
|
45
|
+
range: [start: number, end: number]
|
46
|
+
}
|
47
|
+
)
|
48
|
+
|
49
|
+
export type IngressRuleArgs = {
|
50
|
+
/**
|
51
|
+
* Whether to allow all incoming traffic.
|
52
|
+
*
|
53
|
+
* If set to `true`, all other rules will be ignored for matched traffic.
|
54
|
+
*/
|
55
|
+
fromAll?: Input<boolean>
|
56
|
+
|
57
|
+
/**
|
58
|
+
* The allowed cidr for incoming traffic.
|
59
|
+
*
|
60
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
61
|
+
*/
|
62
|
+
fromCidr?: Input<string>
|
63
|
+
|
64
|
+
/**
|
65
|
+
* The list of allowed cidrs for incoming traffic.
|
66
|
+
*
|
67
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
68
|
+
*/
|
69
|
+
fromCidrs?: InputArray<string>
|
70
|
+
|
71
|
+
/**
|
72
|
+
* The service to allow traffic from.
|
73
|
+
*
|
74
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
75
|
+
*/
|
76
|
+
fromService?: Input<core.v1.Service>
|
77
|
+
|
78
|
+
/**
|
79
|
+
* The list of allowed services for incoming traffic.
|
80
|
+
*
|
81
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
82
|
+
*/
|
83
|
+
fromServices?: InputArray<core.v1.Service>
|
84
|
+
|
85
|
+
/**
|
86
|
+
* The namespace to allow traffic from.
|
87
|
+
*
|
88
|
+
* If provided with `fromSelector(s)`, it will be ANDed with them.
|
89
|
+
* Otherwise, it will match all pods in the namespace.
|
90
|
+
*
|
91
|
+
* Will be ORed with other conditions inside the same rule (except ports and selectors).
|
92
|
+
*/
|
93
|
+
fromNamespace?: Input<NamespaceLike>
|
94
|
+
|
95
|
+
/**
|
96
|
+
* The list of allowed namespaces for incoming traffic.
|
97
|
+
*
|
98
|
+
* If provided with `fromSelector(s)`, it will be ANDed with them.
|
99
|
+
* Otherwise, it will match all pods in the namespaces.
|
100
|
+
*
|
101
|
+
* Will be ORed with other conditions inside the same rule (except ports and selectors).
|
102
|
+
*/
|
103
|
+
fromNamespaces?: InputArray<NamespaceLike>
|
104
|
+
|
105
|
+
/**
|
106
|
+
* The selector for incoming traffic.
|
107
|
+
*
|
108
|
+
* If provided with `fromNamespace(s)`, it will be ANDed with them.
|
109
|
+
* Otherwise, it will match pods in all namespaces.
|
110
|
+
*
|
111
|
+
* Will be ORed with other conditions inside the same rule (except ports and namespaces).
|
112
|
+
*/
|
113
|
+
fromSelector?: Input<SelectorLike>
|
114
|
+
|
115
|
+
/**
|
116
|
+
* The list of selectors for incoming traffic.
|
117
|
+
*
|
118
|
+
* If provided with `fromNamespace(s)`, it will be ANDed with them.
|
119
|
+
* Otherwise, it will match pods in all namespaces.
|
120
|
+
*
|
121
|
+
* Will be ORed with other conditions inside the same rule (except ports and namespaces).
|
122
|
+
*/
|
123
|
+
fromSelectors?: InputArray<SelectorLike>
|
124
|
+
|
125
|
+
/**
|
126
|
+
* The port to allow incoming traffic on.
|
127
|
+
*
|
128
|
+
* Will be ANDed with all conditions inside the same rule.
|
129
|
+
*/
|
130
|
+
toPort?: Input<NetworkPolicyPort>
|
131
|
+
|
132
|
+
/**
|
133
|
+
* The list of allowed ports for incoming traffic.
|
134
|
+
*
|
135
|
+
* Will be ANDed with all conditions inside the same rule.
|
136
|
+
*/
|
137
|
+
toPorts?: InputArray<NetworkPolicyPort>
|
138
|
+
}
|
139
|
+
|
140
|
+
export type EgressRuleArgs = {
|
141
|
+
/**
|
142
|
+
* Whether to allow all outgoing traffic.
|
143
|
+
*
|
144
|
+
* If set to `true`, all other rules will be ignored for matched traffic.
|
145
|
+
*/
|
146
|
+
toAll?: Input<boolean>
|
147
|
+
|
148
|
+
/**
|
149
|
+
* The allowed cidr for outgoing traffic.
|
150
|
+
*
|
151
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
152
|
+
*/
|
153
|
+
toCidr?: Input<string>
|
154
|
+
|
155
|
+
/**
|
156
|
+
* The list of allowed cidrs for outgoing traffic.
|
157
|
+
*
|
158
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
159
|
+
*/
|
160
|
+
toCidrs?: InputArray<string>
|
161
|
+
|
162
|
+
/**
|
163
|
+
* The FQDN to allow outgoing traffic.
|
164
|
+
*
|
165
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
166
|
+
*/
|
167
|
+
toFqdn?: Input<string>
|
168
|
+
|
169
|
+
/**
|
170
|
+
* The list of allowed FQDNs for outgoing traffic.
|
171
|
+
*
|
172
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
173
|
+
*/
|
174
|
+
toFqdns?: InputArray<string>
|
175
|
+
|
176
|
+
/**
|
177
|
+
* Either the FQDN or the IP address of the endpoint to allow outgoing traffic.
|
178
|
+
*
|
179
|
+
* Just a syntactic sugar for `toFqdn` and `toCidr` for cases when the endpoint can be both.
|
180
|
+
*
|
181
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
182
|
+
*/
|
183
|
+
toEndpoint?: Input<string>
|
184
|
+
|
185
|
+
/**
|
186
|
+
* The list of allowed endpoints for outgoing traffic.
|
187
|
+
*
|
188
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
189
|
+
*/
|
190
|
+
toEndpoints?: InputArray<string>
|
191
|
+
|
192
|
+
/**
|
193
|
+
* The service to allow traffic to.
|
194
|
+
*
|
195
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
196
|
+
*/
|
197
|
+
toService?: Input<core.v1.Service>
|
198
|
+
|
199
|
+
/**
|
200
|
+
* The list of allowed services for outgoing traffic.
|
201
|
+
*
|
202
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
203
|
+
*/
|
204
|
+
toServices?: InputArray<core.v1.Service>
|
205
|
+
|
206
|
+
/**
|
207
|
+
* The namespace to allow traffic to.
|
208
|
+
*
|
209
|
+
* If provided with `toSelector(s)`, it will be ANDed with them.
|
210
|
+
* Otherwise, it will match all pods in the namespace.
|
211
|
+
*
|
212
|
+
* Will be ORed with other conditions inside the same rule (except ports and selectors).
|
213
|
+
*/
|
214
|
+
toNamespace?: Input<NamespaceLike>
|
215
|
+
|
216
|
+
/**
|
217
|
+
* The list of allowed namespaces for outgoing traffic.
|
218
|
+
*
|
219
|
+
* If provided with `toSelector(s)`, it will be ANDed with them.
|
220
|
+
* Otherwise, it will match all pods in the namespaces.
|
221
|
+
*
|
222
|
+
* Will be ORed with other conditions inside the same rule (except ports and selectors).
|
223
|
+
*/
|
224
|
+
toNamespaces?: InputArray<NamespaceLike>
|
225
|
+
|
226
|
+
/**
|
227
|
+
* The selector for outgoing traffic.
|
228
|
+
*
|
229
|
+
* If provided with `toNamespace(s)`, it will be ANDe with them.
|
230
|
+
*
|
231
|
+
* Otherwise, it will match pods only in all namespaces.
|
232
|
+
*/
|
233
|
+
toSelector?: Input<SelectorLike>
|
234
|
+
|
235
|
+
/**
|
236
|
+
* The list of selectors for outgoing traffic.
|
237
|
+
*
|
238
|
+
* If provided with `toNamespace(s)`, it will be ANDed with them.
|
239
|
+
* Otherwise, it will match pods only in all namespaces.
|
240
|
+
*/
|
241
|
+
toSelectors?: InputArray<SelectorLike>
|
242
|
+
|
243
|
+
/**
|
244
|
+
* The port to allow outgoing traffic on.
|
245
|
+
*
|
246
|
+
* Will be ANDed with all conditions inside the same rule.
|
247
|
+
*/
|
248
|
+
toPort?: Input<NetworkPolicyPort>
|
249
|
+
|
250
|
+
/**
|
251
|
+
* The list of allowed ports for outgoing traffic.
|
252
|
+
*
|
253
|
+
* Will be ANDed with all conditions inside the same rule.
|
254
|
+
*/
|
255
|
+
toPorts?: InputArray<NetworkPolicyPort>
|
256
|
+
}
|
257
|
+
|
258
|
+
export type NetworkPolicyArgs = CommonArgs & {
|
259
|
+
/**
|
260
|
+
* The description of this network policy.
|
261
|
+
*/
|
262
|
+
description?: Input<string>
|
263
|
+
|
264
|
+
/**
|
265
|
+
* The pod selector for this network policy.
|
266
|
+
* If not provided, it will select all pods in the namespace.
|
267
|
+
*/
|
268
|
+
selector?: SelectorLike
|
269
|
+
|
270
|
+
/**
|
271
|
+
* The rule for incoming traffic.
|
272
|
+
*/
|
273
|
+
ingressRule?: Input<IngressRuleArgs>
|
274
|
+
|
275
|
+
/**
|
276
|
+
* The rules for incoming traffic.
|
277
|
+
*/
|
278
|
+
ingressRules?: InputArray<IngressRuleArgs>
|
279
|
+
|
280
|
+
/**
|
281
|
+
* The rule for outgoing traffic.
|
282
|
+
*/
|
283
|
+
egressRule?: Input<EgressRuleArgs>
|
284
|
+
|
285
|
+
/**
|
286
|
+
* The rules for outgoing traffic.
|
287
|
+
*/
|
288
|
+
egressRules?: InputArray<EgressRuleArgs>
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Enable the isolation of ingress traffic, so that only matched traffic can ingress.
|
292
|
+
*/
|
293
|
+
isolateIngress?: Input<boolean>
|
294
|
+
|
295
|
+
/**
|
296
|
+
* Enable the isolation of egress traffic, so that only matched traffic can egress.
|
297
|
+
*/
|
298
|
+
isolateEgress?: Input<boolean>
|
299
|
+
|
300
|
+
/**
|
301
|
+
* Allow the eggress traffic to the API server of the cluster.
|
302
|
+
*
|
303
|
+
* By default, `false`.
|
304
|
+
*/
|
305
|
+
allowKubeApiServer?: Input<boolean>
|
306
|
+
|
307
|
+
/**
|
308
|
+
* Allow the eggress traffic to the DNS server of the cluster.
|
309
|
+
*
|
310
|
+
* By default, `false`.
|
311
|
+
*/
|
312
|
+
allowKubeDns?: Input<boolean>
|
313
|
+
}
|
314
|
+
|
315
|
+
export type FullNetworkPolicyArgs = NetworkPolicyArgs & {
|
316
|
+
/**
|
317
|
+
* The name of the CNI plugin to use for creating network policies.
|
318
|
+
* If not provided or set to `unknown`, it will use the native `NetworkPolicy` resource.
|
319
|
+
*/
|
320
|
+
cni?: Input<string | undefined>
|
321
|
+
}
|
322
|
+
|
323
|
+
export type NormalizedRuleArgs = {
|
324
|
+
all: boolean
|
325
|
+
cidrs: string[]
|
326
|
+
fqdns: string[]
|
327
|
+
services: core.v1.Service[]
|
328
|
+
namespaces: NamespaceLike[]
|
329
|
+
selectors: SelectorLike[]
|
330
|
+
ports: NetworkPolicyPort[]
|
331
|
+
}
|
332
|
+
|
333
|
+
export type NormalizedNetworkPolicyArgs = Omit<
|
334
|
+
Unwrap<NetworkPolicyArgs>,
|
335
|
+
| "podSelector"
|
336
|
+
| "ingressRule"
|
337
|
+
| "ingressRules"
|
338
|
+
| "egressRule"
|
339
|
+
| "egressRules"
|
340
|
+
| "isolateIngress"
|
341
|
+
| "isolateEgress"
|
342
|
+
| "allowKubeApiServer"
|
343
|
+
| "allowKubeDNS"
|
344
|
+
> & {
|
345
|
+
podSelector: Unwrap<types.input.meta.v1.LabelSelector>
|
346
|
+
|
347
|
+
isolateIngress: boolean
|
348
|
+
isolateEgress: boolean
|
349
|
+
|
350
|
+
allowKubeApiServer: boolean
|
351
|
+
|
352
|
+
ingressRules: NormalizedRuleArgs[]
|
353
|
+
egressRules: NormalizedRuleArgs[]
|
354
|
+
}
|
355
|
+
|
356
|
+
/**
|
357
|
+
* The abstract resource for creating network policies.
|
358
|
+
* Will use different resources depending on the environment.
|
359
|
+
*
|
360
|
+
* Note: In the worst case, it will create native `NetworkPolicy` resources and ignore some features like L7 rules.
|
361
|
+
*/
|
362
|
+
export abstract class NetworkPolicy extends ComponentResource {
|
363
|
+
/**
|
364
|
+
* The underlying network policy resource.
|
365
|
+
*/
|
366
|
+
public readonly networkPolicy: Output<Resource>
|
367
|
+
|
368
|
+
protected constructor(name: string, args: Unwrap<NetworkPolicyArgs>, opts?: ResourceOptions) {
|
369
|
+
super("k8s:network-policy", name, args, opts)
|
370
|
+
|
371
|
+
const normalizedArgs = output(args).apply(args => {
|
372
|
+
const ingressRules = normalize(args.ingressRule, args.ingressRules)
|
373
|
+
const egressRules = normalize(args.egressRule, args.egressRules)
|
374
|
+
|
375
|
+
const endpoints = normalize(args.egressRule?.toEndpoint, args.egressRule?.toEndpoints)
|
376
|
+
const parsedEndpoints = endpoints.map(endpoint => parseDomain(endpoint))
|
377
|
+
|
378
|
+
const cidrsFromEndpoints = parsedEndpoints
|
379
|
+
.filter(result => result.type === ParseResultType.Ip)
|
380
|
+
.map(result => NetworkPolicy.mapCidrFromEndpoint(result))
|
381
|
+
|
382
|
+
const fqdnsFromEndpoints = parsedEndpoints
|
383
|
+
.filter(result => result.type !== ParseResultType.Invalid)
|
384
|
+
.map(result => result.hostname)
|
385
|
+
|
386
|
+
const extraEgressRules: NormalizedRuleArgs[] = []
|
387
|
+
|
388
|
+
if (args.allowKubeDns) {
|
389
|
+
extraEgressRules.push({
|
390
|
+
namespaces: ["kube-system"],
|
391
|
+
selectors: [{ matchLabels: { "k8s-app": "kube-dns" } }],
|
392
|
+
ports: [{ port: 53, protocol: "UDP" }],
|
393
|
+
all: false,
|
394
|
+
cidrs: [],
|
395
|
+
fqdns: [],
|
396
|
+
services: [],
|
397
|
+
})
|
398
|
+
}
|
399
|
+
|
400
|
+
return {
|
401
|
+
...args,
|
402
|
+
|
403
|
+
podSelector: args.selector ? mapSelectorLikeToSelector(args.selector) : {},
|
404
|
+
|
405
|
+
isolateEgress: args.isolateEgress ?? false,
|
406
|
+
isolateIngress: args.isolateIngress ?? false,
|
407
|
+
|
408
|
+
allowKubeApiServer: args.allowKubeApiServer ?? false,
|
409
|
+
|
410
|
+
ingressRules: ingressRules.map(rule => ({
|
411
|
+
all: rule.fromAll ?? false,
|
412
|
+
cidrs: normalize(rule.fromCidr, rule.fromCidrs),
|
413
|
+
fqdns: [],
|
414
|
+
services: normalize(rule.fromService, rule.fromServices),
|
415
|
+
namespaces: normalize(rule.fromNamespace, rule.fromNamespaces),
|
416
|
+
selectors: normalize(rule.fromSelector, rule.fromSelectors),
|
417
|
+
ports: normalize(rule.toPort, rule.toPorts),
|
418
|
+
})),
|
419
|
+
|
420
|
+
egressRules: egressRules
|
421
|
+
.map(rule => {
|
422
|
+
return {
|
423
|
+
all: rule.toAll ?? false,
|
424
|
+
cidrs: normalize(rule.toCidr, rule.toCidrs).concat(cidrsFromEndpoints),
|
425
|
+
fqdns: normalize(rule.toFqdn, rule.toFqdns).concat(fqdnsFromEndpoints),
|
426
|
+
services: normalize(rule.toService, rule.toServices),
|
427
|
+
namespaces: normalize(rule.toNamespace, rule.toNamespaces),
|
428
|
+
selectors: normalize(rule.toSelector, rule.toSelectors),
|
429
|
+
ports: normalize(rule.toPort, rule.toPorts),
|
430
|
+
} as NormalizedRuleArgs
|
431
|
+
})
|
432
|
+
.concat(extraEgressRules),
|
433
|
+
}
|
434
|
+
})
|
435
|
+
|
436
|
+
this.networkPolicy = normalizedArgs.apply(args => {
|
437
|
+
return output(
|
438
|
+
this.create(name, args as NormalizedNetworkPolicyArgs, { ...opts, parent: this }),
|
439
|
+
)
|
440
|
+
})
|
441
|
+
|
442
|
+
this.registerOutputs({ networkPolicy: this.networkPolicy })
|
443
|
+
}
|
444
|
+
|
445
|
+
private static mapCidrFromEndpoint(result: ParseResultIp): string {
|
446
|
+
if (result.ipVersion === 4) {
|
447
|
+
return `${result.hostname}/32`
|
448
|
+
}
|
449
|
+
|
450
|
+
return `${result.hostname}/128`
|
451
|
+
}
|
452
|
+
|
453
|
+
protected abstract create(
|
454
|
+
name: string,
|
455
|
+
args: NormalizedNetworkPolicyArgs,
|
456
|
+
opts?: ResourceOptions,
|
457
|
+
): Input<Resource>
|
458
|
+
|
459
|
+
private static readonly supportedCNIs = ["cilium"]
|
460
|
+
|
461
|
+
static create(
|
462
|
+
name: string,
|
463
|
+
args: FullNetworkPolicyArgs,
|
464
|
+
opts: ResourceOptions,
|
465
|
+
): Output<NetworkPolicy> {
|
466
|
+
return output(args).apply(async args => {
|
467
|
+
if (!args.cni || !NetworkPolicy.supportedCNIs.includes(args.cni)) {
|
468
|
+
return new NativeNetworkPolicy(name, args, opts)
|
469
|
+
}
|
470
|
+
|
471
|
+
const implName = `${capitalize(args.cni)}NetworkPolicy`
|
472
|
+
const implModule = (await import(`@highstate/${args.cni}`)) as Record<string, unknown>
|
473
|
+
|
474
|
+
type NetworkPolicyFactory = new (
|
475
|
+
name: string,
|
476
|
+
args: Unwrap<NetworkPolicyArgs>,
|
477
|
+
opts?: ResourceOptions,
|
478
|
+
) => NetworkPolicy
|
479
|
+
|
480
|
+
const implClass = implModule[implName] as NetworkPolicyFactory | undefined
|
481
|
+
if (!implClass) {
|
482
|
+
throw new Error(`No implementation found for ${args.cni}`)
|
483
|
+
}
|
484
|
+
|
485
|
+
return new implClass(name, args, opts)
|
486
|
+
})
|
487
|
+
}
|
488
|
+
|
489
|
+
static allowInsideNamespace(
|
490
|
+
namespace: Input<NamespaceLike>,
|
491
|
+
k8sCluster: Input<k8s.Cluster>,
|
492
|
+
opts: ResourceOptions,
|
493
|
+
): Output<NetworkPolicy> {
|
494
|
+
return NetworkPolicy.create(
|
495
|
+
"allow-inside-namespace",
|
496
|
+
{
|
497
|
+
namespace,
|
498
|
+
cni: output(k8sCluster).info.cni,
|
499
|
+
|
500
|
+
description: "Allow all traffic inside the namespace.",
|
501
|
+
selector: {},
|
502
|
+
|
503
|
+
ingressRule: { fromNamespace: namespace },
|
504
|
+
egressRule: { toNamespace: namespace },
|
505
|
+
},
|
506
|
+
opts,
|
507
|
+
)
|
508
|
+
}
|
509
|
+
|
510
|
+
static allowKubeApiServer(
|
511
|
+
namespace: Input<NamespaceLike>,
|
512
|
+
k8sCluster: Input<k8s.Cluster>,
|
513
|
+
opts: ResourceOptions,
|
514
|
+
): Output<NetworkPolicy> {
|
515
|
+
return NetworkPolicy.create(
|
516
|
+
"allow-kube-api-server",
|
517
|
+
{
|
518
|
+
namespace,
|
519
|
+
cni: output(k8sCluster).info.cni,
|
520
|
+
|
521
|
+
description: "Allow all traffic to the Kubernetes API server from the namespace.",
|
522
|
+
|
523
|
+
allowKubeApiServer: true,
|
524
|
+
},
|
525
|
+
opts,
|
526
|
+
)
|
527
|
+
}
|
528
|
+
|
529
|
+
static allowKubeDns(
|
530
|
+
namespace: Input<NamespaceLike>,
|
531
|
+
k8sCluster: Input<k8s.Cluster>,
|
532
|
+
opts: ResourceOptions,
|
533
|
+
): Output<NetworkPolicy> {
|
534
|
+
return NetworkPolicy.create(
|
535
|
+
"allow-kube-dns",
|
536
|
+
{
|
537
|
+
namespace,
|
538
|
+
cni: output(k8sCluster).info.cni,
|
539
|
+
|
540
|
+
description: "Allow all traffic to the Kubernetes DNS server from the namespace.",
|
541
|
+
|
542
|
+
allowKubeDns: true,
|
543
|
+
},
|
544
|
+
opts,
|
545
|
+
)
|
546
|
+
}
|
547
|
+
|
548
|
+
static allowAllEgress(
|
549
|
+
namespace: Input<NamespaceLike>,
|
550
|
+
k8sCluster: Input<k8s.Cluster>,
|
551
|
+
opts: ResourceOptions,
|
552
|
+
): Output<NetworkPolicy> {
|
553
|
+
return NetworkPolicy.create(
|
554
|
+
"allow-all-egress",
|
555
|
+
{
|
556
|
+
namespace,
|
557
|
+
cni: output(k8sCluster).info.cni,
|
558
|
+
|
559
|
+
description: "Allow all egress traffic from the namespace.",
|
560
|
+
|
561
|
+
egressRule: { toAll: true },
|
562
|
+
},
|
563
|
+
opts,
|
564
|
+
)
|
565
|
+
}
|
566
|
+
}
|
567
|
+
|
568
|
+
export class NativeNetworkPolicy extends NetworkPolicy {
|
569
|
+
protected create(
|
570
|
+
name: string,
|
571
|
+
args: NormalizedNetworkPolicyArgs,
|
572
|
+
opts?: ResourceOptions,
|
573
|
+
): Resource {
|
574
|
+
const ingress = NativeNetworkPolicy.createIngressRules(args)
|
575
|
+
const egress = NativeNetworkPolicy.createEgressRules(args)
|
576
|
+
|
577
|
+
const policyTypes: string[] = []
|
578
|
+
|
579
|
+
if (ingress.length > 0 || args.isolateIngress) {
|
580
|
+
policyTypes.push("Ingress")
|
581
|
+
}
|
582
|
+
|
583
|
+
if (egress.length > 0 || args.isolateEgress) {
|
584
|
+
policyTypes.push("Egress")
|
585
|
+
}
|
586
|
+
|
587
|
+
return new networking.v1.NetworkPolicy(
|
588
|
+
name,
|
589
|
+
{
|
590
|
+
metadata: mergeDeep(mapMetadata(args, name), {
|
591
|
+
annotations: args.description
|
592
|
+
? { "kubernetes.io/description": args.description }
|
593
|
+
: undefined,
|
594
|
+
}),
|
595
|
+
spec: {
|
596
|
+
podSelector: args.podSelector,
|
597
|
+
ingress,
|
598
|
+
egress,
|
599
|
+
policyTypes,
|
600
|
+
},
|
601
|
+
},
|
602
|
+
opts,
|
603
|
+
)
|
604
|
+
}
|
605
|
+
|
606
|
+
private static fallbackIpBlock: types.input.networking.v1.IPBlock = {
|
607
|
+
cidr: "0.0.0.0/0",
|
608
|
+
except: ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
|
609
|
+
}
|
610
|
+
|
611
|
+
private static createIngressRules(
|
612
|
+
args: NormalizedNetworkPolicyArgs,
|
613
|
+
): types.input.networking.v1.NetworkPolicyIngressRule[] {
|
614
|
+
return args.ingressRules.map(rule => ({
|
615
|
+
from: rule.all ? undefined : NativeNetworkPolicy.createRulePeers(rule),
|
616
|
+
ports: NativeNetworkPolicy.mapPorts(rule.ports),
|
617
|
+
}))
|
618
|
+
}
|
619
|
+
|
620
|
+
private static createEgressRules(
|
621
|
+
args: NormalizedNetworkPolicyArgs,
|
622
|
+
): types.input.networking.v1.NetworkPolicyEgressRule[] {
|
623
|
+
// the native resource does not support FQDNs
|
624
|
+
// to provide compatibility, we need to fallback to all except private CIDRs
|
625
|
+
const needFallback = args.egressRules.some(rule => rule.fqdns.length > 0)
|
626
|
+
if (needFallback) {
|
627
|
+
return [{ to: [{ ipBlock: NativeNetworkPolicy.fallbackIpBlock }] }]
|
628
|
+
}
|
629
|
+
|
630
|
+
const extraRules: types.input.networking.v1.NetworkPolicyEgressRule[] = []
|
631
|
+
|
632
|
+
if (args.allowKubeApiServer) {
|
633
|
+
// TODO: the "10.96.0.1" is not guaranteed to be the API server
|
634
|
+
extraRules.push({ to: [{ ipBlock: { cidr: "10.96.0.1" } }] })
|
635
|
+
}
|
636
|
+
|
637
|
+
return args.egressRules
|
638
|
+
.map(rule => {
|
639
|
+
return {
|
640
|
+
to: rule.all ? undefined : NativeNetworkPolicy.createRulePeers(rule),
|
641
|
+
ports: NativeNetworkPolicy.mapPorts(rule.ports),
|
642
|
+
} as types.input.networking.v1.NetworkPolicyEgressRule
|
643
|
+
})
|
644
|
+
.concat(extraRules)
|
645
|
+
}
|
646
|
+
|
647
|
+
private static createRulePeers(
|
648
|
+
this: void,
|
649
|
+
args: NormalizedRuleArgs,
|
650
|
+
): types.input.networking.v1.NetworkPolicyPeer[] {
|
651
|
+
return [
|
652
|
+
...NativeNetworkPolicy.createCidrPeers(args),
|
653
|
+
...NativeNetworkPolicy.createServicePeers(args),
|
654
|
+
...NativeNetworkPolicy.createSelectorPeers(args),
|
655
|
+
]
|
656
|
+
}
|
657
|
+
|
658
|
+
private static createCidrPeers(
|
659
|
+
args: NormalizedRuleArgs,
|
660
|
+
): types.input.networking.v1.NetworkPolicyPeer[] {
|
661
|
+
return args.cidrs.map(cidr => ({ ipBlock: { cidr } }))
|
662
|
+
}
|
663
|
+
|
664
|
+
private static createServicePeers(
|
665
|
+
args: NormalizedRuleArgs,
|
666
|
+
): types.input.networking.v1.NetworkPolicyPeer[] {
|
667
|
+
return args.services.map(service => {
|
668
|
+
const selector = mapServiceToLabelSelector(service)
|
669
|
+
|
670
|
+
return {
|
671
|
+
namespaceSelector: mapNamespaceNameToSelector(service.metadata.namespace),
|
672
|
+
podSelector: selector,
|
673
|
+
}
|
674
|
+
})
|
675
|
+
}
|
676
|
+
|
677
|
+
private static createSelectorPeers(
|
678
|
+
args: NormalizedRuleArgs,
|
679
|
+
): types.input.networking.v1.NetworkPolicyPeer[] {
|
680
|
+
const selectorPeers = args.selectors.map(selector => ({
|
681
|
+
podSelector: mapSelectorLikeToSelector(selector),
|
682
|
+
}))
|
683
|
+
|
684
|
+
const namespacePeers = args.namespaces.map(NativeNetworkPolicy.createNamespacePeer)
|
685
|
+
|
686
|
+
if (namespacePeers.length === 0) {
|
687
|
+
// if there are no namespaces, we can just return selector peers
|
688
|
+
return selectorPeers
|
689
|
+
}
|
690
|
+
|
691
|
+
if (selectorPeers.length === 0) {
|
692
|
+
// if there are no selectors, we can just return namespace peers
|
693
|
+
return namespacePeers
|
694
|
+
}
|
695
|
+
|
696
|
+
// if there are both, we need to create a cartesian product
|
697
|
+
return flat(
|
698
|
+
selectorPeers.map(selectorPeer => {
|
699
|
+
return namespacePeers.map(namespacePeer => merge(selectorPeer, namespacePeer))
|
700
|
+
}),
|
701
|
+
)
|
702
|
+
}
|
703
|
+
|
704
|
+
private static createNamespacePeer(
|
705
|
+
this: void,
|
706
|
+
namespace: NamespaceLike,
|
707
|
+
): types.input.networking.v1.NetworkPolicyPeer {
|
708
|
+
const namespaceName = mapNamespaceLikeToNamespaceName(namespace)
|
709
|
+
const namespaceSelector = mapNamespaceNameToSelector(namespaceName)
|
710
|
+
|
711
|
+
return { namespaceSelector }
|
712
|
+
}
|
713
|
+
|
714
|
+
private static mapPorts(
|
715
|
+
ports: NetworkPolicyPort[],
|
716
|
+
): types.input.networking.v1.NetworkPolicyPort[] {
|
717
|
+
return ports.map(port => {
|
718
|
+
if ("port" in port) {
|
719
|
+
return {
|
720
|
+
port: port.port,
|
721
|
+
protocol: port.protocol ?? "TCP",
|
722
|
+
}
|
723
|
+
}
|
724
|
+
|
725
|
+
return {
|
726
|
+
port: port.range[0],
|
727
|
+
endPort: port.range[1],
|
728
|
+
protocol: port.protocol ?? "TCP",
|
729
|
+
}
|
730
|
+
})
|
731
|
+
}
|
732
|
+
}
|