From cb929c42a118c33642043900b46ce2e54affcc6a Mon Sep 17 00:00:00 2001 From: Andreas Grub Date: Tue, 7 Jul 2026 15:15:32 +0200 Subject: [PATCH 1/4] feat(azure-vm-starterkit): add missing meshstack_integration.tf (BBD) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The azure-virtual-machine-starterkit shipped only the buildingblock/ implementation — it never had a meshstack_integration.tf, so no building block definition (and no permissions array / ephemeral run key) was ever wired up. Its buildingblock creates a meshProject, a meshstack_tenant_v4 and a composed Azure VM child building block via provider "meshstack" {}, which needs the auto-injected ephemeral token that only a BBD permissions array grants. Add the integration.tf modeled on the AKS/SKE starter kits (workspace-level permissions). Reconstructed, never tested end-to-end — input assignment types (USER_INPUT vs STATIC), the readme, and the composed azure_vm_definition_version_uuid wiring need author review. --- .../meshstack_integration.tf | 247 ++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf diff --git a/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf b/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf new file mode 100644 index 00000000..5a5393b7 --- /dev/null +++ b/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf @@ -0,0 +1,247 @@ +variable "full_platform_identifier" { + type = string + description = "Full identifier of the Azure platform (example: `azure.westeurope`)." +} + +variable "landing_zone_identifier" { + type = string + description = "Azure landing zone identifier for the created tenant." +} + +variable "azure_vm_definition_version_uuid" { + type = string + description = "Version UUID of the Azure Virtual Machine building block definition that this starter kit composes." +} + +variable "project_tags" { + type = map(list(string)) + default = {} + description = "Tags applied to the created meshProject." +} + +variable "notification_subscribers" { + type = list(string) + default = [] +} + +variable "meshstack" { + type = object({ + owning_workspace_identifier = string + + tags = optional(map(list(string)), {}) + }) +} + +variable "hub" { + type = object({ + git_ref = optional(string, "main") + bbd_draft = optional(bool, true) + }) + const = true + default = { + git_ref = "main" + bbd_draft = true + } + description = <<-EOT + `git_ref`: Hub reference. Set to a tag (e.g. 'v1.2.3') or branch or commit sha of meshcloud/meshstack-hub repo.
+ `bbd_draft`: If true, allows changing the building block definition for upgrading dependent building blocks. + EOT +} + +output "building_block_definition" { + description = "BBD is consumed in building block compositions." + value = { + uuid = meshstack_building_block_definition.this.metadata.uuid + version_ref = var.hub.bbd_draft ? meshstack_building_block_definition.this.version_latest : meshstack_building_block_definition.this.version_latest_release + } +} + +locals { + name_regex = "^[a-zA-Z0-9-]{0,24}$" # keep aligned with the other starter kits (project/name length limits) +} + +resource "meshstack_building_block_definition" "this" { + metadata = { + owned_by_workspace = var.meshstack.owning_workspace_identifier + tags = var.meshstack.tags + } + + spec = { + description = "The Azure Virtual Machine Starterkit provisions a dedicated meshProject and Azure tenant, then composes an Azure Virtual Machine building block to deliver a ready-to-use VM." + display_name = "Azure Virtual Machine Starterkit" + notification_subscribers = var.notification_subscribers + symbol = "https://raw.githubusercontent.com/meshcloud/meshstack-hub/${var.hub.git_ref}/modules/azure/azure-virtual-machine-starterkit/buildingblock/logo.png" + + readme = chomp(<<-EOT + The **Azure Virtual Machine Starterkit** gives application teams a pre-configured Azure environment with a single virtual machine, following best practices. It creates a dedicated meshProject and Azure tenant and composes the Azure Virtual Machine building block to provision the VM. + + ## 🎯 When to use it + + This building block is ideal for teams that: + + - Need a quick, governed Azure VM without assembling project, tenant and VM wiring by hand. + - Want a Linux or Windows VM in a landing-zone-compliant tenant. + + ## Resources Created + + - **Azure Project**: A dedicated meshProject for your virtual machine resources. + - **Azure Tenant**: An Azure subscription tenant on your chosen landing zone. + - **Virtual Machine**: A Linux or Windows VM (composed via the Azure Virtual Machine building block). + + ## Shared Responsibilities + + | Responsibility | Platform Team | Application Team | + | ----------------------------------------- | ------------- | ---------------- | + | Provide the Azure platform + landing zone | ✅ | ❌ | + | Provision project, tenant and VM | ✅ | ❌ | + | Manage workloads on the VM | ❌ | ✅ | + | Rotate SSH keys / credentials | ❌ | ✅ | + + --- + EOT + ) + run_transparency = true + } + + version_spec = { + draft = var.hub.bbd_draft + implementation = { + terraform = { + repository_url = "https://github.com/meshcloud/meshstack-hub.git" + terraform_version = "1.9.0" + async = false + ref_name = var.hub.git_ref + repository_path = "modules/azure/azure-virtual-machine-starterkit/buildingblock" + use_mesh_http_backend_fallback = true + } + } + inputs = { + "creator" = { + assignment_type = "AUTHOR" + description = "Information about the creator of the resources who will be assigned Project Admin role." + display_name = "Creator" + type = "CODE" + } + "workspace_identifier" = { + assignment_type = "WORKSPACE_IDENTIFIER" + display_name = "Workspace Identifier" + type = "STRING" + } + "full_platform_identifier" = { + argument = jsonencode(var.full_platform_identifier) + assignment_type = "STATIC" + display_name = "Full Platform Identifier" + type = "STRING" + } + "landing_zone_identifier" = { + argument = jsonencode(var.landing_zone_identifier) + assignment_type = "STATIC" + display_name = "Landing Zone Identifier" + type = "STRING" + } + "azure_vm_definition_version_uuid" = { + argument = jsonencode(var.azure_vm_definition_version_uuid) + assignment_type = "STATIC" + display_name = "Azure VM Definition Version UUID" + type = "STRING" + } + "project_tags_yaml" = { + # buildingblock expects a YAML string it yamldecodes; jsonencode wraps the YAML string as the STATIC argument. + argument = jsonencode(yamlencode(var.project_tags)) + assignment_type = "STATIC" + description = "Tags for the created project (YAML)." + display_name = "Project Tags" + type = "STRING" + } + "name" = { + assignment_type = "USER_INPUT" + description = "Used for the created project and VM." + display_name = "Name" + type = "STRING" + value_validation_regex = local.name_regex + validation_regex_error_message = "No underscore/dots/spaces are allowed. A maximum length of 25 characters is allowed." + } + "vm_location" = { + assignment_type = "USER_INPUT" + description = "Azure region where the VM is deployed." + display_name = "VM Location" + type = "STRING" + default_value = jsonencode("westeurope") + } + "vm_os_type" = { + assignment_type = "USER_INPUT" + description = "Operating system type." + display_name = "VM OS Type" + type = "SINGLE_SELECT" + selectable_values = ["Linux", "Windows"] + default_value = jsonencode("Linux") + } + "vm_size" = { + assignment_type = "USER_INPUT" + description = "Size of the virtual machine." + display_name = "VM Size" + type = "STRING" + default_value = jsonencode("Standard_B1s") + } + "vm_admin_username" = { + assignment_type = "USER_INPUT" + description = "Admin username for the VM." + display_name = "VM Admin Username" + type = "STRING" + default_value = jsonencode("azureuser") + } + "vm_ssh_public_key" = { + assignment_type = "USER_INPUT" + description = "SSH public key for Linux VM authentication (required for Linux)." + display_name = "VM SSH Public Key" + type = "STRING" + } + "vm_admin_password" = { + assignment_type = "USER_INPUT" + description = "Admin password for a Windows VM (required for Windows)." + display_name = "VM Admin Password" + type = "STRING" + sensitive = {} + } + "vm_enable_public_ip" = { + assignment_type = "USER_INPUT" + description = "Whether to assign a public IP to the VM." + display_name = "Enable Public IP" + type = "BOOLEAN" + default_value = jsonencode(false) + } + } + outputs = { + "summary" = { + assignment_type = "SUMMARY" + display_name = "Summary" + type = "STRING" + } + } + permissions = [ + "BUILDINGBLOCK_DELETE", + "BUILDINGBLOCK_LIST", + "BUILDINGBLOCK_SAVE", + "PROJECTPRINCIPALROLE_DELETE", + "PROJECTPRINCIPALROLE_LIST", + "PROJECTPRINCIPALROLE_SAVE", + "PROJECT_DELETE", + "PROJECT_LIST", + "PROJECT_SAVE", + "TENANT_DELETE", + "TENANT_LIST", + "TENANT_SAVE", + ] + } +} + +terraform { + required_version = ">= 1.12.0" + + required_providers { + meshstack = { + source = "meshcloud/meshstack" + version = ">= 0.21.0" + } + } +} From 8ac91d547b4a14b2e3cd6e27a5d70e36b5b96d23 Mon Sep 17 00:00:00 2001 From: Mohammad Alhussan Date: Thu, 16 Jul 2026 09:36:56 +0200 Subject: [PATCH 2/4] feat: complete azure-vm-starterkit BBD with child VM BBD, logo and e2e Adds the composed child azure-virtual-machine BBD, a starter-kit logo and an e2e test, and finishes the starter-kit BBD so it can be deployed and smoke-tested. --- .../backplane/README.md | 32 -- .../buildingblock/logo.png | Bin 0 -> 4706 bytes .../e2e/main.tf | 117 +++++++ .../e2e/terraform.tf | 18 + ..._virtual_machine_starterkit_hub.tftest.hcl | 11 + .../meshstack_integration.tf | 18 +- .../buildingblock/README.md | 1 + .../buildingblock/provider.tf | 4 +- .../buildingblock/variables.tf | 5 + .../meshstack_integration.tf | 319 ++++++++++++++++++ 10 files changed, 487 insertions(+), 38 deletions(-) delete mode 100644 modules/azure/azure-virtual-machine-starterkit/backplane/README.md create mode 100644 modules/azure/azure-virtual-machine-starterkit/buildingblock/logo.png create mode 100644 modules/azure/azure-virtual-machine-starterkit/e2e/main.tf create mode 100644 modules/azure/azure-virtual-machine-starterkit/e2e/terraform.tf create mode 100644 modules/azure/azure-virtual-machine-starterkit/e2e/tests/azure_virtual_machine_starterkit_hub.tftest.hcl create mode 100644 modules/azure/azure-virtual-machine/meshstack_integration.tf diff --git a/modules/azure/azure-virtual-machine-starterkit/backplane/README.md b/modules/azure/azure-virtual-machine-starterkit/backplane/README.md deleted file mode 100644 index 8b9713fb..00000000 --- a/modules/azure/azure-virtual-machine-starterkit/backplane/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Azure Virtual Machine Starterkit Backplane - -There is no terraform for starterkit backplane. - -You need to manually create an API Key in meshStack and fill in the variables in the imported definition. - -## How to create an API Key - -> **Note**: you need to have Organization Admin permission in meshStack to create an API Key with admin rights. - -1. In the Admin Area, go to "Access Control" > "API Keys" -2. Create a new API Key with the required permissions for managing: - - Projects - - Tenants - - Building Blocks -3. Copy the key ID to MESHSTACK_API_KEY and secret to MESHSTACK_API_SECRET - -## Required Building Block Definitions - -This starterkit requires the following building block definition to be configured in your meshStack: - -1. **Azure Virtual Machine Building Block**: The actual VM provisioning building block - - Ensure it's configured to work with your Azure platform - - Note the definition version UUID for the starterkit configuration - -## Configuration - -When configuring the starterkit as a building block definition in meshStack: - -1. Set the appropriate platform support (Azure) -2. Configure all required input variables -3. Link to the correct Azure VM building block definition diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/logo.png b/modules/azure/azure-virtual-machine-starterkit/buildingblock/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7a6597783e204b855c16bfd37ecfc8177dcb7e4a GIT binary patch literal 4706 zcmbtY2{@GP*B?uhG+t%N&_YEh%gl&Tycj##70QyqU@~LIm&C2NFANu_M5 zEGbc1En^$mvnHuXzGuvM-`?-L{@?fgum3eO&vQS&`<&l7=XcKixGu3)7DfX668s<# zNWjEc-v$KY;sMt4e5|WV*ym*sXwy})fdd&I=!wN)Kr$+N?3D}x=1uS?%c$tfAP{IG zQON^~_9CJ2{z|?WG5`VlXfKQ}$H1IG#o};i8HAy#5)9aqGe^5)eaQrWZy6O`;Mv5N zjKKkS00yp>w!p;!_`zYP;i{*R^1u>BB;qjk7`J0sfZb441*xQ>2EcO1jE|d}$sqKA zH4f{80d7VZcOL@FMbDc=zypXO{4iVz#`*xDE!q=J!v03V%9Mg3`C|#b>|zk=N(d!& zb_xFOXdH$O!`X-%f#iW9u_1sDA){g-1498Etgnh5M+M-)7Y)Q-SH}tvLXqQ+^ zSb!I4BMv7l3$VpfH%i$sJB#(e_;c9Uo@4?6N5&HW3Az(}eKGEwR&p58BoZOupJtu} z9H%;t4G}2(AM7l^_J2sqLhZ30WMCFp!=#QtvU6eK#u%)Z_eNy6+7b2+9=&1Asl?wK z?Li1&`>#X4cZIFvhMFV-0pRdL6< z0|*+2^e%k6zP&L6d?8)BY2$|J6Pu_Xc!EAyWPP&Dp0>-KIh;7Gad8w% z@7)>ICw*=}C2`pD^3<-VKH1noNNCqq*0)=f#?ZSoaV+zbQThZT;iKNAajldw33}fV zNBXI}*+cO|hvJ5yk-bj&v+}V_Uh0RvG5uDTr_3@x8D~tw6FwfjII4W%BQkkJ>B5j& z(#VnI5oFScL*9%{_LMM($&&^BlK?%lf- z3dJUS+WPX8bN(z}aOWm!r&GaPd3m|)`9U(7Orz2EME4;QhK?-xmXVPW7Z(>A8d_alT~$?e|Ni~T%1WKoasH4_ zmBf!=YUiChcgo7jT3cJ6KYxDX#*J&&u9cRSUcGuXJw3g!u&|(@AUiudH8u6(#f!DmFHjN~IUhL{T63$L7uzXi74ytC{?*BJro*Lymae1YAkY@Pi9YIhAY+EHHRt$= z-J9pvUOAZ-Nj*K~Xl5txBqD6SAGzZcuRievzZv(z83PZy9T?@emHjq%-allt4HRdW z+r(a40-^gK&J1Y0>=So#2%uzSIj4`B>ntt|Xf)kT3d#u{|JjjsWc=5!{4YP|&I#rV zYCp>NKZmAp<&bv=)`c9Y*ljWLWUXzaJ-qfUcd+A&k(YbUF$WRCSGO;vwdV4GdSztg zR`SCIUc9JfK7PA%n&w!HJRiBpi&1<;BQSS<2milro9VspPPf)M7L=5X*?FnYByJnj zeq7RmaCrEgk|-;}$EzEnQTe1SsARY}BG+njhfrdJn}w_*Q%+&5t7wx}ko@f}n_><$ z-!c*@uS@HIh#AYzV}+tEPq(_qXoB^&eJ95@UPAWze>tlVV8~@e!zaB@Y%J@R6?vYw zZRO}L$X%Dn!@8S;>EA3oj|TDX+VmjdKri@uMb8zGiEjI{83p3f1oPld4r91ZC8Bg($*w$vASz)htiu{jnmzC*hmn)+ruFz3cwQ_yc4}29DKFcxX zZa$q8i)P$*v(&UQ{y4F!KxZ&^=AszUTh#flt)B5IB6ikf-kU1c8HydITxhI0e`Oz2 z&hp4iS-OhO5;m0GvANt~RWg%Ih$kU1f* zYqPt+HKHUwb`IQv%0IpcEz6doC{fc%CceF zOv30FB`Zeic^`0@+P5(sp?a>c>4VAZX8Y%Jec&w+aKGH5ygo}tn$KJVRG0pKv%(GC zOuMx5?SU$$#sbqB(YN^T0PfG2%8P<`Xv>9+u@=x3AKo3WnxHm3Q-fetsPu`~*0qMr zn4m9XZ?q5mI97Nj{DYx)#2Z!a3}vV4L+p08Y;>PipZ+W-mS2fT?;5{8d#52-h+n7ZwdurW($(F zR$H`uu{%R{Y^#-+e{wMRhW(pPr1q+1-{NE+kIVA zCqT9}e92g575d2h&Gm1URT!%T_&MjFyb_kUZZXTbQ`_&{OaPwHihj$U9_tG;o=oKqiacRLz!(R_Gr{2Lz^Wz%e?-M)k z!SD=H^Oufakpd}gei{<~#c6s2l>${EA?v$F?81D5YjR>)F*75u5L& zz6C)a2}{2P36$-X=7Uh~-ST+iC5y<@-$Uo>On|6o1yTLQr2|yviu_>ED+LRp>OXb} z9JE-AQNaZe4C!2Be@@?Om<)Lv9GHe8A@dJPgRl@c>4a$HI&!PuQ~6^_KfsBL1gY-@rL=2wadRU zu2ZDT+m<{JJ^Y=Cy_*CsHIWo>kquR#3$|%VT*&tA7%XY4Q>{KzJ6+UZ)Y7U2i00dO zf+Q)RMZN(**WVh^?M)>IpQx!DEH^XLzO`w=1EUu|3*hKq24z>8nUR9e0i^B6-6RZ= zHZ4q-OxUeqH!DoP^HvsIEQ zPgQR9ns@Hn{@OLQcYBAct)3peZhsz%K6Tz}e&@ICub2U|`!6@V8mvtU1Y6eZ8G__d zpMS-Py<}b)cS<6HJMaS!dq%gvbbb1cW!ECx?^WswwhVl3*Z{e#dDTTBa(9CHtPzZ! zE2u_=Hb5R|PM|4#n2KLLiX9~%J>xO+)ulJZKFRncl;XCvx@IHks=DHuV~YFgrG75M z3HMA2eC8(x|4h^YD{Fr8YYu|$xwFu?|9W+=K%*1=bWoC<*ignM{ba%Js@0pxe16+0 zeb!b{-=pg5VRQ}N?+@HpEVr6_O$vw9Fy;NCmL%UAo9wS#i?A?-URhnKw7H>tA=ffI z$;DLY%9qyciINeKqxsdbVN_H80_^CE$4B*okYCdp%iO&z-@VW-w6KJ0ke3dth0)9< zg5wryCU8G@^@{YLofudUUy?7cd%Y^J)MKO1dq}I{P``oy*09h1E?)xgKyLWU!LhSCdROfxHppdOMyhd)ADLvJ#3BiHzqd2(KE WwOKCv;RgKg2xMYlp 0 + error_message = "expected a non-empty summary output from the starter kit" + } +} diff --git a/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf b/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf index 5a5393b7..c513f2d3 100644 --- a/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf +++ b/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf @@ -30,6 +30,7 @@ variable "meshstack" { tags = optional(map(list(string)), {}) }) + description = "Shared meshStack context. Tags are optional and propagated to building block definition metadata." } variable "hub" { @@ -43,8 +44,8 @@ variable "hub" { bbd_draft = true } description = <<-EOT - `git_ref`: Hub reference. Set to a tag (e.g. 'v1.2.3') or branch or commit sha of meshcloud/meshstack-hub repo.
- `bbd_draft`: If true, allows changing the building block definition for upgrading dependent building blocks. + `git_ref`: Hub release reference. Set to a tag (e.g. 'v1.2.3') or branch or commit sha of the meshstack-hub repo. + `bbd_draft`: If true, the building block definition version is kept in draft mode, which allows changing it (useful during development in LCF/ICF). EOT } @@ -192,16 +193,23 @@ resource "meshstack_building_block_definition" "this" { } "vm_ssh_public_key" = { assignment_type = "USER_INPUT" - description = "SSH public key for Linux VM authentication (required for Linux)." + description = "SSH public key for Linux VM authentication (required for Linux). Leave empty for Windows." display_name = "VM SSH Public Key" type = "STRING" + # Only one of ssh_public_key / admin_password applies per OS; default both to empty so + # neither is force-required in the form. The buildingblock validates the correct one per vm_os_type. + default_value = jsonencode("") } "vm_admin_password" = { assignment_type = "USER_INPUT" - description = "Admin password for a Windows VM (required for Windows)." + description = "Admin password for a Windows VM (required for Windows). Leave empty for Linux." display_name = "VM Admin Password" type = "STRING" - sensitive = {} + sensitive = { + default_value = { + secret_value = "" + } + } } "vm_enable_public_ip" = { assignment_type = "USER_INPUT" diff --git a/modules/azure/azure-virtual-machine/buildingblock/README.md b/modules/azure/azure-virtual-machine/buildingblock/README.md index 91f4a46a..6b6f7f18 100644 --- a/modules/azure/azure-virtual-machine/buildingblock/README.md +++ b/modules/azure/azure-virtual-machine/buildingblock/README.md @@ -194,6 +194,7 @@ No modules. | [spot\_max\_bid\_price](#input\_spot\_max\_bid\_price) | Maximum price to pay for spot instance per hour. -1 means pay up to on-demand price. Default is -1 for maximum availability | `number` | `-1` | no | | [ssh\_public\_key](#input\_ssh\_public\_key) | SSH public key for Linux VM authentication (required for Linux) | `string` | `null` | no | | [subnet\_address\_prefix](#input\_subnet\_address\_prefix) | The address prefix for the subnet | `string` | `"10.0.1.0/24"` | no | +| [subscription\_id](#input\_subscription\_id) | The Azure subscription ID where the virtual machine will be deployed (the target tenant's subscription). | `string` | n/a | yes | | [tags](#input\_tags) | Tags to apply to all resources | `map(string)` | `{}` | no | | [vm\_name](#input\_vm\_name) | The name of the virtual machine | `string` | n/a | yes | | [vm\_size](#input\_vm\_size) | The size of the virtual machine | `string` | `"Standard_B1s"` | no | diff --git a/modules/azure/azure-virtual-machine/buildingblock/provider.tf b/modules/azure/azure-virtual-machine/buildingblock/provider.tf index d339328a..3b8499ac 100644 --- a/modules/azure/azure-virtual-machine/buildingblock/provider.tf +++ b/modules/azure/azure-virtual-machine/buildingblock/provider.tf @@ -1,4 +1,6 @@ provider "azurerm" { features {} - # Configuration options + # subscription_id targets the tenant's Azure subscription; authentication is provided via the + # ARM_* OIDC/WIF environment inputs wired by meshstack_integration.tf. + subscription_id = var.subscription_id } diff --git a/modules/azure/azure-virtual-machine/buildingblock/variables.tf b/modules/azure/azure-virtual-machine/buildingblock/variables.tf index 719ed963..9b3609a6 100644 --- a/modules/azure/azure-virtual-machine/buildingblock/variables.tf +++ b/modules/azure/azure-virtual-machine/buildingblock/variables.tf @@ -1,3 +1,8 @@ +variable "subscription_id" { + type = string + description = "The Azure subscription ID where the virtual machine will be deployed (the target tenant's subscription)." +} + variable "vm_name" { type = string description = "The name of the virtual machine" diff --git a/modules/azure/azure-virtual-machine/meshstack_integration.tf b/modules/azure/azure-virtual-machine/meshstack_integration.tf new file mode 100644 index 00000000..990afc8a --- /dev/null +++ b/modules/azure/azure-virtual-machine/meshstack_integration.tf @@ -0,0 +1,319 @@ +variable "azure_tenant_id" { + type = string + description = "Azure Entra tenant ID used for provider authentication." +} + +variable "azure_scope" { + type = string + description = "Azure management group or subscription ID used for the backplane role scope (typically the parent of all landing zones)." +} + +variable "backplane_name" { + type = string + default = "azure-virtual-machine" + description = "Name for the backplane resources (service principal, role definition). Must match pattern ^[-a-z0-9]+$." +} + +variable "notification_subscribers" { + type = list(string) + default = [] + description = "List of email addresses to notify on building block lifecycle events." +} + +variable "meshstack" { + type = object({ + owning_workspace_identifier = string + tags = optional(map(list(string)), {}) + }) + description = "Shared meshStack context. Tags are optional and propagated to building block definition metadata." +} + +variable "hub" { + type = object({ + git_ref = optional(string, "main") + bbd_draft = optional(bool, true) + }) + const = true + default = { + git_ref = "main" + bbd_draft = true + } + description = <<-EOT + `git_ref`: Hub release reference. Set to a tag (e.g. 'v1.2.3') or branch or commit sha of the meshstack-hub repo. + `bbd_draft`: If true, the building block definition version is kept in draft mode, which allows changing it (useful during development in LCF/ICF). + EOT +} + +output "building_block_definition" { + description = "BBD is consumed in building block compositions." + value = { + uuid = meshstack_building_block_definition.this.metadata.uuid + version_ref = var.hub.bbd_draft ? meshstack_building_block_definition.this.version_latest : meshstack_building_block_definition.this.version_latest_release + } +} + +data "meshstack_integrations" "integrations" {} + +module "backplane" { + source = "github.com/meshcloud/meshstack-hub//modules/azure/azure-virtual-machine/backplane?ref=${var.hub.git_ref}" + + name = var.backplane_name + scope = var.azure_scope + + create_service_principal_name = var.backplane_name + + workload_identity_federation = { + issuer = data.meshstack_integrations.integrations.workload_identity_federation.replicator.issuer + subject = "${trimsuffix(data.meshstack_integrations.integrations.workload_identity_federation.replicator.subject, ":replicator")}:workspace.${var.meshstack.owning_workspace_identifier}.buildingblockdefinition.${meshstack_building_block_definition.this.metadata.uuid}" + } +} + +resource "meshstack_building_block_definition" "this" { + metadata = { + owned_by_workspace = var.meshstack.owning_workspace_identifier + tags = var.meshstack.tags + } + + spec = { + display_name = "Azure Virtual Machine" + description = "Provisions a single Azure Virtual Machine (Linux or Windows) with its own virtual network, subnet, network security group and optional public IP and data disk, in the target tenant's subscription." + support_url = "mailto:support@meshcloud.io" + documentation_url = "https://hub.meshcloud.io/platforms/azure/definitions/azure-virtual-machine" + notification_subscribers = var.notification_subscribers + symbol = "https://raw.githubusercontent.com/meshcloud/meshstack-hub/${var.hub.git_ref}/modules/azure/azure-virtual-machine/buildingblock/logo.png" + target_type = "TENANT_LEVEL" + supported_platforms = [{ name = "AZURE" }] + + readme = chomp(<<-EOT + Provisions a single **Azure Virtual Machine** (Linux or Windows) with a dedicated virtual network, subnet, network security group, system-assigned managed identity and an optional public IP and data disk. The VM is deployed into the target tenant's Azure subscription. + + ## 🎯 When to use it + + Use this building block when your team needs a dedicated compute instance with full OS control, for example to: + + - Run a Linux or Windows workload that isn't a good fit for managed/containerized services. + - Host an application server, database, build agent or lift-and-shift migration. + - Get an isolated dev/test environment with predictable performance. + + ## Resources Created + + - **Virtual Machine**: A Linux or Windows VM with a system-assigned managed identity. + - **Networking**: A virtual network, subnet, network interface and network security group (plus an optional public IP). + - **Storage**: An OS disk and an optional data disk. + + ## Shared Responsibilities + + | Responsibility | Platform Team | Application Team | + | ----------------------------------------------- | :-----------: | :--------------: | + | Provision and configure VM infrastructure | ✅ | ❌ | + | Manage virtual networks and subnets | ✅ | ❌ | + | Provide secure access methods (Bastion, VPN) | ✅ | ❌ | + | Install and configure applications | ❌ | ✅ | + | Manage OS updates and patches | ❌ | ✅ | + | Manage user access and SSH keys / credentials | ❌ | ✅ | + EOT + ) + } + + version_spec = { + draft = var.hub.bbd_draft + + deletion_mode = "DELETE" + + implementation = { + terraform = { + terraform_version = "1.9.0" + repository_url = "https://github.com/meshcloud/meshstack-hub.git" + repository_path = "modules/azure/azure-virtual-machine/buildingblock" + ref_name = var.hub.git_ref + use_mesh_http_backend_fallback = true + } + } + + inputs = { + ARM_CLIENT_ID = { + type = "STRING" + display_name = "ARM Client ID" + description = "Client ID of the service principal used to authenticate with Azure." + assignment_type = "STATIC" + is_environment = true + argument = jsonencode(module.backplane.created_service_principal.client_id) + } + ARM_TENANT_ID = { + type = "STRING" + display_name = "ARM Tenant ID" + description = "Azure Entra tenant ID for authentication." + assignment_type = "STATIC" + is_environment = true + argument = jsonencode(var.azure_tenant_id) + } + ARM_USE_OIDC = { + type = "STRING" + display_name = "ARM Use OIDC" + description = "Enables OIDC-based workload identity federation for the Azure provider." + assignment_type = "STATIC" + is_environment = true + argument = jsonencode("true") + } + ARM_OIDC_TOKEN_FILE_PATH = { + type = "STRING" + display_name = "ARM OIDC Token File Path" + description = "Path to the OIDC token file used for workload identity federation authentication." + assignment_type = "STATIC" + is_environment = true + argument = jsonencode("/var/run/secrets/workload-identity/azure/token") + } + subscription_id = { + type = "STRING" + display_name = "Subscription ID" + description = "The Azure subscription ID (target tenant) where the virtual machine will be deployed." + assignment_type = "PLATFORM_TENANT_ID" + } + vm_name = { + type = "STRING" + display_name = "VM Name" + description = "The name of the virtual machine (also used to name the resource group and networking resources)." + assignment_type = "USER_INPUT" + } + location = { + type = "STRING" + display_name = "Location" + description = "The Azure region where the VM will be deployed." + assignment_type = "USER_INPUT" + default_value = jsonencode("westeurope") + } + os_type = { + type = "SINGLE_SELECT" + display_name = "OS Type" + description = "The operating system type." + assignment_type = "USER_INPUT" + selectable_values = ["Linux", "Windows"] + default_value = jsonencode("Linux") + } + vm_size = { + type = "STRING" + display_name = "VM Size" + description = "The size of the virtual machine." + assignment_type = "USER_INPUT" + default_value = jsonencode("Standard_B1s") + } + admin_username = { + type = "STRING" + display_name = "Admin Username" + description = "The admin username for the VM." + assignment_type = "USER_INPUT" + default_value = jsonencode("azureuser") + } + ssh_public_key = { + type = "STRING" + display_name = "SSH Public Key" + description = "SSH public key for Linux VM authentication (required for Linux). Leave empty for Windows." + assignment_type = "USER_INPUT" + default_value = jsonencode("") + } + admin_password = { + type = "STRING" + display_name = "Admin Password" + description = "Admin password for a Windows VM (required for Windows). Leave empty for Linux." + assignment_type = "USER_INPUT" + sensitive = { + default_value = { + secret_value = "" + } + } + } + enable_public_ip = { + type = "BOOLEAN" + display_name = "Enable Public IP" + description = "Whether to create and assign a public IP address to the VM." + assignment_type = "USER_INPUT" + default_value = jsonencode(false) + } + os_disk_size_gb = { + type = "INTEGER" + display_name = "OS Disk Size (GB)" + description = "The size of the OS disk in GB." + assignment_type = "USER_INPUT" + default_value = jsonencode(30) + } + data_disk_size_gb = { + type = "INTEGER" + display_name = "Data Disk Size (GB)" + description = "The size of the data disk in GB. Set to 0 to skip data disk creation." + assignment_type = "USER_INPUT" + default_value = jsonencode(0) + } + enable_spot_instance = { + type = "BOOLEAN" + display_name = "Enable Spot Instance" + description = "Run the VM as a cost-optimized spot instance (can be evicted when Azure needs capacity). Suitable for dev/test and non-critical workloads." + assignment_type = "USER_INPUT" + default_value = jsonencode(false) + } + } + + outputs = { + vm_id = { + type = "STRING" + display_name = "VM ID" + description = "The Azure resource ID of the virtual machine." + assignment_type = "NONE" + } + vm_name = { + type = "STRING" + display_name = "VM Name" + description = "The name of the virtual machine." + assignment_type = "NONE" + } + vm_private_ip = { + type = "STRING" + display_name = "Private IP" + description = "The private IP address of the VM." + assignment_type = "NONE" + } + vm_public_ip = { + type = "STRING" + display_name = "Public IP" + description = "The public IP address of the VM (if enabled)." + assignment_type = "NONE" + } + resource_group_name = { + type = "STRING" + display_name = "Resource Group" + description = "The name of the resource group containing the VM." + assignment_type = "NONE" + } + azure_portal_url = { + type = "STRING" + display_name = "Azure Portal URL" + description = "Direct link to the VM in the Azure Portal." + assignment_type = "NONE" + } + summary = { + type = "STRING" + display_name = "Summary" + description = "Markdown summary of the created VM with connection instructions." + assignment_type = "SUMMARY" + } + } + } +} + +terraform { + required_version = ">= 1.12.0" + + required_providers { + meshstack = { + source = "meshcloud/meshstack" + version = ">= 0.21.0" + } + azurerm = { + source = "hashicorp/azurerm" + version = ">= 4.50" + } + azuread = { + source = "hashicorp/azuread" + version = ">= 3.6" + } + } +} From 11a47c5fcc7d050d0fc8425ef9efcd10b4ab43e1 Mon Sep 17 00:00:00 2001 From: Mohammad Alhussan Date: Thu, 16 Jul 2026 14:50:11 +0200 Subject: [PATCH 3/4] feat: restrict azure-virtual-machine to Linux only meshStack has no optional-input concept, so the mutually-exclusive Linux/Windows credentials couldn't both be non-required. Drop Windows support (VM resources, os_type, admin_password) from the module and starter kit, leaving a required SSH key. --- .../buildingblock/README.md | 39 +----- .../buildingblock/main.tf | 55 +++----- .../buildingblock/outputs.tf | 8 +- .../buildingblock/variables.tf | 20 +-- .../e2e/main.tf | 1 - .../meshstack_integration.tf | 28 +--- .../buildingblock/APP_TEAM_README.md | 120 ------------------ .../buildingblock/README.md | 48 +------ .../buildingblock/main.tf | 76 +---------- .../buildingblock/outputs.tf | 21 +-- .../buildingblock/variables.tf | 20 +-- .../meshstack_integration.tf | 32 +---- 12 files changed, 61 insertions(+), 407 deletions(-) delete mode 100644 modules/azure/azure-virtual-machine/buildingblock/APP_TEAM_README.md diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/README.md b/modules/azure/azure-virtual-machine-starterkit/buildingblock/README.md index 12c52cf7..f885b670 100644 --- a/modules/azure/azure-virtual-machine-starterkit/buildingblock/README.md +++ b/modules/azure/azure-virtual-machine-starterkit/buildingblock/README.md @@ -21,7 +21,7 @@ The Azure VM Starterkit building block automates the creation of a complete Azur ## Features - Single unified project (no dev/prod separation) -- Flexible VM configuration (Linux or Windows) +- Linux VM with SSH key authentication - Optional public IP assignment - Automatic project admin assignment for the creator - Customizable project tags @@ -64,13 +64,11 @@ No modules. | [landing\_zone\_identifier](#input\_landing\_zone\_identifier) | Azure Landing zone identifier for the tenant. | `string` | n/a | yes | | [name](#input\_name) | This name will be used for the created project and VM | `string` | n/a | yes | | [project\_tags\_yaml](#input\_project\_tags\_yaml) | YAML configuration for project tags. Expected structure:
yaml
key1:
- "value1"
- "value2"
key2:
- "value3"
| `string` | `"{}"` | no | -| [vm\_admin\_password](#input\_vm\_admin\_password) | The admin password for Windows VM (required for Windows). | `string` | `null` | no | | [vm\_admin\_username](#input\_vm\_admin\_username) | The admin username for the VM. | `string` | `"azureuser"` | no | | [vm\_enable\_public\_ip](#input\_vm\_enable\_public\_ip) | Whether to create and assign a public IP address to the VM. | `bool` | `false` | no | | [vm\_location](#input\_vm\_location) | The Azure region where the VM will be deployed. | `string` | `"westeurope"` | no | -| [vm\_os\_type](#input\_vm\_os\_type) | The operating system type (Linux or Windows). | `string` | `"Linux"` | no | | [vm\_size](#input\_vm\_size) | The size of the virtual machine. | `string` | `"Standard_B1s"` | no | -| [vm\_ssh\_public\_key](#input\_vm\_ssh\_public\_key) | SSH public key for Linux VM authentication (required for Linux). | `string` | `null` | no | +| [vm\_ssh\_public\_key](#input\_vm\_ssh\_public\_key) | SSH public key used to authenticate as the VM's admin user. | `string` | n/a | yes | | [workspace\_identifier](#input\_workspace\_identifier) | The identifier of the meshStack workspace | `string` | n/a | yes | ## Outputs @@ -106,7 +104,6 @@ module "vm_starterkit" { username = "jdoe" } - vm_os_type = "Linux" vm_size = "Standard_B2s" vm_location = "westeurope" vm_ssh_public_key = file("~/.ssh/id_rsa.pub") @@ -114,39 +111,9 @@ module "vm_starterkit" { } ``` -### Windows VM - -```hcl -module "vm_starterkit" { - source = "./modules/azure/azure-virtual-machine/starterkit/buildingblock" - - workspace_identifier = "my-workspace" - name = "my-win-vm" - full_platform_identifier = "azure.my-platform" - landing_zone_identifier = "my-landing-zone" - - # Building block UUID - azure_vm_definition_version_uuid = "..." - - creator = { - type = "User" - identifier = "user456" - displayName = "Jane Smith" - username = "jsmith" - } - - vm_os_type = "Windows" - vm_size = "Standard_D2s_v3" - vm_location = "northeurope" - vm_admin_password = var.windows_admin_password - vm_enable_public_ip = true -} -``` - ## Notes - The resource group will be automatically created by the Azure VM building block -- Ensure SSH public key is provided for Linux VMs -- Ensure admin password is provided for Windows VMs +- An SSH public key is required (the VM uses SSH key authentication) - Public IP is disabled by default for security - Project tags can be customized using YAML format diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf b/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf index c9b232ff..b6ab924d 100644 --- a/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf +++ b/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf @@ -61,41 +61,26 @@ resource "meshstack_building_block" "azure_vm" { uuid = meshstack_tenant_v4.vm_tenant.metadata.uuid } display_name = "Azure Virtual Machine" - inputs = merge( - { - vm_name = { - value = jsonencode(local.identifier) - } - location = { - value = jsonencode(var.vm_location) - } - os_type = { - value = jsonencode(var.vm_os_type) - } - vm_size = { - value = jsonencode(var.vm_size) - } - admin_username = { - value = jsonencode(var.vm_admin_username) - } - enable_public_ip = { - value = jsonencode(var.vm_enable_public_ip) - } - }, - # Only send the OS-specific credential input for the matching OS. This mirrors - # the pre-v3 behavior where a null `value_string` omitted the input entirely; - # under v3 a `jsonencode(... : null)` would instead send an explicit JSON null. - var.vm_os_type == "Linux" ? { - ssh_public_key = { - value = jsonencode(var.vm_ssh_public_key) - } - } : {}, - var.vm_os_type == "Windows" ? { - admin_password = { - value = jsonencode(var.vm_admin_password) - } - } : {}, - ) + inputs = { + vm_name = { + value = jsonencode(local.identifier) + } + location = { + value = jsonencode(var.vm_location) + } + vm_size = { + value = jsonencode(var.vm_size) + } + admin_username = { + value = jsonencode(var.vm_admin_username) + } + enable_public_ip = { + value = jsonencode(var.vm_enable_public_ip) + } + ssh_public_key = { + value = jsonencode(var.vm_ssh_public_key) + } + } } } diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/outputs.tf b/modules/azure/azure-virtual-machine-starterkit/buildingblock/outputs.tf index 354c6986..794dc61c 100644 --- a/modules/azure/azure-virtual-machine-starterkit/buildingblock/outputs.tf +++ b/modules/azure/azure-virtual-machine-starterkit/buildingblock/outputs.tf @@ -32,14 +32,14 @@ This starter kit has set up the following resources in workspace `${var.workspac - **Azure Project**: A dedicated project for your virtual machine resources - **Azure Tenant**: An Azure subscription tenant with your chosen landing zone -- **Virtual Machine**: ${var.vm_os_type} VM (${var.vm_size}) in ${var.vm_location} +- **Virtual Machine**: Linux VM (${var.vm_size}) in ${var.vm_location} --- ## VM Details - **VM Name**: ${local.identifier} -- **Operating System**: ${var.vm_os_type} +- **Operating System**: Linux - **Size**: ${var.vm_size} - **Region**: ${var.vm_location} - **Public IP**: ${var.vm_enable_public_ip ? "Enabled" : "Disabled"} @@ -50,9 +50,7 @@ This starter kit has set up the following resources in workspace `${var.workspac ## Next Steps ### 1. Access Your VM -${var.vm_os_type == "Linux" && var.vm_enable_public_ip ? "- Connect via SSH using your provided SSH key" : ""} -${var.vm_os_type == "Windows" && var.vm_enable_public_ip ? "- Connect via RDP using the admin credentials" : ""} -${!var.vm_enable_public_ip ? "- Connect through Azure Bastion or VPN (no public IP assigned)" : ""} +${var.vm_enable_public_ip ? "- Connect via SSH using your provided SSH key" : "- Connect through Azure Bastion or VPN (no public IP assigned)"} ### 2. View Azure Resources - [Access Azure Tenant](/#/w/${var.workspace_identifier}/p/${meshstack_project.vm_project.metadata.name}/i/${var.full_platform_identifier}/overview) diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/variables.tf b/modules/azure/azure-virtual-machine-starterkit/buildingblock/variables.tf index 99f51169..69ac9ff7 100644 --- a/modules/azure/azure-virtual-machine-starterkit/buildingblock/variables.tf +++ b/modules/azure/azure-virtual-machine-starterkit/buildingblock/variables.tf @@ -63,16 +63,6 @@ variable "vm_location" { default = "westeurope" } -variable "vm_os_type" { - type = string - description = "The operating system type (Linux or Windows)." - default = "Linux" - validation { - condition = contains(["Linux", "Windows"], var.vm_os_type) - error_message = "vm_os_type must be either 'Linux' or 'Windows'" - } -} - variable "vm_size" { type = string description = "The size of the virtual machine." @@ -87,15 +77,7 @@ variable "vm_admin_username" { variable "vm_ssh_public_key" { type = string - description = "SSH public key for Linux VM authentication (required for Linux)." - default = null -} - -variable "vm_admin_password" { - type = string - description = "The admin password for Windows VM (required for Windows)." - default = null - sensitive = true + description = "SSH public key used to authenticate as the VM's admin user." } variable "vm_enable_public_ip" { diff --git a/modules/azure/azure-virtual-machine-starterkit/e2e/main.tf b/modules/azure/azure-virtual-machine-starterkit/e2e/main.tf index 0ca24dc0..e1779b84 100644 --- a/modules/azure/azure-virtual-machine-starterkit/e2e/main.tf +++ b/modules/azure/azure-virtual-machine-starterkit/e2e/main.tf @@ -107,7 +107,6 @@ resource "meshstack_building_block" "this" { inputs = { name = { value = jsonencode(local.vm_name) } - vm_os_type = { value = jsonencode("Linux") } vm_location = { value = jsonencode("westeurope") } vm_size = { value = jsonencode("Standard_B1s") } vm_enable_public_ip = { value = jsonencode(false) } diff --git a/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf b/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf index c513f2d3..305cae88 100644 --- a/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf +++ b/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf @@ -81,13 +81,13 @@ resource "meshstack_building_block_definition" "this" { This building block is ideal for teams that: - Need a quick, governed Azure VM without assembling project, tenant and VM wiring by hand. - - Want a Linux or Windows VM in a landing-zone-compliant tenant. + - Want a Linux VM in a landing-zone-compliant tenant. ## Resources Created - **Azure Project**: A dedicated meshProject for your virtual machine resources. - **Azure Tenant**: An Azure subscription tenant on your chosen landing zone. - - **Virtual Machine**: A Linux or Windows VM (composed via the Azure Virtual Machine building block). + - **Virtual Machine**: A Linux VM (composed via the Azure Virtual Machine building block). ## Shared Responsibilities @@ -169,14 +169,6 @@ resource "meshstack_building_block_definition" "this" { type = "STRING" default_value = jsonencode("westeurope") } - "vm_os_type" = { - assignment_type = "USER_INPUT" - description = "Operating system type." - display_name = "VM OS Type" - type = "SINGLE_SELECT" - selectable_values = ["Linux", "Windows"] - default_value = jsonencode("Linux") - } "vm_size" = { assignment_type = "USER_INPUT" description = "Size of the virtual machine." @@ -193,23 +185,9 @@ resource "meshstack_building_block_definition" "this" { } "vm_ssh_public_key" = { assignment_type = "USER_INPUT" - description = "SSH public key for Linux VM authentication (required for Linux). Leave empty for Windows." + description = "SSH public key used to authenticate as the VM's admin user." display_name = "VM SSH Public Key" type = "STRING" - # Only one of ssh_public_key / admin_password applies per OS; default both to empty so - # neither is force-required in the form. The buildingblock validates the correct one per vm_os_type. - default_value = jsonencode("") - } - "vm_admin_password" = { - assignment_type = "USER_INPUT" - description = "Admin password for a Windows VM (required for Windows). Leave empty for Linux." - display_name = "VM Admin Password" - type = "STRING" - sensitive = { - default_value = { - secret_value = "" - } - } } "vm_enable_public_ip" = { assignment_type = "USER_INPUT" diff --git a/modules/azure/azure-virtual-machine/buildingblock/APP_TEAM_README.md b/modules/azure/azure-virtual-machine/buildingblock/APP_TEAM_README.md deleted file mode 100644 index e25ad761..00000000 --- a/modules/azure/azure-virtual-machine/buildingblock/APP_TEAM_README.md +++ /dev/null @@ -1,120 +0,0 @@ -# Azure Virtual Machine - -## Description -An Azure Virtual Machine (VM) is an on-demand, scalable computing resource that provides the flexibility of virtualization without the need to buy and maintain physical hardware. Azure VMs support both Linux and Windows operating systems and can be configured with various sizes and capabilities to meet specific workload requirements. - -Key features include: -- **Flexible Sizing**: Choose from a wide range of VM sizes optimized for different workloads (general purpose, compute-intensive, memory-optimized, etc.) -- **Multiple OS Support**: Run Linux distributions or Windows Server -- **Managed Disks**: Persistent storage for OS and data with various performance tiers -- **Network Isolation**: Deploy VMs in virtual networks with network security groups for enhanced security -- **Managed Identity**: System-assigned identities for secure authentication to Azure services without storing credentials - -## Usage Motivation -This building block provisions Azure Virtual Machines to provide isolated, dedicated compute resources for various workloads. VMs are ideal when you need: -- Full control over the operating system and software stack -- Ability to install custom applications or legacy software -- Dedicated compute resources with predictable performance -- Migration of on-premises workloads to the cloud (lift-and-shift) - -## Usage Examples - -### Development and Testing Environments -Deploy VMs for development teams to create isolated environments for building and testing applications. Each team can have their own VM with specific configurations, tools, and dependencies without affecting other teams. - -### Application Hosting -Host web applications, APIs, or microservices on VMs when containerization isn't feasible or when you need full OS control. The VM can run application servers like Apache, Nginx, IIS, or custom software stacks. - -### Database Servers -Deploy VMs to host database management systems like PostgreSQL, MySQL, SQL Server, or MongoDB when managed database services don't meet specific requirements or when migrating existing database installations. - -### Build and CI/CD Agents -Use VMs as build agents for CI/CD pipelines, providing isolated environments for compiling code, running tests, and creating deployment artifacts. - -### Data Processing -Deploy VMs for batch processing jobs, data transformation tasks, or computational workloads that require specific software or configurations. - -## Shared Responsibility - -| Responsibility | Platform Team | Application Team | -|------------------------|--------------|----------------| -| Provisioning and configuring VM infrastructure | ✅ | ❌ | -| Managing virtual networks and subnets | ✅ | ❌ | -| Providing secure access methods (Bastion, VPN) | ✅ | ❌ | -| Installing and configuring applications | ❌ | ✅ | -| Managing OS updates and patches | ❌ | ✅ | -| Configuring firewall rules and NSG policies | ✅ | ⚠️ (within team's NSG) | -| Backup and disaster recovery configuration | ⚠️ | ✅ | -| Monitoring application performance | ❌ | ✅ | -| Managing user access and SSH keys | ❌ | ✅ | - -## VM Size Selection Guide - -Choose the appropriate VM size based on your workload requirements: - -| VM Series | Use Case | Example Sizes | -|-----------|----------|---------------| -| **B-Series** | Burstable, cost-effective for low CPU utilization | B1s, B2s, B2ms | -| **D-Series** | General purpose, balanced CPU-to-memory | D2s_v3, D4s_v3, D8s_v3 | -| **E-Series** | Memory-optimized, high memory-to-CPU ratio | E4s_v3, E8s_v3, E16s_v3 | -| **F-Series** | Compute-optimized, high CPU-to-memory ratio | F4s_v2, F8s_v2, F16s_v2 | - -Start with smaller sizes (e.g., B2s for dev/test) and scale up as needed. - -## Recommendations for Secure and Efficient VM Usage - -### Security Best Practices -- **Avoid Public IPs**: Use Azure Bastion or VPN for remote access instead of exposing VMs to the internet -- **Use SSH Keys**: For Linux VMs, always use SSH key authentication instead of passwords -- **Strong Passwords**: For Windows VMs, use complex passwords and consider Azure AD integration -- **Managed Identity**: Leverage system-assigned managed identities to authenticate to Azure services -- **Network Security Groups**: Configure NSG rules to allow only necessary traffic -- **Regular Updates**: Keep the OS and applications updated with the latest security patches -- **Azure Security Center**: Enable for security recommendations and threat detection - -### Performance and Cost Optimization -- **Right-Size VMs**: Monitor resource utilization and adjust VM size accordingly -- **Use Premium SSD**: For production workloads requiring consistent performance -- **Spot Instances**: Enable spot instances for dev/test and non-critical workloads to save up to 90% on costs - - Be aware that spot VMs can be evicted when Azure needs capacity - - Best for stateless workloads and batch processing - - Not suitable for production or databases with local data -- **Reserved Instances**: Purchase reserved instances for long-running production VMs to save costs -- **Auto-Shutdown**: Configure automatic shutdown schedules for non-production VMs -- **Azure Hybrid Benefit**: Use existing Windows Server licenses to reduce costs - -### Operational Best Practices -- **Backup Strategy**: Implement regular backups using Azure Backup -- **Monitoring**: Enable Azure Monitor and configure alerts for critical metrics -- **Tagging**: Apply consistent tags for cost tracking and resource management -- **Documentation**: Document VM purpose, configurations, and dependencies -- **Disaster Recovery**: Plan for disaster recovery with Azure Site Recovery if needed - -### Data Disk Best Practices -- **Separate OS and Data**: Use separate data disks for application data -- **Choose Right Storage Type**: Use Premium SSD for I/O intensive workloads, Standard SSD for regular workloads -- **Plan Disk Size**: Provision appropriate disk size upfront as resizing requires downtime - -## Getting Started - -### For Linux VMs -1. Generate an SSH key pair if you don't have one: `ssh-keygen -t rsa -b 4096` -2. Request VM provisioning with your public key -3. Connect via SSH: `ssh azureuser@` -4. Install required software and configure your application - -### For Windows VMs -1. Request VM provisioning with a secure password -2. Connect via Azure Bastion or RDP -3. Configure Windows features and install required software -4. Set up your application and services - -## Support and Troubleshooting - -Common issues and solutions: -- **Cannot connect to VM**: Verify NSG rules allow traffic and check if VM is running -- **Slow performance**: Check VM metrics in Azure Monitor, consider scaling up or optimizing workload -- **Disk full**: Monitor disk usage and attach additional data disks or resize existing disks -- **Application errors**: Check VM logs, event viewer (Windows), or system logs (Linux) - -For additional support, contact the Platform Team. diff --git a/modules/azure/azure-virtual-machine/buildingblock/README.md b/modules/azure/azure-virtual-machine/buildingblock/README.md index 6b6f7f18..126b852a 100644 --- a/modules/azure/azure-virtual-machine/buildingblock/README.md +++ b/modules/azure/azure-virtual-machine/buildingblock/README.md @@ -3,16 +3,16 @@ name: Azure Virtual Machine supportedPlatforms: - azure description: | - (ALPHA) Provisions an Azure Virtual Machine (VM) with support for both Linux and Windows operating systems, including network interface, optional public IP, network security group, and optional data disk. + (ALPHA) Provisions a Linux Azure Virtual Machine (VM) including network interface, optional public IP, network security group, and optional data disk. --- # Azure Virtual Machine -This Terraform module provisions an Azure Virtual Machine along with necessary networking components and optional data disks. +This Terraform module provisions a Linux Azure Virtual Machine along with necessary networking components and optional data disks. ## Features -- Support for both Linux and Windows VMs +- Linux VM with SSH key authentication - Automatic virtual network and subnet creation - Configurable network address spaces - Configurable VM size and disk types @@ -54,7 +54,6 @@ module "linux_vm" { vm_name = "my-linux-vm" resource_group_name = "my-rg" location = "West Europe" - os_type = "Linux" vm_size = "Standard_B2s" admin_username = "azureuser" ssh_public_key = file("~/.ssh/id_rsa.pub") @@ -71,33 +70,6 @@ module "linux_vm" { } ``` -### Windows VM with Password - -```hcl -module "windows_vm" { - source = "./buildingblock" - - vm_name = "my-windows-vm" - resource_group_name = "my-rg" - location = "West Europe" - os_type = "Windows" - vm_size = "Standard_D2s_v3" - admin_username = "adminuser" - admin_password = "P@ssw0rd123!" - enable_public_ip = true - - image_publisher = "MicrosoftWindowsServer" - image_offer = "WindowsServer" - image_sku = "2022-datacenter-azure-edition" - image_version = "latest" - - tags = { - Environment = "Production" - Project = "MyProject" - } -} -``` - ### VM with Data Disk ```hcl @@ -107,7 +79,6 @@ module "vm_with_data_disk" { vm_name = "my-vm-with-disk" resource_group_name = "my-rg" location = "West Europe" - os_type = "Linux" admin_username = "azureuser" ssh_public_key = file("~/.ssh/id_rsa.pub") @@ -125,7 +96,6 @@ module "spot_vm" { vm_name = "my-spot-vm" resource_group_name = "my-rg" location = "West Europe" - os_type = "Linux" admin_username = "azureuser" ssh_public_key = file("~/.ssh/id_rsa.pub") @@ -157,15 +127,12 @@ No modules. | [azurerm_network_interface.vm_nic](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_interface) | resource | | [azurerm_network_interface_security_group_association.vm_nsg_association](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_interface_security_group_association) | resource | | [azurerm_network_security_group.vm_nsg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group) | resource | -| [azurerm_network_security_rule.allow_rdp](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_rule) | resource | | [azurerm_network_security_rule.allow_ssh](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_rule) | resource | | [azurerm_public_ip.vm_public_ip](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/public_ip) | resource | | [azurerm_resource_group.vm_rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | | [azurerm_subnet.vm_subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource | -| [azurerm_virtual_machine_data_disk_attachment.linux_data_disk_attachment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_data_disk_attachment) | resource | -| [azurerm_virtual_machine_data_disk_attachment.windows_data_disk_attachment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_data_disk_attachment) | resource | +| [azurerm_virtual_machine_data_disk_attachment.data_disk_attachment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_data_disk_attachment) | resource | | [azurerm_virtual_network.vm_vnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network) | resource | -| [azurerm_windows_virtual_machine.vm](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/windows_virtual_machine) | resource | | [random_string.resource_code](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | | [azurerm_client_config.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/client_config) | data source | | [azurerm_resource_group.vm_rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source | @@ -175,7 +142,6 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [admin\_password](#input\_admin\_password) | The admin password for Windows VM (required for Windows) | `string` | `null` | no | | [admin\_username](#input\_admin\_username) | The admin username for the VM | `string` | `"azureuser"` | no | | [data\_disk\_size\_gb](#input\_data\_disk\_size\_gb) | The size of the data disk in GB. Set to 0 to skip data disk creation | `number` | `0` | no | | [data\_disk\_storage\_type](#input\_data\_disk\_storage\_type) | The storage account type for the data disk | `string` | `"Standard_LRS"` | no | @@ -188,11 +154,10 @@ No modules. | [location](#input\_location) | The Azure region where resources will be deployed | `string` | n/a | yes | | [os\_disk\_size\_gb](#input\_os\_disk\_size\_gb) | The size of the OS disk in GB | `number` | `30` | no | | [os\_disk\_storage\_type](#input\_os\_disk\_storage\_type) | The storage account type for the OS disk | `string` | `"Standard_LRS"` | no | -| [os\_type](#input\_os\_type) | The operating system type (Linux or Windows) | `string` | `"Linux"` | no | | [resource\_group\_name](#input\_resource\_group\_name) | The name or full resource ID of the resource group (e.g., '/subscriptions/.../resourceGroups/my-rg'). If not provided, a new resource group will be created. | `string` | `null` | no | | [spot\_eviction\_policy](#input\_spot\_eviction\_policy) | Eviction policy for spot instances (Deallocate or Delete) | `string` | `"Deallocate"` | no | | [spot\_max\_bid\_price](#input\_spot\_max\_bid\_price) | Maximum price to pay for spot instance per hour. -1 means pay up to on-demand price. Default is -1 for maximum availability | `number` | `-1` | no | -| [ssh\_public\_key](#input\_ssh\_public\_key) | SSH public key for Linux VM authentication (required for Linux) | `string` | `null` | no | +| [ssh\_public\_key](#input\_ssh\_public\_key) | SSH public key for the VM's admin user. | `string` | n/a | yes | | [subnet\_address\_prefix](#input\_subnet\_address\_prefix) | The address prefix for the subnet | `string` | `"10.0.1.0/24"` | no | | [subscription\_id](#input\_subscription\_id) | The Azure subscription ID where the virtual machine will be deployed (the target tenant's subscription). | `string` | n/a | yes | | [tags](#input\_tags) | Tags to apply to all resources | `map(string)` | `{}` | no | @@ -247,6 +212,5 @@ Azure Spot VMs offer significant cost savings (up to 90% off on-demand prices) b - VMs are deployed with system-assigned managed identities for secure Azure resource access - Network Security Groups are automatically created for network isolation -- Linux VMs use SSH key authentication (password authentication disabled) -- Windows VMs require secure password configuration +- VMs use SSH key authentication (password authentication disabled) - Consider using Azure Bastion or VPN for secure remote access instead of public IPs diff --git a/modules/azure/azure-virtual-machine/buildingblock/main.tf b/modules/azure/azure-virtual-machine/buildingblock/main.tf index 6c9d8bf8..c081fc10 100644 --- a/modules/azure/azure-virtual-machine/buildingblock/main.tf +++ b/modules/azure/azure-virtual-machine/buildingblock/main.tf @@ -95,9 +95,9 @@ resource "azurerm_network_security_group" "vm_nsg" { tags = var.tags } -# NSG Rule: Allow SSH for Linux VMs with public IP +# NSG Rule: Allow SSH when a public IP is assigned resource "azurerm_network_security_rule" "allow_ssh" { - count = var.os_type == "Linux" && var.enable_public_ip ? 1 : 0 + count = var.enable_public_ip ? 1 : 0 name = "AllowSSH" priority = 1000 direction = "Inbound" @@ -111,22 +111,6 @@ resource "azurerm_network_security_rule" "allow_ssh" { network_security_group_name = azurerm_network_security_group.vm_nsg.name } -# NSG Rule: Allow RDP for Windows VMs with public IP -resource "azurerm_network_security_rule" "allow_rdp" { - count = var.os_type == "Windows" && var.enable_public_ip ? 1 : 0 - name = "AllowRDP" - priority = 1001 - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "3389" - source_address_prefix = "*" - destination_address_prefix = "*" - resource_group_name = local.rg_name - network_security_group_name = azurerm_network_security_group.vm_nsg.name -} - # NSG Association resource "azurerm_network_interface_security_group_association" "vm_nsg_association" { network_interface_id = azurerm_network_interface.vm_nic.id @@ -135,7 +119,6 @@ resource "azurerm_network_interface_security_group_association" "vm_nsg_associat # Linux Virtual Machine resource "azurerm_linux_virtual_machine" "vm" { - count = var.os_type == "Linux" ? 1 : 0 name = var.vm_name location = local.rg_location resource_group_name = local.rg_name @@ -177,44 +160,6 @@ resource "azurerm_linux_virtual_machine" "vm" { tags = var.tags } -# Windows Virtual Machine -resource "azurerm_windows_virtual_machine" "vm" { - count = var.os_type == "Windows" ? 1 : 0 - name = var.vm_name - location = local.rg_location - resource_group_name = local.rg_name - size = var.vm_size - admin_username = var.admin_username - admin_password = var.admin_password - - network_interface_ids = [ - azurerm_network_interface.vm_nic.id, - ] - - os_disk { - caching = "ReadWrite" - storage_account_type = var.os_disk_storage_type - disk_size_gb = var.os_disk_size_gb - } - - source_image_reference { - publisher = var.image_publisher - offer = var.image_offer - sku = var.image_sku - version = var.image_version - } - - identity { - type = "SystemAssigned" - } - - priority = var.enable_spot_instance ? "Spot" : "Regular" - eviction_policy = var.enable_spot_instance ? var.spot_eviction_policy : null - max_bid_price = var.enable_spot_instance ? var.spot_max_bid_price : null - - tags = var.tags -} - # Managed Data Disk (optional) resource "azurerm_managed_disk" "data_disk" { count = var.data_disk_size_gb > 0 ? 1 : 0 @@ -228,20 +173,11 @@ resource "azurerm_managed_disk" "data_disk" { tags = var.tags } -# Attach Data Disk to Linux VM -resource "azurerm_virtual_machine_data_disk_attachment" "linux_data_disk_attachment" { - count = var.os_type == "Linux" && var.data_disk_size_gb > 0 ? 1 : 0 - managed_disk_id = azurerm_managed_disk.data_disk[0].id - virtual_machine_id = azurerm_linux_virtual_machine.vm[0].id - lun = 0 - caching = "ReadWrite" -} - -# Attach Data Disk to Windows VM -resource "azurerm_virtual_machine_data_disk_attachment" "windows_data_disk_attachment" { - count = var.os_type == "Windows" && var.data_disk_size_gb > 0 ? 1 : 0 +# Attach Data Disk to the VM +resource "azurerm_virtual_machine_data_disk_attachment" "data_disk_attachment" { + count = var.data_disk_size_gb > 0 ? 1 : 0 managed_disk_id = azurerm_managed_disk.data_disk[0].id - virtual_machine_id = azurerm_windows_virtual_machine.vm[0].id + virtual_machine_id = azurerm_linux_virtual_machine.vm.id lun = 0 caching = "ReadWrite" } diff --git a/modules/azure/azure-virtual-machine/buildingblock/outputs.tf b/modules/azure/azure-virtual-machine/buildingblock/outputs.tf index 72465152..e5525a9d 100644 --- a/modules/azure/azure-virtual-machine/buildingblock/outputs.tf +++ b/modules/azure/azure-virtual-machine/buildingblock/outputs.tf @@ -1,5 +1,5 @@ output "vm_id" { - value = var.os_type == "Linux" ? azurerm_linux_virtual_machine.vm[0].id : azurerm_windows_virtual_machine.vm[0].id + value = azurerm_linux_virtual_machine.vm.id description = "The ID of the virtual machine" } @@ -44,7 +44,7 @@ output "subnet_id" { } output "vm_identity_principal_id" { - value = var.os_type == "Linux" ? azurerm_linux_virtual_machine.vm[0].identity[0].principal_id : azurerm_windows_virtual_machine.vm[0].identity[0].principal_id + value = azurerm_linux_virtual_machine.vm.identity[0].principal_id description = "The Principal ID of the system-assigned managed identity" } @@ -65,7 +65,7 @@ Your Azure Virtual Machine was successfully created! - **Name**: ${var.vm_name} - **Resource Group**: ${local.rg_name} - **Location**: ${local.rg_location} -- **Operating System**: ${var.os_type} +- **Operating System**: Linux - **VM Size**: ${var.vm_size} - **Private IP**: ${azurerm_network_interface.vm_nic.private_ip_address}${var.enable_public_ip ? "\n- **Public IP**: ${azurerm_public_ip.vm_public_ip[0].ip_address}" : ""} - **Spot Instance**: ${var.enable_spot_instance ? "Yes (cost-optimized)" : "No"} @@ -84,20 +84,23 @@ Your Azure Virtual Machine was successfully created! ## Connection Instructions -### ${var.os_type == "Linux" ? "For Linux VM (SSH)" : "For Windows VM (RDP)"} +Connect to your Linux VM using SSH: -${var.os_type == "Linux" ? "Connect to your Linux VM using SSH:" : "Connect to your Windows VM using Remote Desktop Protocol (RDP):"} - -${var.os_type == "Linux" ? "```bash\n# If using Azure Bastion or VPN (recommended):\nssh ${var.admin_username}@${azurerm_network_interface.vm_nic.private_ip_address}\n${var.enable_public_ip ? "\n# If public IP is enabled (less secure):\nssh ${var.admin_username}@${azurerm_public_ip.vm_public_ip[0].ip_address}\n" : ""}```" : "```powershell\n# If using Azure Bastion (recommended):\n# Use Azure Portal to connect via Bastion\n${var.enable_public_ip ? "\n# If public IP is enabled:\nmstsc /v:${azurerm_public_ip.vm_public_ip[0].ip_address}\n# Username: ${var.admin_username}\n" : ""}\n```"} +```bash +# If using Azure Bastion or VPN (recommended): +ssh ${var.admin_username}@${azurerm_network_interface.vm_nic.private_ip_address} +${var.enable_public_ip ? "\n# If public IP is enabled (less secure):\nssh ${var.admin_username}@${azurerm_public_ip.vm_public_ip[0].ip_address}\n" : ""}``` ${!var.enable_public_ip ? "**Note**: This VM does not have a public IP. Use Azure Bastion, VPN, or a jump host to connect." : "**Security Warning**: This VM has a public IP. Consider using Azure Bastion for more secure access."} -${var.os_type == "Linux" ? "### SSH Key Authentication\n\nThis VM is configured with SSH key authentication. Ensure you have the private key corresponding to the public key used during provisioning." : "### Windows Authentication\n\nUse the admin username and password configured during provisioning."} +### SSH Key Authentication + +This VM is configured with SSH key authentication. Ensure you have the private key corresponding to the public key used during provisioning. ## Managed Identity This VM has a system-assigned managed identity enabled: -- **Principal ID**: ${var.os_type == "Linux" ? azurerm_linux_virtual_machine.vm[0].identity[0].principal_id : azurerm_windows_virtual_machine.vm[0].identity[0].principal_id} +- **Principal ID**: ${azurerm_linux_virtual_machine.vm.identity[0].principal_id} Use this identity to grant the VM access to other Azure resources without storing credentials. diff --git a/modules/azure/azure-virtual-machine/buildingblock/variables.tf b/modules/azure/azure-virtual-machine/buildingblock/variables.tf index 9b3609a6..33f4272c 100644 --- a/modules/azure/azure-virtual-machine/buildingblock/variables.tf +++ b/modules/azure/azure-virtual-machine/buildingblock/variables.tf @@ -31,16 +31,6 @@ variable "subnet_address_prefix" { default = "10.0.1.0/24" } -variable "os_type" { - type = string - description = "The operating system type (Linux or Windows)" - default = "Linux" - validation { - condition = contains(["Linux", "Windows"], var.os_type) - error_message = "os_type must be either 'Linux' or 'Windows'" - } -} - variable "vm_size" { type = string description = "The size of the virtual machine" @@ -53,17 +43,9 @@ variable "admin_username" { default = "azureuser" } -variable "admin_password" { - type = string - description = "The admin password for Windows VM (required for Windows)" - default = null - sensitive = true -} - variable "ssh_public_key" { type = string - description = "SSH public key for Linux VM authentication (required for Linux)" - default = null + description = "SSH public key for the VM's admin user." } variable "enable_public_ip" { diff --git a/modules/azure/azure-virtual-machine/meshstack_integration.tf b/modules/azure/azure-virtual-machine/meshstack_integration.tf index 990afc8a..fbdca1bd 100644 --- a/modules/azure/azure-virtual-machine/meshstack_integration.tf +++ b/modules/azure/azure-virtual-machine/meshstack_integration.tf @@ -76,7 +76,7 @@ resource "meshstack_building_block_definition" "this" { spec = { display_name = "Azure Virtual Machine" - description = "Provisions a single Azure Virtual Machine (Linux or Windows) with its own virtual network, subnet, network security group and optional public IP and data disk, in the target tenant's subscription." + description = "Provisions a single Linux Azure Virtual Machine with its own virtual network, subnet, network security group and optional public IP and data disk, in the target tenant's subscription." support_url = "mailto:support@meshcloud.io" documentation_url = "https://hub.meshcloud.io/platforms/azure/definitions/azure-virtual-machine" notification_subscribers = var.notification_subscribers @@ -85,19 +85,19 @@ resource "meshstack_building_block_definition" "this" { supported_platforms = [{ name = "AZURE" }] readme = chomp(<<-EOT - Provisions a single **Azure Virtual Machine** (Linux or Windows) with a dedicated virtual network, subnet, network security group, system-assigned managed identity and an optional public IP and data disk. The VM is deployed into the target tenant's Azure subscription. + Provisions a single **Linux Azure Virtual Machine** with a dedicated virtual network, subnet, network security group, system-assigned managed identity and an optional public IP and data disk. The VM is deployed into the target tenant's Azure subscription. ## 🎯 When to use it - Use this building block when your team needs a dedicated compute instance with full OS control, for example to: + Use this building block when your team needs a dedicated Linux compute instance with full OS control, for example to: - - Run a Linux or Windows workload that isn't a good fit for managed/containerized services. + - Run a Linux workload that isn't a good fit for managed/containerized services. - Host an application server, database, build agent or lift-and-shift migration. - Get an isolated dev/test environment with predictable performance. ## Resources Created - - **Virtual Machine**: A Linux or Windows VM with a system-assigned managed identity. + - **Virtual Machine**: A Linux VM with a system-assigned managed identity. - **Networking**: A virtual network, subnet, network interface and network security group (plus an optional public IP). - **Storage**: An OS disk and an optional data disk. @@ -182,14 +182,6 @@ resource "meshstack_building_block_definition" "this" { assignment_type = "USER_INPUT" default_value = jsonencode("westeurope") } - os_type = { - type = "SINGLE_SELECT" - display_name = "OS Type" - description = "The operating system type." - assignment_type = "USER_INPUT" - selectable_values = ["Linux", "Windows"] - default_value = jsonencode("Linux") - } vm_size = { type = "STRING" display_name = "VM Size" @@ -207,20 +199,8 @@ resource "meshstack_building_block_definition" "this" { ssh_public_key = { type = "STRING" display_name = "SSH Public Key" - description = "SSH public key for Linux VM authentication (required for Linux). Leave empty for Windows." - assignment_type = "USER_INPUT" - default_value = jsonencode("") - } - admin_password = { - type = "STRING" - display_name = "Admin Password" - description = "Admin password for a Windows VM (required for Windows). Leave empty for Linux." + description = "SSH public key used to authenticate as the VM's admin user." assignment_type = "USER_INPUT" - sensitive = { - default_value = { - secret_value = "" - } - } } enable_public_ip = { type = "BOOLEAN" From 90c9bd9847dd0f04065e79c06fc29284a85c6420 Mon Sep 17 00:00:00 2001 From: Mohammad Alhussan Date: Thu, 16 Jul 2026 17:19:25 +0200 Subject: [PATCH 4/4] feat: bump azure-vm BBDs to OpenTofu 1.11.5 Enables the meshstack_building_block_v2 -> meshstack_building_block moved block: cross-type moves need OpenTofu >= 1.10 (1.9 errors "Resource type mismatch"), and the provider implements the move since v0.23.0. --- .../azure-virtual-machine-starterkit/meshstack_integration.tf | 2 +- modules/azure/azure-virtual-machine/meshstack_integration.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf b/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf index 305cae88..1a4a3ebc 100644 --- a/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf +++ b/modules/azure/azure-virtual-machine-starterkit/meshstack_integration.tf @@ -109,7 +109,7 @@ resource "meshstack_building_block_definition" "this" { implementation = { terraform = { repository_url = "https://github.com/meshcloud/meshstack-hub.git" - terraform_version = "1.9.0" + terraform_version = "1.11.5" async = false ref_name = var.hub.git_ref repository_path = "modules/azure/azure-virtual-machine-starterkit/buildingblock" diff --git a/modules/azure/azure-virtual-machine/meshstack_integration.tf b/modules/azure/azure-virtual-machine/meshstack_integration.tf index fbdca1bd..57527a3a 100644 --- a/modules/azure/azure-virtual-machine/meshstack_integration.tf +++ b/modules/azure/azure-virtual-machine/meshstack_integration.tf @@ -122,7 +122,7 @@ resource "meshstack_building_block_definition" "this" { implementation = { terraform = { - terraform_version = "1.9.0" + terraform_version = "1.11.5" repository_url = "https://github.com/meshcloud/meshstack-hub.git" repository_path = "modules/azure/azure-virtual-machine/buildingblock" ref_name = var.hub.git_ref