Skip to Content
Use case · Cloud infrastructure and security

A live Azure platform moved into code and put behind Cloudflare

The platform had grown one portal click at a time, with no record of how it was set up. We imported every resource into Terraform, put the public apps behind Cloudflare and closed the database to everyone except approved users. The business kept the platform it had and can now rebuild, review and change it safely.

8production container apps brought under Terraform2environments, production and test, defined as code
productiontestIllustration1module "container_apps" { … }2module "static_web_apps" { … }3module "network" { … }4module "key_vault" { … }5module "storage" { … }6module "postgres" { … }7backend "azurerm" { … }8module "cloudflare" { … }9module "zero_trust" { … }TERMINALproduction $ terraform planNo changes. Your infrastructurematches the configuration.test $ terraform planNo changes. Your infrastructurematches the configuration.Public usersMICROSOFT AZUREApp 1?App 2?App 3?App 4?App 5?App 6?App 7?App 8?Web apps?Key Vault?Network?Storage?PostgreSQLSet up by hand in the portalNo firewallDatabase open to the networkShared stateIn TerraformCloudflareDNSWAFApproved userZero Trust
The problem

A platform that works, until you need to change it

A cloud platform built one resource at a time in the Azure portal can run happily for years. What it doesn’t have is a written record of what’s there and why each setting is the way it is, so every change, audit question or rebuild starts with someone clicking through the portal and trying to remember.

No record of what’s running

Resources were added by hand over the years. A simple question about the setup means opening each one in the portal, and an audit request turns into an afternoon of clicking.

Test doesn’t match production

Small differences build up between environments. A release that passed in test breaks in production, and the fix is another manual change that nobody writes down.

One person holds the map

The engineer who set it up is the only one who knows why things are the way they are. When they’re on leave or move on, changes stop or get guessed.

The database is open wider than intended

Network access was opened for a quick fix and never closed again. The database that holds your customers’ data is one leaked password away from a breach.

Public apps take every hit directly

With no firewall in front, scans, bots and junk traffic go straight to your apps, and your servers carry the load and the risk.

Rebuilding means starting from memory

If an environment breaks or gets deleted, getting it back means clicking it together again, with no way to check it came back the same.

The setup lives in the portal and in one or two people’s heads, and every change is a gamble on what they remember.

Before and after

From hand-built to defined in code

Flip the switch to see the estate before and after the work.

BeforeWith the system
  • Resources running in Azure with no definition in codeEvery resource imported into Terraform
  • Changes clicked into the portal and never recordedChanges planned and applied through Terraform, from shared state
  • Test rebuilt from memory after it breaksProduction and test each have their own Terraform, so test can be rebuilt to match
  • Database reachable over the networkDatabase reached only through a Cloudflare Tunnel with Zero Trust access
  • No firewall in front of the public appsCloudflare DNS and web application firewall rules in front of the platform
  • No outside view of how the estate is builtA findings report with performance recommendations, measured against CBOS’s infrastructure guidelines

A platform that lives in the portal and in one person’s memory.

An estate written down in code, behind proper access controls.

How it works

Four steps on a platform that was already live

Click through each step to see it working.

01Import what’s already running
02One shared state, a definition per environment
03Cloudflare in front of the public apps
04Zero Trust access to the database
Step 01

Import what’s already running

We wrote Terraform for each resource that was already running (container apps, static web apps, networking, Key Vault, storage and the PostgreSQL database) and imported it. Importing reads a resource into Terraform’s state without changing it, so a plan afterwards shows whether the code matches what’s live.

Step 02

One shared state, a definition per environment

Terraform’s state sits in a storage account, so every change runs from one source of truth. Production and test each have their own Terraform, so test can be rebuilt to match.

Step 03

Cloudflare in front of the public apps

DNS moved to Cloudflare and web application firewall rules went in front of the public apps, so traffic is filtered before it reaches them.

Step 04

Zero Trust access to the database

The PostgreSQL database sits behind a Cloudflare Tunnel. Approved people get in through Zero Trust access, and the database is no longer reachable over the network.

What we built

Six pieces of work on a running estate

01

Terraform import

Brought the existing Azure resources (container apps, static web apps, networking, Key Vault, storage and the PostgreSQL database) into Terraform without rebuilding them.

02

Shared state

Set up Terraform state in a storage account, so changes run from one source of truth.

03

Separate production and test definitions

Each environment has its own Terraform, so the test setup can be rebuilt to match.

04

Cloudflare in front

Moved DNS to Cloudflare and added web application firewall rules for the public apps.

05

Zero Trust database access

Put the PostgreSQL database behind a Cloudflare Tunnel, so only approved people get in.

06

Findings report

A detailed report on what we found in the estate, with performance recommendations, measured against CBOS’s own infrastructure guidelines.

Hover over a card for more.

What changes

What changes for the people who run it

Changes start as a plan

An engineer edits the Terraform, reads the plan and applies it, so what’s about to change is visible before it happens.

Test can be rebuilt to match

Test has its own definition, so getting it back after it breaks means applying that definition again.

The setup is written down

Anyone on the team can read how the estate is built, in code that’s versioned with every change.

Database access is per person

Approved people reach the database through Zero Trust access, and nobody else reaches it at all.

Public apps sit behind WAF rulesTraffic passes Cloudflare’s firewall rules before it reaches them.
Changes made outside Terraform get noticedThe next plan shows any setting someone changed in the portal.
A findings report to work fromPerformance recommendations measured against CBOS’s infrastructure guidelines.
Built with

The stack

TerraformMicrosoft AzureAzure Container AppsAzure Static Web AppsAzure Database for PostgreSQLAzure Key VaultCloudflare (DNS, Tunnel, Zero Trust, WAF)
Where we’d start

Three steps with your estate

1

Review

We go through your estate and write up what we find against our own infrastructure guidelines, with performance recommendations.

2

Bring it into code

We import what’s running into Terraform, set up shared state and give each environment its own definition.

3

Lock it down

Cloudflare DNS and firewall rules in front of your public apps, and Zero Trust access to the database.

Before you start

Questions worth asking first

Do we have to rebuild our platform?

No. Terraform can import resources that already exist, so they come under code where they stand. That’s how this project brought in the existing container apps, static web apps, networking, Key Vault, storage and database.

Will importing cause downtime?

Importing reads a resource into Terraform’s state and doesn’t change it. Anything that would change shows up in the plan first, so you decide when it happens.

Can we still use the Azure portal?

You can still look at everything in the portal. If someone changes a setting there, the next Terraform plan shows the difference, so it gets caught and either written into code or put back.

Do the people who need the database lose access?

Approved people keep their access through a Cloudflare Tunnel with Zero Trust. What goes away is access for anyone else on the network.

We’re not sure what state our estate is in. Where do we begin?

With a review. On this project that was a detailed findings report, measured against CBOS’s own infrastructure guidelines, with performance recommendations.

Quick check

Sound like your business?

Tick what sounds familiar.

Your cloud resources were set up by hand in the portal over several years.
Nobody could rebuild your test or production environment from scratch with confidence.
Your database can be reached from outside your private network.
Your public apps have no web application firewall in front of them.
Infrastructure changes depend on one person who remembers how things were set up.
of 5 ticked

0 to 1 ticked

Your infrastructure sounds well managed. A short review can still confirm nothing has drifted from what you think is running.

2 to 3 ticked

There are gaps worth closing before they cause an outage or a breach. We can review your estate and tell you which ones to fix first.

4 to 5 ticked

Your estate is in the state this project started from. We can bring it into code and lock it down without rebuilding your platform.

Talk it through with us
Let's talk

Could you rebuild your cloud setup tomorrow if you had to?

Tell us what you run in Azure today and we’ll tell you what it would take to get it into code and behind proper access controls.

Let's Connect

Interested in building a smarter, more connected operation? Contact us to discuss how AI can support your business goals.