diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index ae74e34ea..dee85ebf9 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -11,7 +11,9 @@ categories: - 'bugfix' - 'bug' - title: 'Maintenance' - label: 'chore' + labels: + - 'chore' + - 'documentation' - title: 'Dependencies' label: 'dependencies' change-template: '- $TITLE @$AUTHOR (#$NUMBER)' @@ -32,6 +34,7 @@ version-resolver: - 'chore' - 'dependencies' - 'enhancement' + - 'documentation' default: patch template: | ## Changes diff --git a/.github/workflows/enforce-pr-labels.yaml b/.github/workflows/enforce-pr-labels.yaml index 6610ae2ea..7518212b0 100644 --- a/.github/workflows/enforce-pr-labels.yaml +++ b/.github/workflows/enforce-pr-labels.yaml @@ -13,7 +13,7 @@ jobs: with: script: | const requiredLabels = [ - 'feature', 'enhancement', 'fix', 'bugfix', 'bug', 'chore', 'dependencies', 'major', 'minor', 'patch' + 'feature', 'enhancement', 'documentation','fix', 'bugfix', 'bug', 'chore', 'dependencies', 'major', 'minor', 'patch' ]; const prLabels = context.payload.pull_request.labels.map(label => label.name); const hasRequiredLabel = prLabels.some(label => requiredLabels.includes(label)); diff --git a/.github/workflows/terraform-docs.yml b/.github/workflows/terraform-docs.yml new file mode 100644 index 000000000..7efe827d5 --- /dev/null +++ b/.github/workflows/terraform-docs.yml @@ -0,0 +1,67 @@ +name: Generate terraform docs +on: + pull_request: + +permissions: + contents: write + pull-requests: write + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Install Task + uses: arduino/setup-task@b91d5d2c96a56797b48ac1e0e89220bf64044611 # v2.0.0 + with: + version: '3.43.3' + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Generate Terraform docs + run: task docs + + - name: Create or update PR + if: success() + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const sourcePR = context.payload.pull_request; + const branchName = `docs/${sourcePR.head.ref}`; + + // Configure git + await exec.exec('git', ['config', '--local', 'user.name', 'GitHub Action']); + await exec.exec('git', ['config', '--local', 'user.email', 'action@github.com']); + + // Create or update branch + await exec.exec('git', ['checkout', '-B', branchName]); + await exec.exec('git', ['add', 'docs/terraform/']); + + const { stdout: diffOutput } = await exec.exec('git', ['diff', '--staged', '--quiet'], { ignoreReturnCode: true }); + if (diffOutput !== '') { + await exec.exec('git', ['commit', '-m', `docs: update terraform documentation for #${sourcePR.number}`]); + await exec.exec('git', ['push', '-f', 'origin', branchName]); + + // Create PR if it doesn't exist + const { data: existingPRs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: `${context.repo.owner}:${branchName}`, + base: 'main' + }); + + if (existingPRs.length === 0) { + await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: `docs: update terraform documentation for #${sourcePR.number}`, + body: `Automated documentation update for PR #${sourcePR.number}: ${sourcePR.title}\n\n${sourcePR.html_url}`, + head: branchName, + base: 'main', + labels: ['documentation'] + }); + } + } else { + console.log('No changes to commit'); + } diff --git a/Taskfile.yaml b/Taskfile.yaml index 11f8707c1..b7520afaa 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -24,4 +24,20 @@ tasks: fmt: desc: Check Terraform formatting cmds: - - terraform fmt -recursive \ No newline at end of file + - terraform fmt -recursive + + docs: + desc: Generate Terraform documentation + cmds: + - rm -rf docs/terraform/* + - | + find terraform -type d -exec test -e '{}/main.tf' -a -e '{}/variables.tf' \; -print | while read -r dir; do + rel_path="${dir#terraform/}" + output_file="docs/terraform/$rel_path/$(basename "$dir").md" + mkdir -p "$(dirname "$output_file")" + if [ -f "$dir/README.md" ]; then + cat "$dir/README.md" > "$output_file" + echo >> "$output_file" + fi + docker run --rm -v "$(pwd):/src" -w "/src/$dir" quay.io/terraform-docs/terraform-docs:0.20.0 markdown . >> "$output_file" + done diff --git a/docs/terraform/backend/azurerm/azurerm.md b/docs/terraform/backend/azurerm/azurerm.md new file mode 100644 index 000000000..db24c4f27 --- /dev/null +++ b/docs/terraform/backend/azurerm/azurerm.md @@ -0,0 +1,46 @@ +## Requirements + +| Name | Version | +|------|---------| +| [azurerm](#requirement\_azurerm) | 4.28.0 | + +## Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | 4.28.0 | +| [local](#provider\_local) | 2.5.3 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.28.0/docs/resources/resource_group) | resource | +| [azurerm_storage_account.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.28.0/docs/resources/storage_account) | resource | +| [azurerm_storage_container.this](https://registry.terraform.io/providers/hashicorp/azurerm/4.28.0/docs/resources/storage_container) | resource | +| [azurerm_user_assigned_identity.storage](https://registry.terraform.io/providers/hashicorp/azurerm/4.28.0/docs/resources/user_assigned_identity) | resource | +| [local_file.backend_config](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [allow\_public\_access](#input\_allow\_public\_access) | Allow public access to the storage account | `bool` | `true` | no | +| [allowed\_ip\_ranges](#input\_allowed\_ip\_ranges) | List of IP ranges to allow access to the storage account | `list(string)` | `[]` | no | +| [container\_name](#input\_container\_name) | Name of the blob container for Terraform state | `string` | `""` | no | +| [context\_id](#input\_context\_id) | Context ID for the resources | `string` | n/a | yes | +| [context\_path](#input\_context\_path) | The path to the context folder | `string` | `""` | no | +| [enable\_cmk](#input\_enable\_cmk) | Enable customer managed key encryption | `bool` | `false` | no | +| [key\_vault\_key\_id](#input\_key\_vault\_key\_id) | The ID of the Key Vault Key to use for CMK encryption | `string` | `""` | no | +| [location](#input\_location) | Azure region where resources will be created | `string` | `"eastus2"` | no | +| [resource\_group\_name](#input\_resource\_group\_name) | Name of the resource group where the storage account will be created | `string` | `""` | no | +| [storage\_account\_name](#input\_storage\_account\_name) | Name of the storage account. If not provided, a default name will be generated | `string` | `""` | no | +| [tags](#input\_tags) | Additional tags to apply to resources | `map(string)` | `{}` | no | + +## Outputs + +No outputs. diff --git a/docs/terraform/backend/s3/s3.md b/docs/terraform/backend/s3/s3.md new file mode 100644 index 000000000..ace853386 --- /dev/null +++ b/docs/terraform/backend/s3/s3.md @@ -0,0 +1,53 @@ +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | 5.97.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | 5.97.0 | +| [local](#provider\_local) | 2.5.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_dynamodb_table.terraform_locks](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/dynamodb_table) | resource | +| [aws_kms_alias.terraform_state_alias](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/kms_alias) | resource | +| [aws_kms_key.terraform_state](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/kms_key) | resource | +| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket_lifecycle_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/s3_bucket_lifecycle_configuration) | resource | +| [aws_s3_bucket_logging.this](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/s3_bucket_logging) | resource | +| [aws_s3_bucket_policy.this](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/s3_bucket_policy) | resource | +| [aws_s3_bucket_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/s3_bucket_public_access_block) | resource | +| [aws_s3_bucket_server_side_encryption_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/s3_bucket_server_side_encryption_configuration) | resource | +| [aws_s3_bucket_versioning.this](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/resources/s3_bucket_versioning) | resource | +| [local_file.backend_config](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/5.97.0/docs/data-sources/caller_identity) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [context\_id](#input\_context\_id) | Context ID for the resources | `string` | `null` | no | +| [context\_path](#input\_context\_path) | The path to the context folder | `string` | `""` | no | +| [enable\_dynamodb](#input\_enable\_dynamodb) | Feature flag to enable DynamoDB table creation | `bool` | `true` | no | +| [enable\_kms](#input\_enable\_kms) | Feature flag to enable KMS encryption | `bool` | `true` | no | +| [kms\_key\_alias](#input\_kms\_key\_alias) | The KMS key ID for encrypting the S3 bucket | `string` | `""` | no | +| [kms\_policy\_override](#input\_kms\_policy\_override) | Override for the KMS policy document (for testing) | `string` | `null` | no | +| [region](#input\_region) | The AWS Region for the S3 Bucket and DynamoDB Table | `string` | `"us-east-2"` | no | +| [s3\_bucket\_name](#input\_s3\_bucket\_name) | The name of the S3 bucket for storing Terraform state, overrides the default bucket name | `string` | `""` | no | +| [s3\_log\_bucket\_name](#input\_s3\_log\_bucket\_name) | Name of a pre-existing, centralized S3 logging bucket to receive access logs. Must be created outside this module. | `string` | `""` | no | +| [tags](#input\_tags) | Additional tags to apply to resources (default is empty). | `map(string)` | `{}` | no | +| [terraform\_state\_iam\_roles](#input\_terraform\_state\_iam\_roles) | List of IAM role ARNs that should have access to the Terraform state bucket | `list(string)` | `[]` | no | + +## Outputs + +No outputs. diff --git a/docs/terraform/cluster/azure-aks/azure-aks.md b/docs/terraform/cluster/azure-aks/azure-aks.md new file mode 100644 index 000000000..715b1a45c --- /dev/null +++ b/docs/terraform/cluster/azure-aks/azure-aks.md @@ -0,0 +1,72 @@ +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >=1.8 | +| [azurerm](#requirement\_azurerm) | ~> 4.28.0 | + +## Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | 4.28.0 | +| [local](#provider\_local) | 2.5.3 | +| [random](#provider\_random) | 3.7.2 | +| [time](#provider\_time) | 0.13.1 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [azurerm_disk_encryption_set.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/disk_encryption_set) | resource | +| [azurerm_key_vault.key_vault](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault) | resource | +| [azurerm_key_vault_access_policy.key_vault_access_policy](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource | +| [azurerm_key_vault_access_policy.key_vault_access_policy_disk](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource | +| [azurerm_key_vault_key.key_vault_key](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_key) | resource | +| [azurerm_kubernetes_cluster.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster) | resource | +| [azurerm_kubernetes_cluster_node_pool.autoscaled](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster_node_pool) | resource | +| [azurerm_log_analytics_workspace.aks_logs](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/log_analytics_workspace) | resource | +| [azurerm_resource_group.aks](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_user_assigned_identity.cluster](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource | +| [local_file.kube_config](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [random_string.key](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | +| [time_static.expiry](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/static) | resource | +| [azurerm_client_config.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/client_config) | data source | +| [azurerm_subnet.private](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [additional\_cluster\_identity\_ids](#input\_additional\_cluster\_identity\_ids) | Additional user assigned identity IDs for the AKS cluster | `list(string)` | `[]` | no | +| [auto\_scaler\_profile](#input\_auto\_scaler\_profile) | Configuration for the AKS cluster's auto-scaler |
object({
balance_similar_node_groups = bool
max_graceful_termination_sec = number
scale_down_delay_after_add = string
scale_down_delay_after_delete = string
scale_down_delay_after_failure = string
scan_interval = string
scale_down_unneeded = string
scale_down_unready = string
scale_down_utilization_threshold = string
}) | {
"balance_similar_node_groups": true,
"max_graceful_termination_sec": 600,
"scale_down_delay_after_add": "10m",
"scale_down_delay_after_delete": "10s",
"scale_down_delay_after_failure": "3m",
"scale_down_unneeded": "10m",
"scale_down_unready": "20m",
"scale_down_utilization_threshold": "0.5",
"scan_interval": "10s"
} | no |
+| [automatic\_upgrade\_channel](#input\_automatic\_upgrade\_channel) | The automatic upgrade channel for the AKS cluster | `string` | `"stable"` | no |
+| [autoscaled\_node\_pool](#input\_autoscaled\_node\_pool) | Configuration for the autoscaled node pool | object({
enabled = bool
name = string
vm_size = string
mode = string
os_disk_type = string
max_pods = number
host_encryption_enabled = bool
min_count = number
max_count = number
}) | {
"enabled": true,
"host_encryption_enabled": true,
"max_count": 3,
"max_pods": 30,
"min_count": 1,
"mode": "User",
"name": "autoscaled",
"os_disk_type": "Managed",
"vm_size": "Standard_D2s_v3"
} | no |
+| [azure\_policy\_enabled](#input\_azure\_policy\_enabled) | Whether to enable Azure Policy for the AKS cluster | `bool` | `true` | no |
+| [cluster\_name](#input\_cluster\_name) | Name of the AKS cluster | `string` | `null` | no |
+| [context\_id](#input\_context\_id) | Context ID for the resources | `string` | `null` | no |
+| [context\_path](#input\_context\_path) | The path to the context folder, where kubeconfig is stored | `string` | `""` | no |
+| [default\_node\_pool](#input\_default\_node\_pool) | Configuration for the default node pool | object({
name = string
vm_size = string
os_disk_type = string
max_pods = number
host_encryption_enabled = bool
min_count = number
max_count = number
node_count = number
}) | {
"host_encryption_enabled": true,
"max_count": 3,
"max_pods": 30,
"min_count": 1,
"name": "system",
"node_count": 1,
"os_disk_type": "Managed",
"vm_size": "Standard_D2s_v3"
} | no |
+| [expiration\_date](#input\_expiration\_date) | The expiration date for the AKS cluster's key vault | `string` | `null` | no |
+| [kubernetes\_version](#input\_kubernetes\_version) | Version of Kubernetes to use | `string` | `"1.32"` | no |
+| [local\_account\_disabled](#input\_local\_account\_disabled) | Whether to disable local accounts for the AKS cluster | `bool` | `false` | no |
+| [network\_acls\_default\_action](#input\_network\_acls\_default\_action) | The default action for the AKS cluster's network ACLs | `string` | `"Allow"` | no |
+| [private\_cluster\_enabled](#input\_private\_cluster\_enabled) | Whether to enable private cluster for the AKS cluster | `bool` | `false` | no |
+| [public\_network\_access\_enabled](#input\_public\_network\_access\_enabled) | Whether to enable public network access for the AKS cluster | `bool` | `true` | no |
+| [region](#input\_region) | Region for the resources | `string` | `"eastus"` | no |
+| [resource\_group\_name](#input\_resource\_group\_name) | Name of the resource group | `string` | `null` | no |
+| [role\_based\_access\_control\_enabled](#input\_role\_based\_access\_control\_enabled) | Whether to enable role-based access control for the AKS cluster | `bool` | `true` | no |
+| [sku\_tier](#input\_sku\_tier) | The SKU tier for the AKS cluster | `string` | `"Standard"` | no |
+| [soft\_delete\_retention\_days](#input\_soft\_delete\_retention\_days) | The number of days to retain the AKS cluster's key vault | `number` | `7` | no |
+| [vnet\_name](#input\_vnet\_name) | Name of the VNET | `string` | `null` | no |
+| [vnet\_resource\_group\_name](#input\_vnet\_resource\_group\_name) | Name of the VNET resource group | `string` | `null` | no |
+| [vnet\_subnet\_id](#input\_vnet\_subnet\_id) | ID of the subnet | `string` | `null` | no |
+| [workload\_autoscaler\_profile](#input\_workload\_autoscaler\_profile) | Configuration for the AKS cluster's workload autoscaler | object({
keda_enabled = bool
vertical_pod_autoscaler_enabled = bool
}) | {
"keda_enabled": false,
"vertical_pod_autoscaler_enabled": false
} | no |
+
+## Outputs
+
+No outputs.
diff --git a/docs/terraform/cluster/talos/modules/machine/machine.md b/docs/terraform/cluster/talos/modules/machine/machine.md
new file mode 100644
index 000000000..dcbd09ddc
--- /dev/null
+++ b/docs/terraform/cluster/talos/modules/machine/machine.md
@@ -0,0 +1,50 @@
+## Requirements
+
+No requirements.
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [talos](#provider\_talos) | 0.8.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [talos_machine_bootstrap.bootstrap](https://registry.terraform.io/providers/siderolabs/talos/latest/docs/resources/machine_bootstrap) | resource |
+| [talos_machine_configuration_apply.this](https://registry.terraform.io/providers/siderolabs/talos/latest/docs/resources/machine_configuration_apply) | resource |
+| [talos_machine_configuration.this](https://registry.terraform.io/providers/siderolabs/talos/latest/docs/data-sources/machine_configuration) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [bootstrap](#input\_bootstrap) | Indicates whether to bootstrap the machine. | `bool` | `false` | no |
+| [client\_configuration](#input\_client\_configuration) | The Talos client configuration. | `any` | n/a | yes |
+| [cluster\_endpoint](#input\_cluster\_endpoint) | The cluster endpoint. | `string` | n/a | yes |
+| [cluster\_name](#input\_cluster\_name) | The name of the cluster. | `string` | n/a | yes |
+| [config\_patches](#input\_config\_patches) | The configuration patches to apply to the machine. | `list(string)` | `[]` | no |
+| [disk\_selector](#input\_disk\_selector) | The disk selector to use for the machine. | object({
busPath = string
modalias = string
model = string
name = string
serial = string
size = string
type = string
uuid = string
wwid = string
}) | `null` | no |
+| [endpoint](#input\_endpoint) | The endpoint of the machine. | `string` | n/a | yes |
+| [extensions](#input\_extensions) | The extensions to use for the machine. | `list(object({ image = string }))` | `[]` | no |
+| [extra\_kernel\_args](#input\_extra\_kernel\_args) | Additional kernel arguments to pass to the machine. | `list(string)` | `[]` | no |
+| [hostname](#input\_hostname) | The hostname of the machine. | `string` | `""` | no |
+| [image](#input\_image) | The Talos image to install. | `string` | `"ghcr.io/siderolabs/installer:latest"` | no |
+| [kubernetes\_version](#input\_kubernetes\_version) | The Kubernetes version. | `string` | n/a | yes |
+| [machine\_secrets](#input\_machine\_secrets) | The Talos machine secrets. | `any` | n/a | yes |
+| [machine\_type](#input\_machine\_type) | The machine type, which must be either 'controlplane' or 'worker'. | `string` | n/a | yes |
+| [node](#input\_node) | The node address of the machine. | `string` | n/a | yes |
+| [talos\_version](#input\_talos\_version) | The Talos version. | `string` | n/a | yes |
+| [wipe\_disk](#input\_wipe\_disk) | Indicates whether to wipe the install disk. | `bool` | `true` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [endpoint](#output\_endpoint) | n/a |
+| [node](#output\_node) | n/a |
diff --git a/docs/terraform/cluster/talos/talos.md b/docs/terraform/cluster/talos/talos.md
new file mode 100644
index 000000000..bdfc7657b
--- /dev/null
+++ b/docs/terraform/cluster/talos/talos.md
@@ -0,0 +1,53 @@
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >=1.8 |
+| [talos](#requirement\_talos) | 0.8.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [local](#provider\_local) | 2.5.2 |
+| [null](#provider\_null) | 3.2.4 |
+| [talos](#provider\_talos) | 0.8.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [controlplane\_bootstrap](#module\_controlplane\_bootstrap) | ./modules/machine | n/a |
+| [controlplanes](#module\_controlplanes) | ./modules/machine | n/a |
+| [workers](#module\_workers) | ./modules/machine | n/a |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [local_sensitive_file.kubeconfig](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/sensitive_file) | resource |
+| [local_sensitive_file.talosconfig](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/sensitive_file) | resource |
+| [null_resource.healthcheck](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
+| [talos_cluster_kubeconfig.this](https://registry.terraform.io/providers/siderolabs/talos/0.8.0/docs/resources/cluster_kubeconfig) | resource |
+| [talos_machine_secrets.this](https://registry.terraform.io/providers/siderolabs/talos/0.8.0/docs/resources/machine_secrets) | resource |
+| [talos_client_configuration.this](https://registry.terraform.io/providers/siderolabs/talos/0.8.0/docs/data-sources/client_configuration) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [cluster\_endpoint](#input\_cluster\_endpoint) | The external controlplane API endpoint of the kubernetes API. | `string` | `"https://localhost:6443"` | no |
+| [cluster\_name](#input\_cluster\_name) | The name of the cluster. | `string` | `"talos"` | no |
+| [common\_config\_patches](#input\_common\_config\_patches) | A YAML string of common config patches to apply. Can be an empty string or valid YAML. | `string` | `""` | no |
+| [context\_path](#input\_context\_path) | The path to the context folder, where kubeconfig and talosconfig are stored | `string` | `""` | no |
+| [controlplane\_config\_patches](#input\_controlplane\_config\_patches) | A YAML string of controlplane config patches to apply. Can be an empty string or valid YAML. | `string` | `""` | no |
+| [controlplanes](#input\_controlplanes) | A list of machine configuration details for control planes. | list(object({
hostname = optional(string)
endpoint = string
node = string
disk_selector = optional(object({
busPath = optional(string)
modalias = optional(string)
model = optional(string)
name = optional(string)
serial = optional(string)
size = optional(string)
type = optional(string)
uuid = optional(string)
wwid = optional(string)
}))
wipe_disk = optional(bool, true)
extra_kernel_args = optional(list(string), [])
config_patches = optional(string, "")
})) | `[]` | no |
+| [kubernetes\_version](#input\_kubernetes\_version) | The kubernetes version to deploy. | `string` | `"1.33.0"` | no |
+| [os\_type](#input\_os\_type) | The operating system type, must be either 'unix' or 'windows' | `string` | `"unix"` | no |
+| [talos\_version](#input\_talos\_version) | The talos version to deploy. | `string` | `"1.10.1"` | no |
+| [worker\_config\_patches](#input\_worker\_config\_patches) | A YAML string of worker config patches to apply. Can be an empty string or valid YAML. | `string` | `""` | no |
+| [workers](#input\_workers) | A list of machine configuration details | list(object({
hostname = optional(string)
endpoint = string
node = string
disk_selector = optional(object({
busPath = optional(string)
modalias = optional(string)
model = optional(string)
name = optional(string)
serial = optional(string)
size = optional(string)
type = optional(string)
uuid = optional(string)
wwid = optional(string)
}))
wipe_disk = optional(bool, true)
extra_kernel_args = optional(list(string), [])
config_patches = optional(string, "")
})) | `[]` | no |
+
+## Outputs
+
+No outputs.
diff --git a/docs/terraform/gitops/flux/flux.md b/docs/terraform/gitops/flux/flux.md
new file mode 100644
index 000000000..66197141e
--- /dev/null
+++ b/docs/terraform/gitops/flux/flux.md
@@ -0,0 +1,45 @@
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >=1.7.3 |
+| [kubernetes](#requirement\_kubernetes) | 2.36.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [helm](#provider\_helm) | 2.17.0 |
+| [kubernetes](#provider\_kubernetes) | 2.36.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [helm_release.flux_system](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
+| [kubernetes_namespace.flux_system](https://registry.terraform.io/providers/hashicorp/kubernetes/2.36.0/docs/resources/namespace) | resource |
+| [kubernetes_secret.git_auth](https://registry.terraform.io/providers/hashicorp/kubernetes/2.36.0/docs/resources/secret) | resource |
+| [kubernetes_secret.webhook_token](https://registry.terraform.io/providers/hashicorp/kubernetes/2.36.0/docs/resources/secret) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [flux\_helm\_version](#input\_flux\_helm\_version) | The version of Flux Helm chart to install | `string` | `"2.15.0"` | no |
+| [flux\_namespace](#input\_flux\_namespace) | The namespace in which Flux will be installed | `string` | `"system-gitops"` | no |
+| [flux\_version](#input\_flux\_version) | The version of Flux to install | `string` | `"2.5.1"` | no |
+| [git\_auth\_secret](#input\_git\_auth\_secret) | The name of the secret to store the git authentication details | `string` | `"flux-system"` | no |
+| [git\_password](#input\_git\_password) | The git password or PAT used to authenticte with the git provider | `string` | `""` | no |
+| [git\_username](#input\_git\_username) | The git user to use to authenticte with the git provider | `string` | `"git"` | no |
+| [ssh\_known\_hosts](#input\_ssh\_known\_hosts) | The known hosts to use for SSH authentication | `string` | `""` | no |
+| [ssh\_private\_key](#input\_ssh\_private\_key) | The private key to use for SSH authentication | `string` | `""` | no |
+| [ssh\_public\_key](#input\_ssh\_public\_key) | The public key to use for SSH authentication | `string` | `""` | no |
+| [webhook\_token](#input\_webhook\_token) | The token to use for the webhook | `string` | `""` | no |
+
+## Outputs
+
+No outputs.
diff --git a/docs/terraform/network/azure-vnet/azure-vnet.md b/docs/terraform/network/azure-vnet/azure-vnet.md
new file mode 100644
index 000000000..54c449a4c
--- /dev/null
+++ b/docs/terraform/network/azure-vnet/azure-vnet.md
@@ -0,0 +1,47 @@
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >=1.8 |
+| [azurerm](#requirement\_azurerm) | ~> 4.28.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | 4.28.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_nat_gateway.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/nat_gateway) | resource |
+| [azurerm_nat_gateway_public_ip_association.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/nat_gateway_public_ip_association) | resource |
+| [azurerm_public_ip.nat](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/public_ip) | resource |
+| [azurerm_resource_group.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource |
+| [azurerm_subnet.data](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource |
+| [azurerm_subnet.private](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource |
+| [azurerm_subnet.public](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource |
+| [azurerm_subnet_nat_gateway_association.data](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_nat_gateway_association) | resource |
+| [azurerm_subnet_nat_gateway_association.private](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_nat_gateway_association) | resource |
+| [azurerm_virtual_network.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [context\_id](#input\_context\_id) | Context ID for the resources | `string` | `null` | no |
+| [region](#input\_region) | Region for the resources | `string` | `"eastus"` | no |
+| [resource\_group\_name](#input\_resource\_group\_name) | Name of the resource group | `string` | `null` | no |
+| [vnet\_cidr](#input\_vnet\_cidr) | CIDR block for VNET | `string` | `"10.20.0.0/16"` | no |
+| [vnet\_name](#input\_vnet\_name) | Name of the VNET | `string` | `null` | no |
+| [vnet\_subnets](#input\_vnet\_subnets) | Subnets to create in the VNET | `map(list(string))` | {
"data": [],
"private": [],
"public": []
} | no |
+| [vnet\_zones](#input\_vnet\_zones) | Number of availability zones to create | `number` | `1` | no |
+
+## Outputs
+
+No outputs.
diff --git a/terraform/.terraform-docs.yml b/terraform/.terraform-docs.yml
new file mode 100644
index 000000000..2a4d42359
--- /dev/null
+++ b/terraform/.terraform-docs.yml
@@ -0,0 +1,47 @@
+formatter: markdown
+
+recursive:
+ enabled: true
+ path: .
+ include-main: true
+
+sections:
+ show:
+ - header
+ - requirements
+ - providers
+ - inputs
+ - outputs
+ - resources
+
+content: |-
+ {{ .Header }}
+
+ {{ .Requirements }}
+
+ {{ .Providers }}
+
+ {{ .Inputs }}
+
+ {{ .Outputs }}
+
+ {{ .Resources }}
+
+output:
+ file: "docs/terraform/{{ .Path }}.md"
+ mode: replace
+
+settings:
+ anchor: true
+ color: true
+ default: true
+ description: true
+ escape: true
+ hide-empty: false
+ html: true
+ indent: 2
+ lockfile: true
+ read-comments: true
+ required: true
+ sensitive: true
+ type: true