@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.
Files changed (63) hide show
  1. package/dist/integrity.json +8 -4
  2. package/dist/manifest.json +1 -1
  3. package/dist/rules/latest-image-tag.ts +121 -0
  4. package/dist/rules/missing-resource-limits.ts +111 -0
  5. package/dist/rules/wk8204.ts +33 -1
  6. package/dist/rules/wk8304.ts +70 -0
  7. package/dist/rules/wk8305.ts +115 -0
  8. package/dist/rules/wk8306.ts +50 -0
  9. package/package.json +27 -24
  10. package/src/codegen/docs.ts +1 -1
  11. package/src/composites/adot-collector.ts +8 -2
  12. package/src/composites/agic-ingress.ts +148 -0
  13. package/src/composites/aks-external-dns-agent.ts +199 -0
  14. package/src/composites/alb-ingress.ts +2 -1
  15. package/src/composites/autoscaled-service.ts +25 -7
  16. package/src/composites/azure-disk-storage-class.ts +82 -0
  17. package/src/composites/azure-file-storage-class.ts +77 -0
  18. package/src/composites/azure-monitor-collector.ts +232 -0
  19. package/src/composites/batch-job.ts +36 -3
  20. package/src/composites/composites.test.ts +1060 -0
  21. package/src/composites/config-connector-context.ts +62 -0
  22. package/src/composites/configured-app.ts +6 -0
  23. package/src/composites/cron-workload.ts +6 -0
  24. package/src/composites/ebs-storage-class.ts +4 -4
  25. package/src/composites/external-dns-agent.ts +6 -0
  26. package/src/composites/filestore-storage-class.ts +79 -0
  27. package/src/composites/fluent-bit-agent.ts +5 -0
  28. package/src/composites/gce-ingress.ts +143 -0
  29. package/src/composites/gce-pd-storage-class.ts +85 -0
  30. package/src/composites/gke-external-dns-agent.ts +175 -0
  31. package/src/composites/gke-fluent-bit-agent.ts +219 -0
  32. package/src/composites/gke-gateway.ts +143 -0
  33. package/src/composites/gke-otel-collector.ts +229 -0
  34. package/src/composites/index.ts +31 -0
  35. package/src/composites/metrics-server.ts +1 -1
  36. package/src/composites/monitored-service.ts +6 -0
  37. package/src/composites/network-isolated-app.ts +6 -0
  38. package/src/composites/node-agent.ts +6 -0
  39. package/src/composites/security-context.ts +10 -0
  40. package/src/composites/sidecar-app.ts +6 -0
  41. package/src/composites/stateful-app.ts +4 -7
  42. package/src/composites/web-app.ts +4 -7
  43. package/src/composites/worker-pool.ts +4 -7
  44. package/src/composites/workload-identity-sa.ts +118 -0
  45. package/src/composites/workload-identity-service-account.ts +116 -0
  46. package/src/index.ts +20 -1
  47. package/src/lint/post-synth/post-synth.test.ts +362 -1
  48. package/src/lint/post-synth/wk8204.ts +33 -1
  49. package/src/lint/post-synth/wk8304.ts +70 -0
  50. package/src/lint/post-synth/wk8305.ts +115 -0
  51. package/src/lint/post-synth/wk8306.ts +50 -0
  52. package/src/lint/rules/latest-image-tag.ts +121 -0
  53. package/src/lint/rules/missing-resource-limits.ts +111 -0
  54. package/src/lint/rules/rules.test.ts +192 -0
  55. package/src/plugin.test.ts +2 -2
  56. package/src/plugin.ts +129 -209
  57. package/src/serializer.test.ts +120 -0
  58. package/src/serializer.ts +16 -4
  59. package/src/skills/chant-k8s-aks.md +146 -0
  60. package/src/skills/chant-k8s-gke.md +191 -0
  61. package/src/skills/kubernetes-patterns.md +183 -0
  62. package/src/skills/kubernetes-security.md +237 -0
  63. /package/{dist → src}/skills/chant-k8s-eks.md +0 -0
@@ -0,0 +1,191 @@
1
+ ---
2
+ skill: chant-k8s-gke
3
+ description: GKE-specific Kubernetes patterns and composites
4
+ user-invocable: true
5
+ ---
6
+
7
+ # GKE Kubernetes Patterns
8
+
9
+ ## GKE Composites Overview
10
+
11
+ These composites produce K8s YAML with GKE-specific annotations and configurations.
12
+
13
+ ### WorkloadIdentityServiceAccount — ServiceAccount with GCP SA annotation
14
+
15
+ ```typescript
16
+ import { WorkloadIdentityServiceAccount } from "@intentius/chant-lexicon-k8s";
17
+
18
+ const { serviceAccount, role, roleBinding } = WorkloadIdentityServiceAccount({
19
+ name: "app-sa",
20
+ gcpServiceAccountEmail: "app@my-project.iam.gserviceaccount.com",
21
+ rbacRules: [
22
+ { apiGroups: [""], resources: ["secrets"], verbs: ["get"] },
23
+ ],
24
+ namespace: "prod",
25
+ });
26
+ ```
27
+
28
+ Annotates the ServiceAccount with `iam.gke.io/gcp-service-account` for GKE Workload Identity.
29
+
30
+ ### GceIngress — Ingress with GCE ingress class annotations
31
+
32
+ ```typescript
33
+ import { GceIngress } from "@intentius/chant-lexicon-k8s";
34
+
35
+ const { ingress } = GceIngress({
36
+ name: "api-ingress",
37
+ hosts: [
38
+ {
39
+ hostname: "api.example.com",
40
+ paths: [{ path: "/", serviceName: "api", servicePort: 80 }],
41
+ },
42
+ ],
43
+ staticIpName: "api-ip",
44
+ managedCertificate: "api-cert",
45
+ namespace: "prod",
46
+ });
47
+ ```
48
+
49
+ Features:
50
+ - Sets `kubernetes.io/ingress.class: "gce"` annotation
51
+ - `staticIpName` binds a reserved global static IP via `kubernetes.io/ingress.global-static-ip-name`
52
+ - `managedCertificate` attaches a GKE-managed SSL certificate via `networking.gke.io/managed-certificates`
53
+ - Auto-generates FrontendConfig for SSL redirect when `managedCertificate` is set (override with `sslRedirect: false`)
54
+ - Pairs naturally with Config Connector `ComputeAddress` resources for static IPs
55
+
56
+ ### GkeGateway — Gateway API with GKE gateway classes
57
+
58
+ ```typescript
59
+ import { GkeGateway } from "@intentius/chant-lexicon-k8s";
60
+
61
+ const { gateway, httpRoute } = GkeGateway({
62
+ name: "api-gateway",
63
+ gatewayClassName: "gke-l7-global-external-managed",
64
+ hosts: [
65
+ {
66
+ hostname: "api.example.com",
67
+ paths: [{ path: "/", serviceName: "api", servicePort: 80 }],
68
+ },
69
+ ],
70
+ certificateName: "api-cert",
71
+ namespace: "prod",
72
+ });
73
+ ```
74
+
75
+ Gateway class options:
76
+ - `gke-l7-global-external-managed` — Global external (default)
77
+ - `gke-l7-regional-external-managed` — Regional external
78
+ - `gke-l7-rilb` — Regional internal
79
+
80
+ ### GcePdStorageClass — StorageClass for GCE Persistent Disk CSI
81
+
82
+ ```typescript
83
+ import { GcePdStorageClass } from "@intentius/chant-lexicon-k8s";
84
+
85
+ const { storageClass } = GcePdStorageClass({
86
+ name: "pd-balanced",
87
+ type: "pd-balanced",
88
+ replicationType: "none",
89
+ allowVolumeExpansion: true,
90
+ });
91
+ ```
92
+
93
+ Disk types: `pd-standard`, `pd-ssd`, `pd-balanced` (default), `pd-extreme`.
94
+
95
+ ### FilestoreStorageClass — StorageClass for Filestore CSI (ReadWriteMany)
96
+
97
+ ```typescript
98
+ import { FilestoreStorageClass } from "@intentius/chant-lexicon-k8s";
99
+
100
+ const { storageClass } = FilestoreStorageClass({
101
+ name: "filestore-shared",
102
+ tier: "standard",
103
+ network: "my-vpc",
104
+ });
105
+ ```
106
+
107
+ Use Filestore when you need ReadWriteMany (shared across pods/nodes). Use GCE PD for ReadWriteOnce (single pod).
108
+
109
+ ### GkeExternalDnsAgent — ExternalDNS for Cloud DNS
110
+
111
+ ```typescript
112
+ import { GkeExternalDnsAgent } from "@intentius/chant-lexicon-k8s";
113
+
114
+ const result = GkeExternalDnsAgent({
115
+ gcpServiceAccountEmail: "dns@my-project.iam.gserviceaccount.com",
116
+ gcpProjectId: "my-project",
117
+ domainFilters: ["example.com"],
118
+ txtOwnerId: "my-cluster",
119
+ });
120
+ ```
121
+
122
+ ### GkeFluentBitAgent — DaemonSet for Cloud Logging
123
+
124
+ ```typescript
125
+ import { GkeFluentBitAgent } from "@intentius/chant-lexicon-k8s";
126
+
127
+ const result = GkeFluentBitAgent({
128
+ clusterName: "my-cluster",
129
+ projectId: "my-project",
130
+ gcpServiceAccountEmail: "logging@my-project.iam.gserviceaccount.com",
131
+ });
132
+ ```
133
+
134
+ ### GkeOtelCollector — OTel for Cloud Trace + Cloud Monitoring
135
+
136
+ ```typescript
137
+ import { GkeOtelCollector } from "@intentius/chant-lexicon-k8s";
138
+
139
+ const result = GkeOtelCollector({
140
+ clusterName: "my-cluster",
141
+ projectId: "my-project",
142
+ gcpServiceAccountEmail: "monitoring@my-project.iam.gserviceaccount.com",
143
+ });
144
+ ```
145
+
146
+ ### ConfigConnectorContext — Config Connector namespace bootstrap
147
+
148
+ ```typescript
149
+ import { ConfigConnectorContext } from "@intentius/chant-lexicon-k8s";
150
+
151
+ const { context } = ConfigConnectorContext({
152
+ googleServiceAccountEmail: "cc-sa@my-project.iam.gserviceaccount.com",
153
+ namespace: "config-connector",
154
+ stateIntoSpec: "absent",
155
+ });
156
+ ```
157
+
158
+ Required when using Config Connector to manage GCP resources from within the cluster.
159
+
160
+ ## Workload Identity vs Key-Based Auth
161
+
162
+ | Feature | Workload Identity | Key-based (JSON key file) |
163
+ |---------|------------------|--------------------------|
164
+ | K8s annotation needed | Yes (`iam.gke.io/gcp-service-account`) | No |
165
+ | Composite available | **WorkloadIdentityServiceAccount** | None needed (mount key as Secret) |
166
+ | Setup | GKE cluster WI enabled + IAM binding | Create key → K8s Secret → volume mount |
167
+ | Security | No long-lived credentials, auto-rotated | Static key, must rotate manually |
168
+ | When to use | Always (recommended) | Legacy workloads, non-GKE clusters |
169
+
170
+ Workload Identity is the recommended approach for all GKE workloads. Key-based auth requires no K8s-side composite — create a Secret from the JSON key and mount it.
171
+
172
+ ## Config Connector Considerations
173
+
174
+ Config Connector (CC) runs as a GKE add-on and manages GCP resources declaratively via K8s CRDs:
175
+ - **Bootstrap cluster required** — CC needs an existing GKE cluster to run in; use `npm run bootstrap` to create one
176
+ - **CC service account** — a GCP SA with editor/IAM roles, bound to the CC controller pod via Workload Identity
177
+ - **Reconciliation** — CC continuously reconciles; deleting a CC resource deletes the underlying GCP resource
178
+ - **ConfigConnectorContext** — use the composite to configure CC per-namespace (SA email, stateIntoSpec policy)
179
+
180
+ ## GKE Add-ons
181
+
182
+ Common add-ons managed via GKE (not K8s manifests):
183
+ - **Config Connector** — manage GCP resources as K8s CRDs
184
+ - **Workload Identity** — pod-to-GCP-SA identity federation (required for WorkloadIdentityServiceAccount)
185
+ - **GKE Gateway Controller** — Gateway API implementation (required for GkeGateway)
186
+ - **GKE managed Prometheus** — alternative to GkeOtelCollector for metrics
187
+ - **GKE Dataplane V2** — eBPF-based networking with built-in NetworkPolicy enforcement
188
+ - **Filestore CSI driver** — required for FilestoreStorageClass
189
+ - **Compute Engine persistent disk CSI driver** — enabled by default, required for GcePdStorageClass
190
+
191
+ Configure add-ons via the GCP lexicon (`@intentius/chant-lexicon-gcp`) Config Connector resources.
@@ -0,0 +1,183 @@
1
+ ---
2
+ skill: kubernetes-patterns
3
+ description: Kubernetes deployment strategies, stateful workloads, RBAC, and networking patterns
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Kubernetes Infrastructure Patterns
8
+
9
+ ## Deployment Strategies
10
+
11
+ ### Rolling Update (default)
12
+
13
+ Gradually replaces pods with zero downtime. Configure surge and unavailability:
14
+
15
+ ```typescript
16
+ import { WebApp } from "@intentius/chant-lexicon-k8s";
17
+
18
+ const { deployment, service } = WebApp({
19
+ name: "api",
20
+ image: "api:2.0",
21
+ replicas: 4,
22
+ strategy: {
23
+ type: "RollingUpdate",
24
+ rollingUpdate: { maxSurge: "25%", maxUnavailable: "25%" },
25
+ },
26
+ });
27
+ ```
28
+
29
+ ### Blue/Green Deployment
30
+
31
+ Run two full deployments and switch traffic by updating the Service selector:
32
+
33
+ ```typescript
34
+ import { WebApp } from "@intentius/chant-lexicon-k8s";
35
+
36
+ const blue = WebApp({ name: "app-blue", image: "app:1.0", replicas: 3 });
37
+ const green = WebApp({ name: "app-green", image: "app:2.0", replicas: 3 });
38
+
39
+ // Switch traffic: update the Service selector to point at green
40
+ // kubectl patch svc app -p '{"spec":{"selector":{"version":"green"}}}'
41
+ ```
42
+
43
+ ### Canary Deployment
44
+
45
+ Deploy a small replica set alongside the main deployment to test new versions:
46
+
47
+ ```typescript
48
+ import { AutoscaledService, WebApp } from "@intentius/chant-lexicon-k8s";
49
+
50
+ const main = AutoscaledService({
51
+ name: "app",
52
+ image: "app:1.0",
53
+ port: 8080,
54
+ minReplicas: 9,
55
+ maxReplicas: 20,
56
+ });
57
+
58
+ const canary = WebApp({
59
+ name: "app-canary",
60
+ image: "app:2.0",
61
+ replicas: 1,
62
+ labels: { track: "canary" },
63
+ });
64
+ ```
65
+
66
+ Both share the same `app.kubernetes.io/name` label so the Service routes traffic to both.
67
+
68
+ ## Stateful Workloads
69
+
70
+ ### StatefulSet with Persistent Storage
71
+
72
+ Use `StatefulApp` for databases, caches, and other stateful services:
73
+
74
+ ```typescript
75
+ import { StatefulApp } from "@intentius/chant-lexicon-k8s";
76
+
77
+ const { statefulSet, service } = StatefulApp({
78
+ name: "postgres",
79
+ image: "postgres:16",
80
+ port: 5432,
81
+ replicas: 3,
82
+ storageSize: "50Gi",
83
+ storageClass: "gp3-encrypted",
84
+ env: [
85
+ { name: "POSTGRES_DB", value: "app" },
86
+ { name: "POSTGRES_PASSWORD", valueFrom: { secretKeyRef: { name: "pg-creds", key: "password" } } },
87
+ ],
88
+ });
89
+ ```
90
+
91
+ ### Headless Service for StatefulSet Discovery
92
+
93
+ `StatefulApp` creates a headless Service (`clusterIP: None`) automatically. Pods are addressable as `postgres-0.postgres.namespace.svc.cluster.local`.
94
+
95
+ ### PersistentVolumeClaim Retention
96
+
97
+ StatefulSet PVCs persist after pod deletion by default. To clean up:
98
+
99
+ ```bash
100
+ kubectl delete pvc -l app.kubernetes.io/name=postgres
101
+ ```
102
+
103
+ ## RBAC Patterns
104
+
105
+ ### Least-Privilege ServiceAccount
106
+
107
+ Use `WorkerPool` or `BatchJob` composites which create scoped RBAC automatically:
108
+
109
+ ```typescript
110
+ import { WorkerPool } from "@intentius/chant-lexicon-k8s";
111
+
112
+ const { deployment, serviceAccount, role, roleBinding } = WorkerPool({
113
+ name: "queue-worker",
114
+ image: "worker:1.0",
115
+ replicas: 3,
116
+ rbacRules: [
117
+ { apiGroups: [""], resources: ["configmaps"], verbs: ["get", "list"] },
118
+ { apiGroups: ["batch"], resources: ["jobs"], verbs: ["create"] },
119
+ ],
120
+ });
121
+ ```
122
+
123
+ ### Namespace-Scoped vs Cluster-Scoped
124
+
125
+ - Use `Role` + `RoleBinding` for namespace-scoped permissions (default in composites)
126
+ - Use `ClusterRole` + `ClusterRoleBinding` for cross-namespace access (node agents, monitoring)
127
+
128
+ ```typescript
129
+ import { NodeAgent } from "@intentius/chant-lexicon-k8s";
130
+
131
+ const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding } = NodeAgent({
132
+ name: "log-agent",
133
+ image: "fluent-bit:2.2",
134
+ rbacRules: [
135
+ { apiGroups: [""], resources: ["pods", "namespaces"], verbs: ["get", "list", "watch"] },
136
+ ],
137
+ });
138
+ ```
139
+
140
+ ## Networking Patterns
141
+
142
+ ### Default-Deny with Selective Allow
143
+
144
+ Use `NamespaceEnv` for namespace-level isolation, then `NetworkIsolatedApp` for per-app rules:
145
+
146
+ ```typescript
147
+ import { NamespaceEnv, NetworkIsolatedApp } from "@intentius/chant-lexicon-k8s";
148
+
149
+ const ns = NamespaceEnv({
150
+ name: "prod",
151
+ defaultDenyIngress: true,
152
+ defaultDenyEgress: true,
153
+ cpuLimit: "8",
154
+ memoryLimit: "16Gi",
155
+ });
156
+
157
+ const app = NetworkIsolatedApp({
158
+ name: "api",
159
+ image: "api:1.0",
160
+ port: 8080,
161
+ namespace: "prod",
162
+ allowIngressFrom: [
163
+ { podSelector: { "app.kubernetes.io/name": "gateway" } },
164
+ ],
165
+ allowEgressTo: [
166
+ { podSelector: { "app.kubernetes.io/name": "postgres" }, ports: [{ port: 5432 }] },
167
+ ],
168
+ });
169
+ ```
170
+
171
+ ### Service Mesh (Istio/Linkerd)
172
+
173
+ For mTLS between services, use a sidecar-injected namespace:
174
+
175
+ ```bash
176
+ kubectl label namespace prod istio-injection=enabled
177
+ ```
178
+
179
+ Then deploy with standard composites. The mesh proxy is injected automatically.
180
+
181
+ ### DNS-Based Service Discovery
182
+
183
+ Services are discoverable at `<service>.<namespace>.svc.cluster.local`. For headless services (StatefulSets), individual pods are at `<pod>.<service>.<namespace>.svc.cluster.local`.
@@ -0,0 +1,237 @@
1
+ ---
2
+ skill: kubernetes-security
3
+ description: Kubernetes pod security, image scanning, network policies, and secrets management
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Kubernetes Security Patterns
8
+
9
+ ## Pod Security
10
+
11
+ ### Security Context (container-level)
12
+
13
+ All Deployment-based composites accept `securityContext` for hardened containers:
14
+
15
+ ```typescript
16
+ import { WebApp } from "@intentius/chant-lexicon-k8s";
17
+
18
+ const { deployment, service } = WebApp({
19
+ name: "api",
20
+ image: "api:1.0",
21
+ port: 8080,
22
+ securityContext: {
23
+ runAsNonRoot: true,
24
+ runAsUser: 1000,
25
+ readOnlyRootFilesystem: true,
26
+ allowPrivilegeEscalation: false,
27
+ capabilities: { drop: ["ALL"] },
28
+ },
29
+ });
30
+ ```
31
+
32
+ ### Pod Security Standards
33
+
34
+ Kubernetes enforces three levels via Pod Security Admission:
35
+
36
+ | Level | What it blocks | When to use |
37
+ |-------|---------------|-------------|
38
+ | `privileged` | Nothing | System namespaces only |
39
+ | `baseline` | hostNetwork, hostPID, privileged containers | Development |
40
+ | `restricted` | Non-root, no capabilities, read-only root FS | Production |
41
+
42
+ Apply to a namespace:
43
+
44
+ ```bash
45
+ kubectl label namespace prod pod-security.kubernetes.io/enforce=restricted
46
+ kubectl label namespace prod pod-security.kubernetes.io/warn=restricted
47
+ ```
48
+
49
+ ### Post-Synth Security Checks
50
+
51
+ chant catches security issues at build time:
52
+
53
+ | Check | What it detects |
54
+ |-------|----------------|
55
+ | WK8005 | Secrets exposed in environment variables |
56
+ | WK8006 | `latest` image tags (non-deterministic) |
57
+ | WK8041 | API keys or tokens in plain text |
58
+ | WK8042 | Hardcoded passwords in container env |
59
+ | WK8201 | Missing resource limits (CPU/memory) |
60
+ | WK8202 | Privileged containers |
61
+ | WK8203 | Host namespace sharing (hostPID/hostNetwork) |
62
+ | WK8204 | Writable root filesystem |
63
+ | WK8205 | Containers running as root |
64
+
65
+ ## Image Security
66
+
67
+ ### Pin Image Digests
68
+
69
+ Use image digests instead of tags for immutability:
70
+
71
+ ```typescript
72
+ const { deployment } = WebApp({
73
+ name: "api",
74
+ image: "api@sha256:abc123def456...",
75
+ port: 8080,
76
+ });
77
+ ```
78
+
79
+ ### Private Registry with imagePullSecrets
80
+
81
+ ```typescript
82
+ import { Deployment, Secret } from "@intentius/chant-lexicon-k8s";
83
+
84
+ export const registryCreds = new Secret({
85
+ metadata: { name: "registry-creds" },
86
+ type: "kubernetes.io/dockerconfigjson",
87
+ data: { ".dockerconfigjson": "${DOCKER_CONFIG_JSON}" },
88
+ });
89
+
90
+ export const deployment = new Deployment({
91
+ spec: {
92
+ template: {
93
+ spec: {
94
+ imagePullSecrets: [{ name: "registry-creds" }],
95
+ containers: [{ name: "app", image: "private.registry.io/app:1.0" }],
96
+ },
97
+ },
98
+ },
99
+ });
100
+ ```
101
+
102
+ ### Image Policy
103
+
104
+ Block unsigned or unscanned images with admission controllers:
105
+ - **Kyverno**: policy-based, Kubernetes-native
106
+ - **OPA/Gatekeeper**: Rego-based policies
107
+ - **Sigstore/Cosign**: image signature verification
108
+
109
+ ## Network Policies
110
+
111
+ ### Default Deny All
112
+
113
+ Start with deny-all and add explicit allows:
114
+
115
+ ```typescript
116
+ import { NamespaceEnv } from "@intentius/chant-lexicon-k8s";
117
+
118
+ const ns = NamespaceEnv({
119
+ name: "prod",
120
+ defaultDenyIngress: true,
121
+ defaultDenyEgress: true,
122
+ });
123
+ ```
124
+
125
+ ### Allow Specific Traffic
126
+
127
+ ```typescript
128
+ import { NetworkIsolatedApp } from "@intentius/chant-lexicon-k8s";
129
+
130
+ const app = NetworkIsolatedApp({
131
+ name: "api",
132
+ image: "api:1.0",
133
+ port: 8080,
134
+ namespace: "prod",
135
+ allowIngressFrom: [
136
+ { podSelector: { "app.kubernetes.io/name": "gateway" } },
137
+ { namespaceSelector: { "kubernetes.io/metadata.name": "monitoring" } },
138
+ ],
139
+ allowEgressTo: [
140
+ { podSelector: { "app.kubernetes.io/name": "postgres" }, ports: [{ port: 5432 }] },
141
+ { ipBlock: { cidr: "10.0.0.0/8" }, ports: [{ port: 443 }] },
142
+ ],
143
+ });
144
+ ```
145
+
146
+ ### Allow DNS Egress
147
+
148
+ Most pods need DNS. Always allow egress to kube-dns:
149
+
150
+ ```yaml
151
+ egress:
152
+ - to:
153
+ - namespaceSelector:
154
+ matchLabels:
155
+ kubernetes.io/metadata.name: kube-system
156
+ ports:
157
+ - port: 53
158
+ protocol: UDP
159
+ - port: 53
160
+ protocol: TCP
161
+ ```
162
+
163
+ ## Secrets Management
164
+
165
+ ### External Secrets Operator
166
+
167
+ Sync secrets from external providers (AWS Secrets Manager, Vault, etc.):
168
+
169
+ ```yaml
170
+ apiVersion: external-secrets.io/v1beta1
171
+ kind: ExternalSecret
172
+ metadata:
173
+ name: app-secrets
174
+ spec:
175
+ refreshInterval: 1h
176
+ secretStoreRef:
177
+ name: aws-secrets
178
+ kind: ClusterSecretStore
179
+ target:
180
+ name: app-secrets
181
+ data:
182
+ - secretKey: db-password
183
+ remoteRef:
184
+ key: prod/db-password
185
+ ```
186
+
187
+ ### Sealed Secrets
188
+
189
+ Encrypt secrets for safe storage in Git:
190
+
191
+ ```bash
192
+ kubeseal --format yaml < secret.yaml > sealed-secret.yaml
193
+ ```
194
+
195
+ ### Secret Rotation
196
+
197
+ Use the External Secrets Operator `refreshInterval` or Reloader to restart pods on secret changes:
198
+
199
+ ```bash
200
+ kubectl annotate deployment api reloader.stakater.com/auto="true"
201
+ ```
202
+
203
+ ## RBAC Hardening
204
+
205
+ ### Audit RBAC Permissions
206
+
207
+ ```bash
208
+ # Check what a ServiceAccount can do
209
+ kubectl auth can-i --list --as=system:serviceaccount:prod:api-sa
210
+
211
+ # Check specific permission
212
+ kubectl auth can-i create pods --as=system:serviceaccount:prod:api-sa
213
+ ```
214
+
215
+ ### Avoid Cluster-Admin
216
+
217
+ Never bind `cluster-admin` to application ServiceAccounts. Use namespace-scoped Roles with minimal verbs:
218
+
219
+ ```typescript
220
+ import { WorkerPool } from "@intentius/chant-lexicon-k8s";
221
+
222
+ const worker = WorkerPool({
223
+ name: "processor",
224
+ image: "processor:1.0",
225
+ rbacRules: [
226
+ { apiGroups: [""], resources: ["configmaps"], verbs: ["get"] },
227
+ ],
228
+ });
229
+ ```
230
+
231
+ ### Service Account Token Projection
232
+
233
+ Disable auto-mounting of SA tokens when not needed:
234
+
235
+ ```yaml
236
+ automountServiceAccountToken: false
237
+ ```
File without changes