Skip to content

Commit 96da609

Browse files
authored
Fixed docs. Generation in action removed (#10)
* added new nfs module * changed the pipeline * updated readme * updated readme of the example * added docs and removed generatedocs from the pipeline * added readme with real variables
1 parent fe281bb commit 96da609

File tree

4 files changed

+52
-245
lines changed

4 files changed

+52
-245
lines changed

.github/workflows/terraform-module.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ jobs:
5252
- name: Terraform validate
5353
run: terraform validate
5454

55-
- name: Generate terraform-docs (inject & commit)
56-
uses: terraform-docs/[email protected]
57-
with:
58-
working-dir: ${{ matrix.module }}
59-
output-file: README.md
60-
output-method: inject
61-
config-file: ""
62-
git-push: true
55+
# - name: Generate terraform-docs (inject & commit)
56+
# uses: terraform-docs/[email protected]
57+
# with:
58+
# working-dir: ${{ matrix.module }}
59+
# output-file: README.md
60+
# output-method: inject
61+
# config-file: ""
62+
# git-push: true
6363

6464
release:
6565
name: Tag release

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,4 +243,4 @@ module "quix_aks" {
243243
source = "git::ssh://[email protected]/quixio/terraform-quixplatform-azure.git//modules/quix-aks?ref=0.0.2"
244244
# ...same inputs as above
245245
}
246-
```
246+
```

modules/nfs-storage/README.md

Lines changed: 42 additions & 236 deletions
Original file line numberDiff line numberDiff line change
@@ -1,253 +1,59 @@
1-
# Azure NFS Storage Module
2-
3-
Terraform module to deploy Azure File Storage with NFS 4.1 support, secured with Private Endpoint and network security rules.
4-
5-
## Features
6-
7-
- **Azure Files Premium (NFS 4.1)**: High-performance file storage with native Linux NFS support
8-
- **Private Endpoint**: Secure private connectivity from VNet without public internet exposure
9-
- **Network Security Rules**: Default deny policy with explicit subnet and IP allowlists
10-
- **Auto DNS Zone Creation**: Automatically creates and links Private DNS Zone if not provided
11-
- **Multiple NFS Shares**: Support for creating multiple file shares with different quotas
12-
13-
## Architecture
14-
15-
This module deploys:
16-
17-
1. **Storage Account** (Premium FileStorage, LRS) - Optimized for NFS with low latency
18-
2. **Network Security Rules** - Default deny with explicit allowlist for subnets and IPs
19-
3. **Private Endpoint** - Maps storage to private IP inside VNet
20-
4. **Private DNS Zone** (optional) - Auto-created `privatelink.file.core.windows.net` for easy DNS resolution
21-
5. **NFS File Shares** - One or more NFS 4.1 shares for mounting
22-
23-
## Usage
24-
25-
### Basic Example
26-
27-
```hcl
28-
module "nfs_storage" {
29-
source = "../../modules/nfs-storage"
30-
31-
resource_group_name = "rg-myapp"
32-
location = "westeurope"
33-
storage_account_name = "mystorageaccount01"
34-
35-
# Private Endpoint configuration
36-
private_endpoint_subnet_id = azurerm_subnet.private_endpoints.id
37-
38-
# VNet for auto DNS zone creation
39-
vnet_id = azurerm_virtual_network.main.id
40-
41-
# Network Security Rules - Default deny policy
42-
allowed_subnet_ids = [azurerm_subnet.aks_nodes.id]
43-
allowed_ip_addresses = ["1.2.3.4"] # Your public IP for Terraform operations
44-
45-
# Create NFS shares
46-
nfs_shares = [
47-
{
48-
name = "shared-data"
49-
quota_gb = 100
50-
}
51-
]
52-
53-
tags = {
54-
environment = "production"
55-
}
56-
}
57-
```
58-
59-
### With Automatic Public IP Detection
60-
61-
```hcl
62-
data "http" "my_public_ip" {
63-
url = "https://api.ipify.org?format=text"
64-
}
65-
66-
module "nfs_storage" {
67-
source = "../../modules/nfs-storage"
68-
69-
resource_group_name = "rg-myapp"
70-
location = "westeurope"
71-
storage_account_name = "mystorageaccount01"
72-
73-
private_endpoint_subnet_id = azurerm_subnet.private_endpoints.id
74-
vnet_id = azurerm_virtual_network.main.id
75-
76-
allowed_subnet_ids = [azurerm_subnet.aks_nodes.id]
77-
allowed_ip_addresses = [trimspace(data.http.my_public_ip.response_body)]
78-
79-
nfs_shares = [
80-
{
81-
name = "shared-data"
82-
quota_gb = 100
83-
metadata = {
84-
purpose = "application-data"
85-
}
86-
}
87-
]
88-
}
89-
```
90-
91-
### Using Existing Private DNS Zone
92-
93-
```hcl
94-
module "nfs_storage" {
95-
source = "../../modules/nfs-storage"
96-
97-
resource_group_name = "rg-myapp"
98-
location = "westeurope"
99-
storage_account_name = "mystorageaccount01"
100-
101-
private_endpoint_subnet_id = azurerm_subnet.private_endpoints.id
102-
103-
# Use existing DNS zone instead of auto-creating
104-
private_dns_zone_ids = [azurerm_private_dns_zone.storage.id]
105-
106-
allowed_subnet_ids = [azurerm_subnet.aks_nodes.id]
107-
allowed_ip_addresses = ["1.2.3.4"]
108-
109-
nfs_shares = [
110-
{
111-
name = "shared-data"
112-
quota_gb = 100
113-
}
114-
]
115-
}
116-
```
117-
118-
## Mounting NFS Shares
119-
120-
From a Linux VM inside the allowed subnet:
121-
122-
```bash
123-
# Create mount point
124-
sudo mkdir -p /mnt/shared-data
125-
126-
# Mount the NFS share
127-
sudo mount -t nfs -o vers=4.1,sec=sys \
128-
mystorageaccount01.privatelink.file.core.windows.net:/mystorageaccount01/shared-data \
129-
/mnt/shared-data
130-
131-
# Verify mount
132-
df -h | grep shared-data
133-
```
134-
135-
### Persistent Mount (fstab)
136-
137-
Add to `/etc/fstab`:
1+
<!-- BEGIN_TF_DOCS -->
2+
## Requirements
1383

139-
```
140-
mystorageaccount01.privatelink.file.core.windows.net:/mystorageaccount01/shared-data /mnt/shared-data nfs vers=4.1,sec=sys 0 0
141-
```
4+
| Name | Version |
5+
|------|---------|
6+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.5.0 |
7+
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | >= 3.112.0, < 4.0.0 |
1428

143-
## Network Security
9+
## Providers
14410

145-
The module implements a **default deny policy**:
11+
| Name | Version |
12+
|------|---------|
13+
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | >= 3.112.0, < 4.0.0 |
14614

147-
- All public access is denied by default
148-
- Access is only allowed from:
149-
- **Allowed subnets** (e.g., AKS nodes subnet)
150-
- **Allowed IP addresses** (e.g., your public IP for Terraform operations)
151-
- **Azure Services** (if `network_bypass` includes "AzureServices")
15+
## Modules
15216

153-
### Why Allow Public IP?
17+
No modules.
15418

155-
When you run `terraform apply` or `terraform destroy` from outside the VNet, Terraform needs to make data-plane calls to create/delete NFS shares. Adding your public IP to `allowed_ip_addresses` enables these operations.
19+
## Resources
15620

157-
**Options:**
158-
1. Add your public IP temporarily (manually or via `data "http"`)
159-
2. Run Terraform from inside the VNet (e.g., from a VM or Azure DevOps agent)
160-
3. Use Azure Bastion or VPN to access resources
21+
| Name | Type |
22+
|------|------|
23+
| [azurerm_private_dns_zone.storage_file](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone) | resource |
24+
| [azurerm_private_dns_zone_virtual_network_link.storage_file](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone_virtual_network_link) | resource |
25+
| [azurerm_private_endpoint.nfs](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
26+
| [azurerm_storage_account.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account) | resource |
27+
| [azurerm_storage_account_network_rules.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_account_network_rules) | resource |
28+
| [azurerm_storage_share.nfs_shares](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_share) | resource |
16129

16230
## Inputs
16331

16432
| Name | Description | Type | Default | Required |
16533
|------|-------------|------|---------|:--------:|
166-
| `resource_group_name` | Resource group name | `string` | n/a | yes |
167-
| `location` | Azure region | `string` | n/a | yes |
168-
| `storage_account_name` | Storage account name (globally unique, 3-24 lowercase alphanumeric chars) | `string` | n/a | yes |
169-
| `private_endpoint_subnet_id` | Subnet ID for Private Endpoint | `string` | n/a | yes |
170-
| `vnet_id` | VNet ID for auto DNS zone creation (required if `private_dns_zone_ids` not provided) | `string` | `null` | no |
171-
| `private_dns_zone_ids` | List of Private DNS Zone IDs. If not provided, module creates one automatically | `list(string)` | `[]` | no |
172-
| `allowed_subnet_ids` | List of subnet IDs allowed to access storage (e.g., AKS nodes) | `list(string)` | `[]` | no |
173-
| `allowed_ip_addresses` | List of IP addresses allowed to access storage (without CIDR, e.g., "1.2.3.4") | `list(string)` | `[]` | no |
174-
| `network_bypass` | Services that can bypass network rules | `list(string)` | `["AzureServices"]` | no |
175-
| `nfs_shares` | List of NFS file shares to create | `list(object)` | `[]` | no |
176-
| `tags` | Tags to apply to resources | `map(string)` | `{}` | no |
177-
178-
### NFS Shares Object
179-
180-
```hcl
181-
nfs_shares = [
182-
{
183-
name = string # Share name
184-
quota_gb = number # Quota in GB
185-
access_tier = string # Optional: "Hot", "Cool", "TransactionOptimized"
186-
metadata = map(string) # Optional: metadata tags
187-
}
188-
]
189-
```
34+
| <a name="input_allowed_ip_addresses"></a> [allowed\_ip\_addresses](#input\_allowed\_ip\_addresses) | List of IP addresses or CIDR ranges that are allowed to access the storage account (e.g., admin IP for Terraform operations to create file shares) | `list(string)` | `[]` | no |
35+
| <a name="input_allowed_subnet_ids"></a> [allowed\_subnet\_ids](#input\_allowed\_subnet\_ids) | List of subnet IDs that are allowed to access the storage account (e.g., AKS nodes subnet for NFS access) | `list(string)` | `[]` | no |
36+
| <a name="input_location"></a> [location](#input\_location) | Azure region | `string` | n/a | yes |
37+
| <a name="input_network_bypass"></a> [network\_bypass](#input\_network\_bypass) | List of services that can bypass network rules (AzureServices, Logging, Metrics, None) | `list(string)` | <pre>[<br/> "AzureServices"<br/>]</pre> | no |
38+
| <a name="input_nfs_shares"></a> [nfs\_shares](#input\_nfs\_shares) | List of NFS file shares to create | <pre>list(object({<br/> name = string<br/> quota_gb = number<br/> access_tier = optional(string)<br/> metadata = optional(map(string))<br/> }))</pre> | `[]` | no |
39+
| <a name="input_private_dns_zone_ids"></a> [private\_dns\_zone\_ids](#input\_private\_dns\_zone\_ids) | List of Private DNS Zone IDs for privatelink.file.core.windows.net. If not provided, a new Private DNS Zone will be created automatically. | `list(string)` | `[]` | no |
40+
| <a name="input_private_endpoint_subnet_id"></a> [private\_endpoint\_subnet\_id](#input\_private\_endpoint\_subnet\_id) | Subnet ID where the Private Endpoint will be created (typically a dedicated subnet for private endpoints) | `string` | n/a | yes |
41+
| <a name="input_resource_group_name"></a> [resource\_group\_name](#input\_resource\_group\_name) | Resource group name (same RG as AKS) | `string` | n/a | yes |
42+
| <a name="input_storage_account_name"></a> [storage\_account\_name](#input\_storage\_account\_name) | Storage account name (must be globally unique, 3-24 chars, lowercase alphanumeric) | `string` | n/a | yes |
43+
| <a name="input_tags"></a> [tags](#input\_tags) | Tags to apply to resources | `map(string)` | `{}` | no |
44+
| <a name="input_vnet_id"></a> [vnet\_id](#input\_vnet\_id) | VNet ID to link the Private DNS Zone to (required if private\_dns\_zone\_ids is not provided) | `string` | `null` | no |
19045

19146
## Outputs
19247

19348
| Name | Description |
19449
|------|-------------|
195-
| `storage_account_id` | ID of the NFS storage account |
196-
| `storage_account_name` | Name of the NFS storage account |
197-
| `storage_account_primary_location` | Primary location of the storage account |
198-
| `storage_account_primary_file_endpoint` | Primary file endpoint for NFS access |
199-
| `private_endpoint_id` | ID of the Private Endpoint |
200-
| `private_endpoint_ip_address` | Private IP address of the Private Endpoint |
201-
| `private_dns_zone_id` | ID of the Private DNS Zone (auto-created or provided) |
202-
| `private_dns_zone_name` | Name of the Private DNS Zone |
203-
| `nfs_shares` | Map of created NFS file shares with details |
204-
205-
## Requirements
206-
207-
| Name | Version |
208-
|------|---------|
209-
| terraform | >= 1.0 |
210-
| azurerm | >= 3.0 |
211-
212-
## Important Notes
213-
214-
### NFS 4.1 vs NFS 3.0
215-
216-
- This module uses **NFS 4.1** via Azure Files Premium
217-
- NFS 4.1 provides better security, performance, and POSIX compliance
218-
- Different from NFS 3.0 available on Blob Storage with HNS enabled
219-
220-
### HTTPS Traffic
221-
222-
- `https_traffic_only_enabled` is always `false`
223-
- NFS protocol does not use HTTPS
224-
- This is a requirement for NFS support
225-
226-
### Storage Account Naming
227-
228-
- Must be globally unique across Azure
229-
- 3-24 characters
230-
- Only lowercase letters and numbers
231-
- No hyphens or special characters
232-
233-
### Network Rules Best Practices
234-
235-
1. Start with restrictive rules (default deny)
236-
2. Add only necessary subnets and IPs
237-
3. Remove admin IPs after deployment if not needed
238-
4. Use Azure Bastion or VPN for admin access instead of public IPs
239-
5. Monitor access logs for unauthorized attempts
240-
241-
## Examples
242-
243-
See the [examples directory](../../examples/public-quix-infr-nfs-storage) for complete working examples.
244-
245-
## References
246-
247-
- [Azure Files NFS 4.1 Documentation](https://learn.microsoft.com/en-us/azure/storage/files/storage-files-how-to-create-nfs-shares)
248-
- [Azure Private Endpoint](https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-overview)
249-
- [FoggyKitchen Blog: Secure Azure File Storage (NFS) with Private Endpoint using Terraform](https://foggykitchen.com/2025/10/02/azure-file-storage-nfs-terraform/)
250-
251-
## License
252-
253-
This module is maintained by Quix.
50+
| <a name="output_nfs_shares"></a> [nfs\_shares](#output\_nfs\_shares) | Map of NFS mount paths for each share |
51+
| <a name="output_private_dns_zone_id"></a> [private\_dns\_zone\_id](#output\_private\_dns\_zone\_id) | ID of the Private DNS Zone (auto-created or provided) |
52+
| <a name="output_private_dns_zone_name"></a> [private\_dns\_zone\_name](#output\_private\_dns\_zone\_name) | Name of the Private DNS Zone |
53+
| <a name="output_private_endpoint_id"></a> [private\_endpoint\_id](#output\_private\_endpoint\_id) | ID of the Private Endpoint |
54+
| <a name="output_private_endpoint_ip_address"></a> [private\_endpoint\_ip\_address](#output\_private\_endpoint\_ip\_address) | Private IP address of the Private Endpoint |
55+
| <a name="output_storage_account_id"></a> [storage\_account\_id](#output\_storage\_account\_id) | ID of the NFS storage account |
56+
| <a name="output_storage_account_name"></a> [storage\_account\_name](#output\_storage\_account\_name) | Name of the NFS storage account |
57+
| <a name="output_storage_account_primary_file_endpoint"></a> [storage\_account\_primary\_file\_endpoint](#output\_storage\_account\_primary\_file\_endpoint) | Primary file endpoint for NFS access |
58+
| <a name="output_storage_account_primary_location"></a> [storage\_account\_primary\_location](#output\_storage\_account\_primary\_location) | Primary location of the NFS storage account |
59+
<!-- END_TF_DOCS -->

modules/quix-aks/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,5 @@ No modules.
116116
| <a name="output_resource_group_location"></a> [resource\_group\_location](#output\_resource\_group\_location) | Location of the resource group |
117117
| <a name="output_resource_group_name"></a> [resource\_group\_name](#output\_resource\_group\_name) | Name of the resource group |
118118
| <a name="output_vnet_id"></a> [vnet\_id](#output\_vnet\_id) | ID of the virtual network |
119+
| <a name="output_vnet_name"></a> [vnet\_name](#output\_vnet\_name) | Name of the virtual network |
119120
<!-- END_TF_DOCS -->

0 commit comments

Comments
 (0)