If you skip testing, security, and best practices, your cloud infrastructure can break unexpectedly, leak sensitive data, or become impossible to maintain. Testing, Security, and Best Practices for Production are the three pillars that ensure your Terraform code is reliable, safe, and maintainable. For the TF-003 exam, you need to understand how to validate your code, protect your resources, and organise your work like a professional.
Jump to a section
A simple way to picture Testing, Security, and Best Practices for Production
A master carpenter is a person who plans, measures, and tests before building. They secure every joint and nail meticulously to avoid collapse, and they maintain a well-organised workshop with labelled drawers and a clear workflow for every project.
Consider a carpenter tasked with building a custom bookshelf. Before cutting a single piece of wood, they draw a detailed plan, check the plan against the wall where the shelf will go, and test-fit the components using scrap wood. This is testing. They also use proper safety gear, secure the shelf to the wall to prevent tipping, and choose non-toxic varnish. This is security. Finally, they organise their tools so that chisels are with chisels and screws are sorted by size, and they write down the measurements and steps for future repairs. This is best practices for production.
Similarly, an IT professional writes Terraform code to create and manage cloud infrastructure. Testing involves checking that the code works as intended before using it on real systems — like the carpenter's test-fit. Security means protecting cloud resources from unauthorised access and ensuring they are set up safely — like bolting the shelf to the wall. Best practices involve organising code files logically, using version control, and writing clear documentation — like the carpenter's labelled drawers and written plans. This analogy maps precisely to these three pillars of production-grade Terraform.
This chapter covers three interconnected topics that are essential for anyone writing Terraform code in a real-world job. They are testing, security, and best practices. Let's break each down for someone who has never worked in IT.
Testing means checking that your code does what you expect before you use it on live systems. Imagine you are writing a recipe for a cake. You would want to read the recipe to see if you missed an ingredient, and maybe make a small test cake before baking a huge one for a party. In Terraform, testing works similarly. There are different types of tests.
First, there is syntax validation. This is like spell-checking your recipe. Terraform has a command called 'terraform validate' that reads your code and checks for typos, missing brackets, or incorrect keywords. It does not check whether your logic is correct, only that the code is grammatically correct.
Second, there is plan review. The command 'terraform plan' shows you what Terraform will create, change, or destroy without actually making any changes. This is like reading through your recipe and imagining the cake. You can catch mistakes here — like noticing you used salt instead of sugar.
Third, there is automated testing using tools like Terratest or the built-in 'terraform test' command. These actually create real infrastructure in a safe, isolated environment (like a test kitchen) and then confirm that everything works. For example, a test might spin up a small virtual machine, check that it is accessible, and then tear it down. This is the most thorough type of testing.
Security in Terraform is about protecting your cloud resources from threats. Cloud resources are things like virtual machines, databases, or storage buckets — all running on a provider like Amazon Web Services (AWS), Microsoft Azure, or Google Cloud. Security practices ensure that only authorised people can access these resources, and that data is protected.
Key security practices include:
Never hardcode secrets. A secret is a password, API key, or access token. Hardcoding means writing it directly in the code. Instead, use a secrets manager like HashiCorp Vault or environment variables, which are values set outside the code.
Use least privilege for everything. This means giving users and systems only the permissions they absolutely need, nothing more. For IAM roles (Identity and Access Management roles), which define what a user or system can do, you should limit access to only necessary actions.
Enable encryption. Encryption scrambles data so only someone with the key can read it. Terraform can turn on encryption for storage buckets and databases.
Use security groups and network access control lists (ACLs). These are like bouncers at a club — they decide who can enter a network. You should restrict access to only trusted sources.
Scan your code for known vulnerabilities. Tools like tfsec or Checkov can automatically find security issues in your Terraform code before you deploy it.
Best practices for writing and organising Terraform code are about making your work easy to understand, reuse, and maintain. Good organisation saves time and reduces errors.
Key best practices include:
Use version control, like Git. This is a system that tracks changes to your files over time, like saving different drafts of a document. You can always go back to a previous version if something breaks.
Structure your code into modules. A module is a reusable piece of configuration, like a template for a basic web server. Instead of copying and pasting code, you call the module and pass in specific settings.
Follow a consistent naming convention. For example, name resources with a standard pattern like 'project-environment-resource' so everyone on the team knows what each resource does.
Keep your state file secure. The state file is a record of what Terraform has created. It should be stored remotely (like in an S3 bucket or Azure Storage) with access controls, and never committed to version control.
Use workspaces to manage different environments (like development, staging, production) with the same configuration. A workspace is like a separate folder for each version of your infrastructure.
Document your code. Write clear comments in the code and maintain a README file that explains what the module does, what variables it needs, and how to use it.
These three areas — testing, security, and best practices — work together. Testing helps you find security problems before they become incidents. Best practices make testing and security easier to implement. For the TF-003 exam, you will be asked to identify the correct testing strategy, recognise insecure code patterns, and choose the most organised structure for production code.
1. Write and format your code
Write the Terraform configuration for a new resource or module. Use 'terraform fmt' to automatically format the code for consistency across your team. This is like setting your workshop in order before starting a project.
2. Validate syntax with terraform validate
Run 'terraform validate' to check for syntax errors, missing required arguments, or invalid resource names. This is a quick check that catches basic typos and structural mistakes before you move further.
3. Review the plan with terraform plan
Execute 'terraform plan' to see a detailed preview of what will be created, changed, or destroyed. Review this output carefully for security misconfigurations (e.g., a publicly accessible database) or unintended changes.
4. Run automated tests in an isolated environment
Create a test environment using a separate workspace or directory. Use 'terraform test' or a tool like Terratest to provision real infrastructure, verify its behaviour, and then destroy it. This confirms your code works correctly and securely.
5. Commit, review, and deploy via a pipeline
Commit your code to a version control system (like Git) with a clear commit message. Use a CI/CD pipeline that automatically runs validation, planning, and security scans. After peer review, the pipeline applies the changes to production, ensuring consistency and safety.
6. Monitor for drift and remediate
Regularly run 'terraform plan' to detect if the real-world infrastructure has changed outside of Terraform (drift). If drift is found, update your code to match or run 'terraform apply' to restore the desired state.
An IT professional, let's call her Priya, works for a company that provides an online shopping platform. She is responsible for managing the cloud infrastructure that runs the platform using Terraform. Her company is about to launch a new payment feature, and she needs to ensure the infrastructure behind it is reliable, secure, and maintainable. Here is what she actually does, step by step.
First, Priya writes Terraform code to create the new payment processing environment. This includes a virtual machine to run the payment software, a database to store transaction data, and a load balancer to distribute traffic. She uses a module she created earlier called 'web-server', which she reuses because it already has the correct security groups and backup policies. She passes in specific variables like the database size and the region.
Second, she runs 'terraform fmt' to automatically format her code consistently. Then she runs 'terraform validate' to check for syntax errors. This catches a missing closing bracket in one of her resource definitions. She fixes it quickly.
Third, she runs 'terraform plan' to see what will be created. The plan shows that the database will be publicly accessible from the internet — a major security risk. Priya realises she forgot to set the 'publicly_accessible' parameter to 'false'. She updates the code and runs the plan again. Now the database is only accessible from the virtual machine.
Fourth, she uses an automated security scanner called tfsec as part of her Git pre-commit hook — a script that runs automatically whenever she tries to save changes. The scanner detects that the database encryption is not enabled. She adds the encryption configuration and resolves the issue.
Fifth, she sets up a test environment that is isolated from production. She uses a separate workspace called 'test-payment'. She runs 'terraform apply' to create the test environment. Then she uses a test script that makes a test payment transaction and checks that the database records it correctly. The test passes. She then runs 'terraform destroy' to tear down the test environment, so she is not paying for unused resources.
Sixth, she commits her code to the main branch in Git. Her team has a policy that code can only be merged after it passes all automated tests and security scans. She creates a pull request, and her colleague reviews the code. They discuss whether the naming convention matches the team's standard. The code is approved.
Finally, she deploys to production using a CI/CD pipeline (continuous integration/continuous deployment) — a system that automatically runs tests and pushes code to the live environment. The pipeline runs 'terraform plan' again, then asks for manual approval before applying. Priya approves, and the new payment feature goes live safely.
All of this — testing, security checks, and organised code — happens every time a change is made. Without these practices, a simple mistake could expose customer credit card data or bring the entire platform down during a busy shopping day. Priya's work ensures the company's infrastructure is robust and trustworthy.
The TF-003 exam tests your understanding of testing, security, and best practices in a targeted way. Here is exactly what you need to know.
For testing, the exam focuses on three types:
Syntax validation with terraform validate. You will be asked when to use it (during coding, before plan or apply).
Plan review with terraform plan. Questions test that you understand it does NOT create resources but shows the execution plan.
Formal integration tests with tools like Terratest or terraform test. Expect questions about why automated testing is important for production.
The exam will present scenarios where you must choose the correct testing approach. Trap: They might say 'validation is enough before production'. The correct answer is that you need all three types for production environments. Another trap: They might say 'terraform plan is the same as terraform apply'. That is false — plan only shows what would happen, apply actually makes changes.
For security, the exam tests several specific concepts. Know these cold:
Secret management. Never hardcode secrets. Use variables with sensitive = true, environment variables, or a secrets manager.
Least privilege for IAM roles. Always restrict permissions to only what is needed.
Encryption at rest and in transit. Enable encryption for storage resources like S3 buckets and Azure storage accounts.
Security groups and network ACLs. These control inbound and outbound traffic. Know how to restrict access to specific IPs or security groups.
Using tainted resources. Marking a resource as tainted will force Terraform to destroy and recreate it on the next apply. This can be a security measure if a resource is compromised.
Trap: The exam might show a code snippet with a hardcoded password and ask you to identify the issue. Another trap: They might suggest using an IAM user key directly in the code. The correct answer is to use an IAM role or temporary credentials.
For best practices, the exam tests how to organise code for production. Key concepts:
Using modules to reuse and organise code. Define standardised modules for common patterns like web servers, databases, networking.
Remote state storage. Use a backend like S3, Azure Storage, or Terraform Cloud to store state files centrally and securely. This enables team collaboration and locking.
State locking. When working in a team, state locking prevents two people from modifying the same infrastructure simultaneously, avoiding conflicts.
Workspaces. Use separate workspaces for development, staging, and production environments. This isolates changes and reduces risk.
Policy as code with Sentinel (for Terraform Cloud) to enforce organisational rules, like requiring all storage buckets to be encrypted.
Version control with Git. Always commit code, use branches for features, and require code review before merging to main.
Trap: The exam might ask you to choose between storing state locally or remotely for a team. The correct answer is always remote state with locking. Another trap: They might suggest using one workspace for all environments. The correct answer is to use separate workspaces or directories.
Finally, the exam tests the concept of 'drift detection'. Drift occurs when the real-world infrastructure changes outside of Terraform (e.g., someone manually deletes a resource). You should regularly run terraform plan to detect drift and correct it. The exam may present a scenario where drift has occurred and ask for the best approach. Correct answer: run terraform plan, then terraform apply to reconcile.
Terraform validate checks syntax only; it cannot catch logic errors or security issues.
Never hardcode secrets in Terraform code; always use a secrets manager or sensitive variables.
Remote state storage with locking is essential for any team using Terraform together.
Use separate workspaces or directories for development, staging, and production environments.
Automated integration tests in an isolated environment catch real-world issues before production deployment.
Taint a resource to force its destruction and recreation on the next apply, useful for security remediation.
Security groups and network ACLs control traffic and must be configured to allow only necessary access.
A terraform plan shows what will change but does not make any actual changes to infrastructure.
These come up on the exam all the time. Here's how to tell them apart.
terraform validate
Checks only syntax and basic structure of code
Does not connect to any cloud provider
Useful as a quick first check during editing
terraform plan
Shows execution details by connecting to the provider
Displays what will be created, changed, or destroyed
Essential for reviewing changes before applying
Local State
State file stored on a single machine
No locking mechanism for concurrent use
Cannot be shared with team members
Remote State
State stored centrally (e.g., S3, Terraform Cloud)
Supports state locking to prevent conflicts
Enables team collaboration and disaster recovery
Hardcoded Secrets
Secrets written directly in .tf or .tfvars files
Risk of leaking in logs or version control history
Difficult to rotate or manage centrally
Sensitive Variables
Secrets passed via environment variables or vault
Marked with 'sensitive = true' to prevent logging
Easier to rotate and manage with a secrets manager
Single Workspace for All Environments
All environments share the same state file
Accidental changes to one environment affect others
Suitable only for learning or very small projects
Separate Workspaces per Environment
Each environment has its own isolated state
Changes are isolated, reducing risk to production
Recommended for all professional and team projects
Manual Testing (Plan Only)
Only reviews the plan without creating resources
Cannot catch runtime errors or functional bugs
Depends entirely on human review of the plan
Automated Integration Testing
Creates actual resources in a test environment
Verifies functionality, security, and performance
Runs automatically in CI/CD pipelines
Mistake
Terraform validate alone is enough to ensure my code is safe to deploy to production.
Correct
Terraform validate only checks syntax, not logic or security. You must also run terraform plan and automated integration tests to catch functional and security issues.
Beginners often mistake syntax correctness for overall correctness, because they have not yet encountered runtime errors or security vulnerabilities.
Mistake
Hardcoding a password in a variable file is fine as long as I do not commit the file to version control.
Correct
Hardcoding secrets anywhere in your code, even in local files, is risky. They can leak through logs or accidental commits. Always use a secrets manager or environment variables with sensitive = true.
People think 'I will just keep the file on my machine' is safe, but they forget about shared access, backups, and the risk of accidentally sharing the file.
Mistake
For a small team, storing the state file locally on one person's computer is perfectly fine.
Correct
State files must be stored remotely with locking for any team. Local state prevents collaboration, risks data loss, and causes conflicts when multiple people run Terraform.
Beginners often start with small personal projects where local state works, and they do not realise that the same pattern breaks in team contexts.
Mistake
Using one workspace for development and production is efficient and avoids duplication of files.
Correct
Using separate workspaces (or directories) for environments is a best practice. A single workspace means changes to one environment can accidentally affect another, increasing risk.
New users think 'duplication is bad' and try to reuse the same workspace, not understanding that isolation is more important than reducing file count.
Mistake
Terraform plan is the same as running a test because it shows me what will happen.
Correct
Terraform plan is a preview, not a test. It does not execute code or verify functionality. Tests (like terraform test) actually create and validate resources in an isolated environment.
The word 'plan' sounds like a review step, but people conflate it with formal testing because both involve checking code before applying.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
Terraform validate checks your code for syntax errors only. Terraform plan goes further by connecting to your cloud provider and showing what resources will be created, changed, or destroyed based on your configuration.
Use a secrets manager like HashiCorp Vault, or store secrets as environment variables and reference them with var.my_secret. Mark variables as 'sensitive = true' so Terraform does not print their values in logs.
Yes, even small projects benefit from testing. At a minimum, run 'terraform validate' and 'terraform plan' before applying. For any project that affects real users or data, automated integration tests are strongly recommended.
A remote state backend stores your Terraform state file in a central location like an S3 bucket or Terraform Cloud. It is needed for team collaboration, state locking, and disaster recovery. Local state is risky for any shared project.
Use separate workspaces for each environment (dev, staging, prod) or separate directories with different backend configurations. This keeps changes isolated and prevents accidental modifications to production.
Tainting marks a resource for destruction and recreation on the next 'terraform apply'. It is used when a resource is compromised or needs to be refreshed without changing the configuration code.
You've finished Testing, Security, and Best Practices for Production. Continue through the TF-003 study guide to build a complete picture of the exam.
Done with this chapter?