Compare commits

6 Commits

Author SHA1 Message Date
Jake dbbb40a9a8 Daily snapshot: 2025-11-13 2025-11-13 05:30:01 +00:00
Jake 7b3c156c7a Daily snapshot: 2025-11-10 2025-11-10 06:56:47 +00:00
Jake b533e11611 Daily snapshot: 2025-11-10 2025-11-10 06:48:33 +00:00
Jake fabb609840 Daily snapshot: 2025-11-08 2025-11-08 21:06:54 +00:00
Jake 36808ca32a potential ci/cd process in the works 2025-11-08 12:47:09 +00:00
Jake 56ea4c6178 test: 🚦 Added some of my own tweaks to build knowledge 2025-11-08 10:55:22 +00:00
21 changed files with 556 additions and 86 deletions
@@ -0,0 +1,9 @@
---
globs: "**/*.tf"
description: When a module depends on another module, it should only reference
the outputs of that module, not its internal resources or variables. This
promotes loose coupling and better maintainability.
alwaysApply: true
---
Avoid tight coupling between modules by having one module depend on another's internal implementation details
+68
View File
@@ -0,0 +1,68 @@
name: Terraform CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
terraform:
runs-on: ubuntu-latest
env:
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Init (Dev)
run: |
cd environments/dev
terraform init
continue-on-error: false
- name: Terraform Plan (Dev)
run: |
cd environments/dev
terraform plan -out=dev.plan
continue-on-error: false
- name: Terraform Apply (Dev)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
cd environments/dev
terraform apply dev.plan
continue-on-error: false
- name: Terraform Init (Prod)
run: |
cd environments/prod
terraform init
continue-on-error: false
- name: Terraform Plan (Prod)
run: |
cd environments/prod
terraform plan -out=prod.plan
continue-on-error: false
- name: Terraform Apply (Prod)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
cd environments/prod
terraform apply prod.plan
continue-on-error: false
- name: Terraform Validate
run: |
cd environments/dev
terraform validate
cd ../prod
terraform validate
-31
View File
@@ -1,31 +0,0 @@
# name: Terraform
# on:
# pull_request:
# branches: [ "main" ]
# push:
# branches: [ "main" ]
# jobs:
# terraform:
# runs-on: ubuntu-latest
# steps:
# - name: Checkout code
# uses: actions/checkout@v3
# - name: Setup Terraform
# uses: hashicorp/setup-terraform@v2
# - name: Terraform Init
# run: terraform -chdir=environments/dev init
# - name: Terraform Validate
# run: terraform -chdir=environments/dev validate
# - name: Terraform Plan
# run: terraform -chdir=environments/dev plan
# - name: Terraform Apply
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
# run: terraform -chdir=environments/dev apply -auto-approve
+68
View File
@@ -0,0 +1,68 @@
name: Terraform CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
terraform:
runs-on: ubuntu-latest
env:
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Init (Dev)
run: |
cd environments/dev
terraform init
continue-on-error: false
- name: Terraform Plan (Dev)
run: |
cd environments/dev
terraform plan -out=dev.plan
continue-on-error: false
- name: Terraform Apply (Dev)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
cd environments/dev
terraform apply dev.plan
continue-on-error: false
- name: Terraform Init (Prod)
run: |
cd environments/prod
terraform init
continue-on-error: false
- name: Terraform Plan (Prod)
run: |
cd environments/prod
terraform plan -out=prod.plan
continue-on-error: false
- name: Terraform Apply (Prod)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
cd environments/prod
terraform apply prod.plan
continue-on-error: false
- name: Terraform Validate
run: |
cd environments/dev
terraform validate
cd ../prod
terraform validate
+3
View File
@@ -7,3 +7,6 @@
# Local configs
terraform.tfvars
*.override.tf
.env
secrets.sh
+2 -8
View File
@@ -1,12 +1,6 @@
# Terraform Azure Bootcamp
# Aiimi Data CoP Azure Sandbox Environment
This repo contains hands-on Terraform projects on Azure, following a structured learning path:
1. Foundations (VM, Virtual Network)
2. Modules
3. Remote State & Environments
4. Scaling & Advanced Patterns
5. Security & Testing
6. Production-Ready 3-Tier Architecture
## 📂 Structure
- `modules/` → reusable Terraform modules (network, compute, database, etc.)
-8
View File
@@ -1,8 +0,0 @@
terraform {
backend "azurerm" {
resource_group_name = "terraform"
storage_account_name = "tfstoracccom"
container_name = "tfstate"
key = "dev.terraform.tfstate"
}
}
+62 -26
View File
@@ -2,35 +2,33 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "4.46.0"
version = "4.52.0"
}
}
}
provider "azurerm" {
features {}
subscription_id = "4b2d6154-f4c5-4854-be82-12dfc82d4d23"
subscription_id = "0c8b6184-985d-4f31-b57e-c91f921241bd"
# JP Personal sub
}
module "network" {
source = "../../modules/network"
vnet_name = "dev-vnet"
resource_group_name = "terraform"
location = "UK South"
address_space = ["10.0.0.0/16"]
subnets = { public = "10.0.1.0/24", private = "10.0.2.0/24" }
environment = "dev"
project = "TerraformBootcamp"
resource "azurerm_resource_group" "rg" {
name = var.resource_group_name
location = var.location
}
data "azurerm_ssh_public_key" "kp" {
name = "terraform-kp"
resource_group_name = "terraform"
resource "azurerm_storage_account" "storage" {
name = var.storage_account_name
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_tier = "Standard"
account_replication_type = "LRS"
}
data "azurerm_ssh_public_key" "sd" {
name = "sbcomsam-d-01"
resource_group_name = "terraform"
resource "azurerm_storage_container" "terraform_state" {
name = "terraform-state"
storage_account_id = azurerm_storage_account.storage.id
}
data "http" "my_ip" {
@@ -39,15 +37,53 @@ data "http" "my_ip" {
locals {
my_ip = chomp(data.http.my_ip.response_body)
ssh_public_key = file("~/.ssh/id_rsa.pub")
storage_account_url = "https://${azurerm_storage_account.storage.name}.blob.core.windows.net"
}
module "compute" {
source = "../../modules/compute"
resource_group_name = "terraform"
location = "UK South"
subnet_id = module.network.subnet_ids["public"]
vm_size = "Standard_B1s"
admin_username = "azureuser"
ssh_public_key = data.azurerm_ssh_public_key.sd.public_key
ex_ip = local.my_ip
module "network" {
source = "../../modules/network"
vnet_name = "vnet"
resource_group_name = var.resource_group_name
location = var.location
address_space = ["10.0.0.0/16"]
subnets = { public = "10.0.1.0/24", private = "10.0.2.0/24" }
environment = var.environment
project = var.project_name
}
module "sql_server" {
source = "../../modules/database"
resource_group_name = var.resource_group_name
location = var.location
environment = var.environment
sql_admin_password = var.sql_admin_password
sql_server_name = var.sql_server_name
olap_database_name = var.olap_database_name
oltp_database_name = var.oltp_database_name
}
module "data_factory" {
source = "../../modules/data_factory"
resource_group_name = var.resource_group_name
location = var.location
environment = var.environment
storage_account_url = local.storage_account_url
data_factory_name = var.data_factory_name
sql_admin_password = var.sql_admin_password
sql_server_name = var.sql_server_name
olap_database_name = var.olap_database_name
oltp_database_name = var.oltp_database_name
}
# module "compute" {
# source = "../../modules/compute"
# resource_group_name = var.resource_group_name
# location = var.location
# subnet_id = module.network.subnet_ids["public"]
# vm_size = "Standard_B1s"
# admin_username = "demo"
# ssh_public_key = file("~/.ssh/id_rsa.pub")
# ex_ip = chomp(data.http.my_ip.response_body)
# }
-7
View File
@@ -1,7 +0,0 @@
output "my_ip" {
value = local.my_ip
}
output "vm_public_ip" {
value = module.compute.vm_public_ip.ip_address
}
+43
View File
@@ -0,0 +1,43 @@
variable "resource_group_name" {
default = "the_data_sandbox_dev"
}
variable "location" {
default = "uksouth"
}
variable "storage_account_name" {
default = "devdatasandboxstore"
}
variable "environment" {
default = "dev"
}
variable "project_name" {
default = "TheDataSandBox"
}
variable "data_factory_name" {
description = "The unique name of the data factory"
type = string
default = "data-sandbox-factory-dev"
}
variable "sql_admin_password" {
description = "SQL Server administrator password"
type = string
default = "4-v3ry-53cr37-p455w0rd" # terraform docs
}
variable "sql_server_name" {
default = "aiimi-cop-sandbox-sql-server"
}
variable "oltp_database_name" {
default = "oltp_master"
}
variable "olap_database_name" {
default = "olap_master"
}
View File
+50
View File
@@ -0,0 +1,50 @@
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "4.52.0"
}
}
}
provider "azurerm" {
features{}
subscription_id = "0c8b6184-985d-4f31-b57e-c91f921241bd"
# JP Personal sub
}
# Remote state backend for prod environment
terraform {
backend "azurerm" {
resource_group_name = "the_data_sandbox"
storage_account_name = "datasandboxstore"
container_name = "terraform-state"
key = "prod.tfstate"
}
}
module "network" {
source = "../../modules/network"
vnet_name = "prod-vnet"
resource_group_name = "the_data_sandbox_prod"
location = "uksouth"
address_space = ["10.1.0.0/16"]
subnets = { public = "10.1.1.0/24", private = "10.1.2.0/24" }
environment = "prod"
project = "TheDataSandBox"
}
module "compute" {
source = "../../modules/compute"
resource_group_name = "the_data_sandbox_prod"
location = "uksouth"
subnet_id = module.network.subnet_ids["public"]
vm_size = "Standard_D2s_v3"
admin_username = "demo"
ssh_public_key = file("~/.ssh/id_rsa.pub")
ex_ip = chomp(data.http.my_ip.response_body)
}
data "http" "my_ip" {
url = "https://checkip.amazonaws.com/"
}
View File
+7
View File
@@ -0,0 +1,7 @@
variable "resource_group_name" {
default = "the_data_sandbox_prod"
}
variable "location" {
default = "uksouth"
}
+6 -2
View File
@@ -59,9 +59,13 @@ resource "azurerm_linux_virtual_machine" "vm" {
storage_account_type = "Standard_LRS"
}
source_image_reference {
offer = "ubuntu-24_04-lts"
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts-gen2"
sku = "server"
version = "latest"
}
tags = {
volatile = true
}
}
+31
View File
@@ -0,0 +1,31 @@
resource "azurerm_data_factory" "factory" {
name = var.data_factory_name
location = var.location
resource_group_name = var.resource_group_name
tags = {
volatile = true
}
}
# Linked services for SQL databases
resource "azurerm_data_factory_linked_service_azure_sql_database" "ls_oltp_database" {
name = "ls_oltp_database"
data_factory_id = azurerm_data_factory.factory.id
connection_string = "data source=${var.sql_server_name}.database.windows.net;initial catalog=${var.oltp_database_name};user id=4dm1n157r470r;Password=${var.sql_admin_password};integrated security=False;encrypt=True;connection timeout=30"
}
resource "azurerm_data_factory_linked_service_azure_sql_database" "ls_olap_database" {
name = "ls_olap_database"
data_factory_id = azurerm_data_factory.factory.id
connection_string = "data source=${var.sql_server_name}.database.windows.net;initial catalog=${var.olap_database_name};user id=4dm1n157r470r;Password=${var.sql_admin_password};integrated security=False;encrypt=True;connection timeout=30"
}
# TODO: Set up linked services and datasets
# resource "azurerm_data_factory_linked_service_data_lake_storage_gen2" "ls_container_storage" {
# name = "ls_container_storage"
# data_factory_id = azurerm_data_factory.factory.id
# url = var.storage_account_url
# }
+47
View File
@@ -0,0 +1,47 @@
variable "resource_group_name" {
description = "Resource Group to create resources in"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "environment" {
description = "Environment tag (dev/prod)"
type = string
}
variable "project" {
description = "Project tag"
type = string
default = "TerraformBootcamp"
}
variable "storage_account_url" {
description = "URL of the storage account to link to data factory"
type = string
}
variable "data_factory_name" {
description = "The unique name of the data factory"
type = string
}
variable "sql_admin_password" {
description = "SQL Server administrator password"
type = string
}
variable "sql_server_name" {
type = string
}
variable "oltp_database_name" {
type = string
}
variable "olap_database_name" {
type = string
}
+54
View File
@@ -0,0 +1,54 @@
resource "azurerm_mssql_server" "sql_server" {
name = var.sql_server_name
resource_group_name = var.resource_group_name
location = var.location
version = "12.0"
administrator_login = "4dm1n157r470r" # terraform docs
administrator_login_password = var.sql_admin_password
}
resource "azurerm_mssql_database" "oltp_database" {
name = var.oltp_database_name
server_id = azurerm_mssql_server.sql_server.id
collation = "SQL_Latin1_General_CP1_CI_AS"
license_type = "LicenseIncluded" # tbc, developer?
sku_name = "S0" # az sql db list-editions -l uksouth -o table
storage_account_type = "Local"
geo_backup_enabled = false
tags = {
volatile = true
}
lifecycle {
# prevent_destroy = true
prevent_destroy = false
# it should actually be true, so data is safe
# however our sandbox environment should be
# ripped out completely.
}
}
resource "azurerm_mssql_database" "olap_database" {
name = var.olap_database_name
server_id = azurerm_mssql_server.sql_server.id
collation = "SQL_Latin1_General_CP1_CI_AS"
license_type = "LicenseIncluded" # tbc, developer?
sku_name = "S0" # az sql db list-editions -l uksouth -o table
storage_account_type = "Local"
geo_backup_enabled = false
tags = {
volatile = true
}
lifecycle {
# prevent_destroy = true
prevent_destroy = false
# it should actually be true, so data is safe
# however our sandbox environment should be
# ripped out completely.
}
}
+3
View File
@@ -0,0 +1,3 @@
output "sql_server_id" {
value = azurerm_mssql_server.sql_server.id
}
+31
View File
@@ -0,0 +1,31 @@
variable "resource_group_name" {
description = "Resource Group to create resources in"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "environment" {
description = "Environment tag (dev/prod)"
type = string
}
variable "sql_admin_password" {
description = "SQL Server administrator password"
type = string
}
variable "sql_server_name" {
type = string
}
variable "oltp_database_name" {
type = string
}
variable "olap_database_name" {
type = string
}
+68
View File
@@ -0,0 +1,68 @@
name: Terraform CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
terraform:
runs-on: ubuntu-latest
env:
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Init (Dev)
run: |
cd environments/dev
terraform init
continue-on-error: false
- name: Terraform Plan (Dev)
run: |
cd environments/dev
terraform plan -out=dev.plan
continue-on-error: false
- name: Terraform Apply (Dev)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
cd environments/dev
terraform apply dev.plan
continue-on-error: false
- name: Terraform Init (Prod)
run: |
cd environments/prod
terraform init
continue-on-error: false
- name: Terraform Plan (Prod)
run: |
cd environments/prod
terraform plan -out=prod.plan
continue-on-error: false
- name: Terraform Apply (Prod)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: |
cd environments/prod
terraform apply prod.plan
continue-on-error: false
- name: Terraform Validate
run: |
cd environments/dev
terraform validate
cd ../prod
terraform validate