@highstate/k8s 0.9.4 → 0.9.5
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/chunk-DQSCJM5S.js +183 -0
- package/dist/chunk-DQSCJM5S.js.map +1 -0
- package/dist/chunk-FKNHHKOL.js +260 -0
- package/dist/chunk-FKNHHKOL.js.map +1 -0
- package/dist/chunk-HW3NS3MC.js +347 -0
- package/dist/chunk-HW3NS3MC.js.map +1 -0
- package/dist/chunk-OQ7UXASD.js +193 -0
- package/dist/chunk-OQ7UXASD.js.map +1 -0
- package/dist/chunk-QGHMLKTW.js +1123 -0
- package/dist/chunk-QGHMLKTW.js.map +1 -0
- package/dist/chunk-UNVSWG6D.js +214 -0
- package/dist/chunk-UNVSWG6D.js.map +1 -0
- package/dist/deployment-ZP3ASKPT.js +10 -0
- package/dist/deployment-ZP3ASKPT.js.map +1 -0
- package/dist/highstate.manifest.json +8 -6
- package/dist/index.js +291 -954
- package/dist/index.js.map +1 -1
- package/dist/stateful-set-2AH7RAF7.js +10 -0
- package/dist/stateful-set-2AH7RAF7.js.map +1 -0
- package/dist/units/access-point/index.js +6 -1
- package/dist/units/access-point/index.js.map +1 -1
- package/dist/units/cert-manager/index.js +19 -24
- package/dist/units/cert-manager/index.js.map +1 -1
- package/dist/units/cluster-dns/index.js +36 -0
- package/dist/units/cluster-dns/index.js.map +1 -0
- package/dist/units/cluster-patch/index.js +34 -0
- package/dist/units/cluster-patch/index.js.map +1 -0
- package/dist/units/dns01-issuer/index.js +2 -2
- package/dist/units/dns01-issuer/index.js.map +1 -1
- package/dist/units/existing-cluster/index.js +22 -14
- package/dist/units/existing-cluster/index.js.map +1 -1
- package/dist/units/gateway-api/index.js +1 -1
- package/package.json +12 -10
- package/src/access-point.ts +44 -39
- package/src/container.ts +54 -5
- package/src/cron-job.ts +14 -30
- package/src/deployment.ts +170 -127
- package/src/gateway/http-route.ts +7 -5
- package/src/helm.ts +57 -8
- package/src/index.ts +11 -4
- package/src/job.ts +14 -32
- package/src/namespace.ts +241 -0
- package/src/network-policy.ts +371 -87
- package/src/network.ts +41 -0
- package/src/pvc.ts +43 -25
- package/src/scripting/bundle.ts +125 -22
- package/src/scripting/container.ts +16 -11
- package/src/scripting/environment.ts +56 -6
- package/src/secret.ts +195 -0
- package/src/service.ts +209 -89
- package/src/shared.ts +42 -51
- package/src/stateful-set.ts +193 -88
- package/src/units/access-point/index.ts +8 -1
- package/src/units/cert-manager/index.ts +15 -20
- package/src/units/cluster-dns/index.ts +37 -0
- package/src/units/cluster-patch/index.ts +35 -0
- package/src/units/dns01-issuer/index.ts +1 -1
- package/src/units/existing-cluster/index.ts +24 -14
- package/src/workload.ts +342 -44
- package/dist/chunk-K4WKJ4L5.js +0 -455
- package/dist/chunk-K4WKJ4L5.js.map +0 -1
- package/dist/chunk-T5Z2M4JE.js +0 -103
- package/dist/chunk-T5Z2M4JE.js.map +0 -1
package/src/network-policy.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import { networking, types, type core } from "@pulumi/kubernetes"
|
2
2
|
import {
|
3
3
|
ComponentResource,
|
4
|
+
interpolate,
|
4
5
|
normalize,
|
5
6
|
output,
|
6
7
|
type Input,
|
@@ -10,10 +11,16 @@ import {
|
|
10
11
|
type ResourceOptions,
|
11
12
|
type Unwrap,
|
12
13
|
} from "@highstate/pulumi"
|
13
|
-
import { capitalize, flat, merge, mergeDeep } from "remeda"
|
14
|
-
import {
|
15
|
-
import { k8s } from "@highstate/library"
|
14
|
+
import { capitalize, flat, groupBy, merge, mergeDeep, uniqueBy } from "remeda"
|
15
|
+
import { k8s, network } from "@highstate/library"
|
16
16
|
import {
|
17
|
+
l34EndpointToString,
|
18
|
+
l3EndpointToCidr,
|
19
|
+
parseL34Endpoint,
|
20
|
+
type InputL34Endpoint,
|
21
|
+
} from "@highstate/common"
|
22
|
+
import {
|
23
|
+
getProvider,
|
17
24
|
mapMetadata,
|
18
25
|
mapNamespaceLikeToNamespaceName,
|
19
26
|
mapNamespaceNameToSelector,
|
@@ -22,7 +29,7 @@ import {
|
|
22
29
|
type NamespaceLike,
|
23
30
|
type SelectorLike,
|
24
31
|
} from "./shared"
|
25
|
-
import { mapServiceToLabelSelector } from "./service"
|
32
|
+
import { getServiceMetadata, isFromCluster, mapServiceToLabelSelector } from "./service"
|
26
33
|
|
27
34
|
export type NetworkPolicyPort = {
|
28
35
|
/**
|
@@ -36,7 +43,7 @@ export type NetworkPolicyPort = {
|
|
36
43
|
/**
|
37
44
|
* The single port to match.
|
38
45
|
*/
|
39
|
-
port: number
|
46
|
+
port: number | string
|
40
47
|
}
|
41
48
|
| {
|
42
49
|
/**
|
@@ -68,6 +75,30 @@ export type IngressRuleArgs = {
|
|
68
75
|
*/
|
69
76
|
fromCidrs?: InputArray<string>
|
70
77
|
|
78
|
+
/**
|
79
|
+
* The list of allowed L3 or L4 endpoints for outgoing traffic.
|
80
|
+
*
|
81
|
+
* Just a syntactic sugar for `fromFqdn` and `fromService` for cases when the endpoint can be one of them + optional port/protocol.
|
82
|
+
*
|
83
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
84
|
+
*
|
85
|
+
* If a single endpoint also has a port/protocol/service metadata,
|
86
|
+
* it will produce separate rule for it with them and ORed with the rest of the rules.
|
87
|
+
*/
|
88
|
+
fromEndpoint?: Input<InputL34Endpoint>
|
89
|
+
|
90
|
+
/**
|
91
|
+
* The list of allowed L3 or L4 endpoints for incoming traffic.
|
92
|
+
*
|
93
|
+
* Just a syntactic sugar for `fromFqdn` and `fromService` for cases when the endpoint can be one of them + optional port/protocol.
|
94
|
+
*
|
95
|
+
* Will be ORed with other conditions inside the same rule (except ports).
|
96
|
+
*
|
97
|
+
* If a single endpoint also has a port/protocol/service metadata,
|
98
|
+
* it will produce separate rule for it with them and ORed with the rest of the rules.
|
99
|
+
*/
|
100
|
+
fromEndpoints?: InputArray<InputL34Endpoint>
|
101
|
+
|
71
102
|
/**
|
72
103
|
* The service to allow traffic from.
|
73
104
|
*
|
@@ -174,20 +205,28 @@ export type EgressRuleArgs = {
|
|
174
205
|
toFqdns?: InputArray<string>
|
175
206
|
|
176
207
|
/**
|
177
|
-
*
|
208
|
+
* The L3 or L4 endpoint to allow outgoing traffic.
|
178
209
|
*
|
179
|
-
* Just a syntactic sugar for `toFqdn` and `
|
210
|
+
* Just a syntactic sugar for `toFqdn`, `toCidr` and `toService` for cases when the endpoint can be one of them + optional port/protocol.
|
180
211
|
*
|
181
212
|
* Will be ORed with other conditions inside the same rule (except ports).
|
213
|
+
*
|
214
|
+
* If a single endpoint also has a port/protocol/service metadata,
|
215
|
+
* it will produce separate rule for it with them and ORed with the rest of the rules.
|
182
216
|
*/
|
183
|
-
toEndpoint?: Input<
|
217
|
+
toEndpoint?: Input<InputL34Endpoint>
|
184
218
|
|
185
219
|
/**
|
186
|
-
* The list of allowed endpoints for outgoing traffic.
|
220
|
+
* The list of allowed L3 or L4 endpoints for outgoing traffic.
|
221
|
+
*
|
222
|
+
* Just a syntactic sugar for `toFqdn`, `toCidr` and `toService` for cases when the endpoint can be one of them + optional port/protocol.
|
187
223
|
*
|
188
224
|
* Will be ORed with other conditions inside the same rule (except ports).
|
225
|
+
*
|
226
|
+
* If a single endpoint also has a port/protocol/service metadata,
|
227
|
+
* it will produce separate rule for it with them and ORed with the rest of the rules.
|
189
228
|
*/
|
190
|
-
toEndpoints?: InputArray<
|
229
|
+
toEndpoints?: InputArray<InputL34Endpoint>
|
191
230
|
|
192
231
|
/**
|
193
232
|
* The service to allow traffic to.
|
@@ -369,17 +408,6 @@ export abstract class NetworkPolicy extends ComponentResource {
|
|
369
408
|
const ingressRules = normalize(args.ingressRule, args.ingressRules)
|
370
409
|
const egressRules = normalize(args.egressRule, args.egressRules)
|
371
410
|
|
372
|
-
const endpoints = normalize(args.egressRule?.toEndpoint, args.egressRule?.toEndpoints)
|
373
|
-
const parsedEndpoints = endpoints.map(endpoint => parseDomain(endpoint))
|
374
|
-
|
375
|
-
const cidrsFromEndpoints = parsedEndpoints
|
376
|
-
.filter(result => result.type === ParseResultType.Ip)
|
377
|
-
.map(result => NetworkPolicy.mapCidrFromEndpoint(result))
|
378
|
-
|
379
|
-
const fqdnsFromEndpoints = parsedEndpoints
|
380
|
-
.filter(result => result.type !== ParseResultType.Invalid)
|
381
|
-
.map(result => result.hostname)
|
382
|
-
|
383
411
|
const extraEgressRules: NormalizedRuleArgs[] = []
|
384
412
|
|
385
413
|
if (args.allowKubeDns) {
|
@@ -404,47 +432,182 @@ export abstract class NetworkPolicy extends ComponentResource {
|
|
404
432
|
|
405
433
|
allowKubeApiServer: args.allowKubeApiServer ?? false,
|
406
434
|
|
407
|
-
ingressRules: ingressRules.
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
selectors: normalize(rule.fromSelector, rule.fromSelectors),
|
414
|
-
ports: normalize(rule.toPort, rule.toPorts),
|
415
|
-
})),
|
435
|
+
ingressRules: ingressRules.flatMap(rule => {
|
436
|
+
const endpoints = normalize(
|
437
|
+
args.ingressRule?.fromEndpoint,
|
438
|
+
args.ingressRule?.fromEndpoints,
|
439
|
+
)
|
440
|
+
const parsedEndpoints = endpoints.map(parseL34Endpoint)
|
416
441
|
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
442
|
+
const endpointsByPortsAndNamespaces = groupBy(parsedEndpoints, endpoint => {
|
443
|
+
const namespace = isFromCluster(endpoint, args.cluster)
|
444
|
+
? endpoint.metadata.k8sService.namespace
|
445
|
+
: ""
|
446
|
+
|
447
|
+
const port = isFromCluster(endpoint, args.cluster)
|
448
|
+
? endpoint.metadata.k8sService.targetPort
|
449
|
+
: endpoint.port
|
450
|
+
|
451
|
+
return `${port ?? "0"}:${namespace}`
|
452
|
+
})
|
453
|
+
|
454
|
+
const l3OnlyRule = endpointsByPortsAndNamespaces["0:"]
|
455
|
+
? NetworkPolicy.getRuleFromEndpoint(
|
456
|
+
undefined,
|
457
|
+
endpointsByPortsAndNamespaces["0:"],
|
458
|
+
args.cluster,
|
459
|
+
)
|
460
|
+
: undefined
|
461
|
+
|
462
|
+
const otherRules = Object.entries(endpointsByPortsAndNamespaces)
|
463
|
+
.filter(([key]) => key !== "0:")
|
464
|
+
.map(([key, endpoints]) => {
|
465
|
+
const [port] = key.split(":")
|
466
|
+
const portNumber = parseInt(port, 10)
|
467
|
+
const portValue = isNaN(portNumber) ? port : portNumber
|
468
|
+
|
469
|
+
return NetworkPolicy.getRuleFromEndpoint(portValue, endpoints, args.cluster)
|
470
|
+
})
|
471
|
+
|
472
|
+
return [
|
473
|
+
{
|
474
|
+
all: rule.fromAll ?? false,
|
475
|
+
cidrs: normalize(rule.fromCidr, rule.fromCidrs).concat(l3OnlyRule?.cidrs ?? []),
|
476
|
+
fqdns: [],
|
477
|
+
services: normalize(rule.fromService, rule.fromServices),
|
478
|
+
namespaces: normalize(rule.fromNamespace, rule.fromNamespaces),
|
479
|
+
selectors: normalize(rule.fromSelector, rule.fromSelectors),
|
426
480
|
ports: normalize(rule.toPort, rule.toPorts),
|
427
|
-
} as NormalizedRuleArgs
|
481
|
+
} as NormalizedRuleArgs,
|
482
|
+
|
483
|
+
...otherRules,
|
484
|
+
].filter(rule => !NetworkPolicy.isEmptyRule(rule))
|
485
|
+
}),
|
486
|
+
|
487
|
+
egressRules: egressRules
|
488
|
+
.flatMap(rule => {
|
489
|
+
const endpoints = normalize(args.egressRule?.toEndpoint, args.egressRule?.toEndpoints)
|
490
|
+
const parsedEndpoints = endpoints.map(parseL34Endpoint)
|
491
|
+
|
492
|
+
const endpointsByPortsAnsNamespaces = groupBy(parsedEndpoints, endpoint => {
|
493
|
+
const namespace = isFromCluster(endpoint, args.cluster)
|
494
|
+
? endpoint.metadata.k8sService.namespace
|
495
|
+
: ""
|
496
|
+
|
497
|
+
const port = isFromCluster(endpoint, args.cluster)
|
498
|
+
? endpoint.metadata.k8sService.targetPort
|
499
|
+
: endpoint.port
|
500
|
+
|
501
|
+
return `${port ?? "0"}:${namespace}`
|
502
|
+
})
|
503
|
+
|
504
|
+
const l3OnlyRule = endpointsByPortsAnsNamespaces["0:"]
|
505
|
+
? NetworkPolicy.getRuleFromEndpoint(
|
506
|
+
undefined,
|
507
|
+
endpointsByPortsAnsNamespaces["0:"],
|
508
|
+
args.cluster,
|
509
|
+
)
|
510
|
+
: undefined
|
511
|
+
|
512
|
+
const otherRules = Object.entries(endpointsByPortsAnsNamespaces)
|
513
|
+
.filter(([key]) => key !== "0:")
|
514
|
+
.map(([key, endpoints]) => {
|
515
|
+
const [port] = key.split(":")
|
516
|
+
const portNumber = parseInt(port, 10)
|
517
|
+
const portValue = isNaN(portNumber) ? port : portNumber
|
518
|
+
|
519
|
+
return NetworkPolicy.getRuleFromEndpoint(portValue, endpoints, args.cluster)
|
520
|
+
})
|
521
|
+
|
522
|
+
return [
|
523
|
+
{
|
524
|
+
all: rule.toAll ?? false,
|
525
|
+
cidrs: normalize(rule.toCidr, rule.toCidrs).concat(l3OnlyRule?.cidrs ?? []),
|
526
|
+
fqdns: normalize(rule.toFqdn, rule.toFqdns).concat(l3OnlyRule?.fqdns ?? []),
|
527
|
+
services: normalize(rule.toService, rule.toServices),
|
528
|
+
namespaces: normalize(rule.toNamespace, rule.toNamespaces),
|
529
|
+
selectors: normalize(rule.toSelector, rule.toSelectors),
|
530
|
+
ports: normalize(rule.toPort, rule.toPorts),
|
531
|
+
} as NormalizedRuleArgs,
|
532
|
+
|
533
|
+
...otherRules,
|
534
|
+
].filter(rule => !NetworkPolicy.isEmptyRule(rule))
|
428
535
|
})
|
429
536
|
.concat(extraEgressRules),
|
430
537
|
}
|
431
538
|
})
|
432
539
|
|
433
|
-
this.networkPolicy =
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
540
|
+
this.networkPolicy = output(
|
541
|
+
normalizedArgs.apply(async args => {
|
542
|
+
return output(
|
543
|
+
this.create(name, args as NormalizedNetworkPolicyArgs, {
|
544
|
+
...opts,
|
545
|
+
parent: this,
|
546
|
+
provider: await getProvider(args.cluster),
|
547
|
+
}),
|
548
|
+
)
|
549
|
+
}),
|
550
|
+
)
|
551
|
+
}
|
552
|
+
|
553
|
+
private static mapCidrFromEndpoint(
|
554
|
+
this: void,
|
555
|
+
result: network.L3Endpoint & { type: "ipv4" | "ipv6" },
|
556
|
+
): string {
|
557
|
+
if (result.type === "ipv4") {
|
558
|
+
return `${result.address}/32`
|
559
|
+
}
|
438
560
|
|
439
|
-
|
561
|
+
return `${result.address}/128`
|
440
562
|
}
|
441
563
|
|
442
|
-
private static
|
443
|
-
|
444
|
-
|
564
|
+
private static getRuleFromEndpoint(
|
565
|
+
port: number | string | undefined,
|
566
|
+
endpoints: network.L34Endpoint[],
|
567
|
+
cluster: k8s.Cluster,
|
568
|
+
): NormalizedRuleArgs {
|
569
|
+
const ports: NetworkPolicyPort[] = port
|
570
|
+
? [{ port, protocol: endpoints[0].protocol?.toUpperCase() }]
|
571
|
+
: []
|
572
|
+
|
573
|
+
const cidrs = endpoints
|
574
|
+
.filter(endpoint => !isFromCluster(endpoint, cluster))
|
575
|
+
.filter(endpoint => endpoint.type === "ipv4" || endpoint.type === "ipv6")
|
576
|
+
.map(NetworkPolicy.mapCidrFromEndpoint)
|
577
|
+
|
578
|
+
const fqdns = endpoints
|
579
|
+
.filter(endpoint => endpoint.type === "hostname")
|
580
|
+
.map(endpoint => endpoint.hostname)
|
581
|
+
|
582
|
+
const selectors = endpoints
|
583
|
+
.filter(endpoint => isFromCluster(endpoint, cluster))
|
584
|
+
.map(endpoint => endpoint.metadata.k8sService.selector)
|
585
|
+
|
586
|
+
const namespace = endpoints
|
587
|
+
.filter(endpoint => isFromCluster(endpoint, cluster))
|
588
|
+
.map(endpoint => getServiceMetadata(endpoint)?.namespace)[0]
|
589
|
+
|
590
|
+
return {
|
591
|
+
all: false,
|
592
|
+
cidrs,
|
593
|
+
fqdns,
|
594
|
+
services: [],
|
595
|
+
namespaces: namespace ? [namespace] : [],
|
596
|
+
selectors,
|
597
|
+
ports,
|
445
598
|
}
|
599
|
+
}
|
446
600
|
|
447
|
-
|
601
|
+
private static isEmptyRule(rule: NormalizedRuleArgs): boolean {
|
602
|
+
return (
|
603
|
+
!rule.all &&
|
604
|
+
rule.cidrs.length === 0 &&
|
605
|
+
rule.fqdns.length === 0 &&
|
606
|
+
rule.services.length === 0 &&
|
607
|
+
rule.namespaces.length === 0 &&
|
608
|
+
rule.selectors.length === 0 &&
|
609
|
+
rule.ports.length === 0
|
610
|
+
)
|
448
611
|
}
|
449
612
|
|
450
613
|
protected abstract create(
|
@@ -453,17 +616,15 @@ export abstract class NetworkPolicy extends ComponentResource {
|
|
453
616
|
opts?: ResourceOptions,
|
454
617
|
): Input<Resource>
|
455
618
|
|
456
|
-
private static readonly supportedCNIs = ["cilium"]
|
457
|
-
|
458
619
|
static create(
|
459
620
|
name: string,
|
460
621
|
args: NetworkPolicyArgs,
|
461
|
-
opts
|
622
|
+
opts?: ResourceOptions,
|
462
623
|
): Output<NetworkPolicy> {
|
463
624
|
return output(args).apply(async args => {
|
464
|
-
const cni = args.cluster.
|
625
|
+
const cni = args.cluster.cni
|
465
626
|
|
466
|
-
if (
|
627
|
+
if (cni === "other") {
|
467
628
|
return new NativeNetworkPolicy(name, args, opts)
|
468
629
|
}
|
469
630
|
|
@@ -485,10 +646,30 @@ export abstract class NetworkPolicy extends ComponentResource {
|
|
485
646
|
})
|
486
647
|
}
|
487
648
|
|
649
|
+
static isolate(
|
650
|
+
namespace: Input<NamespaceLike>,
|
651
|
+
cluster: Input<k8s.Cluster>,
|
652
|
+
opts?: ResourceOptions,
|
653
|
+
) {
|
654
|
+
return NetworkPolicy.create(
|
655
|
+
"isolate",
|
656
|
+
{
|
657
|
+
namespace,
|
658
|
+
cluster,
|
659
|
+
|
660
|
+
description: "By default, deny all traffic to/from the namespace.",
|
661
|
+
|
662
|
+
isolateEgress: true,
|
663
|
+
isolateIngress: true,
|
664
|
+
},
|
665
|
+
opts,
|
666
|
+
)
|
667
|
+
}
|
668
|
+
|
488
669
|
static allowInsideNamespace(
|
489
670
|
namespace: Input<NamespaceLike>,
|
490
671
|
cluster: Input<k8s.Cluster>,
|
491
|
-
opts
|
672
|
+
opts?: ResourceOptions,
|
492
673
|
): Output<NetworkPolicy> {
|
493
674
|
return NetworkPolicy.create(
|
494
675
|
"allow-inside-namespace",
|
@@ -509,7 +690,7 @@ export abstract class NetworkPolicy extends ComponentResource {
|
|
509
690
|
static allowKubeApiServer(
|
510
691
|
namespace: Input<NamespaceLike>,
|
511
692
|
cluster: Input<k8s.Cluster>,
|
512
|
-
opts
|
693
|
+
opts?: ResourceOptions,
|
513
694
|
): Output<NetworkPolicy> {
|
514
695
|
return NetworkPolicy.create(
|
515
696
|
"allow-kube-api-server",
|
@@ -528,7 +709,7 @@ export abstract class NetworkPolicy extends ComponentResource {
|
|
528
709
|
static allowKubeDns(
|
529
710
|
namespace: Input<NamespaceLike>,
|
530
711
|
cluster: Input<k8s.Cluster>,
|
531
|
-
opts
|
712
|
+
opts?: ResourceOptions,
|
532
713
|
): Output<NetworkPolicy> {
|
533
714
|
return NetworkPolicy.create(
|
534
715
|
"allow-kube-dns",
|
@@ -547,7 +728,7 @@ export abstract class NetworkPolicy extends ComponentResource {
|
|
547
728
|
static allowAllEgress(
|
548
729
|
namespace: Input<NamespaceLike>,
|
549
730
|
cluster: Input<k8s.Cluster>,
|
550
|
-
opts
|
731
|
+
opts?: ResourceOptions,
|
551
732
|
): Output<NetworkPolicy> {
|
552
733
|
return NetworkPolicy.create(
|
553
734
|
"allow-all-egress",
|
@@ -562,6 +743,69 @@ export abstract class NetworkPolicy extends ComponentResource {
|
|
562
743
|
opts,
|
563
744
|
)
|
564
745
|
}
|
746
|
+
|
747
|
+
static allowAllIngress(
|
748
|
+
namespace: Input<NamespaceLike>,
|
749
|
+
cluster: Input<k8s.Cluster>,
|
750
|
+
opts?: ResourceOptions,
|
751
|
+
): Output<NetworkPolicy> {
|
752
|
+
return NetworkPolicy.create(
|
753
|
+
"allow-all-ingress",
|
754
|
+
{
|
755
|
+
namespace,
|
756
|
+
cluster,
|
757
|
+
|
758
|
+
description: "Allow all ingress traffic to the namespace.",
|
759
|
+
|
760
|
+
ingressRule: { fromAll: true },
|
761
|
+
},
|
762
|
+
opts,
|
763
|
+
)
|
764
|
+
}
|
765
|
+
|
766
|
+
static allowEgressToEndpoint(
|
767
|
+
endpoint: InputL34Endpoint,
|
768
|
+
namespace: Input<NamespaceLike>,
|
769
|
+
cluster: Input<k8s.Cluster>,
|
770
|
+
opts?: ResourceOptions,
|
771
|
+
): Output<NetworkPolicy> {
|
772
|
+
const parsedEndpoint = parseL34Endpoint(endpoint)
|
773
|
+
|
774
|
+
return NetworkPolicy.create(
|
775
|
+
`allow-egress-to-${l34EndpointToString(parsedEndpoint)}`,
|
776
|
+
{
|
777
|
+
namespace,
|
778
|
+
cluster,
|
779
|
+
|
780
|
+
description: interpolate`Allow egress traffic to "${l34EndpointToString(parsedEndpoint)}" from the namespace.`,
|
781
|
+
|
782
|
+
egressRule: { toEndpoint: endpoint },
|
783
|
+
},
|
784
|
+
opts,
|
785
|
+
)
|
786
|
+
}
|
787
|
+
|
788
|
+
static allowIngressFromEndpoint(
|
789
|
+
endpoint: InputL34Endpoint,
|
790
|
+
namespace: Input<NamespaceLike>,
|
791
|
+
cluster: Input<k8s.Cluster>,
|
792
|
+
opts?: ResourceOptions,
|
793
|
+
): Output<NetworkPolicy> {
|
794
|
+
const parsedEndpoint = parseL34Endpoint(endpoint)
|
795
|
+
|
796
|
+
return NetworkPolicy.create(
|
797
|
+
`allow-ingress-from-${l34EndpointToString(parsedEndpoint)}`,
|
798
|
+
{
|
799
|
+
namespace,
|
800
|
+
cluster,
|
801
|
+
|
802
|
+
description: interpolate`Allow ingress traffic from "${l34EndpointToString(parsedEndpoint)}" to the namespace.`,
|
803
|
+
|
804
|
+
ingressRule: { fromEndpoint: endpoint },
|
805
|
+
},
|
806
|
+
opts,
|
807
|
+
)
|
808
|
+
}
|
565
809
|
}
|
566
810
|
|
567
811
|
export class NativeNetworkPolicy extends NetworkPolicy {
|
@@ -607,56 +851,96 @@ export class NativeNetworkPolicy extends NetworkPolicy {
|
|
607
851
|
except: ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
|
608
852
|
}
|
609
853
|
|
854
|
+
private static fallbackDnsRule: types.input.networking.v1.NetworkPolicyEgressRule = {
|
855
|
+
to: [
|
856
|
+
{
|
857
|
+
namespaceSelector: { matchLabels: { "kubernetes.io/metadata.name": "kube-system" } },
|
858
|
+
podSelector: { matchLabels: { "k8s-app": "kube-dns" } },
|
859
|
+
},
|
860
|
+
],
|
861
|
+
ports: [{ port: 53, protocol: "UDP" }],
|
862
|
+
}
|
863
|
+
|
610
864
|
private static createIngressRules(
|
611
865
|
args: NormalizedNetworkPolicyArgs,
|
612
866
|
): types.input.networking.v1.NetworkPolicyIngressRule[] {
|
613
|
-
return
|
614
|
-
|
615
|
-
|
616
|
-
|
867
|
+
return uniqueBy(
|
868
|
+
args.ingressRules.map(rule => ({
|
869
|
+
from: rule.all ? [] : NativeNetworkPolicy.createRulePeers(rule),
|
870
|
+
ports: NativeNetworkPolicy.mapPorts(rule.ports),
|
871
|
+
})),
|
872
|
+
rule => JSON.stringify(rule),
|
873
|
+
)
|
617
874
|
}
|
618
875
|
|
619
876
|
private static createEgressRules(
|
620
877
|
args: NormalizedNetworkPolicyArgs,
|
621
878
|
): types.input.networking.v1.NetworkPolicyEgressRule[] {
|
879
|
+
const extraRules: types.input.networking.v1.NetworkPolicyEgressRule[] = []
|
880
|
+
|
881
|
+
const needKubeDns = args.egressRules.some(rule => rule.fqdns.length > 0)
|
882
|
+
if (needKubeDns) {
|
883
|
+
extraRules.push(NativeNetworkPolicy.fallbackDnsRule)
|
884
|
+
}
|
885
|
+
|
622
886
|
// the native resource does not support FQDNs
|
623
887
|
// to provide compatibility, we need to fallback to all except private CIDRs
|
624
|
-
const needFallback = args.egressRules.some(rule =>
|
888
|
+
const needFallback = args.egressRules.some(rule =>
|
889
|
+
rule.fqdns.some(fqdn => !fqdn.endsWith(".cluster.local")),
|
890
|
+
)
|
625
891
|
if (needFallback) {
|
626
|
-
|
892
|
+
extraRules.push({ to: [{ ipBlock: NativeNetworkPolicy.fallbackIpBlock }] })
|
627
893
|
}
|
628
894
|
|
629
|
-
|
630
|
-
|
895
|
+
// apply fallback rules for kube-apiserver
|
631
896
|
if (args.allowKubeApiServer) {
|
632
|
-
const
|
633
|
-
const apiServerPort = args.cluster.info.kubeApiServerPort ?? 443
|
897
|
+
const { quirks, apiEndpoints } = args.cluster
|
634
898
|
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
899
|
+
if (quirks?.fallbackKubeApiAccess) {
|
900
|
+
extraRules.push({
|
901
|
+
to: [{ ipBlock: { cidr: `${quirks?.fallbackKubeApiAccess.serverIp}/32` } }],
|
902
|
+
ports: [{ port: quirks?.fallbackKubeApiAccess.serverPort, protocol: "TCP" }],
|
903
|
+
})
|
904
|
+
} else {
|
905
|
+
const rules = apiEndpoints
|
906
|
+
.filter(endpoint => endpoint.type !== "hostname")
|
907
|
+
.map(endpoint => ({
|
908
|
+
to: [{ ipBlock: { cidr: l3EndpointToCidr(endpoint) } }],
|
909
|
+
ports: [{ port: endpoint.port, protocol: "TCP" }],
|
910
|
+
}))
|
911
|
+
|
912
|
+
extraRules.push(...rules)
|
913
|
+
}
|
639
914
|
}
|
640
915
|
|
641
|
-
return
|
642
|
-
.
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
916
|
+
return uniqueBy(
|
917
|
+
args.egressRules
|
918
|
+
.map(rule => {
|
919
|
+
return {
|
920
|
+
to: rule.all ? [] : NativeNetworkPolicy.createRulePeers(rule),
|
921
|
+
ports: NativeNetworkPolicy.mapPorts(rule.ports),
|
922
|
+
} as types.input.networking.v1.NetworkPolicyEgressRule
|
923
|
+
})
|
924
|
+
.filter(rule => rule.to !== undefined)
|
925
|
+
.concat(extraRules),
|
926
|
+
rule => JSON.stringify(rule),
|
927
|
+
)
|
649
928
|
}
|
650
929
|
|
651
930
|
private static createRulePeers(
|
652
931
|
this: void,
|
653
932
|
args: NormalizedRuleArgs,
|
654
|
-
): types.input.networking.v1.NetworkPolicyPeer[] {
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
933
|
+
): types.input.networking.v1.NetworkPolicyPeer[] | undefined {
|
934
|
+
const peers = uniqueBy(
|
935
|
+
[
|
936
|
+
...NativeNetworkPolicy.createCidrPeers(args),
|
937
|
+
...NativeNetworkPolicy.createServicePeers(args),
|
938
|
+
...NativeNetworkPolicy.createSelectorPeers(args),
|
939
|
+
],
|
940
|
+
peer => JSON.stringify(peer),
|
941
|
+
)
|
942
|
+
|
943
|
+
return peers.length > 0 ? peers : undefined
|
660
944
|
}
|
661
945
|
|
662
946
|
private static createCidrPeers(
|
package/src/network.ts
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
import type { k8s, network } from "@highstate/library"
|
2
|
+
import { filterEndpoints } from "@highstate/common"
|
3
|
+
import { isFromCluster } from "./service"
|
4
|
+
|
5
|
+
export function getBestEndpoint(
|
6
|
+
endpoints: network.L4Endpoint[],
|
7
|
+
cluster?: k8s.Cluster,
|
8
|
+
): network.L4Endpoint | undefined {
|
9
|
+
if (!endpoints.length) {
|
10
|
+
return undefined
|
11
|
+
}
|
12
|
+
|
13
|
+
if (endpoints.length === 1) {
|
14
|
+
return endpoints[0]
|
15
|
+
}
|
16
|
+
|
17
|
+
if (!cluster) {
|
18
|
+
return filterEndpoints(endpoints)[0]
|
19
|
+
}
|
20
|
+
|
21
|
+
const clusterEndpoint = endpoints.find(endpoint => isFromCluster(endpoint, cluster))
|
22
|
+
|
23
|
+
if (clusterEndpoint) {
|
24
|
+
return clusterEndpoint
|
25
|
+
}
|
26
|
+
|
27
|
+
return filterEndpoints(endpoints)[0]
|
28
|
+
}
|
29
|
+
|
30
|
+
export function requireBestEndpoint(
|
31
|
+
endpoints: network.L4Endpoint[],
|
32
|
+
cluster: k8s.Cluster,
|
33
|
+
): network.L4Endpoint {
|
34
|
+
const endpoint = getBestEndpoint(endpoints, cluster)
|
35
|
+
|
36
|
+
if (!endpoint) {
|
37
|
+
throw new Error(`No best endpoint found for cluster "${cluster.name}" (${cluster.id})`)
|
38
|
+
}
|
39
|
+
|
40
|
+
return endpoint
|
41
|
+
}
|