@intentius/chant-lexicon-azure 0.124.31 → 0.124.32

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 (117) hide show
  1. package/dist/actions/appservice.js +7 -0
  2. package/dist/actions/compute.js +9 -0
  3. package/dist/actions/container.js +14 -0
  4. package/dist/actions/identity.js +11 -0
  5. package/dist/actions/index.js +11 -0
  6. package/dist/actions/keyvault.js +12 -0
  7. package/dist/actions/network.js +9 -0
  8. package/dist/actions/sql.js +9 -0
  9. package/dist/actions/storage.js +15 -0
  10. package/dist/api/read-client.js +146 -0
  11. package/dist/codegen/docs-cli.js +2 -0
  12. package/dist/codegen/docs.js +83 -0
  13. package/dist/codegen/generate-cli.js +11 -0
  14. package/dist/codegen/generate-lexicon.js +77 -0
  15. package/dist/codegen/generate-typescript.js +163 -0
  16. package/dist/codegen/generate.js +106 -0
  17. package/dist/codegen/naming.js +139 -0
  18. package/dist/codegen/package.js +64 -0
  19. package/dist/composites/aks-cluster.js +68 -0
  20. package/dist/composites/app-service.js +62 -0
  21. package/dist/composites/application-gateway.js +107 -0
  22. package/dist/composites/catalog.js +856 -0
  23. package/dist/composites/container-instance.js +36 -0
  24. package/dist/composites/container-registry.js +62 -0
  25. package/dist/composites/cosmos-database.js +56 -0
  26. package/dist/composites/from-arm.js +47 -0
  27. package/dist/composites/function-app.js +57 -0
  28. package/dist/composites/index.js +16 -0
  29. package/dist/composites/keyvault.js +69 -0
  30. package/dist/composites/landing-zone.js +119 -0
  31. package/dist/composites/private-endpoint.js +61 -0
  32. package/dist/composites/redis-cache.js +21 -0
  33. package/dist/composites/service-bus-pipeline.js +54 -0
  34. package/dist/composites/sql-database.js +62 -0
  35. package/dist/composites/storage-account.js +59 -0
  36. package/dist/composites/vm-linux.js +139 -0
  37. package/dist/composites/vnet-default.js +102 -0
  38. package/dist/coverage.js +28 -0
  39. package/dist/deep-observe.js +356 -0
  40. package/dist/default-tags.js +50 -0
  41. package/dist/deploy-scopes.d.ts.map +1 -1
  42. package/dist/deploy-scopes.js +157 -0
  43. package/dist/describe-resources.js +187 -0
  44. package/dist/detect.js +17 -0
  45. package/dist/export-resources.js +108 -0
  46. package/dist/generated/index.js +16598 -0
  47. package/dist/generated/runtime.js +4 -0
  48. package/dist/governance.js +144 -0
  49. package/dist/import/generator.js +140 -0
  50. package/dist/import/live-export.js +39 -0
  51. package/dist/import/parser.js +192 -0
  52. package/dist/index.js +44 -0
  53. package/dist/integrity.json +2 -2
  54. package/dist/intrinsics.js +179 -0
  55. package/dist/lint/audit-catalog.js +36 -0
  56. package/dist/lint/audit-lineage.js +71 -0
  57. package/dist/lint/post-synth/arm-refs.js +94 -0
  58. package/dist/lint/post-synth/azr010.js +45 -0
  59. package/dist/lint/post-synth/azr011.js +43 -0
  60. package/dist/lint/post-synth/azr012.js +41 -0
  61. package/dist/lint/post-synth/azr013.js +50 -0
  62. package/dist/lint/post-synth/azr014.js +49 -0
  63. package/dist/lint/post-synth/azr015.js +66 -0
  64. package/dist/lint/post-synth/azr016.js +37 -0
  65. package/dist/lint/post-synth/azr017.js +37 -0
  66. package/dist/lint/post-synth/azr018.js +42 -0
  67. package/dist/lint/post-synth/azr019.js +41 -0
  68. package/dist/lint/post-synth/azr020.js +37 -0
  69. package/dist/lint/post-synth/azr021.js +36 -0
  70. package/dist/lint/post-synth/azr022.js +39 -0
  71. package/dist/lint/post-synth/azr023.js +39 -0
  72. package/dist/lint/post-synth/azr024.js +39 -0
  73. package/dist/lint/post-synth/azr025.js +37 -0
  74. package/dist/lint/post-synth/azr026.js +38 -0
  75. package/dist/lint/post-synth/azr027.js +37 -0
  76. package/dist/lint/post-synth/azr028.js +37 -0
  77. package/dist/lint/post-synth/azr029.js +38 -0
  78. package/dist/lint/post-synth/azr030.js +44 -0
  79. package/dist/lint/post-synth/azr031.js +36 -0
  80. package/dist/lint/post-synth/azr032.js +53 -0
  81. package/dist/lint/post-synth/azr033.js +35 -0
  82. package/dist/lint/post-synth/index.js +50 -0
  83. package/dist/lint/rules/hardcoded-location.js +82 -0
  84. package/dist/lint/rules/index.js +6 -0
  85. package/dist/lint/rules/nsg-wildcard.js +44 -0
  86. package/dist/lint/rules/storage-https.js +62 -0
  87. package/dist/lsp/completions.d.ts.map +1 -1
  88. package/dist/lsp/completions.js +18 -0
  89. package/dist/lsp/hover.d.ts.map +1 -1
  90. package/dist/lsp/hover.js +44 -0
  91. package/dist/manifest.json +1 -1
  92. package/dist/op/activities/az-apply.js +563 -0
  93. package/dist/op/activities/azure.js +48 -0
  94. package/dist/op/activities/floci-az.js +37 -0
  95. package/dist/op/activities/index.js +10 -0
  96. package/dist/op/builders.js +70 -0
  97. package/dist/ownership.js +13 -0
  98. package/dist/package-cli.js +21 -0
  99. package/dist/parameter.js +13 -0
  100. package/dist/plugin.d.ts.map +1 -1
  101. package/dist/plugin.js +472 -0
  102. package/dist/pseudo.js +40 -0
  103. package/dist/serializer.js +457 -0
  104. package/dist/spec/api-versions.js +130 -0
  105. package/dist/spec/fetch.js +196 -0
  106. package/dist/spec/parse.js +308 -0
  107. package/dist/taggable.js +34 -0
  108. package/dist/validate-cli.js +16 -0
  109. package/dist/validate.js +53 -0
  110. package/package.json +8 -8
  111. package/src/codegen/package.ts +2 -2
  112. package/src/deploy-scopes.ts +2 -1
  113. package/src/lsp/completions.ts +2 -1
  114. package/src/lsp/hover.ts +2 -1
  115. package/src/plugin.ts +3 -2
  116. package/src/serializer.ts +2 -2
  117. package/src/taggable.ts +2 -2
@@ -0,0 +1,66 @@
1
+ /**
2
+ * AZR015: Missing Encryption on Storage Account
3
+ *
4
+ * Warns when a Storage Account does not have encryption configured.
5
+ * Storage accounts should have encryption services enabled for blob,
6
+ * file, table, and queue to protect data at rest.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const STORAGE_ACCOUNT_TYPE = "Microsoft.Storage/storageAccounts";
10
+ export const azr015 = {
11
+ id: "AZR015",
12
+ description: "Missing encryption on storage account — enable encryption services to protect data at rest",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== STORAGE_ACCOUNT_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ const encryption = props.encryption;
25
+ if (!encryption) {
26
+ diagnostics.push({
27
+ checkId: "AZR015",
28
+ severity: "warning",
29
+ message: `Storage account "${resourceName}" has no encryption configuration — enable encryption services for blob, file, table, and queue`,
30
+ entity: resourceName,
31
+ lexicon: "azure",
32
+ });
33
+ continue;
34
+ }
35
+ // Check that encryption services are defined
36
+ const services = encryption.services;
37
+ if (!services) {
38
+ diagnostics.push({
39
+ checkId: "AZR015",
40
+ severity: "warning",
41
+ message: `Storage account "${resourceName}" has encryption configured but no encryption services specified — enable blob, file, table, and queue encryption`,
42
+ entity: resourceName,
43
+ lexicon: "azure",
44
+ });
45
+ continue;
46
+ }
47
+ // Check for blob and file at minimum
48
+ const missingServices = [];
49
+ if (!services.blob)
50
+ missingServices.push("blob");
51
+ if (!services.file)
52
+ missingServices.push("file");
53
+ if (missingServices.length > 0) {
54
+ diagnostics.push({
55
+ checkId: "AZR015",
56
+ severity: "warning",
57
+ message: `Storage account "${resourceName}" is missing encryption for: ${missingServices.join(", ")}`,
58
+ entity: resourceName,
59
+ lexicon: "azure",
60
+ });
61
+ }
62
+ }
63
+ }
64
+ return diagnostics;
65
+ },
66
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * AZR016: Key Vault soft-delete not enabled
3
+ *
4
+ * Warns when a Key Vault does not have soft-delete enabled.
5
+ * Soft delete is required to protect against accidental deletion
6
+ * of keys, secrets, and certificates.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const KEY_VAULT_TYPE = "Microsoft.KeyVault/vaults";
10
+ export const azr016 = {
11
+ id: "AZR016",
12
+ description: "Key Vault soft-delete not enabled — enable to protect against accidental deletion",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== KEY_VAULT_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ if (props.enableSoftDelete !== true) {
25
+ diagnostics.push({
26
+ checkId: "AZR016",
27
+ severity: "warning",
28
+ message: `Key Vault "${resourceName}" does not have soft-delete enabled — set enableSoftDelete to true`,
29
+ entity: resourceName,
30
+ lexicon: "azure",
31
+ });
32
+ }
33
+ }
34
+ }
35
+ return diagnostics;
36
+ },
37
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * AZR017: Key Vault purge protection not enabled
3
+ *
4
+ * Warns when a Key Vault does not have purge protection enabled.
5
+ * Purge protection prevents permanent deletion of soft-deleted vaults
6
+ * and vault objects during the retention period.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const KEY_VAULT_TYPE = "Microsoft.KeyVault/vaults";
10
+ export const azr017 = {
11
+ id: "AZR017",
12
+ description: "Key Vault purge protection not enabled — enable to prevent permanent deletion during retention period",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== KEY_VAULT_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ if (props.enablePurgeProtection !== true) {
25
+ diagnostics.push({
26
+ checkId: "AZR017",
27
+ severity: "warning",
28
+ message: `Key Vault "${resourceName}" does not have purge protection enabled — set enablePurgeProtection to true`,
29
+ entity: resourceName,
30
+ lexicon: "azure",
31
+ });
32
+ }
33
+ }
34
+ }
35
+ return diagnostics;
36
+ },
37
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * AZR018: SQL Server missing auditing
3
+ *
4
+ * Warns when a SQL Server does not have auditing configured.
5
+ * Azure SQL auditing tracks database events and writes them
6
+ * to an audit log, helping meet compliance requirements.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const SQL_SERVER_TYPE = "Microsoft.Sql/servers";
10
+ const AUDIT_TYPE = "Microsoft.Sql/servers/auditingSettings";
11
+ export const azr018 = {
12
+ id: "AZR018",
13
+ description: "SQL Server missing auditing — enable auditing for compliance and threat detection",
14
+ check(ctx) {
15
+ const diagnostics = [];
16
+ for (const [_lexicon, output] of ctx.outputs) {
17
+ const template = parseArmTemplate(output);
18
+ if (!template?.resources)
19
+ continue;
20
+ const sqlServers = template.resources.filter((r) => r.type === SQL_SERVER_TYPE);
21
+ const auditSettings = template.resources.filter((r) => r.type === AUDIT_TYPE);
22
+ for (const server of sqlServers) {
23
+ const serverName = typeof server.name === "string" ? server.name : String(server.name);
24
+ // Check for a matching auditing settings resource
25
+ const hasAudit = auditSettings.some((a) => {
26
+ const auditName = typeof a.name === "string" ? a.name : String(a.name);
27
+ return auditName.startsWith(`${serverName}/`);
28
+ });
29
+ if (!hasAudit) {
30
+ diagnostics.push({
31
+ checkId: "AZR018",
32
+ severity: "warning",
33
+ message: `SQL Server "${serverName}" does not have auditing configured — add a Microsoft.Sql/servers/auditingSettings resource`,
34
+ entity: serverName,
35
+ lexicon: "azure",
36
+ });
37
+ }
38
+ }
39
+ }
40
+ return diagnostics;
41
+ },
42
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * AZR019: SQL Server missing Transparent Data Encryption (TDE)
3
+ *
4
+ * Warns when a SQL Server database does not have TDE configured.
5
+ * TDE provides encryption at rest for the entire database, backups,
6
+ * and transaction log files.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const SQL_DB_TYPE = "Microsoft.Sql/servers/databases";
10
+ const TDE_TYPE = "Microsoft.Sql/servers/databases/transparentDataEncryption";
11
+ export const azr019 = {
12
+ id: "AZR019",
13
+ description: "SQL Server database missing TDE — enable Transparent Data Encryption to protect data at rest",
14
+ check(ctx) {
15
+ const diagnostics = [];
16
+ for (const [_lexicon, output] of ctx.outputs) {
17
+ const template = parseArmTemplate(output);
18
+ if (!template?.resources)
19
+ continue;
20
+ const databases = template.resources.filter((r) => r.type === SQL_DB_TYPE);
21
+ const tdeSettings = template.resources.filter((r) => r.type === TDE_TYPE);
22
+ for (const db of databases) {
23
+ const dbName = typeof db.name === "string" ? db.name : String(db.name);
24
+ const hasTde = tdeSettings.some((t) => {
25
+ const tdeName = typeof t.name === "string" ? t.name : String(t.name);
26
+ return tdeName.startsWith(`${dbName}/`);
27
+ });
28
+ if (!hasTde) {
29
+ diagnostics.push({
30
+ checkId: "AZR019",
31
+ severity: "warning",
32
+ message: `SQL database "${dbName}" does not have TDE configured — add transparentDataEncryption resource`,
33
+ entity: dbName,
34
+ lexicon: "azure",
35
+ });
36
+ }
37
+ }
38
+ }
39
+ return diagnostics;
40
+ },
41
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * AZR020: App Service missing managed identity
3
+ *
4
+ * Warns when a Web App does not have a managed identity configured.
5
+ * Managed identity eliminates the need for credentials in code
6
+ * and enables secure access to Azure services.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const WEB_APP_TYPE = "Microsoft.Web/sites";
10
+ export const azr020 = {
11
+ id: "AZR020",
12
+ description: "App Service missing managed identity — enable SystemAssigned or UserAssigned identity",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== WEB_APP_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const identity = resource.identity;
24
+ if (!identity || !identity.type) {
25
+ diagnostics.push({
26
+ checkId: "AZR020",
27
+ severity: "warning",
28
+ message: `App Service "${resourceName}" does not have managed identity configured — set identity.type to "SystemAssigned" or "UserAssigned"`,
29
+ entity: resourceName,
30
+ lexicon: "azure",
31
+ });
32
+ }
33
+ }
34
+ }
35
+ return diagnostics;
36
+ },
37
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * AZR021: App Service missing HTTPS-only
3
+ *
4
+ * Warns when a Web App does not enforce HTTPS-only traffic.
5
+ * HTTP traffic can be intercepted and exposes sensitive data.
6
+ */
7
+ import { parseArmTemplate } from "./arm-refs.js";
8
+ const WEB_APP_TYPE = "Microsoft.Web/sites";
9
+ export const azr021 = {
10
+ id: "AZR021",
11
+ description: "App Service missing HTTPS-only — set httpsOnly to true to enforce encrypted traffic",
12
+ check(ctx) {
13
+ const diagnostics = [];
14
+ for (const [_lexicon, output] of ctx.outputs) {
15
+ const template = parseArmTemplate(output);
16
+ if (!template?.resources)
17
+ continue;
18
+ for (const resource of template.resources) {
19
+ if (resource.type !== WEB_APP_TYPE)
20
+ continue;
21
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
22
+ const props = resource.properties ?? {};
23
+ if (props.httpsOnly !== true) {
24
+ diagnostics.push({
25
+ checkId: "AZR021",
26
+ severity: "warning",
27
+ message: `App Service "${resourceName}" does not enforce HTTPS-only — set httpsOnly to true`,
28
+ entity: resourceName,
29
+ lexicon: "azure",
30
+ });
31
+ }
32
+ }
33
+ }
34
+ return diagnostics;
35
+ },
36
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * AZR022: App Service missing minimum TLS 1.2
3
+ *
4
+ * Warns when a Web App does not enforce a minimum TLS version of 1.2.
5
+ * Older TLS versions (1.0, 1.1) have known vulnerabilities and should
6
+ * not be used.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const WEB_APP_TYPE = "Microsoft.Web/sites";
10
+ export const azr022 = {
11
+ id: "AZR022",
12
+ description: "App Service missing minimum TLS 1.2 — set minTlsVersion in siteConfig to enforce TLS 1.2+",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== WEB_APP_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ const siteConfig = props.siteConfig;
25
+ const minTlsVersion = siteConfig?.minTlsVersion;
26
+ if (minTlsVersion !== "1.2" && minTlsVersion !== "1.3") {
27
+ diagnostics.push({
28
+ checkId: "AZR022",
29
+ severity: "warning",
30
+ message: `App Service "${resourceName}" does not enforce minimum TLS 1.2 — set siteConfig.minTlsVersion to "1.2"`,
31
+ entity: resourceName,
32
+ lexicon: "azure",
33
+ });
34
+ }
35
+ }
36
+ }
37
+ return diagnostics;
38
+ },
39
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * AZR023: VM missing managed disk
3
+ *
4
+ * Warns when a Virtual Machine's OS disk does not use managed disks.
5
+ * Managed disks provide better reliability, scalability, and
6
+ * simplified management compared to unmanaged (VHD-based) disks.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const VM_TYPE = "Microsoft.Compute/virtualMachines";
10
+ export const azr023 = {
11
+ id: "AZR023",
12
+ description: "VM missing managed disk — use managed disks for better reliability and management",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== VM_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ const storageProfile = props.storageProfile;
25
+ const osDisk = storageProfile?.osDisk;
26
+ if (!osDisk?.managedDisk) {
27
+ diagnostics.push({
28
+ checkId: "AZR023",
29
+ severity: "warning",
30
+ message: `VM "${resourceName}" OS disk does not use managed disks — add managedDisk configuration to storageProfile.osDisk`,
31
+ entity: resourceName,
32
+ lexicon: "azure",
33
+ });
34
+ }
35
+ }
36
+ }
37
+ return diagnostics;
38
+ },
39
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * AZR024: VM missing boot diagnostics
3
+ *
4
+ * Warns when a Virtual Machine does not have boot diagnostics enabled.
5
+ * Boot diagnostics helps troubleshoot VM startup failures by capturing
6
+ * serial console output and screenshots.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const VM_TYPE = "Microsoft.Compute/virtualMachines";
10
+ export const azr024 = {
11
+ id: "AZR024",
12
+ description: "VM missing boot diagnostics — enable for troubleshooting startup failures",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== VM_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ const diagnosticsProfile = props.diagnosticsProfile;
25
+ const bootDiagnostics = diagnosticsProfile?.bootDiagnostics;
26
+ if (!bootDiagnostics || bootDiagnostics.enabled !== true) {
27
+ diagnostics.push({
28
+ checkId: "AZR024",
29
+ severity: "warning",
30
+ message: `VM "${resourceName}" does not have boot diagnostics enabled — set diagnosticsProfile.bootDiagnostics.enabled to true`,
31
+ entity: resourceName,
32
+ lexicon: "azure",
33
+ });
34
+ }
35
+ }
36
+ }
37
+ return diagnostics;
38
+ },
39
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * AZR025: AKS missing RBAC
3
+ *
4
+ * Warns when an AKS cluster does not have RBAC enabled.
5
+ * RBAC provides fine-grained access control for Kubernetes
6
+ * resources within the cluster.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const AKS_TYPE = "Microsoft.ContainerService/managedClusters";
10
+ export const azr025 = {
11
+ id: "AZR025",
12
+ description: "AKS cluster missing RBAC — enable Kubernetes RBAC for access control",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== AKS_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ if (props.enableRBAC !== true) {
25
+ diagnostics.push({
26
+ checkId: "AZR025",
27
+ severity: "warning",
28
+ message: `AKS cluster "${resourceName}" does not have RBAC enabled — set enableRBAC to true`,
29
+ entity: resourceName,
30
+ lexicon: "azure",
31
+ });
32
+ }
33
+ }
34
+ }
35
+ return diagnostics;
36
+ },
37
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * AZR026: AKS missing network policy
3
+ *
4
+ * Warns when an AKS cluster does not have a network policy configured.
5
+ * Network policies control pod-to-pod traffic and are essential for
6
+ * microsegmentation and defense in depth.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const AKS_TYPE = "Microsoft.ContainerService/managedClusters";
10
+ export const azr026 = {
11
+ id: "AZR026",
12
+ description: "AKS cluster missing network policy — configure networkPolicy for pod-to-pod traffic control",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== AKS_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ const networkProfile = props.networkProfile;
25
+ if (!networkProfile?.networkPolicy) {
26
+ diagnostics.push({
27
+ checkId: "AZR026",
28
+ severity: "warning",
29
+ message: `AKS cluster "${resourceName}" does not have a network policy configured — set networkProfile.networkPolicy to "azure" or "calico"`,
30
+ entity: resourceName,
31
+ lexicon: "azure",
32
+ });
33
+ }
34
+ }
35
+ }
36
+ return diagnostics;
37
+ },
38
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * AZR027: Container Registry admin user enabled
3
+ *
4
+ * Warns when a Container Registry has the admin user enabled.
5
+ * Admin user provides shared credentials which cannot be individually
6
+ * revoked. Use Azure AD authentication or service principals instead.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const ACR_TYPE = "Microsoft.ContainerRegistry/registries";
10
+ export const azr027 = {
11
+ id: "AZR027",
12
+ description: "Container Registry admin user enabled — disable admin and use Azure AD or service principals",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== ACR_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ if (props.adminUserEnabled === true) {
25
+ diagnostics.push({
26
+ checkId: "AZR027",
27
+ severity: "warning",
28
+ message: `Container Registry "${resourceName}" has admin user enabled — disable adminUserEnabled and use Azure AD authentication`,
29
+ entity: resourceName,
30
+ lexicon: "azure",
31
+ });
32
+ }
33
+ }
34
+ }
35
+ return diagnostics;
36
+ },
37
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * AZR028: Network interface missing NSG
3
+ *
4
+ * Warns when a Network Interface does not have a Network Security Group
5
+ * associated. NSGs provide essential firewall rules to control inbound
6
+ * and outbound traffic.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const NIC_TYPE = "Microsoft.Network/networkInterfaces";
10
+ export const azr028 = {
11
+ id: "AZR028",
12
+ description: "Network interface missing NSG — associate an NSG to control network traffic",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== NIC_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ if (!props.networkSecurityGroup) {
25
+ diagnostics.push({
26
+ checkId: "AZR028",
27
+ severity: "warning",
28
+ message: `Network interface "${resourceName}" does not have an NSG associated — set networkSecurityGroup.id`,
29
+ entity: resourceName,
30
+ lexicon: "azure",
31
+ });
32
+ }
33
+ }
34
+ }
35
+ return diagnostics;
36
+ },
37
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * AZR029: Managed disk missing encryption
3
+ *
4
+ * Warns when a managed disk resource does not have encryption
5
+ * configured. Encryption at rest protects data on managed disks
6
+ * against unauthorized access.
7
+ */
8
+ import { parseArmTemplate } from "./arm-refs.js";
9
+ const DISK_TYPE = "Microsoft.Compute/disks";
10
+ export const azr029 = {
11
+ id: "AZR029",
12
+ description: "Managed disk missing encryption — enable encryption to protect data at rest",
13
+ check(ctx) {
14
+ const diagnostics = [];
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseArmTemplate(output);
17
+ if (!template?.resources)
18
+ continue;
19
+ for (const resource of template.resources) {
20
+ if (resource.type !== DISK_TYPE)
21
+ continue;
22
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
23
+ const props = resource.properties ?? {};
24
+ const encryption = props.encryption;
25
+ if (!encryption) {
26
+ diagnostics.push({
27
+ checkId: "AZR029",
28
+ severity: "warning",
29
+ message: `Managed disk "${resourceName}" does not have encryption configured — set encryption.type to "EncryptionAtRestWithPlatformKey" or use customer-managed keys`,
30
+ entity: resourceName,
31
+ lexicon: "azure",
32
+ });
33
+ }
34
+ }
35
+ }
36
+ return diagnostics;
37
+ },
38
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * AZR030: Resource deployed at an unsupported template scope
3
+ *
4
+ * Errors when a template contains a resource whose ARM schema does not
5
+ * define it at the template's deployment scope (#1545). The serializer
6
+ * picks the template $schema from the common scope of all resources; a
7
+ * template mixing, say, management groups (tenant-only) with virtual
8
+ * networks (resource-group-only) has no valid single-template scope —
9
+ * split the project so each scope deploys its own template (linked
10
+ * deployments cross scopes).
11
+ */
12
+ import { parseArmTemplate } from "./arm-refs.js";
13
+ import { deployScopesFor, scopeForTemplateSchema } from "../../deploy-scopes.js";
14
+ export const azr030 = {
15
+ id: "AZR030",
16
+ description: "Resource deployed at an unsupported template scope — split scopes into separate templates",
17
+ check(ctx) {
18
+ const diagnostics = [];
19
+ for (const [_lexicon, output] of ctx.outputs) {
20
+ const template = parseArmTemplate(output);
21
+ if (!template?.resources)
22
+ continue;
23
+ const templateScope = scopeForTemplateSchema(template.$schema);
24
+ for (const resource of template.resources) {
25
+ if (typeof resource.type !== "string")
26
+ continue;
27
+ const scopes = deployScopesFor(resource.type);
28
+ if (scopes.includes(templateScope))
29
+ continue;
30
+ const resourceName = typeof resource.name === "string" ? resource.name : String(resource.name);
31
+ diagnostics.push({
32
+ checkId: "AZR030",
33
+ severity: "error",
34
+ message: `Resource "${resourceName}" (${resource.type}) deploys at ` +
35
+ `${scopes.join("/")} scope, but this template targets ${templateScope} scope — ` +
36
+ `move it to a project deployed at a scope its schema supports`,
37
+ entity: resourceName,
38
+ lexicon: "azure",
39
+ });
40
+ }
41
+ }
42
+ return diagnostics;
43
+ },
44
+ };