The simplest Terraform definition is this: Terraform is an open-source infrastructure-as-code tool that lets you describe cloud and on-prem resources in declarative configuration files and then create, change, and version that infrastructure through a predictable plan-and-apply workflow. Instead of clicking through a cloud console or writing imperative scripts, you write what you want the end state to look like, and Terraform figures out the API calls needed to get there.
The core idea: declarative, not imperative
Most people first learn to provision infrastructure imperatively: run this command, then that one, in order. Terraform flips that around. You declare the desired state in files written in HashiCorp Configuration Language (HCL), and Terraform reconciles the real world with your declaration.
resource "aws_s3_bucket" "logs" {
bucket = "app-audit-logs-prod"
}
resource "aws_s3_bucket_public_access_block" "logs" {
bucket = aws_s3_bucket.logs.id
block_public_acls = true
restrict_public_buckets = true
}
You do not tell Terraform how to create the bucket. You tell it the bucket should exist with these properties, and the tool computes the difference between what exists and what you asked for. That difference is the "plan."
What "plan and apply" actually means
The workflow has three commands you will run constantly:
terraform init # download providers and set up the backend
terraform plan # show what will change, without changing anything
terraform apply # make the changes
terraform plan is the safety valve. It prints an explicit diff: what will be created, updated, or destroyed. Reviewing that diff before every apply is the single most important operational habit, because a careless change to a resource can trigger a destroy-and-recreate that takes production down. Reading a plan carefully is a skill worth building deliberately.
State: the part people underestimate
Terraform keeps a state file that maps the resources in your configuration to real resource IDs in the provider. This is central to the Terraform definition because without state, the tool would have no memory of what it created.
State is also a security concern that catches teams off guard. The state file frequently contains sensitive values in plaintext: database passwords, access keys, generated secrets. That means:
- Never commit
terraform.tfstateto a public or even a broadly readable git repository. - Use a remote backend (S3 with encryption and access control, Terraform Cloud, or an equivalent) rather than local files for anything shared.
- Restrict who can read state, because reading state can be equivalent to reading your secrets.
If you treat state as just an implementation detail, you will eventually leak a credential through it.
Providers and modules
Terraform itself is a small core engine. The real work happens in providers: plugins that translate HCL into API calls for AWS, Google Cloud, Azure, Kubernetes, GitHub, and hundreds of other systems. When you run terraform init, it downloads the providers your configuration references.
This is worth naming from a supply chain angle. Providers and community modules are third-party code that runs with your cloud credentials. Pinning provider and module versions, and knowing where a module came from, is the same discipline you would apply to any dependency. A random module from an unvetted source runs with the same permissions you hand your pipeline.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
Pinning to ~> 5.0 lets you take patch and minor updates while blocking a surprise major-version jump that could rewrite behavior underneath you.
Where security fits into infrastructure as code
Because Terraform describes infrastructure as text, security review can happen the same way code review does: before anything is deployed. That is the promise of IaC scanning. Static analysis tools read your .tf files and flag misconfigurations such as an open security group, an unencrypted volume, or an IAM policy with wildcard permissions, all before apply ever runs.
That shift-left capability is a big part of why teams adopt Terraform beyond convenience. It turns a whole category of cloud misconfiguration into something you can catch in a pull request. It does not, however, secure the runtime for you. A perfect Terraform config can still deploy an application full of vulnerable dependencies, which is why IaC scanning sits alongside, not instead of, application-layer controls like SCA. If you are mapping out a full pipeline, the broader picture of shifting security left is covered well in the Safeguard Academy.
Terraform versus similar tools
The Terraform definition often gets confused with related concepts. Configuration management tools like Ansible focus on configuring software inside servers that already exist; Terraform focuses on provisioning the servers and cloud resources themselves. CloudFormation is AWS's native IaC service but is single-cloud, whereas Terraform is provider-agnostic. Pulumi covers similar ground to Terraform but lets you use general-purpose languages instead of HCL. None of these removes the state, secrets, and third-party-code responsibilities described above; they just repackage them.
FAQ
What is Terraform in one sentence?
Terraform is an open-source infrastructure-as-code tool that provisions and manages cloud and on-prem resources from declarative configuration files using a plan-and-apply workflow.
Is Terraform a programming language?
No. Terraform is a tool, and HCL is its configuration language. HCL is declarative and describes desired state rather than step-by-step logic, though it does support variables, loops, and expressions.
Why is the Terraform state file a security risk?
State can store sensitive values such as passwords and access keys in plaintext. Anyone who can read the state file may be able to read those secrets, so state should live in an encrypted, access-controlled remote backend and never in a public repository.
Does Terraform make my infrastructure secure by default?
No. Terraform makes infrastructure repeatable and reviewable, which enables security scanning of your configs before deployment, but it will faithfully build an insecure setup if that is what you declare. Security still depends on the configuration you write and the controls you layer on top.