DEV Community

Akingbade Omosebi
Akingbade Omosebi

Posted on

🌍 From Code to Cloud: My DevOps + DevSecOps Journey. (Part 3/4 - The Execution)

Part 3 – Terraform and Secure Cloud Infrastructure

In Part 2, I showed how my GitHub Actions pipeline automated builds, scans, and deployments for my portfolio app.

Now it’s time to talk about infrastructure — the piece that made everything real in the cloud.

🛠️ Why Terraform?

I could have clicked buttons in the Azure portal and spun up resources manually. I mean I have already done that in the past before and that would also defeat the whole purpose, I wanted something different, a different challenge without straying from my main goal.

The goal of this project was to showcase DevOps discipline:

  • Repeatable deployments (no “...but it works or worked on my machine”)
  • Version-controlled infrastructure (IaC mindset)
  • Security baked in (no leaking secrets in YAML files)

That’s why I chose Terraform.

🚀 The Infrastructure

Here’s what I needed for my app to live in the cloud:

  • Azure Container App → the service to run my Dockerized portfolio
  • Resource Group & Networking → to organize and isolate resources
  • Terraform Cloud → remote state storage & secure variable management

Notice something? I didn’t use Azure Container Registry (ACR).
Instead, I built my images in GitHub Actions and pushed them to AWS ECR.
Why? Because it showed I could integrate AWS + Azure in one pipeline — To showcase a multi-cloud DevSecOps project. A valuable real-world skill.

Provisioned Resource Group and Container App
Provisioned Resource Group and Container App

Terraform Cloud Run Sequence Triggered by GITHUB Actions to provision resources. Status: Successful!
Terraform Cloud Run Sequence Triggered by GITHUB Actions to provision resources. Status: Successful!

💰 Cost Estimation in Terraform Cloud

But did you also pause to notice something?

One underrated feature of Terraform Cloud is Cost Estimation. Every time a terraform plan runs in TFC, it doesn’t just show what resources will change — it also estimates the monthly cloud bill of those changes.

For example, this simple VM resource:

resource "azurerm_linux_virtual_machine" "myvm" {
  name                = "vm1"
  size                = "Standard_B2s"
  admin_username      = "adminuser"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  network_interface_ids = [
    azurerm_network_interface.myvm_nic.id,
  ]
}

Enter fullscreen mode Exit fullscreen mode

Might give me an output like:
Cost estimate: +$24.50/month

This is huge because it helps avoid surprise cloud bills and keeps infra spending predictable. On bigger teams, you can even enforce policies (e.g., block applies if cost > $100/month).

👉 Lesson learned: Don’t just plan for resources, plan for costs. Infrastructure as Code is also Finance as Code.

🔑 Secret Management with Terraform Cloud

One of the trickiest parts was handling secrets.

Terraform needed:

  • My ECR authentication token (from AWS)
  • My Azure credentials (to deploy resources)

I refused to hardcode them anywhere.

👉 My solution: store them as sensitive variables inside Terraform Cloud.
That way:

  • They were encrypted
  • Not visible in logs
  • Automatically injected into Terraform runs

Terraform ENV Variables configured and set for Authentication to ECS & Deployment to Azure
Terraform ENV Variables configured and set for Authentication to ECS & Deployment to Azure

This gave me a secure, enterprise-style workflow without having to build a full secret management system.

You can get the ECR Auth Token from AWS using the following command:

aws ecr get-login-password --region region

🛡️ Security Checks with TFSEC

Terraform is code — which means it can also have vulnerabilities.

For example:

  • Misconfigured networking rules
  • Exposed storage accounts
  • Overly permissive IAM roles

To catch these, I integrated TFSEC into my pipeline.
Every time Terraform code ran, TFSEC checked it against security best practices.

This meant my IaC wasn’t just functional — it was hardened.

TFSEC Pipeline successfully configured and active

📜 A Simplified Terraform Snippet

Here’s a safe example (trimmed down for clarity) of how I deployed my Azure Container App:

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "portfolio-rg"
  location = "West Europe"
}

resource "azurerm_container_app" "portfolio" {
  name                = "portfolio-app"
  resource_group_name = azurerm_resource_group.rg.name
  container_app_environment_id = azurerm_container_app_environment.env.id

  template {
    container {
      name   = "portfolio"
      image  = "ACCOUNT_ID.dkr.ecr.eu-west-1.amazonaws.com/portfolio:${var.image_tag}"
      cpu    = 0.5
      memory = "1.0Gi"
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

Notice the image is pulled from AWS ECR — not ACR.
This cross-cloud integration was a deliberate choice to highlight flexibility.

✅ The Result

When everything was wired up, here’s what I got:

  • A Dockerized portfolio app running on Azure Container Apps
  • Fully managed via Terraform IaC
  • Secrets stored securely in Terraform Cloud
  • IaC continuously scanned with TFSEC
  • Container image scanned with Trivy

Docker Build and Trivy Scanner
Docker build with Trivy Image Scanner.

This setup wasn’t about having the fanciest app.
It was about** proving I could deploy apps securely, consistently, and across multiple clouds.**

Final Application up and running from the Container App Live. Fully automated to make deployment changes based upon new image build
Final Application up and running from the Container App Live. Fully automated to make deployment changes based upon new image build

💡 Why This Matters

Employers don’t just want someone who can write code.
They want engineers who can:

  • Deploy infrastructure securely
  • Work across multi-cloud environments
  • Use IaC for repeatability and control
  • Integrate security scanning into DevOps (aka DevSecOps)

That’s what this part of the project showed.

🚀 Next Up

In Part 4, I’ll share the biggest lessons learned along this journey: the frustrations, the wins, and how I’d improve this pipeline even further.

Stay tuned! Because that’s where it all comes together.

Click here to view the final part. Part 4 ➡️

Top comments (0)