@intentius/chant-lexicon-azure 0.124.30 → 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.
- package/dist/actions/appservice.js +7 -0
- package/dist/actions/compute.js +9 -0
- package/dist/actions/container.js +14 -0
- package/dist/actions/identity.js +11 -0
- package/dist/actions/index.js +11 -0
- package/dist/actions/keyvault.js +12 -0
- package/dist/actions/network.js +9 -0
- package/dist/actions/sql.js +9 -0
- package/dist/actions/storage.js +15 -0
- package/dist/api/read-client.js +146 -0
- package/dist/codegen/docs-cli.js +2 -0
- package/dist/codegen/docs.js +83 -0
- package/dist/codegen/generate-cli.js +11 -0
- package/dist/codegen/generate-lexicon.js +77 -0
- package/dist/codegen/generate-typescript.js +163 -0
- package/dist/codegen/generate.js +106 -0
- package/dist/codegen/naming.js +139 -0
- package/dist/codegen/package.js +64 -0
- package/dist/composites/aks-cluster.js +68 -0
- package/dist/composites/app-service.js +62 -0
- package/dist/composites/application-gateway.js +107 -0
- package/dist/composites/catalog.js +856 -0
- package/dist/composites/container-instance.js +36 -0
- package/dist/composites/container-registry.js +62 -0
- package/dist/composites/cosmos-database.js +56 -0
- package/dist/composites/from-arm.js +47 -0
- package/dist/composites/function-app.js +57 -0
- package/dist/composites/index.js +16 -0
- package/dist/composites/keyvault.js +69 -0
- package/dist/composites/landing-zone.js +119 -0
- package/dist/composites/private-endpoint.js +61 -0
- package/dist/composites/redis-cache.js +21 -0
- package/dist/composites/service-bus-pipeline.js +54 -0
- package/dist/composites/sql-database.js +62 -0
- package/dist/composites/storage-account.js +59 -0
- package/dist/composites/vm-linux.js +139 -0
- package/dist/composites/vnet-default.js +102 -0
- package/dist/coverage.js +28 -0
- package/dist/deep-observe.js +356 -0
- package/dist/default-tags.js +50 -0
- package/dist/deploy-scopes.d.ts.map +1 -1
- package/dist/deploy-scopes.js +157 -0
- package/dist/describe-resources.js +187 -0
- package/dist/detect.js +17 -0
- package/dist/export-resources.js +108 -0
- package/dist/generated/index.js +16598 -0
- package/dist/generated/runtime.js +4 -0
- package/dist/governance.js +144 -0
- package/dist/import/generator.js +140 -0
- package/dist/import/live-export.js +39 -0
- package/dist/import/parser.js +192 -0
- package/dist/index.js +44 -0
- package/dist/integrity.json +2 -2
- package/dist/intrinsics.js +179 -0
- package/dist/lint/audit-catalog.js +36 -0
- package/dist/lint/audit-lineage.js +71 -0
- package/dist/lint/post-synth/arm-refs.js +94 -0
- package/dist/lint/post-synth/azr010.js +45 -0
- package/dist/lint/post-synth/azr011.js +43 -0
- package/dist/lint/post-synth/azr012.js +41 -0
- package/dist/lint/post-synth/azr013.js +50 -0
- package/dist/lint/post-synth/azr014.js +49 -0
- package/dist/lint/post-synth/azr015.js +66 -0
- package/dist/lint/post-synth/azr016.js +37 -0
- package/dist/lint/post-synth/azr017.js +37 -0
- package/dist/lint/post-synth/azr018.js +42 -0
- package/dist/lint/post-synth/azr019.js +41 -0
- package/dist/lint/post-synth/azr020.js +37 -0
- package/dist/lint/post-synth/azr021.js +36 -0
- package/dist/lint/post-synth/azr022.js +39 -0
- package/dist/lint/post-synth/azr023.js +39 -0
- package/dist/lint/post-synth/azr024.js +39 -0
- package/dist/lint/post-synth/azr025.js +37 -0
- package/dist/lint/post-synth/azr026.js +38 -0
- package/dist/lint/post-synth/azr027.js +37 -0
- package/dist/lint/post-synth/azr028.js +37 -0
- package/dist/lint/post-synth/azr029.js +38 -0
- package/dist/lint/post-synth/azr030.js +44 -0
- package/dist/lint/post-synth/azr031.js +36 -0
- package/dist/lint/post-synth/azr032.js +53 -0
- package/dist/lint/post-synth/azr033.js +35 -0
- package/dist/lint/post-synth/index.js +50 -0
- package/dist/lint/rules/hardcoded-location.js +82 -0
- package/dist/lint/rules/index.js +6 -0
- package/dist/lint/rules/nsg-wildcard.js +44 -0
- package/dist/lint/rules/storage-https.js +62 -0
- package/dist/lsp/completions.d.ts.map +1 -1
- package/dist/lsp/completions.js +18 -0
- package/dist/lsp/hover.d.ts.map +1 -1
- package/dist/lsp/hover.js +44 -0
- package/dist/manifest.json +1 -1
- package/dist/op/activities/az-apply.js +563 -0
- package/dist/op/activities/azure.js +48 -0
- package/dist/op/activities/floci-az.js +37 -0
- package/dist/op/activities/index.js +10 -0
- package/dist/op/builders.js +70 -0
- package/dist/ownership.js +13 -0
- package/dist/package-cli.js +21 -0
- package/dist/parameter.js +13 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +472 -0
- package/dist/pseudo.js +40 -0
- package/dist/serializer.js +457 -0
- package/dist/spec/api-versions.js +130 -0
- package/dist/spec/fetch.js +196 -0
- package/dist/spec/parse.js +308 -0
- package/dist/taggable.js +34 -0
- package/dist/validate-cli.js +16 -0
- package/dist/validate.js +53 -0
- package/package.json +8 -8
- package/src/codegen/package.ts +2 -2
- package/src/deploy-scopes.ts +2 -1
- package/src/lsp/completions.ts +2 -1
- package/src/lsp/hover.ts +2 -1
- package/src/plugin.ts +3 -2
- package/src/serializer.ts +2 -2
- package/src/taggable.ts +2 -2
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContainerInstance composite — Container Group.
|
|
3
|
+
*
|
|
4
|
+
* Creates a Container Group with managed identity and no public IP by default.
|
|
5
|
+
*/
|
|
6
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
7
|
+
import { containerGroups } from "../generated/index.js";
|
|
8
|
+
export const ContainerInstance = Composite((props) => {
|
|
9
|
+
const { name, location = "[resourceGroup().location]", image = "mcr.microsoft.com/hello-world", cpu = 1, memoryInGb = 1.5, port = 80, publicIp = false, tags = {}, defaults, } = props;
|
|
10
|
+
const mergedTags = { "managed-by": "chant", ...tags };
|
|
11
|
+
const containerGroup = new containerGroups(mergeDefaults({
|
|
12
|
+
name,
|
|
13
|
+
location,
|
|
14
|
+
tags: mergedTags,
|
|
15
|
+
identity: { type: "SystemAssigned" },
|
|
16
|
+
osType: "Linux",
|
|
17
|
+
restartPolicy: "OnFailure",
|
|
18
|
+
ipAddress: {
|
|
19
|
+
type: publicIp ? "Public" : "Private",
|
|
20
|
+
ports: [{ protocol: "TCP", port }],
|
|
21
|
+
},
|
|
22
|
+
containers: [
|
|
23
|
+
{
|
|
24
|
+
name: `${name}-container`,
|
|
25
|
+
properties: {
|
|
26
|
+
image,
|
|
27
|
+
ports: [{ port }],
|
|
28
|
+
resources: {
|
|
29
|
+
requests: { cpu, memoryInGB: memoryInGb },
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
}, defaults?.containerGroup), { apiVersion: "2023-05-01" });
|
|
35
|
+
return { containerGroup };
|
|
36
|
+
}, "ContainerInstance");
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContainerRegistrySecure composite — Azure Container Registry with security hardening.
|
|
3
|
+
*
|
|
4
|
+
* A higher-level construct for deploying an ACR with
|
|
5
|
+
* admin user disabled, content trust, and quarantine policy.
|
|
6
|
+
*/
|
|
7
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
8
|
+
import { ContainerRegistry } from "../generated/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Create a ContainerRegistrySecure composite — returns an
|
|
11
|
+
* Azure Container Registry with security best practices.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { ContainerRegistrySecure } from "@intentius/chant-lexicon-azure";
|
|
16
|
+
*
|
|
17
|
+
* const { registry } = ContainerRegistrySecure({
|
|
18
|
+
* name: "myacr01",
|
|
19
|
+
* sku: "Premium",
|
|
20
|
+
* tags: { environment: "production" },
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* export { registry };
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export const ContainerRegistrySecure = Composite((props) => {
|
|
27
|
+
const { name, sku = "Premium", location = "[resourceGroup().location]", tags = {}, defaults, } = props;
|
|
28
|
+
const commonTags = {
|
|
29
|
+
"managed-by": "chant",
|
|
30
|
+
...tags,
|
|
31
|
+
};
|
|
32
|
+
const registry = new ContainerRegistry(mergeDefaults({
|
|
33
|
+
name,
|
|
34
|
+
location,
|
|
35
|
+
tags: commonTags,
|
|
36
|
+
sku: {
|
|
37
|
+
name: sku,
|
|
38
|
+
},
|
|
39
|
+
adminUserEnabled: false,
|
|
40
|
+
publicNetworkAccess: "Enabled",
|
|
41
|
+
networkRuleBypassOptions: "AzureServices",
|
|
42
|
+
zoneRedundancy: "Disabled",
|
|
43
|
+
policies: {
|
|
44
|
+
quarantinePolicy: {
|
|
45
|
+
status: "enabled",
|
|
46
|
+
},
|
|
47
|
+
trustPolicy: {
|
|
48
|
+
type: "Notary",
|
|
49
|
+
status: "enabled",
|
|
50
|
+
},
|
|
51
|
+
retentionPolicy: {
|
|
52
|
+
days: 30,
|
|
53
|
+
status: "enabled",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
encryption: {
|
|
57
|
+
status: "disabled",
|
|
58
|
+
},
|
|
59
|
+
dataEndpointEnabled: false,
|
|
60
|
+
}, defaults?.registry), { apiVersion: "2023-07-01" });
|
|
61
|
+
return { registry };
|
|
62
|
+
}, "ContainerRegistrySecure");
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CosmosDatabase composite — Cosmos DB Account + SQL Database + Container.
|
|
3
|
+
*
|
|
4
|
+
* Creates a Cosmos DB Account with automatic failover, network ACL deny,
|
|
5
|
+
* and TLS 1.2, plus a SQL Database and Container.
|
|
6
|
+
*/
|
|
7
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
8
|
+
import { CosmosDb, databaseAccounts_sqlDatabases, databaseAccounts_sqlDatabases_containers, } from "../generated/index.js";
|
|
9
|
+
export const CosmosDatabase = Composite((props) => {
|
|
10
|
+
const { name, location = "[resourceGroup().location]", partitionKeyPath = "/id", tags = {}, defaults, } = props;
|
|
11
|
+
const databaseName = props.databaseName ?? `${name}-db`;
|
|
12
|
+
const containerName = props.containerName ?? `${name}-container`;
|
|
13
|
+
const mergedTags = { "managed-by": "chant", ...tags };
|
|
14
|
+
const account = new CosmosDb(mergeDefaults({
|
|
15
|
+
name,
|
|
16
|
+
location,
|
|
17
|
+
tags: mergedTags,
|
|
18
|
+
kind: "GlobalDocumentDB",
|
|
19
|
+
databaseAccountOfferType: "Standard",
|
|
20
|
+
enableAutomaticFailover: true,
|
|
21
|
+
minimalTlsVersion: "Tls12",
|
|
22
|
+
publicNetworkAccess: "Disabled",
|
|
23
|
+
networkAclBypass: "None",
|
|
24
|
+
consistencyPolicy: {
|
|
25
|
+
defaultConsistencyLevel: "Session",
|
|
26
|
+
},
|
|
27
|
+
locations: [
|
|
28
|
+
{ locationName: location, failoverPriority: 0, isZoneRedundant: false },
|
|
29
|
+
],
|
|
30
|
+
}, defaults?.account), { apiVersion: "2023-11-15" });
|
|
31
|
+
const database = new databaseAccounts_sqlDatabases(mergeDefaults({
|
|
32
|
+
name: `${name}/${databaseName}`,
|
|
33
|
+
resource: { id: databaseName },
|
|
34
|
+
}, defaults?.database), {
|
|
35
|
+
apiVersion: "2023-11-15",
|
|
36
|
+
DependsOn: [
|
|
37
|
+
`[resourceId('Microsoft.DocumentDB/databaseAccounts', '${name}')]`,
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
const container = new databaseAccounts_sqlDatabases_containers(mergeDefaults({
|
|
41
|
+
name: `${name}/${databaseName}/${containerName}`,
|
|
42
|
+
resource: {
|
|
43
|
+
id: containerName,
|
|
44
|
+
partitionKey: {
|
|
45
|
+
paths: [partitionKeyPath],
|
|
46
|
+
kind: "Hash",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
}, defaults?.container), {
|
|
50
|
+
apiVersion: "2023-11-15",
|
|
51
|
+
DependsOn: [
|
|
52
|
+
`[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', '${name}', '${databaseName}')]`,
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
return { account, database, container };
|
|
56
|
+
}, "CosmosDatabase");
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stamps non-enumerable Declarable properties onto plain ARM resource objects
|
|
3
|
+
* so that collectEntities() / isDeclarable() recognizes them.
|
|
4
|
+
*
|
|
5
|
+
* All original enumerable properties stay intact — existing tests that
|
|
6
|
+
* access `.type`, `.properties`, `.tags`, etc. are unaffected.
|
|
7
|
+
*/
|
|
8
|
+
import { DECLARABLE_MARKER } from "@intentius/chant/declarable";
|
|
9
|
+
/** ARM meta-fields that are NOT part of the flattened props. */
|
|
10
|
+
const ARM_META_FIELDS = new Set(["type", "apiVersion", "dependsOn"]);
|
|
11
|
+
/**
|
|
12
|
+
* Mark a plain ARM resource object as Declarable so the build pipeline
|
|
13
|
+
* discovers and serializes it.
|
|
14
|
+
*
|
|
15
|
+
* Adds non-enumerable: DECLARABLE_MARKER, entityType, lexicon, props, attributes.
|
|
16
|
+
* The `props` object is a flattened merge of top-level fields + `properties.*`.
|
|
17
|
+
*/
|
|
18
|
+
export function markAsAzureResource(obj) {
|
|
19
|
+
const type = obj.type;
|
|
20
|
+
const dependsOn = obj.dependsOn;
|
|
21
|
+
// Flatten: top-level non-meta fields + properties.*
|
|
22
|
+
const props = {};
|
|
23
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
24
|
+
if (ARM_META_FIELDS.has(key) || key === "properties")
|
|
25
|
+
continue;
|
|
26
|
+
props[key] = value;
|
|
27
|
+
}
|
|
28
|
+
if (typeof obj.properties === "object" && obj.properties !== null) {
|
|
29
|
+
for (const [key, value] of Object.entries(obj.properties)) {
|
|
30
|
+
props[key] = value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const apiVersion = obj.apiVersion;
|
|
34
|
+
const attributes = {};
|
|
35
|
+
if (dependsOn) {
|
|
36
|
+
attributes.DependsOn = dependsOn;
|
|
37
|
+
}
|
|
38
|
+
if (apiVersion) {
|
|
39
|
+
attributes.apiVersion = apiVersion;
|
|
40
|
+
}
|
|
41
|
+
Object.defineProperty(obj, DECLARABLE_MARKER, { value: true, enumerable: false });
|
|
42
|
+
Object.defineProperty(obj, "entityType", { value: type, enumerable: false });
|
|
43
|
+
Object.defineProperty(obj, "lexicon", { value: "azure", enumerable: false });
|
|
44
|
+
Object.defineProperty(obj, "props", { value: props, enumerable: false, configurable: true });
|
|
45
|
+
Object.defineProperty(obj, "attributes", { value: attributes, enumerable: false, configurable: true });
|
|
46
|
+
return obj;
|
|
47
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FunctionApp composite — Consumption Function App with security defaults.
|
|
3
|
+
*
|
|
4
|
+
* Creates an App Service Plan (Y1 Consumption), Function App, and
|
|
5
|
+
* Storage Account with SystemAssigned identity, HTTPS-only, TLS 1.2,
|
|
6
|
+
* and FTPS disabled.
|
|
7
|
+
*/
|
|
8
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
9
|
+
import { AppServicePlan, AppService as AppServiceResource, StorageAccount, } from "../generated/index.js";
|
|
10
|
+
export const FunctionApp = Composite((props) => {
|
|
11
|
+
const { name, location = "[resourceGroup().location]", runtime = "node", runtimeVersion = "~4", tags = {}, defaults, } = props;
|
|
12
|
+
const mergedTags = { "managed-by": "chant", ...tags };
|
|
13
|
+
const storageName = `${name.replace(/[^a-z0-9]/g, "")}st`;
|
|
14
|
+
const storageAccount = new StorageAccount(mergeDefaults({
|
|
15
|
+
name: storageName,
|
|
16
|
+
location,
|
|
17
|
+
tags: mergedTags,
|
|
18
|
+
sku: { name: "Standard_LRS" },
|
|
19
|
+
kind: "StorageV2",
|
|
20
|
+
supportsHttpsTrafficOnly: true,
|
|
21
|
+
minimumTlsVersion: "TLS1_2",
|
|
22
|
+
allowBlobPublicAccess: false,
|
|
23
|
+
}, defaults?.storageAccount), { apiVersion: "2023-01-01" });
|
|
24
|
+
const plan = new AppServicePlan(mergeDefaults({
|
|
25
|
+
name: `${name}-plan`,
|
|
26
|
+
location,
|
|
27
|
+
tags: mergedTags,
|
|
28
|
+
sku: { name: "Y1", tier: "Dynamic" },
|
|
29
|
+
kind: "functionapp",
|
|
30
|
+
reserved: true,
|
|
31
|
+
}, defaults?.plan), { apiVersion: "2023-01-01" });
|
|
32
|
+
const functionApp = new AppServiceResource(mergeDefaults({
|
|
33
|
+
name,
|
|
34
|
+
location,
|
|
35
|
+
tags: mergedTags,
|
|
36
|
+
kind: "functionapp",
|
|
37
|
+
identity: { type: "SystemAssigned" },
|
|
38
|
+
serverFarmId: `[resourceId('Microsoft.Web/serverfarms', '${name}-plan')]`,
|
|
39
|
+
httpsOnly: true,
|
|
40
|
+
siteConfig: {
|
|
41
|
+
minTlsVersion: "1.2",
|
|
42
|
+
ftpsState: "Disabled",
|
|
43
|
+
appSettings: [
|
|
44
|
+
{ name: "AzureWebJobsStorage", value: `[concat('DefaultEndpointsProtocol=https;AccountName=', '${storageName}', ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', '${storageName}'), '2023-01-01').keys[0].value)]` },
|
|
45
|
+
{ name: "FUNCTIONS_EXTENSION_VERSION", value: runtimeVersion },
|
|
46
|
+
{ name: "FUNCTIONS_WORKER_RUNTIME", value: runtime },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
}, defaults?.functionApp), {
|
|
50
|
+
apiVersion: "2023-01-01",
|
|
51
|
+
DependsOn: [
|
|
52
|
+
`[resourceId('Microsoft.Web/serverfarms', '${name}-plan')]`,
|
|
53
|
+
`[resourceId('Microsoft.Storage/storageAccounts', '${storageName}')]`,
|
|
54
|
+
],
|
|
55
|
+
});
|
|
56
|
+
return { plan, functionApp, storageAccount };
|
|
57
|
+
}, "FunctionApp");
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { StorageAccountSecure } from "./storage-account.js";
|
|
2
|
+
export { VnetDefault } from "./vnet-default.js";
|
|
3
|
+
export { VmLinux } from "./vm-linux.js";
|
|
4
|
+
export { AppService } from "./app-service.js";
|
|
5
|
+
export { AksCluster } from "./aks-cluster.js";
|
|
6
|
+
export { SqlDatabase } from "./sql-database.js";
|
|
7
|
+
export { KeyVaultSecure } from "./keyvault.js";
|
|
8
|
+
export { ContainerRegistrySecure } from "./container-registry.js";
|
|
9
|
+
export { FunctionApp } from "./function-app.js";
|
|
10
|
+
export { ServiceBusPipeline } from "./service-bus-pipeline.js";
|
|
11
|
+
export { CosmosDatabase } from "./cosmos-database.js";
|
|
12
|
+
export { ApplicationGateway } from "./application-gateway.js";
|
|
13
|
+
export { ContainerInstance } from "./container-instance.js";
|
|
14
|
+
export { RedisCache } from "./redis-cache.js";
|
|
15
|
+
export { PrivateEndpoint } from "./private-endpoint.js";
|
|
16
|
+
export { GovernanceFoundation, GovernanceBaseline, LocationRestriction, ActivityLogSink } from "./landing-zone.js";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KeyVaultSecure composite — Key Vault with security hardening.
|
|
3
|
+
*
|
|
4
|
+
* A higher-level construct for deploying an Azure Key Vault with
|
|
5
|
+
* soft delete, purge protection, and RBAC-ready access policies.
|
|
6
|
+
*/
|
|
7
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
8
|
+
import { KeyVault } from "../generated/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Create a KeyVaultSecure composite — returns a Key Vault
|
|
11
|
+
* with security best practices.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { KeyVaultSecure } from "@intentius/chant-lexicon-azure";
|
|
16
|
+
*
|
|
17
|
+
* const { vault } = KeyVaultSecure({
|
|
18
|
+
* name: "my-keyvault",
|
|
19
|
+
* tenantId: "00000000-0000-0000-0000-000000000000",
|
|
20
|
+
* accessPolicies: [
|
|
21
|
+
* {
|
|
22
|
+
* tenantId: "00000000-0000-0000-0000-000000000000",
|
|
23
|
+
* objectId: "11111111-1111-1111-1111-111111111111",
|
|
24
|
+
* permissions: { secrets: ["get", "list", "set"] },
|
|
25
|
+
* },
|
|
26
|
+
* ],
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* export { vault };
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const KeyVaultSecure = Composite((props) => {
|
|
33
|
+
const { name, tenantId, accessPolicies = [], location = "[resourceGroup().location]", tags = {}, defaults, } = props;
|
|
34
|
+
const commonTags = {
|
|
35
|
+
"managed-by": "chant",
|
|
36
|
+
...tags,
|
|
37
|
+
};
|
|
38
|
+
const vault = new KeyVault(mergeDefaults({
|
|
39
|
+
name,
|
|
40
|
+
location,
|
|
41
|
+
tags: commonTags,
|
|
42
|
+
tenantId,
|
|
43
|
+
sku: {
|
|
44
|
+
family: "A",
|
|
45
|
+
name: "standard",
|
|
46
|
+
},
|
|
47
|
+
accessPolicies: accessPolicies.map((policy) => ({
|
|
48
|
+
tenantId: policy.tenantId,
|
|
49
|
+
objectId: policy.objectId,
|
|
50
|
+
permissions: {
|
|
51
|
+
...(policy.permissions.keys && { keys: policy.permissions.keys }),
|
|
52
|
+
...(policy.permissions.secrets && { secrets: policy.permissions.secrets }),
|
|
53
|
+
...(policy.permissions.certificates && { certificates: policy.permissions.certificates }),
|
|
54
|
+
},
|
|
55
|
+
})),
|
|
56
|
+
enabledForDeployment: false,
|
|
57
|
+
enabledForDiskEncryption: false,
|
|
58
|
+
enabledForTemplateDeployment: false,
|
|
59
|
+
enableSoftDelete: true,
|
|
60
|
+
softDeleteRetentionInDays: 90,
|
|
61
|
+
enablePurgeProtection: true,
|
|
62
|
+
enableRbacAuthorization: false,
|
|
63
|
+
networkAcls: {
|
|
64
|
+
bypass: "AzureServices",
|
|
65
|
+
defaultAction: "Allow",
|
|
66
|
+
},
|
|
67
|
+
}, defaults?.vault), { apiVersion: "2023-02-01" });
|
|
68
|
+
return { vault };
|
|
69
|
+
}, "KeyVaultSecure");
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Landing-zone bootstrap composites — the Azure slice.
|
|
3
|
+
*
|
|
4
|
+
* Fixed-shape resources for greenfield creation of the recommended
|
|
5
|
+
* governance foundation. The evaluability rules (EVL002/004) require
|
|
6
|
+
* composites to declare a fixed set of resources, so these carry the
|
|
7
|
+
* foundation only; arbitrary management-group/subscription trees are
|
|
8
|
+
* authored as config with `landingZoneConfig()` (../governance.ts) and
|
|
9
|
+
* reconciled by an external governance reconciler, and further groups/subscriptions
|
|
10
|
+
* are declared as ordinary resources.
|
|
11
|
+
*
|
|
12
|
+
* A single ARM template cannot mix deployment scopes (AZR030, #1545), so
|
|
13
|
+
* unlike the AWS/GCP slices the foundation splits per scope — each
|
|
14
|
+
* composite emits at exactly one scope and belongs in its own project:
|
|
15
|
+
*
|
|
16
|
+
* // tenant-scope project (management groups + subscription tenant policy)
|
|
17
|
+
* const lz = GovernanceFoundation({});
|
|
18
|
+
* // management-group-scope project, deployed to the tenant root group —
|
|
19
|
+
* // policy resources also deploy at subscription scope, so the project
|
|
20
|
+
* // pins the scope explicitly
|
|
21
|
+
* export const scope = deploymentScope("managementGroup");
|
|
22
|
+
* const gb = GovernanceBaseline({});
|
|
23
|
+
* const lr = LocationRestriction({ locations: ["westeurope"] });
|
|
24
|
+
* const al = ActivityLogSink({ workspaceId: "/subscriptions/.../workspaces/audit", location: "westeurope" });
|
|
25
|
+
*
|
|
26
|
+
* There is no OrganizationRoot analog — the tenant and its root management
|
|
27
|
+
* group come from Entra ID, not the resource API, so greenfield and
|
|
28
|
+
* brownfield both start from the existing tenant.
|
|
29
|
+
*/
|
|
30
|
+
import { Composite } from "@intentius/chant";
|
|
31
|
+
import { ManagementGroup, PolicyAssignment, PolicyDefinition, policies as SubscriptionTenantPolicy, } from "../generated/index.js";
|
|
32
|
+
import { ACTIVITY_LOG_TO_LOG_ANALYTICS_DEFINITION_ID, DENY_CLASSIC_RESOURCES, DENY_UNMANAGED_DISKS, locationRestriction, } from "../governance.js";
|
|
33
|
+
function policyDefinition(name, policy) {
|
|
34
|
+
return new PolicyDefinition({
|
|
35
|
+
name,
|
|
36
|
+
displayName: policy.displayName,
|
|
37
|
+
description: policy.description,
|
|
38
|
+
mode: policy.mode ?? "All",
|
|
39
|
+
policyType: "Custom",
|
|
40
|
+
...(policy.parameters && { parameters: policy.parameters }),
|
|
41
|
+
policyRule: policy.policyRule,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The explicit DependsOn (by ARM name) orders the assignment after its
|
|
46
|
+
* definition — the serializer's inference only reads plain resourceId()
|
|
47
|
+
* expressions, not managementGroupResourceId(). Management-group assignment
|
|
48
|
+
* names are capped at 24 characters.
|
|
49
|
+
*/
|
|
50
|
+
function policyAssignment(name, definitionName, policy) {
|
|
51
|
+
return new PolicyAssignment({
|
|
52
|
+
name,
|
|
53
|
+
displayName: policy.displayName,
|
|
54
|
+
policyDefinitionId: `[managementGroupResourceId('Microsoft.Authorization/policyDefinitions', '${definitionName}')]`,
|
|
55
|
+
}, { DependsOn: definitionName });
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Security / Infrastructure / Sandbox / Workloads management groups with
|
|
59
|
+
* subscriptions blocked from leaving the tenant — the same baseline
|
|
60
|
+
* `landingZoneConfig()` declares. Deploys at tenant scope.
|
|
61
|
+
*/
|
|
62
|
+
export const GovernanceFoundation = Composite((props) => {
|
|
63
|
+
const group = (name) => new ManagementGroup({
|
|
64
|
+
name,
|
|
65
|
+
displayName: name,
|
|
66
|
+
...(props.parentId && {
|
|
67
|
+
details: { parent: { id: `/providers/Microsoft.Management/managementGroups/${props.parentId}` } },
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
const subscriptionTenantPolicy = new SubscriptionTenantPolicy({
|
|
71
|
+
name: "default",
|
|
72
|
+
blockSubscriptionsLeavingTenant: props.blockSubscriptionsLeavingTenant ?? true,
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
mgSecurity: group("Security"),
|
|
76
|
+
mgInfrastructure: group("Infrastructure"),
|
|
77
|
+
mgSandbox: group("Sandbox"),
|
|
78
|
+
mgWorkloads: group("Workloads"),
|
|
79
|
+
subscriptionTenantPolicy,
|
|
80
|
+
};
|
|
81
|
+
}, "GovernanceFoundation");
|
|
82
|
+
/**
|
|
83
|
+
* `deny-classic-resources` and `deny-unmanaged-disks` defined and assigned
|
|
84
|
+
* at the management group the project deploys to (the tenant root group for
|
|
85
|
+
* the `landingZoneConfig()` baseline). Custom policy definitions cannot
|
|
86
|
+
* deploy at tenant scope, which is why this is not part of
|
|
87
|
+
* GovernanceFoundation.
|
|
88
|
+
*/
|
|
89
|
+
export const GovernanceBaseline = Composite(() => {
|
|
90
|
+
return {
|
|
91
|
+
definitionDenyClassicResources: policyDefinition("deny-classic-resources", DENY_CLASSIC_RESOURCES),
|
|
92
|
+
definitionDenyUnmanagedDisks: policyDefinition("deny-unmanaged-disks", DENY_UNMANAGED_DISKS),
|
|
93
|
+
assignmentDenyClassicResources: policyAssignment("deny-classic", "deny-classic-resources", DENY_CLASSIC_RESOURCES),
|
|
94
|
+
assignmentDenyUnmanagedDisks: policyAssignment("deny-unmanaged", "deny-unmanaged-disks", DENY_UNMANAGED_DISKS),
|
|
95
|
+
};
|
|
96
|
+
}, "GovernanceBaseline");
|
|
97
|
+
export const LocationRestriction = Composite((props) => {
|
|
98
|
+
const policy = locationRestriction(props.locations);
|
|
99
|
+
return {
|
|
100
|
+
definitionLocationRestriction: policyDefinition("location-restriction", policy),
|
|
101
|
+
assignmentLocationRestriction: policyAssignment("allowed-locations", "location-restriction", policy),
|
|
102
|
+
};
|
|
103
|
+
}, "LocationRestriction");
|
|
104
|
+
/**
|
|
105
|
+
* Assigns the built-in DeployIfNotExists policy that streams every
|
|
106
|
+
* subscription's activity log into a Log Analytics workspace — current and
|
|
107
|
+
* future subscriptions under the management group alike.
|
|
108
|
+
*/
|
|
109
|
+
export const ActivityLogSink = Composite((props) => {
|
|
110
|
+
const assignmentActivityLogSink = new PolicyAssignment({
|
|
111
|
+
name: "activity-log-sink",
|
|
112
|
+
location: props.location,
|
|
113
|
+
identity: { type: "SystemAssigned" },
|
|
114
|
+
displayName: "Stream activity logs to Log Analytics",
|
|
115
|
+
policyDefinitionId: ACTIVITY_LOG_TO_LOG_ANALYTICS_DEFINITION_ID,
|
|
116
|
+
parameters: { logAnalytics: { value: props.workspaceId } },
|
|
117
|
+
});
|
|
118
|
+
return { assignmentActivityLogSink };
|
|
119
|
+
}, "ActivityLogSink");
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrivateEndpoint composite — Private Endpoint + Private DNS Zone + DNS Zone Group.
|
|
3
|
+
*
|
|
4
|
+
* Creates a Private Endpoint for a target resource along with a Private DNS Zone
|
|
5
|
+
* and DNS Zone Group for private connectivity.
|
|
6
|
+
*/
|
|
7
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
8
|
+
import { privateEndpoints, PrivateDnsZone, privateEndpoints_privateDnsZoneGroups, privateDnsZones_virtualNetworkLinks, } from "../generated/index.js";
|
|
9
|
+
export const PrivateEndpoint = Composite((props) => {
|
|
10
|
+
const { name, location = "[resourceGroup().location]", targetResourceId, groupId, subnetId, privateDnsZoneName, vnetId, tags = {}, defaults, } = props;
|
|
11
|
+
const mergedTags = { "managed-by": "chant", ...tags };
|
|
12
|
+
const privateEndpoint = new privateEndpoints(mergeDefaults({
|
|
13
|
+
name,
|
|
14
|
+
location,
|
|
15
|
+
tags: mergedTags,
|
|
16
|
+
subnet: { id: subnetId },
|
|
17
|
+
privateLinkServiceConnections: [
|
|
18
|
+
{
|
|
19
|
+
name: `${name}-connection`,
|
|
20
|
+
properties: {
|
|
21
|
+
privateLinkServiceId: targetResourceId,
|
|
22
|
+
groupIds: [groupId],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
}, defaults?.privateEndpoint), { apiVersion: "2023-05-01" });
|
|
27
|
+
const privateDnsZone = new PrivateDnsZone(mergeDefaults({
|
|
28
|
+
name: privateDnsZoneName,
|
|
29
|
+
location: "global",
|
|
30
|
+
tags: mergedTags,
|
|
31
|
+
}, defaults?.privateDnsZone), { apiVersion: "2020-06-01" });
|
|
32
|
+
const vnetLink = new privateDnsZones_virtualNetworkLinks(mergeDefaults({
|
|
33
|
+
name: `${privateDnsZoneName}/${name}-vnet-link`,
|
|
34
|
+
location: "global",
|
|
35
|
+
virtualNetwork: { id: vnetId },
|
|
36
|
+
registrationEnabled: false,
|
|
37
|
+
}, defaults?.vnetLink), {
|
|
38
|
+
apiVersion: "2020-06-01",
|
|
39
|
+
DependsOn: [
|
|
40
|
+
`[resourceId('Microsoft.Network/privateDnsZones', '${privateDnsZoneName}')]`,
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
const dnsZoneGroup = new privateEndpoints_privateDnsZoneGroups(mergeDefaults({
|
|
44
|
+
name: `${name}/${name}-dns-group`,
|
|
45
|
+
privateDnsZoneConfigs: [
|
|
46
|
+
{
|
|
47
|
+
name: "config1",
|
|
48
|
+
properties: {
|
|
49
|
+
privateDnsZoneId: `[resourceId('Microsoft.Network/privateDnsZones', '${privateDnsZoneName}')]`,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
}, defaults?.dnsZoneGroup), {
|
|
54
|
+
apiVersion: "2023-05-01",
|
|
55
|
+
DependsOn: [
|
|
56
|
+
`[resourceId('Microsoft.Network/privateEndpoints', '${name}')]`,
|
|
57
|
+
`[resourceId('Microsoft.Network/privateDnsZones', '${privateDnsZoneName}')]`,
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
return { privateEndpoint, privateDnsZone, dnsZoneGroup, vnetLink };
|
|
61
|
+
}, "PrivateEndpoint");
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RedisCache composite — Azure Cache for Redis.
|
|
3
|
+
*
|
|
4
|
+
* Creates a Redis Cache with non-SSL port disabled and TLS 1.2.
|
|
5
|
+
*/
|
|
6
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
7
|
+
import { RedisCache as RedisCacheResource } from "../generated/index.js";
|
|
8
|
+
export const RedisCache = Composite((props) => {
|
|
9
|
+
const { name, location = "[resourceGroup().location]", sku = "Standard", family = "C", capacity = 1, tags = {}, defaults, } = props;
|
|
10
|
+
const mergedTags = { "managed-by": "chant", ...tags };
|
|
11
|
+
const redisCache = new RedisCacheResource(mergeDefaults({
|
|
12
|
+
name,
|
|
13
|
+
location,
|
|
14
|
+
tags: mergedTags,
|
|
15
|
+
sku: { name: sku, family, capacity },
|
|
16
|
+
enableNonSslPort: false,
|
|
17
|
+
minimumTlsVersion: "1.2",
|
|
18
|
+
redisConfiguration: {},
|
|
19
|
+
}, defaults?.redisCache), { apiVersion: "2023-08-01" });
|
|
20
|
+
return { redisCache };
|
|
21
|
+
}, "RedisCache");
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServiceBusPipeline composite — ServiceBus Namespace with Queue or Topic.
|
|
3
|
+
*
|
|
4
|
+
* Creates a ServiceBus Namespace and either a Queue (default) or a
|
|
5
|
+
* Topic + Subscription. Enforces TLS 1.2 and Standard SKU.
|
|
6
|
+
*/
|
|
7
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
8
|
+
import { ServiceBusNamespace, namespaces_queues, Sbnamespaces_topics, namespaces_topics_subscriptions, } from "../generated/index.js";
|
|
9
|
+
export const ServiceBusPipeline = Composite((props) => {
|
|
10
|
+
const { name, location = "[resourceGroup().location]", useTopic = false, tags = {}, defaults, } = props;
|
|
11
|
+
const entityName = props.entityName ?? (useTopic ? `${name}-topic` : `${name}-queue`);
|
|
12
|
+
const subscriptionName = props.subscriptionName ?? `${entityName}-sub`;
|
|
13
|
+
const mergedTags = { "managed-by": "chant", ...tags };
|
|
14
|
+
const namespace = new ServiceBusNamespace(mergeDefaults({
|
|
15
|
+
name,
|
|
16
|
+
location,
|
|
17
|
+
tags: mergedTags,
|
|
18
|
+
sku: { name: "Standard", tier: "Standard" },
|
|
19
|
+
minimumTlsVersion: "1.2",
|
|
20
|
+
}, defaults?.namespace), { apiVersion: "2022-10-01-preview" });
|
|
21
|
+
if (useTopic) {
|
|
22
|
+
const topic = new Sbnamespaces_topics(mergeDefaults({
|
|
23
|
+
name: `${name}/${entityName}`,
|
|
24
|
+
maxSizeInMegabytes: 1024,
|
|
25
|
+
}, defaults?.topic), {
|
|
26
|
+
apiVersion: "2022-10-01-preview",
|
|
27
|
+
DependsOn: [
|
|
28
|
+
`[resourceId('Microsoft.ServiceBus/namespaces', '${name}')]`,
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
const subscription = new namespaces_topics_subscriptions(mergeDefaults({
|
|
32
|
+
name: `${name}/${entityName}/${subscriptionName}`,
|
|
33
|
+
maxDeliveryCount: 10,
|
|
34
|
+
}, defaults?.subscription), {
|
|
35
|
+
apiVersion: "2022-10-01-preview",
|
|
36
|
+
DependsOn: [
|
|
37
|
+
`[resourceId('Microsoft.ServiceBus/namespaces/topics', '${name}', '${entityName}')]`,
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
return { namespace, topic, subscription };
|
|
41
|
+
}
|
|
42
|
+
const queue = new namespaces_queues(mergeDefaults({
|
|
43
|
+
name: `${name}/${entityName}`,
|
|
44
|
+
maxSizeInMegabytes: 1024,
|
|
45
|
+
lockDuration: "PT1M",
|
|
46
|
+
maxDeliveryCount: 10,
|
|
47
|
+
}, defaults?.queue), {
|
|
48
|
+
apiVersion: "2022-10-01-preview",
|
|
49
|
+
DependsOn: [
|
|
50
|
+
`[resourceId('Microsoft.ServiceBus/namespaces', '${name}')]`,
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
return { namespace, queue };
|
|
54
|
+
}, "ServiceBusPipeline");
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SqlDatabase composite — SQL Server + Database + Firewall Rule.
|
|
3
|
+
*
|
|
4
|
+
* A higher-level construct for deploying an Azure SQL Database with
|
|
5
|
+
* a logical server, a database, and a firewall rule allowing Azure services.
|
|
6
|
+
*/
|
|
7
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
8
|
+
import { SqlServer, SqlDatabase as SqlDatabaseResource, SqlFirewallRule } from "../generated/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Create a SqlDatabase composite — returns a SQL Server, Database,
|
|
11
|
+
* and Firewall Rule.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { SqlDatabase } from "@intentius/chant-lexicon-azure";
|
|
16
|
+
*
|
|
17
|
+
* const { server, database, firewallRule } = SqlDatabase({
|
|
18
|
+
* name: "my-sql-server",
|
|
19
|
+
* adminLogin: "sqladmin",
|
|
20
|
+
* adminPassword: "P@ssw0rd!",
|
|
21
|
+
* sku: "S1",
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* export { server, database, firewallRule };
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const SqlDatabase = Composite((props) => {
|
|
28
|
+
const { name, adminLogin, adminPassword, sku = "S0", location = "[resourceGroup().location]", tags = {}, defaults, } = props;
|
|
29
|
+
const commonTags = {
|
|
30
|
+
"managed-by": "chant",
|
|
31
|
+
...tags,
|
|
32
|
+
};
|
|
33
|
+
const dbName = `${name}-db`;
|
|
34
|
+
const server = new SqlServer(mergeDefaults({
|
|
35
|
+
name,
|
|
36
|
+
location,
|
|
37
|
+
tags: commonTags,
|
|
38
|
+
administratorLogin: adminLogin,
|
|
39
|
+
administratorLoginPassword: adminPassword,
|
|
40
|
+
version: "12.0",
|
|
41
|
+
minimalTlsVersion: "1.2",
|
|
42
|
+
publicNetworkAccess: "Enabled",
|
|
43
|
+
}, defaults?.server), { apiVersion: "2022-05-01-preview" });
|
|
44
|
+
const database = new SqlDatabaseResource(mergeDefaults({
|
|
45
|
+
name: `${name}/${dbName}`,
|
|
46
|
+
location,
|
|
47
|
+
tags: commonTags,
|
|
48
|
+
sku: {
|
|
49
|
+
name: sku,
|
|
50
|
+
},
|
|
51
|
+
collation: "SQL_Latin1_General_CP1_CI_AS",
|
|
52
|
+
maxSizeBytes: 2147483648,
|
|
53
|
+
catalogCollation: "SQL_Latin1_General_CP1_CI_AS",
|
|
54
|
+
zoneRedundant: false,
|
|
55
|
+
}, defaults?.database), { apiVersion: "2022-05-01-preview" });
|
|
56
|
+
const firewallRule = new SqlFirewallRule(mergeDefaults({
|
|
57
|
+
name: `${name}/AllowAllAzureIps`,
|
|
58
|
+
startIpAddress: "0.0.0.0",
|
|
59
|
+
endIpAddress: "0.0.0.0",
|
|
60
|
+
}, defaults?.firewallRule), { apiVersion: "2022-05-01-preview" });
|
|
61
|
+
return { server, database, firewallRule };
|
|
62
|
+
}, "SqlDatabase");
|