Posted: Wednesday, January 11, 2023

Word Count: 766

Reading Time: 4 minutes


Summary

Introduction

Azure storage is a cost affordable option for hosting static websites, and fairly easy to setup. This lab was created to deploy a static website on Azure Storage leverage terraform code.

Diagram

Tools

UtilityLink
Azure Storage Static Website RepositoryClick Here
Visual Studio CodeClick Here

Cost Summary Table

The cost assumes the following:

ResourcesCost Estimate Per Month
Storage Account (LRS)$0.30
100,000 write operations$0.50
100,000 list and create operations$0.50
1,000,000 read operations$0.40
300,000 remaining operations$0.12
Total Monthly Estimate$1.82

Summary of modules

I’m a fan of modularization, and although this could have been deployed into a single tf file, creating modules allows more versatility and personalization to the deployment. I realize that not everything needs to be modularized; however, I also know that when I’m searching for code, I’ve come to appreciate those who create modules. It allows me to grab what I need versus sifting through 1000+ lines of code. For this lab, I created 7 terraform modules.

ModulesDescription
currentInfo.tfContains information regarding current subscription id, client id and external IP address.
randomid.tfused to generate random id for storage account name
uploadprovisioner.tfruns a task to upload a test index.html File into the $web folder
storageAccount.tfProvisions a static web enabled storage account
storageAccountNetworkRulesApplies an Access list to the storage account

Module(s) Detail

The contents of each module are provided in this section.

currentInfo.tf

The only thing this lab leverages is the bolded resource. However it’s a module that I use quite often and simply copy as is it to the required deployment.

data "http" "ip" {
  url = "http://ipv4.icanhazip.com"
}

data "azurerm_client_config" "current" {}

output "MyextIP" {
  value = chomp(data.http.ip.response_body)
}

output "myextIPCIDR" {
  value = "${chomp(data.http.ip.response_body)}/32"
}

output "tenant_id" {
  value = data.azurerm_client_config.current.tenant_id
}

output "subscription_id" {
  value = data.azurerm_client_config.current.subscription_id
}

output "object_id" {
  value = data.azurerm_client_config.current.object_id
}

output "client_id" {
  value = data.azurerm_client_config.current.client_id
}
randomId.tf

Its sole purpose is to generate a random value that can be appended to the storage account name since storage account names are required to be globally unique.

resource "random_id" "randomId" {
  byte_length = 4

}

output "id" {
  value = random_id.randomId.id

}

output "hex" {
  value = random_id.randomId.hex

}
uploadProvisioner

This module is executed after the creation of the storage account and uploads the embedded index.html file into the $web directory.

resource "null_resource" "fileUpload" {
  provisioner "local-exec" {
    command = <<Settings
    $resourceGroupName = "${var.resource_group_name}"
    $storageAccountName = "${var.storage_account_name}"
    $storageAccount = Get-AzStorageAccount -StorageAccountName $storageAccountName -ResourceGroupName $resourceGroupName
    $context = $storageAccount.context
    $HTMLUL = @{
    File             = 'index.html'
    Container        = '$web'
    Blob             = 'index.html'
    Context          = $context
    StandardBlobTier = 'Hot'
  }

  Set-AzStorageBlobContent @HTMLUL -Properties @{"ContentType" = "text/html"} -Verbose
    Settings

    interpreter = ["PowerShell", "-Command"]
  }
}
storageAccount

Provisions the storage account and enables static web hosting.

resource "azurerm_storage_account" "storage_account" {

  name                          = var.storage_account_name
  location                      = var.location
  tags                          = var.tags
  account_kind                  = var.account_kind
  public_network_access_enabled = var.public_network_access_enabled

  resource_group_name           = var.resource_group_name
  account_tier                  = var.account_tier
  account_replication_type      = var.account_replication_type
  access_tier                   = var.access_tier
  enable_https_traffic_only     = var.enable_https_traffic_only
  static_website {
    index_document = var.index_document
  }

}


output "URL" {
  value = azurerm_storage_account.storage_account.primary_web_endpoint
}
storageAccountNetworkRules

Creates an access list that only allows access to the website from the originating external IP.

resource "azurerm_storage_account_network_rules" "saNetworkRules" {
  storage_account_id         = var.storage_account_id
  default_action             = var.default_action
  ip_rules                   = [var.ip_rules]
}
resourceGroup

Provisions the resource group that the resources will be contained within.

resource "azurerm_resource_group" "RG" {
  name     = var.resource_group_name
  location = var.location
  tags     = var.tags
}

output "resource_group_name" {
  value = azurerm_resource_group.RG.name
}

Conclusion

Once the script has completed, the storage account should be provisioned, the $web folder created, and the index.html file uploaded. The URL should be immediately accessible. You will find the URL apart of the outputs once the script has completed.