This post will show you how to deploy a Static Website on a Storage Account protected with Private Endpoint using Terraform:
Define the terraform providers to use
Create a providers.tf file with the following contents:
1terraform {
2 required_version = "> 0.12"
3 required_providers {
4 azurerm = {
5 source = "azurerm"
6 version = "~> 2.26"
7 }
8 }
9}
10
11provider "azurerm" {
12 features {}
13 skip_provider_registration = true
14}
Define the variables
Create a variables.tf file with the following contents:
1variable "location" {
2 default = "west europe"
3}
4
5variable "resource_group" {
6 default = "web-sta-private-endpoint"
7}
8
9variable "sa_name" {
10 default = "webstapecfm"
11}
Define the required resources
Create a main.tf file with the following contents:
1# Create Resource Group
2resource "azurerm_resource_group" "rg" {
3 name = var.resource_group
4 location = var.location
5}
6
7# Create VNet
8resource "azurerm_virtual_network" "vnet" {
9 name = "private-network"
10 address_space = ["10.0.0.0/16"]
11 location = azurerm_resource_group.rg.location
12 resource_group_name = azurerm_resource_group.rg.name
13}
14
15# Create the Subnet for the jumpbox.
16resource "azurerm_subnet" "jump" {
17 name = "jump"
18 resource_group_name = azurerm_resource_group.rg.name
19 virtual_network_name = azurerm_virtual_network.vnet.name
20 address_prefixes = ["10.0.1.0/24"]
21}
22
23# Create the Subnet for the private endpoints. This is where the IP of the private endpoint will live.
24resource "azurerm_subnet" "endpoint" {
25 name = "endpoint"
26 resource_group_name = azurerm_resource_group.rg.name
27 virtual_network_name = azurerm_virtual_network.vnet.name
28 address_prefixes = ["10.0.2.0/24"]
29
30 enforce_private_link_endpoint_network_policies = true
31}
32
33# Get current public IP. We'll need this so we can access the Storage Account from our PC.
34data "http" "current_public_ip" {
35 url = "http://ipinfo.io/json"
36 request_headers = {
37 Accept = "application/json"
38 }
39}
40
41# Create the "private" Storage Account.
42resource "azurerm_storage_account" "sa" {
43 name = var.sa_name
44 resource_group_name = azurerm_resource_group.rg.name
45 location = azurerm_resource_group.rg.location
46 account_tier = "Standard"
47 account_replication_type = "GRS"
48 enable_https_traffic_only = true
49 # We are enabling the firewall only allowing traffic from our PC's public IP.
50 network_rules {
51 default_action = "Deny"
52 virtual_network_subnet_ids = []
53 ip_rules = [
54 jsondecode(data.http.current_public_ip.body).ip
55 ]
56 }
57
58 static_website {
59 }
60}
61
62resource "azurerm_storage_blob" "page" {
63 name = "index.html"
64 storage_account_name = azurerm_storage_account.sa.name
65 storage_container_name = "$web"
66 type = "Block"
67 source = "index.html"
68}
69
70# Create the privatelink.web.core.windows.net Private DNS Zone
71resource "azurerm_private_dns_zone" "private_web" {
72 name = "privatelink.web.core.windows.net"
73 resource_group_name = azurerm_resource_group.rg.name
74}
75
76# Create the Private endpoint. This is where the Storage account gets a private IP inside the VNet.
77resource "azurerm_private_endpoint" "endpoint_web" {
78 name = "sa-endpoint_web"
79 location = azurerm_resource_group.rg.location
80 resource_group_name = azurerm_resource_group.rg.name
81 subnet_id = azurerm_subnet.endpoint.id
82
83 private_service_connection {
84 name = "sa-privateserviceconnection-web"
85 private_connection_resource_id = azurerm_storage_account.sa.id
86 is_manual_connection = false
87 subresource_names = ["web"]
88 }
89
90 private_dns_zone_group {
91 name = "privatelink-file-web-core-windows-net"
92 private_dns_zone_ids = [azurerm_private_dns_zone.private_web.id]
93 }
94}
95
96# Link the Private Zone with the VNet
97resource "azurerm_private_dns_zone_virtual_network_link" "sa_private_web" {
98 name = "test_web"
99 resource_group_name = azurerm_resource_group.rg.name
100 private_dns_zone_name = azurerm_private_dns_zone.private_web.name
101 virtual_network_id = azurerm_virtual_network.vnet.id
102}
103
104# Public IP for the jumpbox
105resource "azurerm_public_ip" "pip" {
106 name = "jumpbox-ip"
107 location = azurerm_resource_group.rg.location
108 resource_group_name = azurerm_resource_group.rg.name
109 allocation_method = "Static"
110}
111
112# NIC for the jumpbox
113resource "azurerm_network_interface" "nic" {
114 name = "jumpbox-nic"
115 location = azurerm_resource_group.rg.location
116 resource_group_name = azurerm_resource_group.rg.name
117
118 ip_configuration {
119 name = "internal"
120 subnet_id = azurerm_subnet.jump.id
121 private_ip_address_allocation = "Dynamic"
122 public_ip_address_id = azurerm_public_ip.pip.id
123 }
124}
125
126# Create the jumpbox VM
127resource "azurerm_linux_virtual_machine" "jumpbox" {
128 name = "jumpbox"
129 resource_group_name = azurerm_resource_group.rg.name
130 location = azurerm_resource_group.rg.location
131 size = "Standard_F2"
132 admin_username = "adminuser"
133 network_interface_ids = [
134 azurerm_network_interface.nic.id,
135 ]
136
137 os_disk {
138 caching = "ReadWrite"
139 storage_account_type = "Standard_LRS"
140 }
141
142 admin_ssh_key {
143 username = "adminuser"
144 public_key = file(pathexpand("~/.ssh/id_rsa.pub"))
145 }
146
147 source_image_reference {
148 publisher = "Canonical"
149 offer = "UbuntuServer"
150 sku = "16.04-LTS"
151 version = "latest"
152 }
153}
Note:
- The above definition will deploy a jumpbox server with a public IP address so you can access it from your PC. This jumpbox is also deployed in the same VNet as the Storage Account’s Private Endpoint.
- The definition requires your public key to be in
~/.ssh/id_rsa.pub
Define the outputs
Create a outputs.tf file with the following contents:
1output "jumpbox_ip" {
2 value = azurerm_public_ip.pip.ip_address
3}
4
5output "sa_name" {
6 value = var.sa_name
7}
Create a simple Web Page
Create a index.html file with the following contents:
1<!doctype html>
2<html>
3 <head>
4 <title>This is your private static web app.</title>
5 </head>
6 <body>
7 <p>This is your private static web app.</p>
8 </body>
9</html>
Deploy the resources
Run:
1terraform init
2terraform apply
Test the static website
Login to the jumpbox server
1$jumpboxIp=$(terraform output jumpbox_ip)
2ssh adminuser@$jumpboxIp
Run the following command, to test the static website:
1curl -i https://<storage account name>.z6.web.core.windows.net/index.html
You should get a response similar to:
1HTTP/1.1 200 OK
2Content-Length: 180
3Content-Type: application/octet-stream
4Last-Modified: Fri, 17 Sep 2021 11:59:00 GMT
5Accept-Ranges: bytes
6ETag: "0x8D979D28981C913"
7Server: Windows-Azure-Web/1.0 Microsoft-HTTPAPI/2.0
8x-ms-request-id: fb6880b7-a01e-0014-42bb-ab0938000000
9x-ms-version: 2018-03-28
10Date: Fri, 17 Sep 2021 12:01:41 GMT
11
12<!doctype html>
13<html>
14 <head>
15 <title>This is your private static web app.</title>
16 </head>
17 <body>
18 <p>This is your private static web app.</p>
19 </body>
20</html>
That’s it. Hope it helps!!!
Please find the complete terraform configuration here
Comments