Skip to main content
Back to module
DevOps & Cloud Delivery · Infrastructure as Code

Cost and policy guardrails

Reading44mLesson 3 of 3 in this module

Add required tags, input validation and a budget alert so infrastructure stays labelled, within policy and within budget.

Why it matters

The cloud makes it easy to create resources and just as easy to forget them. Real teams find untagged servers nobody owns, test databases left running for months, and a GPU instance someone started "for an hour". A large part of a cloud engineer's value is preventing that: every resource should have an owner, stay within agreed rules and show up in a budget that someone watches. This practice of managing cloud spending as a shared responsibility of engineering and finance is called FinOps.

Infrastructure as code is the best place for these guardrails, because rules written in code apply to every change automatically.

Guardrail 1: tags on everything

Tags (called labels on Google Cloud and Docker) are key-value pairs attached to resources. Billing tools group costs by tag, so tags answer "which team, project and environment is this money for?" A typical required set:

TagExampleWhy
ownerteam-paymentsWho to ask before deleting it
projecthello-devopsCost reports per product
envstagingSeparate production cost from test cost
managed-byterraformWarns people not to edit it by hand

In Terraform, define tags once and apply them everywhere. The AWS provider has default_tags, which adds them to every resource it creates:

provider "aws" {
  region = "us-east-1"
  default_tags {
    tags = {
      owner      = "team-payments"
      project    = "hello-devops"
      env        = var.env
      managed-by = "terraform"
    }
  }
}

With the local Docker provider you can practise the same idea using container labels and a dynamic block:

locals {
  tags = merge(var.tags, { env = var.env, managed-by = "terraform" })
}

resource "docker_container" "web" {
  name  = "tf-web-${var.env}"
  image = docker_image.nginx.image_id

  dynamic "labels" {
    for_each = local.tags
    content {
      label = labels.key
      value = labels.value
    }
  }
}

Guardrail 2: validation and policy

Terraform variable validation rejects bad input during plan, before anything is created:

variable "env" {
  type = string
  validation {
    condition     = contains(["dev", "staging", "prod"], var.env)
    error_message = "env must be dev, staging or prod."
  }
}

variable "tags" {
  type = map(string)
  validation {
    condition     = alltrue([for k in ["owner", "project"] : contains(keys(var.tags), k)])
    error_message = "tags must include owner and project."
  }
}

variable "instance_size" {
  type    = string
  default = "small"
  validation {
    condition     = contains(["small", "medium"], var.instance_size)
    error_message = "Only small or medium sizes are allowed without an approved exception."
  }
}

The same idea scales up through policy as code: tools such as Open Policy Agent (with Conftest), Checkov, tfsec/Trivy, or HashiCorp Sentinel check a plan in CI against rules like "no public storage buckets", "every resource has an owner tag" or "no instance types larger than X". Cloud providers add their own account-level controls (AWS Service Control Policies, Azure Policy, Google Cloud Organization Policy). A rule in CI catches mistakes during review; an account-level rule catches what slips past CI.

Guardrail 3: budgets and alerts

A budget alert emails you when actual or forecast spending crosses a threshold. Every major cloud has one: AWS Budgets, Azure Cost Management budgets and Google Cloud Billing budgets. Create one in every account you use, including practice accounts, before you create anything else. A sensible practice setup is a small monthly budget (for example 5 or 10 in your currency) with alerts at 50%, 80% and 100% of actual spend and 100% of forecast.

Two honest warnings:

  • A budget alert does not stop spending. It tells you; you still have to act. Some providers let you attach automated actions, but they need careful setup.
  • Billing data can lag by hours. Do not wait for an alert to clean up: delete practice resources as soon as you finish.

Finding and cutting waste

The usual big wins are boring: delete unused resources (idle VMs, unattached disks, old snapshots, unused public IP addresses and load balancers), right-size instances that run at 5% CPU, stop non-production environments at night, set lifecycle rules on storage, and use reserved or committed-use pricing only for steady workloads. Tags make all of this possible, because you can see what each resource is for.

Common mistakes

  • Tagging by hand, so tags are missing or spelled five ways (Env, env, environment).
  • Treating a budget alert as a spending cap.
  • Validation messages that do not say how to fix the problem.
  • Policies so strict that people work around them; start with warnings, then enforce.

Quick recap

  • Required tags (owner, project, env) make cost and ownership visible.
  • Variable validation and policy-as-code reject bad infrastructure at plan time.
  • Set a budget alert in every account first; it warns but does not stop spending.
  • Delete unused resources promptly; tags tell you which ones they are.

Try it

The Do tab has you add tag and validation guardrails to your local Terraform project and set a budget alert on your cloud practice account.

Also in this lesson: