@swovohq/fuel 0.2.2-alpha.9 → 0.2.2-alpha.91

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 (232) hide show
  1. package/README.md +173 -69
  2. package/dist/bin/fuel.js +77 -31
  3. package/dist/bin/fuel.js.map +1 -1
  4. package/dist/cleanup/finalize.d.ts.map +1 -1
  5. package/dist/cleanup/finalize.js +11 -3
  6. package/dist/cleanup/finalize.js.map +1 -1
  7. package/dist/commands/config-verify.d.ts.map +1 -1
  8. package/dist/commands/config-verify.js +14 -6
  9. package/dist/commands/config-verify.js.map +1 -1
  10. package/dist/commands/create-app.d.ts.map +1 -1
  11. package/dist/commands/create-app.js +41 -7
  12. package/dist/commands/create-app.js.map +1 -1
  13. package/dist/commands/infra-deploy.d.ts +15 -1
  14. package/dist/commands/infra-deploy.d.ts.map +1 -1
  15. package/dist/commands/infra-deploy.js +164 -18
  16. package/dist/commands/infra-deploy.js.map +1 -1
  17. package/dist/commands/infra-destroy.d.ts.map +1 -1
  18. package/dist/commands/infra-destroy.js +3 -3
  19. package/dist/commands/infra-destroy.js.map +1 -1
  20. package/dist/commands/infra-init.d.ts +91 -0
  21. package/dist/commands/infra-init.d.ts.map +1 -1
  22. package/dist/commands/infra-init.js +644 -113
  23. package/dist/commands/infra-init.js.map +1 -1
  24. package/dist/commands/infra-pull.d.ts +8 -0
  25. package/dist/commands/infra-pull.d.ts.map +1 -0
  26. package/dist/commands/infra-pull.js +81 -0
  27. package/dist/commands/infra-pull.js.map +1 -0
  28. package/dist/commands/list-modules.d.ts.map +1 -1
  29. package/dist/commands/list-modules.js +10 -3
  30. package/dist/commands/list-modules.js.map +1 -1
  31. package/dist/engines/convention.d.ts +2 -2
  32. package/dist/engines/convention.d.ts.map +1 -1
  33. package/dist/engines/convention.js +8 -6
  34. package/dist/engines/convention.js.map +1 -1
  35. package/dist/engines/dependencies.d.ts +2 -0
  36. package/dist/engines/dependencies.d.ts.map +1 -1
  37. package/dist/engines/dependencies.js.map +1 -1
  38. package/dist/engines/monorepo.d.ts.map +1 -1
  39. package/dist/engines/monorepo.js.map +1 -1
  40. package/dist/engines/template-source.d.ts.map +1 -1
  41. package/dist/engines/template-source.js +3 -1
  42. package/dist/engines/template-source.js.map +1 -1
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/infra/azure-defaults.d.ts +49 -0
  46. package/dist/infra/azure-defaults.d.ts.map +1 -0
  47. package/dist/infra/azure-defaults.js +52 -0
  48. package/dist/infra/azure-defaults.js.map +1 -0
  49. package/dist/infra/azure-keyvault-client.d.ts +4 -0
  50. package/dist/infra/azure-keyvault-client.d.ts.map +1 -0
  51. package/dist/infra/azure-keyvault-client.js +57 -0
  52. package/dist/infra/azure-keyvault-client.js.map +1 -0
  53. package/dist/infra/azure-rbac.d.ts +11 -0
  54. package/dist/infra/azure-rbac.d.ts.map +1 -0
  55. package/dist/infra/azure-rbac.js +49 -0
  56. package/dist/infra/azure-rbac.js.map +1 -0
  57. package/dist/infra/azure-state-storage.d.ts +20 -0
  58. package/dist/infra/azure-state-storage.d.ts.map +1 -0
  59. package/dist/infra/azure-state-storage.js +229 -0
  60. package/dist/infra/azure-state-storage.js.map +1 -0
  61. package/dist/infra/config-loader.d.ts.map +1 -1
  62. package/dist/infra/config-loader.js.map +1 -1
  63. package/dist/infra/config-writer.js +1 -1
  64. package/dist/infra/credentials.d.ts +2 -2
  65. package/dist/infra/credentials.d.ts.map +1 -1
  66. package/dist/infra/credentials.js +8 -4
  67. package/dist/infra/credentials.js.map +1 -1
  68. package/dist/infra/dependency-checker.d.ts.map +1 -1
  69. package/dist/infra/dependency-checker.js.map +1 -1
  70. package/dist/infra/deployment-detect.d.ts +9 -0
  71. package/dist/infra/deployment-detect.d.ts.map +1 -0
  72. package/dist/infra/deployment-detect.js +53 -0
  73. package/dist/infra/deployment-detect.js.map +1 -0
  74. package/dist/infra/git-client.d.ts.map +1 -1
  75. package/dist/infra/git-client.js +6 -10
  76. package/dist/infra/git-client.js.map +1 -1
  77. package/dist/infra/github-client.d.ts +7 -0
  78. package/dist/infra/github-client.d.ts.map +1 -1
  79. package/dist/infra/github-client.js +47 -7
  80. package/dist/infra/github-client.js.map +1 -1
  81. package/dist/infra/github-secrets-client.d.ts.map +1 -1
  82. package/dist/infra/github-secrets-client.js +2 -2
  83. package/dist/infra/github-secrets-client.js.map +1 -1
  84. package/dist/infra/github-token-link.d.ts +4 -0
  85. package/dist/infra/github-token-link.d.ts.map +1 -0
  86. package/dist/infra/github-token-link.js +32 -0
  87. package/dist/infra/github-token-link.js.map +1 -0
  88. package/dist/infra/orchestrator.d.ts +4 -1
  89. package/dist/infra/orchestrator.d.ts.map +1 -1
  90. package/dist/infra/orchestrator.js +218 -63
  91. package/dist/infra/orchestrator.js.map +1 -1
  92. package/dist/infra/port-utils.d.ts.map +1 -1
  93. package/dist/infra/port-utils.js.map +1 -1
  94. package/dist/infra/preflight.d.ts.map +1 -1
  95. package/dist/infra/preflight.js +25 -11
  96. package/dist/infra/preflight.js.map +1 -1
  97. package/dist/infra/remote-secret.d.ts +14 -0
  98. package/dist/infra/remote-secret.d.ts.map +1 -0
  99. package/dist/infra/remote-secret.js +42 -0
  100. package/dist/infra/remote-secret.js.map +1 -0
  101. package/dist/infra/s3-state-bucket.d.ts.map +1 -1
  102. package/dist/infra/s3-state-bucket.js +8 -4
  103. package/dist/infra/s3-state-bucket.js.map +1 -1
  104. package/dist/infra/secrets-manager-client.d.ts.map +1 -1
  105. package/dist/infra/secrets-manager-client.js +8 -5
  106. package/dist/infra/secrets-manager-client.js.map +1 -1
  107. package/dist/infra/subprocess.js +1 -1
  108. package/dist/infra/template-engine.d.ts +14 -5
  109. package/dist/infra/template-engine.d.ts.map +1 -1
  110. package/dist/infra/template-engine.js +157 -39
  111. package/dist/infra/template-engine.js.map +1 -1
  112. package/dist/infra/tofu-runner.d.ts +4 -3
  113. package/dist/infra/tofu-runner.d.ts.map +1 -1
  114. package/dist/infra/tofu-runner.js +40 -34
  115. package/dist/infra/tofu-runner.js.map +1 -1
  116. package/dist/infra/types.d.ts +241 -17
  117. package/dist/infra/types.d.ts.map +1 -1
  118. package/dist/infra/types.js +419 -22
  119. package/dist/infra/types.js.map +1 -1
  120. package/dist/infra-templates/TODO-azure-prod.md +127 -0
  121. package/dist/infra-templates/modules/azure-container-app/main.tf +124 -0
  122. package/dist/infra-templates/modules/azure-container-app/outputs.tf +24 -0
  123. package/dist/infra-templates/modules/azure-container-app/variables.tf +80 -0
  124. package/dist/infra-templates/modules/azure-container-apps-environment/main.tf +18 -0
  125. package/dist/infra-templates/modules/azure-container-apps-environment/outputs.tf +14 -0
  126. package/dist/infra-templates/modules/azure-container-apps-environment/variables.tf +24 -0
  127. package/dist/infra-templates/modules/azure-container-registry/main.tf +10 -0
  128. package/dist/infra-templates/modules/azure-container-registry/outputs.tf +14 -0
  129. package/dist/infra-templates/modules/azure-container-registry/variables.tf +20 -0
  130. package/dist/infra-templates/modules/azure-front-door/main.tf +80 -0
  131. package/dist/infra-templates/modules/azure-front-door/outputs.tf +20 -0
  132. package/dist/infra-templates/modules/azure-front-door/variables.tf +26 -0
  133. package/dist/infra-templates/modules/azure-github-oidc/main.tf +48 -0
  134. package/dist/infra-templates/modules/azure-github-oidc/outputs.tf +9 -0
  135. package/dist/infra-templates/modules/azure-github-oidc/variables.tf +69 -0
  136. package/dist/infra-templates/modules/azure-key-vault/main.tf +21 -0
  137. package/dist/infra-templates/modules/azure-key-vault/outputs.tf +11 -0
  138. package/dist/infra-templates/modules/azure-key-vault/variables.tf +43 -0
  139. package/dist/infra-templates/modules/azure-monitor/main.tf +29 -0
  140. package/dist/infra-templates/modules/azure-monitor/outputs.tf +17 -0
  141. package/dist/infra-templates/modules/azure-monitor/variables.tf +32 -0
  142. package/dist/infra-templates/modules/azure-network/main.tf +134 -0
  143. package/dist/infra-templates/modules/azure-network/outputs.tf +44 -0
  144. package/dist/infra-templates/modules/azure-network/variables.tf +56 -0
  145. package/dist/infra-templates/modules/azure-postgresql-flexible/main.tf +34 -0
  146. package/dist/infra-templates/modules/azure-postgresql-flexible/outputs.tf +20 -0
  147. package/dist/infra-templates/modules/azure-postgresql-flexible/variables.tf +54 -0
  148. package/dist/infra-templates/modules/azure-redis-cache/main.tf +32 -0
  149. package/dist/infra-templates/modules/azure-redis-cache/outputs.tf +15 -0
  150. package/dist/infra-templates/modules/azure-redis-cache/variables.tf +30 -0
  151. package/dist/infra-templates/modules/azure-resource-group/main.tf +5 -0
  152. package/dist/infra-templates/modules/azure-resource-group/outputs.tf +11 -0
  153. package/dist/infra-templates/modules/azure-resource-group/variables.tf +16 -0
  154. package/dist/infra-templates/modules/azure-sql-database/main.tf +63 -0
  155. package/dist/infra-templates/modules/azure-sql-database/outputs.tf +20 -0
  156. package/dist/infra-templates/modules/azure-sql-database/variables.tf +78 -0
  157. package/dist/infra-templates/modules/azure-storage-account/main.tf +13 -0
  158. package/dist/infra-templates/modules/azure-storage-account/outputs.tf +16 -0
  159. package/dist/infra-templates/modules/azure-storage-account/variables.tf +38 -0
  160. package/dist/infra-templates/modules/cloud-watch/event-bridge.tf +15 -0
  161. package/dist/infra-templates/modules/cloud-watch/lambda.tf +84 -0
  162. package/dist/infra-templates/modules/cloud-watch/lambda_function.zip +0 -0
  163. package/dist/infra-templates/modules/cloud-watch/lambda_function_deploy.zip +0 -0
  164. package/dist/infra-templates/modules/cloud-watch/main.tf +156 -0
  165. package/dist/infra-templates/modules/cloud-watch/sns.tf +3 -0
  166. package/dist/infra-templates/modules/cloud-watch/variables.tf +38 -0
  167. package/dist/infra-templates/modules/ecs-core/alb.tf +126 -0
  168. package/dist/infra-templates/modules/ecs-core/cloudwatch.tf +48 -0
  169. package/dist/infra-templates/modules/ecs-core/iam.tf +95 -0
  170. package/dist/infra-templates/modules/ecs-core/main.tf +12 -0
  171. package/dist/infra-templates/modules/ecs-core/outputs.tf +44 -0
  172. package/dist/infra-templates/modules/ecs-core/secrets.tf +9 -0
  173. package/dist/infra-templates/modules/ecs-core/security_groups.tf +73 -0
  174. package/dist/infra-templates/modules/ecs-core/variables.tf +96 -0
  175. package/dist/infra-templates/modules/ecs-service/ecs_autoscaling.tf +51 -0
  176. package/dist/infra-templates/modules/ecs-service/ecs_service.tf +39 -0
  177. package/dist/infra-templates/modules/ecs-service/ecs_task_definition.tf +56 -0
  178. package/dist/infra-templates/modules/ecs-service/variables.tf +170 -0
  179. package/dist/infra-templates/modules/elastic-container-registry/main.tf +32 -0
  180. package/dist/infra-templates/modules/elastic-container-registry/outputs.tf +9 -0
  181. package/dist/infra-templates/modules/elastic-container-registry/variables.tf +25 -0
  182. package/dist/infra-templates/modules/github-oidc-role/main.tf +46 -0
  183. package/dist/infra-templates/modules/github-oidc-role/outputs.tf +4 -0
  184. package/dist/infra-templates/modules/github-oidc-role/variables.tf +11 -0
  185. package/dist/infra-templates/modules/guardduty/main.tf +8 -0
  186. package/dist/infra-templates/modules/iam/main.tf +205 -0
  187. package/dist/infra-templates/modules/iam/outputs.tf +3 -0
  188. package/dist/infra-templates/modules/iam/variables.tf +4 -0
  189. package/dist/infra-templates/modules/random-key/main.tf +11 -0
  190. package/dist/infra-templates/modules/random-key/outputs.tf +4 -0
  191. package/dist/infra-templates/modules/random-key/variables.tf +10 -0
  192. package/dist/infra-templates/modules/redis/main.tf +47 -0
  193. package/dist/infra-templates/modules/redis/outputs.tf +8 -0
  194. package/dist/infra-templates/modules/redis/variables.tf +20 -0
  195. package/dist/infra-templates/modules/relational-database-service/main.tf +44 -0
  196. package/dist/infra-templates/modules/relational-database-service/outputs.tf +13 -0
  197. package/dist/infra-templates/modules/relational-database-service/security-group.tf +15 -0
  198. package/dist/infra-templates/modules/relational-database-service/variables.tf +50 -0
  199. package/dist/infra-templates/modules/secret/main.tf +14 -0
  200. package/dist/infra-templates/modules/secret/outputs.tf +3 -0
  201. package/dist/infra-templates/modules/secret/variables.tf +8 -0
  202. package/dist/infra-templates/modules/simple-storage-service/main.tf +28 -0
  203. package/dist/infra-templates/modules/simple-storage-service/variables.tf +4 -0
  204. package/dist/infra-templates/modules/vpc/data.tf +2 -0
  205. package/dist/infra-templates/modules/vpc/main.tf +76 -0
  206. package/dist/infra-templates/modules/vpc/outputs.tf +23 -0
  207. package/dist/infra-templates/modules/vpc/variables.tf +5 -0
  208. package/dist/infra-templates/package.json +6 -0
  209. package/dist/infra-templates/templates/azure/MANUAL_DEPLOY.md +168 -0
  210. package/dist/infra-templates/templates/azure/backend.tf +8 -0
  211. package/dist/infra-templates/templates/azure/data.tf +21 -0
  212. package/dist/infra-templates/templates/azure/default.tfvars +0 -0
  213. package/dist/infra-templates/templates/azure/locals.tf +116 -0
  214. package/dist/infra-templates/templates/azure/main.tf +421 -0
  215. package/dist/infra-templates/templates/azure/outputs.tf +40 -0
  216. package/dist/infra-templates/templates/azure/providers.tf +65 -0
  217. package/dist/infra-templates/templates/azure/variables.tf +69 -0
  218. package/dist/infra-templates/templates/azure/workflows/build_and_deploy.yml +155 -0
  219. package/dist/infra-templates/templates/azure/workflows/tests.yml +63 -0
  220. package/dist/infra-templates/templates/ecs/README.md +235 -0
  221. package/dist/infra-templates/templates/ecs/backend.tf +7 -0
  222. package/dist/infra-templates/templates/ecs/data.tf +6 -0
  223. package/dist/infra-templates/templates/ecs/default.tfvars +1 -0
  224. package/dist/infra-templates/templates/ecs/locals.tf +97 -0
  225. package/dist/infra-templates/templates/ecs/main.tf +185 -0
  226. package/dist/infra-templates/templates/ecs/outputs.tf +42 -0
  227. package/dist/infra-templates/templates/ecs/providers.tf +21 -0
  228. package/dist/infra-templates/templates/ecs/variables.tf +105 -0
  229. package/dist/infra-templates/templates/ecs/workflows/build_and_deploy.yml +188 -0
  230. package/dist/infra-templates/templates/ecs/workflows/tests.yml +65 -0
  231. package/package.json +10 -2
  232. package/schema/fuel.schema.json +570 -91
@@ -0,0 +1,29 @@
1
+ resource "azurerm_log_analytics_workspace" "this" {
2
+ name = "${var.project_name}-law"
3
+ resource_group_name = var.resource_group_name
4
+ location = var.location
5
+ sku = "PerGB2018"
6
+ retention_in_days = var.retention_days
7
+ }
8
+
9
+ resource "azurerm_application_insights" "this" {
10
+ name = "${var.project_name}-appi"
11
+ resource_group_name = var.resource_group_name
12
+ location = var.location
13
+ application_type = "web"
14
+ workspace_id = azurerm_log_analytics_workspace.this.id
15
+ daily_data_cap_in_gb = var.daily_data_cap_gb
16
+ retention_in_days = var.retention_days
17
+ }
18
+
19
+ resource "azurerm_portal_dashboard" "this" {
20
+ count = var.dashboard_count
21
+ name = "${var.project_name}-dashboard-${count.index + 1}"
22
+ resource_group_name = var.resource_group_name
23
+ location = var.location
24
+
25
+ dashboard_properties = jsonencode({
26
+ lenses = {}
27
+ metadata = {}
28
+ })
29
+ }
@@ -0,0 +1,17 @@
1
+ output "log_analytics_workspace_id" {
2
+ value = azurerm_log_analytics_workspace.this.id
3
+ }
4
+
5
+ output "instrumentation_key" {
6
+ value = azurerm_application_insights.this.instrumentation_key
7
+ sensitive = true
8
+ }
9
+
10
+ output "connection_string" {
11
+ value = azurerm_application_insights.this.connection_string
12
+ sensitive = true
13
+ }
14
+
15
+ output "app_insights_id" {
16
+ value = azurerm_application_insights.this.id
17
+ }
@@ -0,0 +1,32 @@
1
+ variable "project_name" {
2
+ type = string
3
+ description = "Project name, used to derive resource names"
4
+ }
5
+
6
+ variable "resource_group_name" {
7
+ type = string
8
+ description = "Resource group where the monitoring resources are created"
9
+ }
10
+
11
+ variable "location" {
12
+ type = string
13
+ description = "Azure region"
14
+ }
15
+
16
+ variable "daily_data_cap_gb" {
17
+ type = number
18
+ description = "Daily data ingestion cap in GB for Application Insights"
19
+ default = 1
20
+ }
21
+
22
+ variable "retention_days" {
23
+ type = number
24
+ description = "Data retention in days"
25
+ default = 90
26
+ }
27
+
28
+ variable "dashboard_count" {
29
+ type = number
30
+ description = "Number of portal dashboards to create"
31
+ default = 0
32
+ }
@@ -0,0 +1,134 @@
1
+ # Keeps every database/cache reachable only from inside this VNet. Container Apps
2
+ # ingress stays public (Front Door needs a public origin) — this only closes off
3
+ # the data-plane services that have no reason to be reachable from the internet.
4
+ resource "azurerm_virtual_network" "this" {
5
+ name = "${var.project_name}-vnet"
6
+ resource_group_name = var.resource_group_name
7
+ location = var.location
8
+ address_space = var.address_space
9
+ }
10
+
11
+ resource "azurerm_subnet" "container_apps_infra" {
12
+ name = "${var.project_name}-cae-subnet"
13
+ resource_group_name = var.resource_group_name
14
+ virtual_network_name = azurerm_virtual_network.this.name
15
+ address_prefixes = var.container_apps_subnet_prefix
16
+
17
+ delegation {
18
+ name = "container-apps-environment"
19
+ service_delegation {
20
+ name = "Microsoft.App/environments"
21
+ actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
22
+ }
23
+ }
24
+ }
25
+
26
+ # A subnet has no reliable outbound internet path of its own once placed in a custom
27
+ # VNet — Azure's "default outbound access" is being retired for newly created resources.
28
+ # Without this, every Container App revision hangs pulling its image (any image, from
29
+ # any registry) until the platform gives up ("Operation expired"). This is Microsoft's
30
+ # own recommended pattern for Container Apps in a BYO VNet.
31
+ resource "azurerm_public_ip" "container_apps_nat" {
32
+ name = "${var.project_name}-cae-nat-ip"
33
+ resource_group_name = var.resource_group_name
34
+ location = var.location
35
+ allocation_method = "Static"
36
+ sku = "Standard"
37
+ }
38
+
39
+ resource "azurerm_nat_gateway" "container_apps" {
40
+ name = "${var.project_name}-cae-nat"
41
+ resource_group_name = var.resource_group_name
42
+ location = var.location
43
+ sku_name = "Standard"
44
+ }
45
+
46
+ resource "azurerm_nat_gateway_public_ip_association" "container_apps" {
47
+ nat_gateway_id = azurerm_nat_gateway.container_apps.id
48
+ public_ip_address_id = azurerm_public_ip.container_apps_nat.id
49
+ }
50
+
51
+ resource "azurerm_subnet_nat_gateway_association" "container_apps" {
52
+ subnet_id = azurerm_subnet.container_apps_infra.id
53
+ nat_gateway_id = azurerm_nat_gateway.container_apps.id
54
+ }
55
+
56
+ # Postgres Flexible Server's private-access model is VNet integration (delegated_subnet_id
57
+ # + private_dns_zone_id directly on the server resource) rather than a standard Private
58
+ # Endpoint — it needs its own subnet delegated specifically to the Postgres RP.
59
+ resource "azurerm_subnet" "postgres" {
60
+ count = var.postgres_needed ? 1 : 0
61
+
62
+ name = "${var.project_name}-postgres-subnet"
63
+ resource_group_name = var.resource_group_name
64
+ virtual_network_name = azurerm_virtual_network.this.name
65
+ address_prefixes = var.postgres_subnet_prefix
66
+
67
+ delegation {
68
+ name = "postgres-flexible-server"
69
+ service_delegation {
70
+ name = "Microsoft.DBforPostgreSQL/flexibleServers"
71
+ actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
72
+ }
73
+ }
74
+ }
75
+
76
+ # Azure SQL and Azure Managed Redis use standard Private Link — a plain (non-delegated)
77
+ # subnet with network policies disabled, shared across both.
78
+ resource "azurerm_subnet" "private_endpoints" {
79
+ count = (var.mssql_needed || var.redis_needed) ? 1 : 0
80
+
81
+ name = "${var.project_name}-pe-subnet"
82
+ resource_group_name = var.resource_group_name
83
+ virtual_network_name = azurerm_virtual_network.this.name
84
+ address_prefixes = var.private_endpoints_subnet_prefix
85
+ private_endpoint_network_policies = "Disabled"
86
+ }
87
+
88
+ resource "azurerm_private_dns_zone" "postgres" {
89
+ count = var.postgres_needed ? 1 : 0
90
+
91
+ name = "privatelink.postgres.database.azure.com"
92
+ resource_group_name = var.resource_group_name
93
+ }
94
+
95
+ resource "azurerm_private_dns_zone_virtual_network_link" "postgres" {
96
+ count = var.postgres_needed ? 1 : 0
97
+
98
+ name = "${var.project_name}-postgres-link"
99
+ resource_group_name = var.resource_group_name
100
+ private_dns_zone_name = azurerm_private_dns_zone.postgres[0].name
101
+ virtual_network_id = azurerm_virtual_network.this.id
102
+ }
103
+
104
+ resource "azurerm_private_dns_zone" "mssql" {
105
+ count = var.mssql_needed ? 1 : 0
106
+
107
+ name = "privatelink.database.windows.net"
108
+ resource_group_name = var.resource_group_name
109
+ }
110
+
111
+ resource "azurerm_private_dns_zone_virtual_network_link" "mssql" {
112
+ count = var.mssql_needed ? 1 : 0
113
+
114
+ name = "${var.project_name}-mssql-link"
115
+ resource_group_name = var.resource_group_name
116
+ private_dns_zone_name = azurerm_private_dns_zone.mssql[0].name
117
+ virtual_network_id = azurerm_virtual_network.this.id
118
+ }
119
+
120
+ resource "azurerm_private_dns_zone" "redis" {
121
+ count = var.redis_needed ? 1 : 0
122
+
123
+ name = "privatelink.redis.azure.net"
124
+ resource_group_name = var.resource_group_name
125
+ }
126
+
127
+ resource "azurerm_private_dns_zone_virtual_network_link" "redis" {
128
+ count = var.redis_needed ? 1 : 0
129
+
130
+ name = "${var.project_name}-redis-link"
131
+ resource_group_name = var.resource_group_name
132
+ private_dns_zone_name = azurerm_private_dns_zone.redis[0].name
133
+ virtual_network_id = azurerm_virtual_network.this.id
134
+ }
@@ -0,0 +1,44 @@
1
+ output "vnet_id" {
2
+ value = azurerm_virtual_network.this.id
3
+ }
4
+
5
+ output "container_apps_subnet_id" {
6
+ value = azurerm_subnet.container_apps_infra.id
7
+ }
8
+
9
+ # Static outbound IP for the Container Apps environment — useful for allowlisting this
10
+ # project's apps against third-party APIs/firewalls that require a fixed source IP.
11
+ output "container_apps_outbound_ip" {
12
+ value = azurerm_public_ip.container_apps_nat.ip_address
13
+ }
14
+
15
+ output "postgres_subnet_id" {
16
+ value = try(azurerm_subnet.postgres[0].id, null)
17
+ }
18
+
19
+ output "private_endpoints_subnet_id" {
20
+ value = try(azurerm_subnet.private_endpoints[0].id, null)
21
+ }
22
+
23
+ output "postgres_dns_zone_id" {
24
+ value = try(azurerm_private_dns_zone.postgres[0].id, null)
25
+ }
26
+
27
+ output "mssql_dns_zone_id" {
28
+ value = try(azurerm_private_dns_zone.mssql[0].id, null)
29
+ }
30
+
31
+ output "redis_dns_zone_id" {
32
+ value = try(azurerm_private_dns_zone.redis[0].id, null)
33
+ }
34
+
35
+ # So callers can `depends_on = [module.network]` and be sure the VNet links (not just the
36
+ # zones) exist before creating a resource that needs private DNS resolution to work.
37
+ # Only includes links for zones actually created (postgres_needed/mssql_needed/redis_needed).
38
+ output "ready" {
39
+ value = compact([
40
+ try(azurerm_private_dns_zone_virtual_network_link.postgres[0].id, null),
41
+ try(azurerm_private_dns_zone_virtual_network_link.mssql[0].id, null),
42
+ try(azurerm_private_dns_zone_virtual_network_link.redis[0].id, null),
43
+ ])
44
+ }
@@ -0,0 +1,56 @@
1
+ variable "project_name" {
2
+ type = string
3
+ description = "Used as a naming prefix for the VNet, subnets, and private DNS zones"
4
+ }
5
+
6
+ variable "resource_group_name" {
7
+ type = string
8
+ description = "Resource group where networking resources are created"
9
+ }
10
+
11
+ variable "location" {
12
+ type = string
13
+ description = "Azure region"
14
+ }
15
+
16
+ variable "address_space" {
17
+ type = list(string)
18
+ description = "VNet address space"
19
+ default = ["10.20.0.0/16"]
20
+ }
21
+
22
+ variable "container_apps_subnet_prefix" {
23
+ type = list(string)
24
+ description = "Subnet for the Container Apps environment's infrastructure. /23 minimum (Consumption-only environments require /23; a /27 workload-profile environment would fit too)."
25
+ default = ["10.20.0.0/23"]
26
+ }
27
+
28
+ variable "postgres_subnet_prefix" {
29
+ type = list(string)
30
+ description = "Subnet delegated to Microsoft.DBforPostgreSQL/flexibleServers. Shared by every Postgres flexible server in this project (Azure minimum is /28; sized larger for headroom)."
31
+ default = ["10.20.2.0/26"]
32
+ }
33
+
34
+ variable "private_endpoints_subnet_prefix" {
35
+ type = list(string)
36
+ description = "Subnet for standard Private Link endpoints (Azure SQL, Azure Managed Redis)."
37
+ default = ["10.20.3.0/26"]
38
+ }
39
+
40
+ variable "postgres_needed" {
41
+ type = bool
42
+ description = "Whether any app in this project uses the Postgres engine. Skips the delegated subnet + private DNS zone when false."
43
+ default = true
44
+ }
45
+
46
+ variable "mssql_needed" {
47
+ type = bool
48
+ description = "Whether any app in this project uses the mssql engine. Skips its private DNS zone when false."
49
+ default = true
50
+ }
51
+
52
+ variable "redis_needed" {
53
+ type = bool
54
+ description = "Whether any app in this project has Redis enabled. Skips its private DNS zone when false."
55
+ default = true
56
+ }
@@ -0,0 +1,34 @@
1
+ resource "random_password" "this" {
2
+ length = 24
3
+ special = true
4
+ override_special = "!#$%&*()-_=+[]{}<>:?"
5
+ }
6
+
7
+ locals {
8
+ effective_password = var.admin_password != "" ? var.admin_password : random_password.this.result
9
+ }
10
+
11
+ resource "azurerm_postgresql_flexible_server" "this" {
12
+ name = var.server_name
13
+ resource_group_name = var.resource_group_name
14
+ location = var.location
15
+ administrator_login = var.admin_username
16
+ administrator_password = local.effective_password
17
+ sku_name = var.sku_name
18
+ storage_mb = var.storage_mb
19
+ version = "16"
20
+ # zone intentionally not specified — let Azure choose.
21
+
22
+ # VNet-integrated instead of public: reachable only from the delegated subnet's VNet
23
+ # (the Container Apps environment lives there too), no public endpoint at all.
24
+ delegated_subnet_id = var.delegated_subnet_id
25
+ private_dns_zone_id = var.private_dns_zone_id
26
+ public_network_access_enabled = false
27
+ }
28
+
29
+ resource "azurerm_postgresql_flexible_server_database" "this" {
30
+ server_id = azurerm_postgresql_flexible_server.this.id
31
+ name = var.database_name
32
+ collation = "en_US.utf8"
33
+ charset = "UTF8"
34
+ }
@@ -0,0 +1,20 @@
1
+ output "fqdn" {
2
+ value = azurerm_postgresql_flexible_server.this.fqdn
3
+ description = "Fully qualified domain name of the PostgreSQL Flexible Server"
4
+ }
5
+
6
+ output "database_name" {
7
+ value = azurerm_postgresql_flexible_server_database.this.name
8
+ description = "Name of the PostgreSQL database"
9
+ }
10
+
11
+ output "admin_username" {
12
+ value = var.admin_username
13
+ description = "Administrator username for the PostgreSQL Flexible Server"
14
+ }
15
+
16
+ output "admin_password" {
17
+ value = local.effective_password
18
+ sensitive = true
19
+ description = "Effective administrator password for the PostgreSQL Flexible Server"
20
+ }
@@ -0,0 +1,54 @@
1
+ variable "server_name" {
2
+ description = "Name of the PostgreSQL Flexible Server. Must be globally unique."
3
+ type = string
4
+ }
5
+
6
+ variable "database_name" {
7
+ description = "Name of the PostgreSQL database"
8
+ type = string
9
+ }
10
+
11
+ variable "resource_group_name" {
12
+ description = "Name of the resource group where the server will be created"
13
+ type = string
14
+ }
15
+
16
+ variable "location" {
17
+ description = "Azure region where the server will be created"
18
+ type = string
19
+ }
20
+
21
+ variable "admin_username" {
22
+ description = "Administrator login for the PostgreSQL Flexible Server"
23
+ type = string
24
+ default = "pgadmin"
25
+ }
26
+
27
+ variable "admin_password" {
28
+ description = "Administrator password for the PostgreSQL Flexible Server. Leave empty to auto-generate."
29
+ type = string
30
+ default = ""
31
+ sensitive = true
32
+ }
33
+
34
+ variable "sku_name" {
35
+ description = "SKU name for the PostgreSQL Flexible Server"
36
+ type = string
37
+ default = "GP_Standard_D4s_v3"
38
+ }
39
+
40
+ variable "storage_mb" {
41
+ description = "Max storage allowed for the PostgreSQL Flexible Server, in MB"
42
+ type = number
43
+ default = 32768
44
+ }
45
+
46
+ variable "delegated_subnet_id" {
47
+ description = "Subnet delegated to Microsoft.DBforPostgreSQL/flexibleServers. Postgres Flexible Server's private-access model wires this directly on the server, not via a separate private endpoint."
48
+ type = string
49
+ }
50
+
51
+ variable "private_dns_zone_id" {
52
+ description = "Private DNS zone (privatelink.postgres.database.azure.com) linked to the same VNet as delegated_subnet_id."
53
+ type = string
54
+ }
@@ -0,0 +1,32 @@
1
+ resource "azurerm_managed_redis" "this" {
2
+ name = var.name
3
+ resource_group_name = var.resource_group_name
4
+ location = var.location
5
+ sku_name = var.sku_name
6
+ public_network_access = "Disabled"
7
+
8
+ default_database {
9
+ client_protocol = "Encrypted"
10
+ clustering_policy = "EnterpriseCluster"
11
+ eviction_policy = "VolatileLRU"
12
+ }
13
+ }
14
+
15
+ resource "azurerm_private_endpoint" "this" {
16
+ name = "${var.name}-pe"
17
+ resource_group_name = var.resource_group_name
18
+ location = var.location
19
+ subnet_id = var.private_endpoint_subnet_id
20
+
21
+ private_service_connection {
22
+ name = "${var.name}-psc"
23
+ private_connection_resource_id = azurerm_managed_redis.this.id
24
+ subresource_names = ["redisEnterprise"]
25
+ is_manual_connection = false
26
+ }
27
+
28
+ private_dns_zone_group {
29
+ name = "default"
30
+ private_dns_zone_ids = [var.private_dns_zone_id]
31
+ }
32
+ }
@@ -0,0 +1,15 @@
1
+ output "hostname" {
2
+ value = azurerm_managed_redis.this.hostname
3
+ description = "Hostname of the Azure Managed Redis instance"
4
+ }
5
+
6
+ output "ssl_port" {
7
+ value = azurerm_managed_redis.this.default_database[0].port
8
+ description = "TLS port of the Azure Managed Redis instance"
9
+ }
10
+
11
+ output "primary_access_key" {
12
+ value = azurerm_managed_redis.this.default_database[0].primary_access_key
13
+ sensitive = true
14
+ description = "Primary access key for the Azure Managed Redis default database"
15
+ }
@@ -0,0 +1,30 @@
1
+ variable "name" {
2
+ description = "Name of the Redis Enterprise cluster"
3
+ type = string
4
+ }
5
+
6
+ variable "resource_group_name" {
7
+ description = "Name of the resource group where the Redis Enterprise cluster will be created"
8
+ type = string
9
+ }
10
+
11
+ variable "location" {
12
+ description = "Azure region where the Redis Enterprise cluster will be created"
13
+ type = string
14
+ }
15
+
16
+ variable "sku_name" {
17
+ description = "SKU name for the Redis Enterprise cluster (Azure Managed Redis 'Balanced' tier, e.g. Balanced_B0, Balanced_B1, Balanced_B5)"
18
+ type = string
19
+ default = "Balanced_B0"
20
+ }
21
+
22
+ variable "private_endpoint_subnet_id" {
23
+ description = "Subnet for the Private Link endpoint (non-delegated, network policies disabled)"
24
+ type = string
25
+ }
26
+
27
+ variable "private_dns_zone_id" {
28
+ description = "Private DNS zone (privatelink.redis.azure.net) linked to the same VNet as private_endpoint_subnet_id"
29
+ type = string
30
+ }
@@ -0,0 +1,5 @@
1
+ resource "azurerm_resource_group" "this" {
2
+ name = var.name
3
+ location = var.location
4
+ tags = var.tags
5
+ }
@@ -0,0 +1,11 @@
1
+ output "name" {
2
+ value = azurerm_resource_group.this.name
3
+ }
4
+
5
+ output "id" {
6
+ value = azurerm_resource_group.this.id
7
+ }
8
+
9
+ output "location" {
10
+ value = azurerm_resource_group.this.location
11
+ }
@@ -0,0 +1,16 @@
1
+ variable "name" {
2
+ type = string
3
+ description = "Resource group name"
4
+ }
5
+
6
+ variable "location" {
7
+ type = string
8
+ description = "Azure region"
9
+ default = "eastus"
10
+ }
11
+
12
+ variable "tags" {
13
+ type = map(string)
14
+ description = "Tags applied to the resource group"
15
+ default = {}
16
+ }
@@ -0,0 +1,63 @@
1
+ resource "random_password" "this" {
2
+ length = 24
3
+ special = true
4
+ override_special = "!#$%&*()-_=+[]{}<>:?"
5
+ }
6
+
7
+ locals {
8
+ effective_password = var.admin_password != "" ? var.admin_password : random_password.this.result
9
+ }
10
+
11
+ resource "azurerm_mssql_server" "this" {
12
+ name = var.server_name
13
+ resource_group_name = var.resource_group_name
14
+ location = var.location
15
+ administrator_login = var.admin_username
16
+ administrator_login_password = local.effective_password
17
+ version = "12.0"
18
+ minimum_tls_version = "1.2"
19
+
20
+ public_network_access_enabled = false
21
+ }
22
+
23
+ resource "azurerm_private_endpoint" "this" {
24
+ name = "${var.server_name}-pe"
25
+ resource_group_name = var.resource_group_name
26
+ location = var.location
27
+ subnet_id = var.private_endpoint_subnet_id
28
+
29
+ private_service_connection {
30
+ name = "${var.server_name}-psc"
31
+ private_connection_resource_id = azurerm_mssql_server.this.id
32
+ subresource_names = ["sqlServer"]
33
+ is_manual_connection = false
34
+ }
35
+
36
+ private_dns_zone_group {
37
+ name = "default"
38
+ private_dns_zone_ids = [var.private_dns_zone_id]
39
+ }
40
+ }
41
+
42
+ resource "azurerm_mssql_database" "this" {
43
+ name = var.database_name
44
+ server_id = azurerm_mssql_server.this.id
45
+ sku_name = var.sku_name
46
+ min_capacity = var.min_capacity
47
+ auto_pause_delay_in_minutes = var.auto_pause_delay_in_minutes
48
+ storage_account_type = var.storage_account_type
49
+
50
+ short_term_retention_policy {
51
+ retention_days = var.pitr_retention_days
52
+ }
53
+
54
+ # Azure rejects long-term retention on a serverless database while auto-pause is
55
+ # enabled (LtrConfigPolicyUnsupportedIfAutoPauseEnabled) — only apply LTR once
56
+ # auto-pause is explicitly disabled (-1), e.g. for provisioned prod databases.
57
+ dynamic "long_term_retention_policy" {
58
+ for_each = var.auto_pause_delay_in_minutes == -1 ? [1] : []
59
+ content {
60
+ weekly_retention = var.ltr_weekly_retention
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,20 @@
1
+ output "fqdn" {
2
+ value = azurerm_mssql_server.this.fully_qualified_domain_name
3
+ description = "Fully qualified domain name of the SQL Server"
4
+ }
5
+
6
+ output "database_name" {
7
+ value = azurerm_mssql_database.this.name
8
+ description = "Name of the SQL database"
9
+ }
10
+
11
+ output "admin_username" {
12
+ value = var.admin_username
13
+ description = "Administrator username for the SQL Server"
14
+ }
15
+
16
+ output "admin_password" {
17
+ value = local.effective_password
18
+ sensitive = true
19
+ description = "Effective administrator password for the SQL Server"
20
+ }