Skip to content

Commit

Permalink
feat: terraform networking (#1)
Browse files Browse the repository at this point in the history
Adds `terraform-init` for setting up the Storage Account to be used for
terraform state
Adds `terraform` for deploying the resource group, virtual network,
subnet and a Ubuntu 24.04 VM with the SSH key saved as a file.
  • Loading branch information
shejri authored Sep 18, 2024
1 parent 160c57d commit ab9a96a
Show file tree
Hide file tree
Showing 28 changed files with 534 additions and 0 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/terraform.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: 'Terraform Azure Deployment'

on:
workflow_dispatch:
inputs:
directory:
type: choice
description: Terraform directory to apply
required: true
options:
- terraform-init
- terraform
workspace:
type: choice
description: Terraform workspace used for staging
required: true
options:
- dev
- qa
- prod

jobs:
terraform:
name: 'Terraform Apply'
runs-on: ubuntu-latest

steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4

- name: 'Setup Terraform'
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.9.5

- name: 'Configure Azure Credentials - az login'
run: |
az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }}
az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: 'Terraform Init'
run: |
cd ${{github.event.inputs.directory}}
source scripts/helpers.sh
export RESOURCE_GROUP_NAME=$(extract_value "resource_group_name" config.azurerm.tfbackend)
export STORAGE_ACCOUNT_NAME=$(extract_value "storage_account_name" config.azurerm.tfbackend)
export ARM_ACCESS_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP_NAME --account-name $STORAGE_ACCOUNT_NAME --query '[0].value' -o tsv)
terraform workspace list
terraform workspace new ${{github.event.inputs.directory}}
terraform workspace select ${{github.event.inputs.directory}}
terrafor workspace show
terraform init --backend-config=config.azurerm.tfbackend
- name: 'Terraform Plan'
run: |
terraform plan -out main.tfplan
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.*
*.tfstate
*.tfstate.backup
*.tfplan
*temp*.txt
*.pem
ssh.key

!.github
!.gitignore
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,65 @@
# wp10-image-factory
CARIAD Frame Contract WP10 Image Factory

# Contents
- `terraform-init` - terraform code for setting up an Azure Storage Account that can be used for saving the terraform state
- `terraform` - terraform modules for deploying the resource group, virtual network, subnet, VM

# Requirements
- Access to Azure Resource Manager
- `terraform >=1.0.0`, tested with `1.9.5`
- Azure CLI, tested with `2.64.0`
- Azure credentials saved as environment variables:
```
export AZURE_CLIENT_ID=
export AZURE_CLIENT_SECRET=
export AZURE_TENANT_ID=
export AZURE_SUBSCRIPTION_ID=
```

# Usage
Login to Azure and select subscription
```
az login --service-principal -u $AZURE_CLIENT_ID -p AZURE_CLIENT_SECRET --tenant AZURE_TENANT_ID
az account set --subscription AZURE_SUBSCRIPTION_ID
```

Setting up a Storage Account for the terraform state backend using terraform-init
```
# Change directory to
cd terraform-init
terraform init
terraform plan
terraform apply
```
Mark down the output containing Azure Storage Account details and create `config.azurerm.tfbackend` from `config.azurerm.tfbackend.tempalte`

Deploying network and runner modules
```
# Change into main terraform directory
cd terraform
# Source helper functions
source scripts/helpers.sh
# Retrieve Storage Account Access key
export RESOURCE_GROUP_NAME=$(extract_value "resource_group_name" config.azurerm.tfbackend)
export STORAGE_ACCOUNT_NAME=$(extract_value "storage_account_name" config.azurerm.tfbackend)
export ARM_ACCESS_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP_NAME --account-name $STORAGE_ACCOUNT_NAME --query '[0].value' -o tsv)
# Decide on a terraform workspace
terraform workspace list
terraform workspace new # Create a terraform workspace, can be used for staging
terraform workspace select # Or select an existing workspace
# Initialize terraform with Azure Storage Account backend
terraform init --backend-config=config.azurerm.tfbackend
# Plan, review and apply
terraform plan -out main.tfplan
terraform apply main.tfplan
```

The SSH key associated with the VM will be saved in the current working directory as `private_key.pem`
18 changes: 18 additions & 0 deletions terraform-init/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
terraform {
required_version = ">=1.0"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~>3.0"
}
random = {
source = "hashicorp/random"
version = "~>3.0"
}
}
}

provider "azurerm" {
features {}
}
6 changes: 6 additions & 0 deletions terraform-init/modules.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module "state_storage" {
source = "./modules/state-storage"

prefix = var.prefix
resource_group_location = var.state_rg_location
}
1 change: 1 addition & 0 deletions terraform-init/modules/state-storage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO
11 changes: 11 additions & 0 deletions terraform-init/modules/state-storage/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
output "resource_group_name" {
value = azurerm_resource_group.state_rg.name
}

output "state_storage_account_name" {
value = azurerm_storage_account.tfstate.name
}

output "state_container_name" {
value = azurerm_storage_container.tfstate.name
}
29 changes: 29 additions & 0 deletions terraform-init/modules/state-storage/storage.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
resource "azurerm_resource_group" "state_rg" {
location = var.resource_group_location
name = "${var.prefix}-state-rg"
}

resource "azurerm_storage_account" "tfstate" {
name = "tfstate${random_string.resource_code.result}"
resource_group_name = azurerm_resource_group.state_rg.name
location = azurerm_resource_group.state_rg.location
account_tier = "Standard"
account_replication_type = "LRS"
allow_nested_items_to_be_public = false

tags = {
environment = "staging"
}
}

resource "azurerm_storage_container" "tfstate" {
name = "tfstate"
storage_account_name = azurerm_storage_account.tfstate.name
container_access_type = "private"
}

resource "random_string" "resource_code" {
length = 5
special = false
upper = false
}
9 changes: 9 additions & 0 deletions terraform-init/modules/state-storage/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
variable "prefix" {
type = string
description = "Prefix of the resource name"
}

variable "resource_group_location" {
type = string
description = "Location of the resource group."
}
11 changes: 11 additions & 0 deletions terraform-init/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
output "resource_group_name" {
value = module.state_storage.resource_group_name
}

output "state_storage_account_name" {
value = module.state_storage.state_storage_account_name
}

output "state_container_name" {
value = module.state_storage.state_container_name
}
16 changes: 16 additions & 0 deletions terraform-init/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
variable "state_rg_location" {
default = "westeurope"
description = "Location of the resource group."
}

variable "resource_group_location" {
default = "westeurope"
description = "Location of the resource group."
}

variable "prefix" {
type = string
default = "cariad-wp10"
description = "Prefix of the resource name"
}

4 changes: 4 additions & 0 deletions terraform/config.azurerm.tfbackend
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resource_group_name = "cariad-wp10-state-rg"
storage_account_name = "tfstateodd4r"
container_name = "tfstate"
key = "imagefactory.tfstate"
9 changes: 9 additions & 0 deletions terraform/config.azurerm.tfbackend.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# az login
# ACCOUNT_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP_NAME --account-name $STORAGE_ACCOUNT_NAME --query '[0].value' -o tsv)
# where $RESOURCE_GROUP_NAME and $STORAGE_ACCOUNT_NAME correspond to ones set below
# export ARM_ACCESS_KEY=$ACCOUNT_KEY

resource_group_name = "example-rg"
storage_account_name = "examplestorage"
container_name = "examplecontainer"
key = "example.tfstate"
27 changes: 27 additions & 0 deletions terraform/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
terraform {
required_version = ">=1.0"

required_providers {
azapi = {
source = "Azure/azapi"
version = "~>1.15"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~>3.0"
}
random = {
source = "hashicorp/random"
version = "~>3.0"
}
}

backend "azurerm" {}
}

provider "azurerm" {
features {}
}

provider "azapi" {
}
17 changes: 17 additions & 0 deletions terraform/modules.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module "network" {
source = "./modules/network"

prefix = var.prefix
resource_group_location = var.resource_group_location
}

module "runner" {
source = "./modules/runner"

prefix = var.prefix
resource_group_location = var.resource_group_location
resource_group_name = module.network.resource_group.name
resource_group_id = module.network.resource_group.id
subnet_id = module.network.azurerm_subnet.id
}

Empty file.
20 changes: 20 additions & 0 deletions terraform/modules/network/network.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
resource "azurerm_resource_group" "wp10_rg" {
location = var.resource_group_location
name = "${var.prefix}-rg"
}

# Create virtual network
resource "azurerm_virtual_network" "wp10_vnet" {
name = "${var.prefix}-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.wp10_rg.location
resource_group_name = azurerm_resource_group.wp10_rg.name
}

# Create subnet
resource "azurerm_subnet" "wp10_subnet" {
name = "${var.prefix}-subnet"
resource_group_name = azurerm_resource_group.wp10_rg.name
virtual_network_name = azurerm_virtual_network.wp10_vnet.name
address_prefixes = ["10.0.1.0/24"]
}
9 changes: 9 additions & 0 deletions terraform/modules/network/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "resource_group" {
value = azurerm_resource_group.wp10_rg
}
output "azurerm_virtual_network" {
value = azurerm_virtual_network.wp10_vnet
}
output "azurerm_subnet" {
value = azurerm_subnet.wp10_subnet
}
12 changes: 12 additions & 0 deletions terraform/modules/network/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
variable "prefix" {
type = string
description = "Prefix of the resource name"
}

variable "resource_group_location" {
type = string
description = "Location of the resource group."
}



1 change: 1 addition & 0 deletions terraform/modules/runner/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TODO
8 changes: 8 additions & 0 deletions terraform/modules/runner/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
output "public_ip_address" {
value = azurerm_linux_virtual_machine.main.public_ip_address
}

output "key_data" {
value = azapi_resource_action.ssh_public_key_gen.output.publicKey
}

10 changes: 10 additions & 0 deletions terraform/modules/runner/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">=1.0"

required_providers {
azapi = {
source = "Azure/azapi"
version = "~>1.15"
}
}
}
Loading

0 comments on commit ab9a96a

Please sign in to comment.