@intentius/chant-lexicon-k8s 0.0.15 → 0.0.18
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 +4 -3
- 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/package.json +2 -2
- package/src/codegen/docs.ts +10 -0
- package/src/composites/agic-ingress.ts +0 -1
- package/src/composites/aks-external-dns-agent.ts +199 -0
- package/src/composites/azure-monitor-collector.ts +2 -2
- package/src/composites/cockroachdb-cluster.ts +421 -0
- package/src/composites/composites.test.ts +526 -0
- package/src/composites/gce-ingress.ts +143 -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-otel-collector.ts +229 -0
- package/src/composites/index.ts +14 -0
- package/src/index.ts +14 -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.ts +125 -208
- 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
package/dist/integrity.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "xxhash64",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "d4efb3b22f42dfb",
|
|
5
5
|
"meta.json": "1ce194f36f9b5f90",
|
|
6
6
|
"types/index.d.ts": "beec4cc869064186",
|
|
7
|
+
"rules/missing-resource-limits.ts": "a6f776d2ff477948",
|
|
8
|
+
"rules/latest-image-tag.ts": "eb48e8d61e4ca84e",
|
|
7
9
|
"rules/hardcoded-namespace.ts": "54b216c71018e101",
|
|
8
10
|
"rules/wk8201.ts": "4dbbd20e21b5fa04",
|
|
9
11
|
"rules/wk8204.ts": "9244d6fdd6d2f7d",
|
|
@@ -30,8 +32,7 @@
|
|
|
30
32
|
"rules/k8s-helpers.ts": "53a6d3bfbedb2852",
|
|
31
33
|
"rules/wk8207.ts": "6f2bc621d530afa2",
|
|
32
34
|
"skills/chant-k8s.md": "c7db82c3ba37c78",
|
|
33
|
-
"skills/chant-k8s-eks.md": "f79f31f058c7f2ed",
|
|
34
35
|
"skills/chant-k8s-patterns.md": "c5151ed799145c4b"
|
|
35
36
|
},
|
|
36
|
-
"composite": "
|
|
37
|
+
"composite": "a997382724e0b6c5"
|
|
37
38
|
}
|
package/dist/manifest.json
CHANGED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { LintRule, LintDiagnostic, LintContext } from "@intentius/chant/lint/rule";
|
|
2
|
+
import * as ts from "typescript";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* WK8002: Latest Image Tag
|
|
6
|
+
*
|
|
7
|
+
* Detects when a K8s workload resource uses the `:latest` image tag or no tag
|
|
8
|
+
* at all in a container image string literal. Untagged or `:latest` images are
|
|
9
|
+
* non-deterministic and can cause unexpected rollouts.
|
|
10
|
+
*
|
|
11
|
+
* Bad: new Deployment({ spec: { template: { spec: { containers: [{ image: "nginx:latest" }] } } } })
|
|
12
|
+
* Bad: new Deployment({ spec: { template: { spec: { containers: [{ image: "nginx" }] } } } })
|
|
13
|
+
* Good: new Deployment({ spec: { template: { spec: { containers: [{ image: "nginx:1.25" }] } } } })
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const WORKLOAD_KINDS = new Set([
|
|
17
|
+
"Deployment",
|
|
18
|
+
"StatefulSet",
|
|
19
|
+
"DaemonSet",
|
|
20
|
+
"CronJob",
|
|
21
|
+
"Job",
|
|
22
|
+
"ReplicaSet",
|
|
23
|
+
"Pod",
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns true if the string looks like a container image reference that is
|
|
28
|
+
* either untagged or using `:latest`.
|
|
29
|
+
*
|
|
30
|
+
* A string is considered a container image if it:
|
|
31
|
+
* - Contains at least one alphabetic character
|
|
32
|
+
* - Does not contain spaces
|
|
33
|
+
* - Is not a simple keyword like "true", "false", etc.
|
|
34
|
+
*/
|
|
35
|
+
function isProblematicImage(value: string): boolean {
|
|
36
|
+
if (!value || value.includes(" ") || value.length === 0) return false;
|
|
37
|
+
|
|
38
|
+
// Skip values that are clearly not images
|
|
39
|
+
const nonImagePatterns = [
|
|
40
|
+
/^(true|false|null|undefined|yes|no)$/i,
|
|
41
|
+
/^\d+$/, // pure numbers
|
|
42
|
+
/^[.\/]/, // relative/absolute paths without image-like structure
|
|
43
|
+
];
|
|
44
|
+
for (const pat of nonImagePatterns) {
|
|
45
|
+
if (pat.test(value)) return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check for :latest explicitly
|
|
49
|
+
if (value.endsWith(":latest")) return true;
|
|
50
|
+
|
|
51
|
+
// Check for untagged image: no colon at all, but looks like an image name
|
|
52
|
+
// Images contain alphanumeric chars and may have / for registry prefix
|
|
53
|
+
// Must have at least one alpha char and match image naming conventions
|
|
54
|
+
if (!value.includes(":") && !value.includes("@") && /^[a-zA-Z0-9._\-\/]+$/.test(value) && /[a-zA-Z]/.test(value)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const latestImageTagRule: LintRule = {
|
|
62
|
+
id: "WK8002",
|
|
63
|
+
severity: "warning",
|
|
64
|
+
category: "security",
|
|
65
|
+
description:
|
|
66
|
+
"Detects :latest or untagged container images — use explicit version tags for reproducibility",
|
|
67
|
+
|
|
68
|
+
check(context: LintContext): LintDiagnostic[] {
|
|
69
|
+
const { sourceFile } = context;
|
|
70
|
+
const diagnostics: LintDiagnostic[] = [];
|
|
71
|
+
|
|
72
|
+
function isInsideWorkloadConstructor(node: ts.Node): boolean {
|
|
73
|
+
let current: ts.Node | undefined = node.parent;
|
|
74
|
+
while (current) {
|
|
75
|
+
if (
|
|
76
|
+
ts.isNewExpression(current) &&
|
|
77
|
+
ts.isIdentifier(current.expression) &&
|
|
78
|
+
WORKLOAD_KINDS.has(current.expression.text)
|
|
79
|
+
) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
current = current.parent;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function visit(node: ts.Node): void {
|
|
88
|
+
// Look for property assignments like `image: "nginx:latest"` or `image: "nginx"`
|
|
89
|
+
if (
|
|
90
|
+
ts.isPropertyAssignment(node) &&
|
|
91
|
+
ts.isIdentifier(node.name) &&
|
|
92
|
+
node.name.text === "image" &&
|
|
93
|
+
ts.isStringLiteral(node.initializer) &&
|
|
94
|
+
isInsideWorkloadConstructor(node)
|
|
95
|
+
) {
|
|
96
|
+
const value = node.initializer.text;
|
|
97
|
+
if (isProblematicImage(value)) {
|
|
98
|
+
const { line, character } =
|
|
99
|
+
sourceFile.getLineAndCharacterOfPosition(
|
|
100
|
+
node.initializer.getStart(),
|
|
101
|
+
);
|
|
102
|
+
const isLatest = value.endsWith(":latest");
|
|
103
|
+
diagnostics.push({
|
|
104
|
+
file: sourceFile.fileName,
|
|
105
|
+
line: line + 1,
|
|
106
|
+
column: character + 1,
|
|
107
|
+
ruleId: "WK8002",
|
|
108
|
+
severity: "warning",
|
|
109
|
+
message: isLatest
|
|
110
|
+
? `Container image "${value}" uses the :latest tag. Pin to a specific version for reproducibility.`
|
|
111
|
+
: `Container image "${value}" has no tag. Pin to a specific version for reproducibility.`,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
ts.forEachChild(node, visit);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
visit(sourceFile);
|
|
119
|
+
return diagnostics;
|
|
120
|
+
},
|
|
121
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { LintRule, LintDiagnostic, LintContext } from "@intentius/chant/lint/rule";
|
|
2
|
+
import * as ts from "typescript";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* WK8003: Missing Resource Limits
|
|
6
|
+
*
|
|
7
|
+
* Detects when a container in a Deployment/StatefulSet spec doesn't have
|
|
8
|
+
* resource limits or requests. Without resource limits, a container can
|
|
9
|
+
* consume unbounded cluster resources and cause noisy-neighbour issues.
|
|
10
|
+
*
|
|
11
|
+
* Bad: new Deployment({ spec: { template: { spec: { containers: [{ name: "app", image: "app:1.0" }] } } } })
|
|
12
|
+
* Good: new Deployment({ spec: { template: { spec: { containers: [{ name: "app", image: "app:1.0", resources: { limits: { cpu: "500m", memory: "256Mi" } } }] } } } })
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const WORKLOAD_KINDS = new Set([
|
|
16
|
+
"Deployment",
|
|
17
|
+
"StatefulSet",
|
|
18
|
+
"DaemonSet",
|
|
19
|
+
"CronJob",
|
|
20
|
+
"Job",
|
|
21
|
+
"ReplicaSet",
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
export const missingResourceLimitsRule: LintRule = {
|
|
25
|
+
id: "WK8003",
|
|
26
|
+
severity: "warning",
|
|
27
|
+
category: "correctness",
|
|
28
|
+
description:
|
|
29
|
+
"Detects containers without resource limits/requests — always set resource constraints",
|
|
30
|
+
|
|
31
|
+
check(context: LintContext): LintDiagnostic[] {
|
|
32
|
+
const { sourceFile } = context;
|
|
33
|
+
const diagnostics: LintDiagnostic[] = [];
|
|
34
|
+
|
|
35
|
+
function isInsideWorkloadConstructor(node: ts.Node): boolean {
|
|
36
|
+
let current: ts.Node | undefined = node.parent;
|
|
37
|
+
while (current) {
|
|
38
|
+
if (
|
|
39
|
+
ts.isNewExpression(current) &&
|
|
40
|
+
ts.isIdentifier(current.expression) &&
|
|
41
|
+
WORKLOAD_KINDS.has(current.expression.text)
|
|
42
|
+
) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
current = current.parent;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function objectLiteralHasProperty(
|
|
51
|
+
obj: ts.ObjectLiteralExpression,
|
|
52
|
+
name: string,
|
|
53
|
+
): boolean {
|
|
54
|
+
return obj.properties.some(
|
|
55
|
+
(p) =>
|
|
56
|
+
ts.isPropertyAssignment(p) &&
|
|
57
|
+
ts.isIdentifier(p.name) &&
|
|
58
|
+
p.name.text === name,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function visit(node: ts.Node): void {
|
|
63
|
+
// Look for object literals inside arrays that represent container specs.
|
|
64
|
+
// A container object literal typically has "name" and "image" properties.
|
|
65
|
+
// We flag it if it lacks a "resources" property.
|
|
66
|
+
if (
|
|
67
|
+
ts.isObjectLiteralExpression(node) &&
|
|
68
|
+
isInsideWorkloadConstructor(node)
|
|
69
|
+
) {
|
|
70
|
+
const hasName = objectLiteralHasProperty(node, "name");
|
|
71
|
+
const hasImage = objectLiteralHasProperty(node, "image");
|
|
72
|
+
const hasResources = objectLiteralHasProperty(node, "resources");
|
|
73
|
+
|
|
74
|
+
if (hasName && hasImage && !hasResources) {
|
|
75
|
+
// Confirm we're inside an array literal (containers array)
|
|
76
|
+
if (node.parent && ts.isArrayLiteralExpression(node.parent)) {
|
|
77
|
+
const { line, character } =
|
|
78
|
+
sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
79
|
+
|
|
80
|
+
// Try to extract the container name for a better message
|
|
81
|
+
let containerName = "unknown";
|
|
82
|
+
for (const prop of node.properties) {
|
|
83
|
+
if (
|
|
84
|
+
ts.isPropertyAssignment(prop) &&
|
|
85
|
+
ts.isIdentifier(prop.name) &&
|
|
86
|
+
prop.name.text === "name" &&
|
|
87
|
+
ts.isStringLiteral(prop.initializer)
|
|
88
|
+
) {
|
|
89
|
+
containerName = prop.initializer.text;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
diagnostics.push({
|
|
95
|
+
file: sourceFile.fileName,
|
|
96
|
+
line: line + 1,
|
|
97
|
+
column: character + 1,
|
|
98
|
+
ruleId: "WK8003",
|
|
99
|
+
severity: "warning",
|
|
100
|
+
message: `Container "${containerName}" is missing resource limits/requests. Set resources.limits and resources.requests to prevent unbounded resource consumption.`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
ts.forEachChild(node, visit);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
visit(sourceFile);
|
|
109
|
+
return diagnostics;
|
|
110
|
+
},
|
|
111
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-k8s",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"prepack": "bun run generate && bun run bundle && bun run validate"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@intentius/chant": "0.0.
|
|
28
|
+
"@intentius/chant": "0.0.18"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"typescript": "^5.9.3"
|
package/src/codegen/docs.ts
CHANGED
|
@@ -1134,6 +1134,16 @@ The lexicon also provides MCP (Model Context Protocol) tools and resources:
|
|
|
1134
1134
|
},
|
|
1135
1135
|
],
|
|
1136
1136
|
basePath: "/chant/lexicons/k8s/",
|
|
1137
|
+
sidebarExtra: [
|
|
1138
|
+
{
|
|
1139
|
+
label: "Vendor Composites",
|
|
1140
|
+
items: [
|
|
1141
|
+
{ label: "EKS Composites", slug: "eks-composites" },
|
|
1142
|
+
{ label: "AKS Composites", slug: "aks-composites" },
|
|
1143
|
+
{ label: "GKE Composites", slug: "gke-composites" },
|
|
1144
|
+
],
|
|
1145
|
+
},
|
|
1146
|
+
],
|
|
1137
1147
|
};
|
|
1138
1148
|
|
|
1139
1149
|
const result = await docsPipeline(config);
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AksExternalDnsAgent composite — Deployment + ServiceAccount + ClusterRole + ClusterRoleBinding.
|
|
3
|
+
*
|
|
4
|
+
* @aks Like ExternalDnsAgent but uses --provider=azure and AKS Workload Identity
|
|
5
|
+
* instead of IRSA for Azure DNS management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface AksExternalDnsAgentProps {
|
|
9
|
+
/** Azure managed identity client ID for Workload Identity. */
|
|
10
|
+
clientId: string;
|
|
11
|
+
/** Azure resource group containing the DNS zone. */
|
|
12
|
+
resourceGroup: string;
|
|
13
|
+
/** Azure subscription ID. */
|
|
14
|
+
subscriptionId: string;
|
|
15
|
+
/** Azure tenant ID. */
|
|
16
|
+
tenantId: string;
|
|
17
|
+
/** Domain filters — only manage DNS records for these domains. */
|
|
18
|
+
domainFilters: string[];
|
|
19
|
+
/** TXT record owner ID for identifying managed records. */
|
|
20
|
+
txtOwnerId?: string;
|
|
21
|
+
/** Source of DNS records (default: "ingress"). */
|
|
22
|
+
source?: string;
|
|
23
|
+
/** Agent name (default: "external-dns"). */
|
|
24
|
+
name?: string;
|
|
25
|
+
/** Container image (default: "registry.k8s.io/external-dns/external-dns:v0.14.0"). */
|
|
26
|
+
image?: string;
|
|
27
|
+
/** Namespace (default: "kube-system"). */
|
|
28
|
+
namespace?: string;
|
|
29
|
+
/** Additional labels. */
|
|
30
|
+
labels?: Record<string, string>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface AksExternalDnsAgentResult {
|
|
34
|
+
deployment: Record<string, unknown>;
|
|
35
|
+
serviceAccount: Record<string, unknown>;
|
|
36
|
+
clusterRole: Record<string, unknown>;
|
|
37
|
+
clusterRoleBinding: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create an AksExternalDnsAgent composite — returns prop objects for
|
|
42
|
+
* a Deployment, ServiceAccount (with AKS Workload Identity), ClusterRole, and ClusterRoleBinding.
|
|
43
|
+
*
|
|
44
|
+
* @aks
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { AksExternalDnsAgent } from "@intentius/chant-lexicon-k8s";
|
|
48
|
+
*
|
|
49
|
+
* const { deployment, serviceAccount, clusterRole, clusterRoleBinding } = AksExternalDnsAgent({
|
|
50
|
+
* clientId: "00000000-0000-0000-0000-000000000000",
|
|
51
|
+
* resourceGroup: "my-rg",
|
|
52
|
+
* subscriptionId: "00000000-0000-0000-0000-000000000000",
|
|
53
|
+
* tenantId: "00000000-0000-0000-0000-000000000000",
|
|
54
|
+
* domainFilters: ["example.com"],
|
|
55
|
+
* txtOwnerId: "my-cluster",
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function AksExternalDnsAgent(props: AksExternalDnsAgentProps): AksExternalDnsAgentResult {
|
|
60
|
+
const {
|
|
61
|
+
clientId,
|
|
62
|
+
resourceGroup,
|
|
63
|
+
subscriptionId,
|
|
64
|
+
tenantId,
|
|
65
|
+
domainFilters,
|
|
66
|
+
txtOwnerId,
|
|
67
|
+
source = "ingress",
|
|
68
|
+
name = "external-dns",
|
|
69
|
+
image = "registry.k8s.io/external-dns/external-dns:v0.14.0",
|
|
70
|
+
namespace = "kube-system",
|
|
71
|
+
labels: extraLabels = {},
|
|
72
|
+
} = props;
|
|
73
|
+
|
|
74
|
+
const saName = `${name}-sa`;
|
|
75
|
+
const clusterRoleName = `${name}-role`;
|
|
76
|
+
const bindingName = `${name}-binding`;
|
|
77
|
+
|
|
78
|
+
const commonLabels: Record<string, string> = {
|
|
79
|
+
"app.kubernetes.io/name": name,
|
|
80
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
81
|
+
...extraLabels,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const args: string[] = [
|
|
85
|
+
`--source=${source}`,
|
|
86
|
+
"--provider=azure",
|
|
87
|
+
`--azure-resource-group=${resourceGroup}`,
|
|
88
|
+
`--azure-subscription-id=${subscriptionId}`,
|
|
89
|
+
"--policy=upsert-only",
|
|
90
|
+
"--registry=txt",
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
for (const domain of domainFilters) {
|
|
94
|
+
args.push(`--domain-filter=${domain}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (txtOwnerId) {
|
|
98
|
+
args.push(`--txt-owner-id=${txtOwnerId}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const deploymentProps: Record<string, unknown> = {
|
|
102
|
+
metadata: {
|
|
103
|
+
name,
|
|
104
|
+
namespace,
|
|
105
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "dns" },
|
|
106
|
+
},
|
|
107
|
+
spec: {
|
|
108
|
+
replicas: 1,
|
|
109
|
+
selector: { matchLabels: { "app.kubernetes.io/name": name } },
|
|
110
|
+
template: {
|
|
111
|
+
metadata: {
|
|
112
|
+
labels: {
|
|
113
|
+
"app.kubernetes.io/name": name,
|
|
114
|
+
"azure.workload.identity/use": "true",
|
|
115
|
+
...extraLabels,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
spec: {
|
|
119
|
+
serviceAccountName: saName,
|
|
120
|
+
containers: [
|
|
121
|
+
{
|
|
122
|
+
name,
|
|
123
|
+
image,
|
|
124
|
+
args,
|
|
125
|
+
env: [
|
|
126
|
+
{ name: "AZURE_TENANT_ID", value: tenantId },
|
|
127
|
+
{ name: "AZURE_SUBSCRIPTION_ID", value: subscriptionId },
|
|
128
|
+
{ name: "AZURE_RESOURCE_GROUP", value: resourceGroup },
|
|
129
|
+
],
|
|
130
|
+
resources: {
|
|
131
|
+
requests: { cpu: "50m", memory: "64Mi" },
|
|
132
|
+
limits: { cpu: "100m", memory: "128Mi" },
|
|
133
|
+
},
|
|
134
|
+
securityContext: {
|
|
135
|
+
runAsNonRoot: true,
|
|
136
|
+
runAsUser: 65534,
|
|
137
|
+
readOnlyRootFilesystem: true,
|
|
138
|
+
allowPrivilegeEscalation: false,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const serviceAccountProps: Record<string, unknown> = {
|
|
148
|
+
metadata: {
|
|
149
|
+
name: saName,
|
|
150
|
+
namespace,
|
|
151
|
+
labels: {
|
|
152
|
+
...commonLabels,
|
|
153
|
+
"app.kubernetes.io/component": "dns",
|
|
154
|
+
"azure.workload.identity/use": "true",
|
|
155
|
+
},
|
|
156
|
+
annotations: {
|
|
157
|
+
"azure.workload.identity/client-id": clientId,
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const clusterRoleProps: Record<string, unknown> = {
|
|
163
|
+
metadata: {
|
|
164
|
+
name: clusterRoleName,
|
|
165
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
166
|
+
},
|
|
167
|
+
rules: [
|
|
168
|
+
{ apiGroups: [""], resources: ["services", "endpoints", "pods"], verbs: ["get", "watch", "list"] },
|
|
169
|
+
{ apiGroups: ["extensions", "networking.k8s.io"], resources: ["ingresses"], verbs: ["get", "watch", "list"] },
|
|
170
|
+
{ apiGroups: [""], resources: ["nodes"], verbs: ["list", "watch"] },
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const clusterRoleBindingProps: Record<string, unknown> = {
|
|
175
|
+
metadata: {
|
|
176
|
+
name: bindingName,
|
|
177
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
178
|
+
},
|
|
179
|
+
roleRef: {
|
|
180
|
+
apiGroup: "rbac.authorization.k8s.io",
|
|
181
|
+
kind: "ClusterRole",
|
|
182
|
+
name: clusterRoleName,
|
|
183
|
+
},
|
|
184
|
+
subjects: [
|
|
185
|
+
{
|
|
186
|
+
kind: "ServiceAccount",
|
|
187
|
+
name: saName,
|
|
188
|
+
namespace,
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
deployment: deploymentProps,
|
|
195
|
+
serviceAccount: serviceAccountProps,
|
|
196
|
+
clusterRole: clusterRoleProps,
|
|
197
|
+
clusterRoleBinding: clusterRoleBindingProps,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
@@ -12,7 +12,7 @@ export interface AzureMonitorCollectorProps {
|
|
|
12
12
|
clusterName: string;
|
|
13
13
|
/** Agent name (default: "azure-monitor-collector"). */
|
|
14
14
|
name?: string;
|
|
15
|
-
/** Collector image (default: "mcr.microsoft.com/azuremonitor/containerinsights/ciprod:
|
|
15
|
+
/** Collector image (default: "mcr.microsoft.com/azuremonitor/containerinsights/ciprod:3.1.35"). */
|
|
16
16
|
image?: string;
|
|
17
17
|
/** Namespace (default: "azure-monitor"). */
|
|
18
18
|
namespace?: string;
|
|
@@ -58,7 +58,7 @@ export function AzureMonitorCollector(props: AzureMonitorCollectorProps): AzureM
|
|
|
58
58
|
workspaceId,
|
|
59
59
|
clusterName,
|
|
60
60
|
name = "azure-monitor-collector",
|
|
61
|
-
image = "mcr.microsoft.com/azuremonitor/containerinsights/ciprod:
|
|
61
|
+
image = "mcr.microsoft.com/azuremonitor/containerinsights/ciprod:3.1.35",
|
|
62
62
|
namespace = "azure-monitor",
|
|
63
63
|
labels: extraLabels = {},
|
|
64
64
|
cpuRequest = "100m",
|