diff --git a/integrations/terraform-modules/Makefile b/integrations/terraform-modules/Makefile index 86a44cf628690..8650bd5a0d85b 100644 --- a/integrations/terraform-modules/Makefile +++ b/integrations/terraform-modules/Makefile @@ -21,7 +21,7 @@ docs: $(README_FILES) ; terraform-docs markdown table --config .terraform-docs.yml $* .PHONY: check -check: +check: clean git ls-files -- . \ | xargs pre-commit run --hook-stage=manual --verbose --files diff --git a/integrations/terraform-modules/teleport/discovery/azure/LICENSE b/integrations/terraform-modules/teleport/discovery/azure/LICENSE new file mode 100644 index 0000000000000..261eeb9e9f8b2 --- /dev/null +++ b/integrations/terraform-modules/teleport/discovery/azure/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/integrations/terraform-modules/teleport/discovery/azure/README.md b/integrations/terraform-modules/teleport/discovery/azure/README.md new file mode 100644 index 0000000000000..b855e9296d3dd --- /dev/null +++ b/integrations/terraform-modules/teleport/discovery/azure/README.md @@ -0,0 +1,100 @@ +# Azure Discovery Terraform module + +This Terraform module creates the Azure and Teleport cluster resources necessary for a Teleport cluster to discover Azure virtual machines: + +- **Azure user-assigned managed identity**: Used by the Teleport Discovery Service to authenticate to Azure APIs for scanning and managing VMs in matching Azure resource groups. +- **Azure federated identity credential**: Establishes trust between Azure and your Teleport cluster by allowing the managed identity to authenticate using OIDC tokens issued by your Teleport proxy. +- **Azure custom role definition and assignment**: Grants the managed identity the minimum required permissions to discover VMs and run installation commands on them. +- **Teleport `discovery_config` cluster resource**: Configures the discovery parameters (subscriptions, resource groups, tags) that determine which Azure VMs will be discovered and enrolled. +- **Teleport `integration` cluster resource**: Stores the Azure OIDC integration configuration in your Teleport cluster, linking the Azure tenant and client ID to enable authentication. +- **Teleport `token` cluster resource**: Provides the join token that discovered Azure VMs will use to authenticate and join your Teleport cluster. + +## Prerequisites + +- [Install Teleport Terraform Provider](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider/) +- Every Azure VM to be discovered must have a managed identity assigned to it with at least the Microsoft.Compute/virtualMachines/read permission. [Read more](https://goteleport.com/docs/enroll-resources/auto-discovery/servers/azure-discovery/#step-35-set-up-managed-identities-for-discovered-nodes) + +## Examples + +- [Discover VMs in a single Azure subscription](./examples/single-subscription) + +## How to get help + +If you're having trouble, check out our [GitHub Discussions](https://github.com/gravitational/teleport/discussions). + +For bugs related to this code, please [open an issue](https://github.com/gravitational/teleport/issues/new/choose). + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.5.7 | +| [azurerm](#requirement\_azurerm) | >= 4.0 | +| [http](#requirement\_http) | >= 3.0 | +| [teleport](#requirement\_teleport) | >= 18.5.1 | + +## Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | >= 4.0 | +| [http](#provider\_http) | >= 3.0 | +| [teleport](#provider\_teleport) | >= 18.5.1 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [azurerm_federated_identity_credential.teleport_discovery_service](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/federated_identity_credential) | resource | +| [azurerm_role_assignment.teleport_discovery](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource | +| [azurerm_role_definition.teleport_discovery](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource | +| [azurerm_user_assigned_identity.teleport_discovery_service](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource | +| teleport_discovery_config.azure | resource | +| teleport_integration.azure_oidc | resource | +| teleport_provision_token.azure | resource | +| [azurerm_client_config.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/client_config) | data source | +| [http_http.teleport_ping](https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [apply\_azure\_tags](#input\_apply\_azure\_tags) | Additional Azure tags to apply to all created Azure resources. | `map(string)` | `{}` | no | +| [apply\_teleport\_resource\_labels](#input\_apply\_teleport\_resource\_labels) | Additional Teleport resource labels to apply to all created Teleport resources. | `map(string)` | `{}` | no | +| [azure\_federated\_identity\_credential\_name](#input\_azure\_federated\_identity\_credential\_name) | Name of the Azure federated identity credential created for workload identity federation. | `string` | `"teleport-federation"` | no | +| [azure\_managed\_identity\_location](#input\_azure\_managed\_identity\_location) | Azure region (location) where the managed identity will be created (e.g., "westus"). | `string` | n/a | yes | +| [azure\_managed\_identity\_name](#input\_azure\_managed\_identity\_name) | Name of the Azure user-assigned managed identity created for Teleport Discovery. | `string` | `"discovery-identity"` | no | +| [azure\_resource\_group\_name](#input\_azure\_resource\_group\_name) | Name of an existing Azure Resource Group where Azure resources will be created. | `string` | n/a | yes | +| [azure\_role\_assignable\_scopes](#input\_azure\_role\_assignable\_scopes) | The scopes at which the Azure discovery role will be assignable. Defaults to the current subscription. | `list(string)` | `[]` | no | +| [azure\_role\_assignment\_scopes](#input\_azure\_role\_assignment\_scopes) | The scopes at which the Azure discovery role will be assigned. Must be a management group ID like /providers/Microsoft.Management/managementGroups/ to support wildcard ('*') Azure subscription discovery. Defaults to the subscription of the azurerm provider. | `list(string)` | `[]` | no | +| [azure\_role\_definition\_name](#input\_azure\_role\_definition\_name) | Name for the Azure custom role definition created for Teleport Discovery. | `string` | `"teleport-discovery"` | no | +| [create](#input\_create) | Toggle creation of all resources. | `bool` | `true` | no | +| [match\_azure\_regions](#input\_match\_azure\_regions) | Azure regions to discover. Defaults to ["*"] which matches all regions. Region names should be the programmatic region name, e.g., "westus". | `list(string)` |
[
"*"
]
| no | +| [match\_azure\_resource\_groups](#input\_match\_azure\_resource\_groups) | Azure resource groups to scan for VMs. Defaults to ["*"] which matches all resource groups. | `list(string)` |
[
"*"
]
| no | +| [match\_azure\_subscriptions](#input\_match\_azure\_subscriptions) | Azure subscriptions to scan for VMs. Defaults to ["*"] which matches all subscriptions. | `list(string)` |
[
"*"
]
| no | +| [match\_azure\_tags](#input\_match\_azure\_tags) | Tag filters for VM discovery; matches VMs with these tags. Defaults to {"*" = ["*"]} which matches all tags. | `map(list(string))` |
{
"*": [
"*"
]
}
| no | +| [teleport\_discovery\_config\_name](#input\_teleport\_discovery\_config\_name) | Name for the `teleport_discovery_config` resource. | `string` | `"discovery"` | no | +| [teleport\_discovery\_config\_use\_name\_prefix](#input\_teleport\_discovery\_config\_use\_name\_prefix) | Whether `teleport_discovery_config_name` is used as a name prefix (true) or as the exact name (false). | `bool` | `true` | no | +| [teleport\_discovery\_group\_name](#input\_teleport\_discovery\_group\_name) | Teleport discovery group to use. For discovery configuration to apply, this name must match at least one Teleport Discovery Service instance's configured `discovery_group`. For Teleport Cloud clusters, use "cloud-discovery-group". | `string` | n/a | yes | +| [teleport\_installer\_script\_name](#input\_teleport\_installer\_script\_name) | Name of an existing Teleport installer script to use. | `string` | `"default-installer"` | no | +| [teleport\_integration\_name](#input\_teleport\_integration\_name) | Name for the `teleport_integration` resource. | `string` | `"discovery"` | no | +| [teleport\_integration\_use\_name\_prefix](#input\_teleport\_integration\_use\_name\_prefix) | Whether `teleport_integration_name` is used as a name prefix (true) or as the exact name (false). | `bool` | `true` | no | +| [teleport\_provision\_token\_name](#input\_teleport\_provision\_token\_name) | Name for the `teleport_provision_token` resource. | `string` | `"discovery"` | no | +| [teleport\_provision\_token\_use\_name\_prefix](#input\_teleport\_provision\_token\_use\_name\_prefix) | Whether `teleport_provision_token_name` is used as a name prefix (true) or as the exact name (false). | `bool` | `true` | no | +| [teleport\_proxy\_public\_addr](#input\_teleport\_proxy\_public\_addr) | Teleport cluster proxy public address in the form (no URL scheme). | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [azure\_discovery\_role\_definition](#output\_azure\_discovery\_role\_definition) | The Azure role definition for Teleport discovery service. | +| [azure\_oidc\_integration\_managed\_identity](#output\_azure\_oidc\_integration\_managed\_identity) | Managed identity used by the Teleport Azure OIDC integration. | +| [teleport\_discovery\_config\_name](#output\_teleport\_discovery\_config\_name) | Name of the Teleport dynamic `discovery_config`. Configuration details can be viewed with `tctl get discovery_config/`. Teleport Discovery Service instances will use this `discovery_config` if they are in the same discovery group as the `discovery_config`. | +| [teleport\_integration\_name](#output\_teleport\_integration\_name) | Name of the Teleport `integration` resource. The integration resource configures Teleport Discovery Service instances to assume an Azure managed identity for discovery using Azure OIDC federation. Integration details can be viewed with `tctl get integrations/` or by visiting the Teleport web UI under 'Zero Trust Access' > 'Integrations'. | +| [teleport\_provision\_token\_name](#output\_teleport\_provision\_token\_name) | Name of the Teleport provision `token` that allows Teleport nodes to join the Teleport cluster using Azure credentials. Token details can be viewed with `tctl get token/`. | + diff --git a/integrations/terraform-modules/teleport/discovery/azure/azure_managed_identity.tf b/integrations/terraform-modules/teleport/discovery/azure/azure_managed_identity.tf new file mode 100644 index 0000000000000..f20dc164a20a9 --- /dev/null +++ b/integrations/terraform-modules/teleport/discovery/azure/azure_managed_identity.tf @@ -0,0 +1,25 @@ +################################################################################ +# Managed identity + federation +################################################################################ + +# User-assigned managed identity for discovery +resource "azurerm_user_assigned_identity" "teleport_discovery_service" { + count = local.create ? 1 : 0 + + location = var.azure_managed_identity_location + name = var.azure_managed_identity_name + resource_group_name = var.azure_resource_group_name + tags = local.apply_azure_tags +} + +# Federated identity credential for the managed identity (trust Teleport proxy issuer) +resource "azurerm_federated_identity_credential" "teleport_discovery_service" { + count = local.create ? 1 : 0 + + audience = ["api://AzureADTokenExchange"] + # Extract the host from proxy_addr (format: host:port) to construct the OIDC issuer URL + issuer = replace(local.teleport_proxy_public_url, "/:[0-9]+.*/", "") + name = var.azure_federated_identity_credential_name + parent_id = one(azurerm_user_assigned_identity.teleport_discovery_service[*].id) + subject = "teleport-azure" +} diff --git a/integrations/terraform-modules/teleport/discovery/azure/azure_role_definition.tf b/integrations/terraform-modules/teleport/discovery/azure/azure_role_definition.tf new file mode 100644 index 0000000000000..9482905cc5eb0 --- /dev/null +++ b/integrations/terraform-modules/teleport/discovery/azure/azure_role_definition.tf @@ -0,0 +1,45 @@ +################################################################################ +# Azure role for Teleport Discovery Service +################################################################################ + +locals { + azure_role_assignable_scopes = coalescelist( + var.azure_role_assignable_scopes, + [local.scope.subscription], + ) + azure_role_assignment_scopes = coalescelist( + var.azure_role_assignment_scopes, + [local.scope.subscription], + ) +} + +# Custom role for discovery permissions +resource "azurerm_role_definition" "teleport_discovery" { + count = local.create ? 1 : 0 + + assignable_scopes = local.azure_role_assignable_scopes + description = "Azure role that allows a Teleport Discovery Service to discover VMs." + name = var.azure_role_definition_name + scope = local.scope.subscription + + permissions { + actions = [ + "Microsoft.Compute/virtualMachines/read", + "Microsoft.Compute/virtualMachines/runCommand/action", + "Microsoft.Compute/virtualMachines/runCommands/delete", + "Microsoft.Compute/virtualMachines/runCommands/read", + "Microsoft.Compute/virtualMachines/runCommands/write", + "Microsoft.Resources/subscriptions/read", + ] + not_actions = [] + } +} + +# Assign the custom role to the managed identity principal +resource "azurerm_role_assignment" "teleport_discovery" { + for_each = local.create ? toset(local.azure_role_assignment_scopes) : [] + + principal_id = one(azurerm_user_assigned_identity.teleport_discovery_service[*].principal_id) + role_definition_id = one(azurerm_role_definition.teleport_discovery[*].role_definition_resource_id) + scope = each.value +} diff --git a/integrations/terraform-modules/teleport/discovery/azure/examples/single-subscription/README.md b/integrations/terraform-modules/teleport/discovery/azure/examples/single-subscription/README.md new file mode 100644 index 0000000000000..d85c33d89077e --- /dev/null +++ b/integrations/terraform-modules/teleport/discovery/azure/examples/single-subscription/README.md @@ -0,0 +1,40 @@ + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.5.7 | +| [azurerm](#requirement\_azurerm) | >= 4.0 | +| [http](#requirement\_http) | >= 3.0 | +| [teleport](#requirement\_teleport) | >= 18.5.1 | + +## Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | >= 4.0 | +| [teleport](#provider\_teleport) | >= 18.5.1 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [azure\_discovery](#module\_azure\_discovery) | ../.. | n/a | + +## Resources + +| Name | Type | +|------|------| +| [azurerm_resource_group.example](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| teleport_installer.example | resource | + +## Inputs + +No inputs. + +## Outputs + +| Name | Description | +|------|-------------| +| [azure\_discovery](#output\_azure\_discovery) | n/a | + \ No newline at end of file diff --git a/integrations/terraform-modules/teleport/discovery/azure/examples/single-subscription/main.tf b/integrations/terraform-modules/teleport/discovery/azure/examples/single-subscription/main.tf new file mode 100644 index 0000000000000..0a4066c633de2 --- /dev/null +++ b/integrations/terraform-modules/teleport/discovery/azure/examples/single-subscription/main.tf @@ -0,0 +1,74 @@ +locals { + apply_azure_tags = { origin = "example" } + apply_teleport_resource_labels = { origin = "example" } +} + +module "azure_discovery" { + source = "../.." + + azure_managed_identity_location = azurerm_resource_group.example.location + azure_resource_group_name = azurerm_resource_group.example.name + teleport_discovery_group_name = "cloud-discovery-group" + teleport_proxy_public_addr = "example.teleport.sh:443" + + # optional + match_azure_regions = ["westus", "eastus"] // discover VMs in these US west and east regions. + match_azure_resource_groups = ["*"] // discover VMs in all resource groups + match_azure_tags = { "env" = ["example"] } + # Apply the additional Azure tag "origin=example" to all Azure resources created by this module + apply_azure_tags = local.apply_azure_tags + # Apply the additional Teleport label "origin=example" to all Teleport resources created by this module + apply_teleport_resource_labels = local.apply_teleport_resource_labels + # Using a custom installer script on discovered VMs instead of the default installer script. + teleport_installer_script_name = teleport_installer.example.metadata.name +} + +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West US" + tags = local.apply_azure_tags +} + + +resource "teleport_installer" "example" { + version = "v1" + metadata = { + name = "custom-azure-installer-example" + description = "Example Teleport Installer" + labels = local.apply_teleport_resource_labels + } + + spec = { + # This "custom" script is actually the default installer script (you can view the default installer to verify: `$ tctl get installer/default-installer`). + # Edit it to customize the commands that the Teleport Discovery Service + # configures virtual machines to run to install Teleport on startup. + script = <