@intentius/chant-lexicon-k8s 0.0.14 → 0.0.16
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/integrity.json +8 -4
- package/dist/manifest.json +1 -1
- package/dist/rules/latest-image-tag.ts +121 -0
- package/dist/rules/missing-resource-limits.ts +111 -0
- package/dist/rules/wk8204.ts +33 -1
- package/dist/rules/wk8304.ts +70 -0
- package/dist/rules/wk8305.ts +115 -0
- package/dist/rules/wk8306.ts +50 -0
- package/package.json +27 -24
- package/src/codegen/docs.ts +1 -1
- package/src/composites/adot-collector.ts +8 -2
- package/src/composites/agic-ingress.ts +148 -0
- package/src/composites/aks-external-dns-agent.ts +199 -0
- package/src/composites/alb-ingress.ts +2 -1
- package/src/composites/autoscaled-service.ts +25 -7
- package/src/composites/azure-disk-storage-class.ts +82 -0
- package/src/composites/azure-file-storage-class.ts +77 -0
- package/src/composites/azure-monitor-collector.ts +232 -0
- package/src/composites/batch-job.ts +36 -3
- package/src/composites/composites.test.ts +1060 -0
- package/src/composites/config-connector-context.ts +62 -0
- package/src/composites/configured-app.ts +6 -0
- package/src/composites/cron-workload.ts +6 -0
- package/src/composites/ebs-storage-class.ts +4 -4
- package/src/composites/external-dns-agent.ts +6 -0
- package/src/composites/filestore-storage-class.ts +79 -0
- package/src/composites/fluent-bit-agent.ts +5 -0
- package/src/composites/gce-ingress.ts +143 -0
- package/src/composites/gce-pd-storage-class.ts +85 -0
- package/src/composites/gke-external-dns-agent.ts +175 -0
- package/src/composites/gke-fluent-bit-agent.ts +219 -0
- package/src/composites/gke-gateway.ts +143 -0
- package/src/composites/gke-otel-collector.ts +229 -0
- package/src/composites/index.ts +31 -0
- package/src/composites/metrics-server.ts +1 -1
- package/src/composites/monitored-service.ts +6 -0
- package/src/composites/network-isolated-app.ts +6 -0
- package/src/composites/node-agent.ts +6 -0
- package/src/composites/security-context.ts +10 -0
- package/src/composites/sidecar-app.ts +6 -0
- package/src/composites/stateful-app.ts +4 -7
- package/src/composites/web-app.ts +4 -7
- package/src/composites/worker-pool.ts +4 -7
- package/src/composites/workload-identity-sa.ts +118 -0
- package/src/composites/workload-identity-service-account.ts +116 -0
- package/src/index.ts +20 -1
- package/src/lint/post-synth/post-synth.test.ts +362 -1
- package/src/lint/post-synth/wk8204.ts +33 -1
- package/src/lint/post-synth/wk8304.ts +70 -0
- package/src/lint/post-synth/wk8305.ts +115 -0
- package/src/lint/post-synth/wk8306.ts +50 -0
- package/src/lint/rules/latest-image-tag.ts +121 -0
- package/src/lint/rules/missing-resource-limits.ts +111 -0
- package/src/lint/rules/rules.test.ts +192 -0
- package/src/plugin.test.ts +2 -2
- package/src/plugin.ts +129 -209
- package/src/serializer.test.ts +120 -0
- package/src/serializer.ts +16 -4
- package/src/skills/chant-k8s-aks.md +146 -0
- package/src/skills/chant-k8s-gke.md +191 -0
- package/src/skills/kubernetes-patterns.md +183 -0
- package/src/skills/kubernetes-security.md +237 -0
- /package/{dist → src}/skills/chant-k8s-eks.md +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigConnectorContext composite — bootstrap Config Connector per-namespace context.
|
|
3
|
+
*
|
|
4
|
+
* @gke Creates a ConfigConnectorContext resource that configures
|
|
5
|
+
* Config Connector to manage GCP resources in a specific namespace.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface ConfigConnectorContextProps {
|
|
9
|
+
/** Context name (default: "configconnectorcontext.core.cnrm.cloud.google.com"). */
|
|
10
|
+
name?: string;
|
|
11
|
+
/** Google service account email for Config Connector to use. */
|
|
12
|
+
googleServiceAccountEmail: string;
|
|
13
|
+
/** Namespace for the context (default: "default"). */
|
|
14
|
+
namespace?: string;
|
|
15
|
+
/** Whether to sync status into spec (default: "absent"). */
|
|
16
|
+
stateIntoSpec?: "absent" | "merge";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ConfigConnectorContextResult {
|
|
20
|
+
context: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a ConfigConnectorContext composite — returns prop objects for
|
|
25
|
+
* a ConfigConnectorContext resource.
|
|
26
|
+
*
|
|
27
|
+
* @gke
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { ConfigConnectorContext } from "@intentius/chant-lexicon-k8s";
|
|
31
|
+
*
|
|
32
|
+
* const { context } = ConfigConnectorContext({
|
|
33
|
+
* googleServiceAccountEmail: "cnrm@my-project.iam.gserviceaccount.com",
|
|
34
|
+
* namespace: "config-connector",
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function ConfigConnectorContext(
|
|
39
|
+
props: ConfigConnectorContextProps,
|
|
40
|
+
): ConfigConnectorContextResult {
|
|
41
|
+
const {
|
|
42
|
+
name = "configconnectorcontext.core.cnrm.cloud.google.com",
|
|
43
|
+
googleServiceAccountEmail,
|
|
44
|
+
namespace = "default",
|
|
45
|
+
stateIntoSpec = "absent",
|
|
46
|
+
} = props;
|
|
47
|
+
|
|
48
|
+
const contextProps: Record<string, unknown> = {
|
|
49
|
+
apiVersion: "core.cnrm.cloud.google.com/v1beta1",
|
|
50
|
+
kind: "ConfigConnectorContext",
|
|
51
|
+
metadata: {
|
|
52
|
+
name,
|
|
53
|
+
namespace,
|
|
54
|
+
},
|
|
55
|
+
spec: {
|
|
56
|
+
googleServiceAccount: googleServiceAccountEmail,
|
|
57
|
+
stateIntoSpec,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return { context: contextProps };
|
|
62
|
+
}
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* Volume.fromSecret(), and container.mount() patterns.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { ContainerSecurityContext } from "./security-context";
|
|
10
|
+
|
|
9
11
|
export interface ConfiguredAppProps {
|
|
10
12
|
/** Application name — used in metadata and labels. */
|
|
11
13
|
name: string;
|
|
@@ -49,6 +51,8 @@ export interface ConfiguredAppProps {
|
|
|
49
51
|
namespace?: string;
|
|
50
52
|
/** Environment variables for the container. */
|
|
51
53
|
env?: Array<{ name: string; value: string }>;
|
|
54
|
+
/** Container security context (supports PSS restricted fields). */
|
|
55
|
+
securityContext?: ContainerSecurityContext;
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
export interface ConfiguredAppResult {
|
|
@@ -96,6 +100,7 @@ export function ConfiguredApp(props: ConfiguredAppProps): ConfiguredAppResult {
|
|
|
96
100
|
memoryRequest = "128Mi",
|
|
97
101
|
namespace,
|
|
98
102
|
env,
|
|
103
|
+
securityContext,
|
|
99
104
|
} = props;
|
|
100
105
|
|
|
101
106
|
const configMapName = `${name}-config`;
|
|
@@ -154,6 +159,7 @@ export function ConfiguredApp(props: ConfiguredAppProps): ConfiguredAppResult {
|
|
|
154
159
|
...(env && { env }),
|
|
155
160
|
...(envFromList.length > 0 && { envFrom: envFromList }),
|
|
156
161
|
...(volumeMounts.length > 0 && { volumeMounts }),
|
|
162
|
+
...(securityContext && { securityContext }),
|
|
157
163
|
};
|
|
158
164
|
|
|
159
165
|
const podSpec: Record<string, unknown> = {
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* proper RBAC permissions.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { ContainerSecurityContext } from "./security-context";
|
|
9
|
+
|
|
8
10
|
export interface CronWorkloadProps {
|
|
9
11
|
/** Workload name — used in metadata and labels. */
|
|
10
12
|
name: string;
|
|
@@ -33,6 +35,8 @@ export interface CronWorkloadProps {
|
|
|
33
35
|
namespace?: string;
|
|
34
36
|
/** Environment variables. */
|
|
35
37
|
env?: Array<{ name: string; value: string }>;
|
|
38
|
+
/** Container security context (supports PSS restricted fields). */
|
|
39
|
+
securityContext?: ContainerSecurityContext;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
export interface CronWorkloadResult {
|
|
@@ -75,6 +79,7 @@ export function CronWorkload(props: CronWorkloadProps): CronWorkloadResult {
|
|
|
75
79
|
labels: extraLabels = {},
|
|
76
80
|
namespace,
|
|
77
81
|
env,
|
|
82
|
+
securityContext,
|
|
78
83
|
} = props;
|
|
79
84
|
|
|
80
85
|
const saName = `${name}-sa`;
|
|
@@ -110,6 +115,7 @@ export function CronWorkload(props: CronWorkloadProps): CronWorkloadResult {
|
|
|
110
115
|
...(command && { command }),
|
|
111
116
|
...(args && { args }),
|
|
112
117
|
...(env && { env }),
|
|
118
|
+
...(securityContext && { securityContext }),
|
|
113
119
|
},
|
|
114
120
|
],
|
|
115
121
|
},
|
|
@@ -10,9 +10,9 @@ export interface EbsStorageClassProps {
|
|
|
10
10
|
/** EBS volume type (default: "gp3"). */
|
|
11
11
|
type?: string;
|
|
12
12
|
/** IOPS for io1/io2/gp3 volumes. */
|
|
13
|
-
iops?: string;
|
|
13
|
+
iops?: string | number;
|
|
14
14
|
/** Throughput for gp3 volumes (MiB/s). */
|
|
15
|
-
throughput?: string;
|
|
15
|
+
throughput?: string | number;
|
|
16
16
|
/** Enable encryption (default: true). */
|
|
17
17
|
encrypted?: boolean;
|
|
18
18
|
/** KMS key ID for encryption. */
|
|
@@ -76,8 +76,8 @@ export function EbsStorageClass(props: EbsStorageClassProps): EbsStorageClassRes
|
|
|
76
76
|
encrypted: String(encrypted),
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
-
if (iops) parameters.iops = iops;
|
|
80
|
-
if (throughput) parameters.throughput = throughput;
|
|
79
|
+
if (iops !== undefined) parameters.iops = String(iops);
|
|
80
|
+
if (throughput !== undefined) parameters.throughput = String(throughput);
|
|
81
81
|
if (kmsKeyId) parameters.kmsKeyId = kmsKeyId;
|
|
82
82
|
|
|
83
83
|
const storageClassProps: Record<string, unknown> = {
|
|
@@ -110,6 +110,12 @@ export function ExternalDnsAgent(props: ExternalDnsAgentProps): ExternalDnsAgent
|
|
|
110
110
|
requests: { cpu: "50m", memory: "64Mi" },
|
|
111
111
|
limits: { cpu: "100m", memory: "128Mi" },
|
|
112
112
|
},
|
|
113
|
+
securityContext: {
|
|
114
|
+
runAsNonRoot: true,
|
|
115
|
+
runAsUser: 65534,
|
|
116
|
+
readOnlyRootFilesystem: true,
|
|
117
|
+
allowPrivilegeEscalation: false,
|
|
118
|
+
},
|
|
113
119
|
},
|
|
114
120
|
],
|
|
115
121
|
},
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FilestoreStorageClass composite — StorageClass for GCP Filestore CSI driver.
|
|
3
|
+
*
|
|
4
|
+
* @gke Creates a StorageClass with the `filestore.csi.storage.gke.io` provisioner.
|
|
5
|
+
* Filestore provides ReadWriteMany access mode (shared across pods/nodes).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface FilestoreStorageClassProps {
|
|
9
|
+
/** StorageClass name. */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Filestore tier (default: "standard"). */
|
|
12
|
+
tier?: "standard" | "premium" | "enterprise";
|
|
13
|
+
/** VPC network for the Filestore instance. */
|
|
14
|
+
network?: string;
|
|
15
|
+
/** Reclaim policy (default: "Delete"). */
|
|
16
|
+
reclaimPolicy?: string;
|
|
17
|
+
/** Volume binding mode (default: "WaitForFirstConsumer"). */
|
|
18
|
+
volumeBindingMode?: string;
|
|
19
|
+
/** Additional labels. */
|
|
20
|
+
labels?: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface FilestoreStorageClassResult {
|
|
24
|
+
storageClass: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a FilestoreStorageClass composite — returns prop objects for
|
|
29
|
+
* a StorageClass with the GCP Filestore CSI provisioner.
|
|
30
|
+
*
|
|
31
|
+
* @gke
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { FilestoreStorageClass } from "@intentius/chant-lexicon-k8s";
|
|
35
|
+
*
|
|
36
|
+
* const { storageClass } = FilestoreStorageClass({
|
|
37
|
+
* name: "filestore-standard",
|
|
38
|
+
* tier: "standard",
|
|
39
|
+
* network: "default",
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function FilestoreStorageClass(props: FilestoreStorageClassProps): FilestoreStorageClassResult {
|
|
44
|
+
const {
|
|
45
|
+
name,
|
|
46
|
+
tier = "standard",
|
|
47
|
+
network,
|
|
48
|
+
reclaimPolicy = "Delete",
|
|
49
|
+
volumeBindingMode = "WaitForFirstConsumer",
|
|
50
|
+
labels: extraLabels = {},
|
|
51
|
+
} = props;
|
|
52
|
+
|
|
53
|
+
const commonLabels: Record<string, string> = {
|
|
54
|
+
"app.kubernetes.io/name": name,
|
|
55
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
56
|
+
...extraLabels,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const parameters: Record<string, string> = {
|
|
60
|
+
tier,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (network) {
|
|
64
|
+
parameters.network = network;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const storageClassProps: Record<string, unknown> = {
|
|
68
|
+
metadata: {
|
|
69
|
+
name,
|
|
70
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
|
|
71
|
+
},
|
|
72
|
+
provisioner: "filestore.csi.storage.gke.io",
|
|
73
|
+
parameters,
|
|
74
|
+
reclaimPolicy,
|
|
75
|
+
volumeBindingMode,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return { storageClass: storageClassProps };
|
|
79
|
+
}
|
|
@@ -130,6 +130,11 @@ export function FluentBitAgent(props: FluentBitAgentProps): FluentBitAgentResult
|
|
|
130
130
|
{ name: "config", mountPath: `/etc/${name}`, readOnly: true },
|
|
131
131
|
{ name: "state", mountPath: "/var/fluent-bit/state" },
|
|
132
132
|
],
|
|
133
|
+
securityContext: {
|
|
134
|
+
runAsUser: 0,
|
|
135
|
+
readOnlyRootFilesystem: true,
|
|
136
|
+
allowPrivilegeEscalation: false,
|
|
137
|
+
},
|
|
133
138
|
};
|
|
134
139
|
|
|
135
140
|
const daemonSetProps: Record<string, unknown> = {
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GceIngress composite — Ingress with GCE Ingress Controller annotations.
|
|
3
|
+
*
|
|
4
|
+
* @gke Full `kubernetes.io/ingress.*` and `networking.gke.io/*` annotation set
|
|
5
|
+
* including static IP, managed certificates, and FrontendConfig.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface GceIngressHost {
|
|
9
|
+
/** Hostname (e.g., "api.example.com"). */
|
|
10
|
+
hostname: string;
|
|
11
|
+
/** Path rules for this host. */
|
|
12
|
+
paths: Array<{
|
|
13
|
+
path: string;
|
|
14
|
+
pathType?: string;
|
|
15
|
+
serviceName: string;
|
|
16
|
+
/** Port on the Kubernetes Service (not the container port). */
|
|
17
|
+
servicePort: number;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface GceIngressProps {
|
|
22
|
+
/** Ingress name — used in metadata and labels. */
|
|
23
|
+
name: string;
|
|
24
|
+
/** Host definitions with paths. */
|
|
25
|
+
hosts: GceIngressHost[];
|
|
26
|
+
/** Global static IP name reserved in GCP (sets `kubernetes.io/ingress.global-static-ip-name`). */
|
|
27
|
+
staticIpName?: string;
|
|
28
|
+
/** GKE managed certificate name (sets `networking.gke.io/managed-certificates`). */
|
|
29
|
+
managedCertificate?: string;
|
|
30
|
+
/** FrontendConfig name for SSL policy / redirects (sets `networking.gke.io/v1beta1.FrontendConfig`). */
|
|
31
|
+
frontendConfig?: string;
|
|
32
|
+
/** Health check path for backend (sets `cloud.google.com/backend-config` is NOT handled here — use BackendConfig CRD). */
|
|
33
|
+
healthCheckPath?: string;
|
|
34
|
+
/** Enable HTTP->HTTPS redirect (default: true when managedCertificate set). */
|
|
35
|
+
sslRedirect?: boolean;
|
|
36
|
+
/** Additional annotations on the Ingress. */
|
|
37
|
+
annotations?: Record<string, string>;
|
|
38
|
+
/** Additional labels to apply to all resources. */
|
|
39
|
+
labels?: Record<string, string>;
|
|
40
|
+
/** Namespace for all resources. */
|
|
41
|
+
namespace?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface GceIngressResult {
|
|
45
|
+
ingress: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a GceIngress composite — returns prop objects for
|
|
50
|
+
* an Ingress with GCE Ingress Controller annotations.
|
|
51
|
+
*
|
|
52
|
+
* @gke
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { GceIngress } from "@intentius/chant-lexicon-k8s";
|
|
56
|
+
*
|
|
57
|
+
* const { ingress } = GceIngress({
|
|
58
|
+
* name: "api-ingress",
|
|
59
|
+
* hosts: [
|
|
60
|
+
* {
|
|
61
|
+
* hostname: "api.example.com",
|
|
62
|
+
* paths: [{ path: "/", serviceName: "api", servicePort: 80 }],
|
|
63
|
+
* },
|
|
64
|
+
* ],
|
|
65
|
+
* staticIpName: "microservice-ip",
|
|
66
|
+
* managedCertificate: "api-cert",
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function GceIngress(props: GceIngressProps): GceIngressResult {
|
|
71
|
+
const {
|
|
72
|
+
name,
|
|
73
|
+
hosts,
|
|
74
|
+
staticIpName,
|
|
75
|
+
managedCertificate,
|
|
76
|
+
frontendConfig,
|
|
77
|
+
healthCheckPath,
|
|
78
|
+
sslRedirect,
|
|
79
|
+
annotations: extraAnnotations = {},
|
|
80
|
+
labels: extraLabels = {},
|
|
81
|
+
namespace,
|
|
82
|
+
} = props;
|
|
83
|
+
|
|
84
|
+
const commonLabels: Record<string, string> = {
|
|
85
|
+
"app.kubernetes.io/name": name,
|
|
86
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
87
|
+
...extraLabels,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Build GCE annotations
|
|
91
|
+
const annotations: Record<string, string> = {
|
|
92
|
+
"kubernetes.io/ingress.class": "gce",
|
|
93
|
+
...extraAnnotations,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
if (staticIpName) {
|
|
97
|
+
annotations["kubernetes.io/ingress.global-static-ip-name"] = staticIpName;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (managedCertificate) {
|
|
101
|
+
annotations["networking.gke.io/managed-certificates"] = managedCertificate;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (frontendConfig) {
|
|
105
|
+
annotations["networking.gke.io/v1beta1.FrontendConfig"] = frontendConfig;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (sslRedirect ?? !!managedCertificate) {
|
|
109
|
+
annotations["networking.gke.io/v1beta1.FrontendConfig"] =
|
|
110
|
+
annotations["networking.gke.io/v1beta1.FrontendConfig"] ?? `${name}-frontend-config`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (healthCheckPath) {
|
|
114
|
+
annotations["cloud.google.com/neg"] = '{"ingress": true}';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const ingressRules = hosts.map((host) => ({
|
|
118
|
+
host: host.hostname,
|
|
119
|
+
http: {
|
|
120
|
+
paths: host.paths.map((p) => ({
|
|
121
|
+
path: p.path,
|
|
122
|
+
pathType: p.pathType ?? "Prefix",
|
|
123
|
+
backend: {
|
|
124
|
+
service: { name: p.serviceName, port: { number: p.servicePort } },
|
|
125
|
+
},
|
|
126
|
+
})),
|
|
127
|
+
},
|
|
128
|
+
}));
|
|
129
|
+
|
|
130
|
+
const ingressProps: Record<string, unknown> = {
|
|
131
|
+
metadata: {
|
|
132
|
+
name,
|
|
133
|
+
...(namespace && { namespace }),
|
|
134
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "ingress" },
|
|
135
|
+
annotations,
|
|
136
|
+
},
|
|
137
|
+
spec: {
|
|
138
|
+
rules: ingressRules,
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return { ingress: ingressProps };
|
|
143
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GcePdStorageClass composite — StorageClass for GCE Persistent Disk CSI driver.
|
|
3
|
+
*
|
|
4
|
+
* @gke Creates a StorageClass with the `pd.csi.storage.gke.io` provisioner.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface GcePdStorageClassProps {
|
|
8
|
+
/** StorageClass name. */
|
|
9
|
+
name: string;
|
|
10
|
+
/** PD type (default: "pd-balanced"). */
|
|
11
|
+
type?: "pd-standard" | "pd-ssd" | "pd-balanced" | "pd-extreme";
|
|
12
|
+
/** Replication type (default: "none"). */
|
|
13
|
+
replicationType?: "none" | "regional-pd";
|
|
14
|
+
/** Filesystem type (default: "ext4"). */
|
|
15
|
+
fsType?: string;
|
|
16
|
+
/** Reclaim policy (default: "Delete"). */
|
|
17
|
+
reclaimPolicy?: string;
|
|
18
|
+
/** Volume binding mode (default: "WaitForFirstConsumer"). */
|
|
19
|
+
volumeBindingMode?: string;
|
|
20
|
+
/** Allow volume expansion (default: true). */
|
|
21
|
+
allowVolumeExpansion?: boolean;
|
|
22
|
+
/** Additional labels. */
|
|
23
|
+
labels?: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface GcePdStorageClassResult {
|
|
27
|
+
storageClass: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a GcePdStorageClass composite — returns prop objects for
|
|
32
|
+
* a StorageClass with the GCE Persistent Disk CSI provisioner.
|
|
33
|
+
*
|
|
34
|
+
* @gke
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { GcePdStorageClass } from "@intentius/chant-lexicon-k8s";
|
|
38
|
+
*
|
|
39
|
+
* const { storageClass } = GcePdStorageClass({
|
|
40
|
+
* name: "pd-ssd",
|
|
41
|
+
* type: "pd-ssd",
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function GcePdStorageClass(props: GcePdStorageClassProps): GcePdStorageClassResult {
|
|
46
|
+
const {
|
|
47
|
+
name,
|
|
48
|
+
type = "pd-balanced",
|
|
49
|
+
replicationType = "none",
|
|
50
|
+
fsType = "ext4",
|
|
51
|
+
reclaimPolicy = "Delete",
|
|
52
|
+
volumeBindingMode = "WaitForFirstConsumer",
|
|
53
|
+
allowVolumeExpansion = true,
|
|
54
|
+
labels: extraLabels = {},
|
|
55
|
+
} = props;
|
|
56
|
+
|
|
57
|
+
const commonLabels: Record<string, string> = {
|
|
58
|
+
"app.kubernetes.io/name": name,
|
|
59
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
60
|
+
...extraLabels,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const parameters: Record<string, string> = {
|
|
64
|
+
type,
|
|
65
|
+
"csi.storage.k8s.io/fstype": fsType,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (replicationType !== "none") {
|
|
69
|
+
parameters["replication-type"] = replicationType;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const storageClassProps: Record<string, unknown> = {
|
|
73
|
+
metadata: {
|
|
74
|
+
name,
|
|
75
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
|
|
76
|
+
},
|
|
77
|
+
provisioner: "pd.csi.storage.gke.io",
|
|
78
|
+
parameters,
|
|
79
|
+
reclaimPolicy,
|
|
80
|
+
volumeBindingMode,
|
|
81
|
+
allowVolumeExpansion,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return { storageClass: storageClassProps };
|
|
85
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GkeExternalDnsAgent composite — Deployment + ServiceAccount + ClusterRole + ClusterRoleBinding.
|
|
3
|
+
*
|
|
4
|
+
* @gke Like ExternalDnsAgent but uses --provider=google and GKE Workload Identity
|
|
5
|
+
* instead of IRSA for Cloud DNS management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface GkeExternalDnsAgentProps {
|
|
9
|
+
/** GCP service account email for Workload Identity (needs Cloud DNS permissions). */
|
|
10
|
+
gcpServiceAccountEmail: string;
|
|
11
|
+
/** GCP project ID. */
|
|
12
|
+
gcpProjectId: string;
|
|
13
|
+
/** Domain filters — only manage DNS records for these domains. */
|
|
14
|
+
domainFilters: string[];
|
|
15
|
+
/** TXT record owner ID for identifying managed records. */
|
|
16
|
+
txtOwnerId?: string;
|
|
17
|
+
/** Source of DNS records (default: "ingress"). */
|
|
18
|
+
source?: string;
|
|
19
|
+
/** Agent name (default: "external-dns"). */
|
|
20
|
+
name?: string;
|
|
21
|
+
/** Container image (default: "registry.k8s.io/external-dns/external-dns:v0.14.0"). */
|
|
22
|
+
image?: string;
|
|
23
|
+
/** Namespace (default: "kube-system"). */
|
|
24
|
+
namespace?: string;
|
|
25
|
+
/** Additional labels. */
|
|
26
|
+
labels?: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface GkeExternalDnsAgentResult {
|
|
30
|
+
deployment: Record<string, unknown>;
|
|
31
|
+
serviceAccount: Record<string, unknown>;
|
|
32
|
+
clusterRole: Record<string, unknown>;
|
|
33
|
+
clusterRoleBinding: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create a GkeExternalDnsAgent composite — returns prop objects for
|
|
38
|
+
* a Deployment, ServiceAccount (with Workload Identity), ClusterRole, and ClusterRoleBinding.
|
|
39
|
+
*
|
|
40
|
+
* @gke
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { GkeExternalDnsAgent } from "@intentius/chant-lexicon-k8s";
|
|
44
|
+
*
|
|
45
|
+
* const { deployment, serviceAccount, clusterRole, clusterRoleBinding } = GkeExternalDnsAgent({
|
|
46
|
+
* gcpServiceAccountEmail: "external-dns@my-project.iam.gserviceaccount.com",
|
|
47
|
+
* gcpProjectId: "my-project",
|
|
48
|
+
* domainFilters: ["example.com"],
|
|
49
|
+
* txtOwnerId: "my-cluster",
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function GkeExternalDnsAgent(props: GkeExternalDnsAgentProps): GkeExternalDnsAgentResult {
|
|
54
|
+
const {
|
|
55
|
+
gcpServiceAccountEmail,
|
|
56
|
+
gcpProjectId,
|
|
57
|
+
domainFilters,
|
|
58
|
+
txtOwnerId,
|
|
59
|
+
source = "ingress",
|
|
60
|
+
name = "external-dns",
|
|
61
|
+
image = "registry.k8s.io/external-dns/external-dns:v0.14.0",
|
|
62
|
+
namespace = "kube-system",
|
|
63
|
+
labels: extraLabels = {},
|
|
64
|
+
} = props;
|
|
65
|
+
|
|
66
|
+
const saName = `${name}-sa`;
|
|
67
|
+
const clusterRoleName = `${name}-role`;
|
|
68
|
+
const bindingName = `${name}-binding`;
|
|
69
|
+
|
|
70
|
+
const commonLabels: Record<string, string> = {
|
|
71
|
+
"app.kubernetes.io/name": name,
|
|
72
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
73
|
+
...extraLabels,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const args: string[] = [
|
|
77
|
+
`--source=${source}`,
|
|
78
|
+
"--provider=google",
|
|
79
|
+
`--google-project=${gcpProjectId}`,
|
|
80
|
+
"--policy=upsert-only",
|
|
81
|
+
"--registry=txt",
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
for (const domain of domainFilters) {
|
|
85
|
+
args.push(`--domain-filter=${domain}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (txtOwnerId) {
|
|
89
|
+
args.push(`--txt-owner-id=${txtOwnerId}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const deploymentProps: Record<string, unknown> = {
|
|
93
|
+
metadata: {
|
|
94
|
+
name,
|
|
95
|
+
namespace,
|
|
96
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "dns" },
|
|
97
|
+
},
|
|
98
|
+
spec: {
|
|
99
|
+
replicas: 1,
|
|
100
|
+
selector: { matchLabels: { "app.kubernetes.io/name": name } },
|
|
101
|
+
template: {
|
|
102
|
+
metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
|
|
103
|
+
spec: {
|
|
104
|
+
serviceAccountName: saName,
|
|
105
|
+
containers: [
|
|
106
|
+
{
|
|
107
|
+
name,
|
|
108
|
+
image,
|
|
109
|
+
args,
|
|
110
|
+
resources: {
|
|
111
|
+
requests: { cpu: "50m", memory: "64Mi" },
|
|
112
|
+
limits: { cpu: "100m", memory: "128Mi" },
|
|
113
|
+
},
|
|
114
|
+
securityContext: {
|
|
115
|
+
runAsNonRoot: true,
|
|
116
|
+
runAsUser: 65534,
|
|
117
|
+
readOnlyRootFilesystem: true,
|
|
118
|
+
allowPrivilegeEscalation: false,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const serviceAccountProps: Record<string, unknown> = {
|
|
128
|
+
metadata: {
|
|
129
|
+
name: saName,
|
|
130
|
+
namespace,
|
|
131
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "dns" },
|
|
132
|
+
annotations: {
|
|
133
|
+
"iam.gke.io/gcp-service-account": gcpServiceAccountEmail,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const clusterRoleProps: Record<string, unknown> = {
|
|
139
|
+
metadata: {
|
|
140
|
+
name: clusterRoleName,
|
|
141
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
142
|
+
},
|
|
143
|
+
rules: [
|
|
144
|
+
{ apiGroups: [""], resources: ["services", "endpoints", "pods"], verbs: ["get", "watch", "list"] },
|
|
145
|
+
{ apiGroups: ["extensions", "networking.k8s.io"], resources: ["ingresses"], verbs: ["get", "watch", "list"] },
|
|
146
|
+
{ apiGroups: [""], resources: ["nodes"], verbs: ["list", "watch"] },
|
|
147
|
+
],
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const clusterRoleBindingProps: Record<string, unknown> = {
|
|
151
|
+
metadata: {
|
|
152
|
+
name: bindingName,
|
|
153
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
154
|
+
},
|
|
155
|
+
roleRef: {
|
|
156
|
+
apiGroup: "rbac.authorization.k8s.io",
|
|
157
|
+
kind: "ClusterRole",
|
|
158
|
+
name: clusterRoleName,
|
|
159
|
+
},
|
|
160
|
+
subjects: [
|
|
161
|
+
{
|
|
162
|
+
kind: "ServiceAccount",
|
|
163
|
+
name: saName,
|
|
164
|
+
namespace,
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
deployment: deploymentProps,
|
|
171
|
+
serviceAccount: serviceAccountProps,
|
|
172
|
+
clusterRole: clusterRoleProps,
|
|
173
|
+
clusterRoleBinding: clusterRoleBindingProps,
|
|
174
|
+
};
|
|
175
|
+
}
|