This content originally appeared on DEV Community and was authored by Achref Rhouma
Building a Secure DevOps Pipeline on Azure with Terraform & GitHub Actions
Why This Guide?
Every DevOps engineer dreams of fully automated, secure infrastructure. This article shows how to build a production-ready Azure pipeline using Terraform and GitHub Actions, with built-in security checks and deployment automation.
1⃣ Step 1 — Provision Azure Infrastructure with Terraform
We’ll create a Resource Group, VNet, and an NSG for secure app deployment.
# main.tf
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rg" {
name = "rg-devsec-demo"
location = "westeurope"
}
resource "azurerm_virtual_network" "vnet" {
name = "vnet-devsec"
address_space = ["10.10.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_subnet" "app_subnet" {
name = "app-subnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.10.1.0/24"]
}
resource "azurerm_network_security_group" "nsg" {
name = "nsg-app"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
security_rule {
name = "Allow-HTTPS-Internet"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_address_prefix = "Internet"
destination_port_range = "443"
}
}
resource "azurerm_subnet_network_security_group_association" "assoc" {
subnet_id = azurerm_subnet.app_subnet.id
network_security_group_id = azurerm_network_security_group.nsg.id
}
2⃣ Step 2 — GitHub Actions Workflow
Automate Terraform plan & apply, plus run a security linting check.
# .github/workflows/terraform.yml
name: Terraform CI/CD
on:
push:
branches:
- main
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
- name: Terraform Init
run: terraform init
- name: Terraform Validate
run: terraform validate
- name: Terraform Plan
run: terraform plan -out=tfplan
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: terraform apply -auto-approve tfplan
Tip: Add
tflint
or checkov
in the workflow for automated security scanning.
3⃣ Step 3 — Integrate Azure Key Vault for Secrets
resource "azurerm_key_vault" "kv" {
name = "kv-devsec-${random_integer.suffix.result}"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
sku_name = "standard"
tenant_id = data.azurerm_client_config.current.tenant_id
purge_protection_enabled = true
soft_delete_enabled = true
}
resource "azurerm_key_vault_access_policy" "admin_policy" {
key_vault_id = azurerm_key_vault.kv.id
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = "YOUR_AAD_GROUP_OBJECT_ID"
key_permissions = [
"get",
"list",
"create",
"delete"
]
}
4⃣ Step 4 — Continuous Security Checks
Add Azure Policy compliance checks to enforce:
- NSG inbound rules restrictions
- Private endpoints for Key Vault
- Tagging policies for all resources
# Assign built-in Azure Policy
az policy assignment create \
--name "nsg-inbound-check" \
--scope "/subscriptions/<SUBSCRIPTION_ID>" \
--policy "/providers/Microsoft.Authorization/policyDefinitions/NSGInboundRule"
Key Takeaways
- Terraform + GitHub Actions = fully automated, secure deployment.
- Always scan and lint your IaC code before deployment.
- Use RBAC + Key Vault to protect secrets and keys.
- Continuous compliance ensures long-term security.
Challenge:
Add a private endpoint to Key Vault and modify the workflow to only deploy when the endpoint is private. Share your code snippets in the comments!
This content originally appeared on DEV Community and was authored by Achref Rhouma