Creating a centralized secure storage for storing Terraform state
In my previous blog post, I discussed on how you can create Azure resources
using Terraform by defining the resources configuration in a Terraform
configuration *.tf
files.
If you have not read my previous blog post, you can check them out below:
Getting Started with a centralized Terraform state secure storage
AzCLI
In this walkthrough section, I will demonstrate an example on how you can use AzCLI to deploy a centralized secure storage to store all your Terraform state.
Firstly, I will start by validating all existing resource group names before creating a new resource group in Azure using AzCLI.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
export \
resource_group_name='rg-terraform' \
resource_location='southeastasia' \
storage_account_name='storageterraformstate' \
storage_account_container_name='tfstate' ;
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Validating resource group" ;
if [ "$(az group show \
--name $resource_group_name \
--query 'properties.provisioningState' \
--output 'tsv')" = 'Succeeded' ] ;
then \
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Existing resource group name found" ;
az group show \
--name $resource_group_name ;
else \
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Existing resource group name not found" ;
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Creating resource group" ;
az group create \
--name $resource_group_name \
--location $resource_location ;
fi ;
Next, I will validate all existing storage account names before creating a new storage account in Azure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Validating storage account" ;
if [ "$(az storage account show \
--name $storage_account_name \
--query 'provisioningState' \
--output 'tsv')" = 'Succeeded' ] ;
then \
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Existing storage account name found" ;
az storage account show \
--name $storage_account_name ;
else \
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Existing storage account name not found" ;
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Creating storage account" ;
az storage account create \
--name $storage_account_name \
--resource-group $resource_group_name \
--location $resource_location \
--kind 'StorageV2' \
--sku 'Standard_LRS' ;
fi ;
Since the storage account is created or exist in Azure, I will obtain the storage account key. The storage account key will be used by Terraform later.
1
2
3
4
5
6
7
# Store Azure storage account key as variable
export \
storage_account_key="$(az storage account keys list \
--name $storage_account_name \
--resource-group $resource_group_name \
--query [0].value \
--output tsv)" ;
Finally, I will need to validate the existing blob container names in the
storage account and create a new blob container is it does not existing in the
storage account in Azure. The blob container will be used to contain the
Terraform *.tfstate
state files.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Validating storage container" ;
if [ "$(az storage container show \
--name $storage_account_container_name \
--account-name $storage_account_name \
--account-key $storage_account_key \
--query 'name' \
--output 'tsv')" = $storage_account_container_name ] ;
then \
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Existing storage container name found" ;
az storage container show \
--name $storage_account_container_name \
--account-name $storage_account_name \
--account-key $storage_account_key ;
else \
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Existing storage container name not found" ;
echo "# $(date '+%Y-%m-%d %H:%M:%S %:z') -" \
"Creating storage container" ;
az storage container create \
--name $storage_account_container_name \
--account-name $storage_account_name \
--account-key $storage_account_key ;
fi ;
↑Top
PowerShell
In this walkthrough section, I will demonstrate an example on how you can use
PowerShell Az
module to deploy a centralized secure storage to store all your
Terraform state.
Firstly, I will start by validating all existing resource group names before creating a new resource group in Azure using PowerShell.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$ResourceGroupName = 'rg-terraform' ;
$ResourceLocation = 'southeastasia' ;
$StorageAccountName = 'storageterraformstate' ;
$StorageAccountContainerName = 'tfstate' ;
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Validating resource group") ;
if( `
$(Get-AzResourceGroup `
-Name $ResourceGroupName).ProvisioningState -eq 'Succeeded' ) `
{ `
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Existing resource group name found") ;
Get-AzResourceGroup `
-Name $ResourceGroupName ;
} `
else `
{ `
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Existing resource group name not found") ;
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Creating resource group") ;
New-AzResourceGroup `
-Name $ResourceGroupName `
-Location $ResourceLocation ;
} ;
Next, I will validate all existing storage account names before creating a new storage account in Azure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Validating storage account") ;
if( `
$(Get-AzStorageAccount `
-Name $StorageAccountName `
-ResourceGroupName $ResourceGroupName).ProvisioningState -eq 'Succeeded' ) `
{ `
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Existing storage account name found") ;
Get-AzStorageAccount `
-Name $StorageAccountName `
-ResourceGroupName $ResourceGroupName ;
} `
else `
{ `
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Existing storage account name not found") ;
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Creating storage account") ;
New-AzStorageAccount `
-Name $StorageAccountName `
-ResourceGroupName $ResourceGroupName `
-Location $ResourceLocation `
-Kind 'StorageV2' `
-SkuName 'Standard_LRS' ;
} ;
Since the storage account is created or exist in Azure, I will obtain the storage account key. The storage account key will be used by Terraform later.
1
2
3
4
# Store Azure storage account key as variable
$StorageAccountKey = (Get-AzStorageAccountKey `
-Name $StorageAccountName `
-ResourceGroupName $ResourceGroupName).Value[0] ;
Finally, I will need to validate the existing blob container names in the
storage account and create a new blob container is it does not existing in the
storage account in Azure. The blob container will be used to contain the
Terraform *.tfstate
state files.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Validating storage container") ;
if( `
$(Get-AzStorageContainer `
-Name $StorageAccountContainerName `
-Context $(Get-AzStorageAccount `
-Name $StorageAccountName `
-ResourceGroupName $ResourceGroupName).Context).Name -eq $StorageAccountContainerName ) `
{ `
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Existing storage container name found") ;
Get-AzStorageContainer `
-Name $StorageAccountContainerName `
-Context $(Get-AzStorageAccount `
-Name $StorageAccountName `
-ResourceGroupName $ResourceGroupName).Context ;
} `
else `
{ `
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Existing storage container name not found") ;
Write-Host $("{0}{1}" `
-f "# $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz') - ", `
"Creating storage container") ;
New-AzStorageContainer `
-Name $StorageAccountContainerName `
-Context $(Get-AzStorageAccount `
-Name $StorageAccountName `
-ResourceGroupName $ResourceGroupName).Context ;
} ;
↑Top
Example - Creating resource group using Terraform with centralized secure storage
Assuming that you already have terraform
in your environment, let us begin
creating a resource group using terraform
as an example with the Terraform
*.tfstate
state file stored in the centralized secure storage in Azure
instead of your local working directory.
If you do not have it, you can refer to my previous blog post on how to obtain it.
Note:
Depending on whether if you are using AzCLI or PowerShell, you will need to authenticate to Azure.
1 2# Login to Azure using AzCLI az login
or
1 2 # Login to Azure using PowerShell Connect-AzAccountOnce you have authenticated, proceed with the steps below with your preferred console or terminal.
1
2
# Create a folder name for the terraform example
mkdir -p ~/Terraform/example2
Note:
Depending on which console or terminal that you are using, you may need to replace the
\
line break for Shell with`
line break for PowerShell.
Firstly, define the provider in the main.tf
file.
1
2
3
4
5
6
7
8
9
echo \
'# Configure the Azure provider
provider "azurerm" {
version = "~>1.5"
}
terraform {
backend "azurerm" {}
}' > ~/Terraform/example2/main.tf
Secondly, define the resource in the resource.tf
file.
1
2
3
4
5
6
7
8
9
10
echo \
'# Create a new resource group
resource "azurerm_resource_group" "rg" {
name = "terraform-resource-group"
location = "southeastasia"
tags = {
Environment = "Development"
DeploymentType = "Terraform"
}
}' > ~/Terraform/example2/resource.tf
Once you have defined the configuration in main.tf
and resource.tf
files,
execute teeraform
with init
argument to initialize the working directory.
1
2
3
4
5
6
7
# Initialize a working directory containing Terraform configuration files
terraform init \
-backend-config="storage_account_name=$StorageAccountName" \
-backend-config="container_name=$StorageAccountContainerName" \
-backend-config="access_key=$StorageAccountKey" \
-backend-config="key=azure.terraform.tfstate" \
~/Terraform/example2
Next, use the plan
argument with the -out
parameter to generate the
execution plan file from the working directory.
1
2
3
4
# Create an execution plan
terraform plan \
-out ~/Terraform/example2/out.plan \
~/Terraform/example2
Finally, use the apply
argument with the execution plan file to apply
changes in Azure.
1
2
3
4
# Apply the changes
terraform apply \
-state ~/Terraform/example2/terraform.tfstate \
~/Terraform/example2/out.plan
Now, go to your Azure and check if the resource group has been created. You can
also find a Terraform *.tfstate
file created in the storage account blob
container as the centralized secure storage location.
↑Top
References
- Microsoft Docs - Azure Terraform Documentation
- Terraform CLI Docs- Terraform Commands (CLI)
- Terraform Docs - Configuration Language
- Terraform Docs - Terraform State
- Getting started with Azure deployment using Terraform
↑Top
Related Books
↑Top