SlideShare a Scribd company logo
Testing Terraform
Nathen Harvey
Chef
@nathenharvey
What am I talking about
• Suppose you use a tool like Terraform to create your infrastructure
• You're onboard with infrastructure as code
• Code should be tested
• How can we test Terraform?
@nathenharvey
1. Deploy n-tier cloud infra
2. Deploy some app
3. Profit
A Motivational Example
Load
Balancer
VM
Instance
VM
Instance
...
@nathenharvey
1. Deploy n-tier cloud infra
2. Deploy some app ???
3. Profit
A Motivational Example
Load
Balancer
VM
Instance
VM
Instance
...
@nathenharvey
So how do you do that in
Terraform?
@nathenharvey
Terraform on AWS: Define an Instance (VM)
resource "aws_instance" "web" {
count = 3
instance_type = "t2.micro"
ami = "${lookup(var.aws_amis, var.aws_region)}"
key_name = "${var.key_name}"
subnet_id = "${aws_subnet.default.id}"
vpc_security_group_ids = [
"${aws_security_group.lb_to_webservers.id}",
"${aws_security_group.ssh_from_office.id}",
]
...
}
@nathenharvey
Terraform on AWS: Define Load Balancer (ELB)
resource "aws_elb" "web" {
name = "testing-terraform-elb"
subnets = ["${aws_subnet.default.id}"]
security_groups = [
"${aws_security_group.world_to_elb.id}",
"${aws_security_group.lb_to_webservers.id}",
]
instances = ["${aws_instance.web.*.id}"]
listener {
instance_port = 80
instance_protocol = "http"
lb_port = 80
lb_protocol = "http"
}
}
@nathenharvey
Terraform on AWS: Define a Firewall Rule
resource "aws_security_group" "ssh_from_office" {
name = "testing-terraform-ssh"
vpc_id = "${aws_vpc.testing_terraform.id}"
# SSH access from special office addresses
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = "${var.ssh_cidrs}"
}
# outbound internet access
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
@nathenharvey
Terraform on AWS: Define a Firewall Rule
resource "aws_security_group" "ssh_from_office" {
name = "testing-terraform-ssh"
vpc_id = "${aws_vpc.testing_terraform.id}"
# SSH access from special office addresses
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = "${var.ssh_cidrs}"
}
# outbound internet access
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
variable "ssh_cidrs" {
default = [
"173.239.212.22/32",
"12.130.117.75/32"
]
}
$
What's the plan, Phil?
terraform plan -out plan.out
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
...
Plan: 11 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
This plan was saved to: plan.out
To perform exactly these actions, run the following command to apply:
terraform apply "plan.out"
$
Make it so!
terraform apply "plan.out"
aws_vpc.testing_terraform: Creating...
assign_generated_ipv6_cidr_block: "" => "false"
cidr_block: "" => "10.0.0.0/16"
default_network_acl_id: "" => "<computed>"
default_route_table_id: "" => "<computed>"
default_security_group_id: "" => "<computed>”
...
aws_elb.web: Creation complete after 25s (ID: testing-terraform-elb)
Apply complete! Resources: 11 added, 0 changed, 0 destroyed.
Outputs:
address = testing-terraform-elb-1345186905.us-east-1.elb.amazonaws.com
@nathenharvey
It's alive!
@nathenharvey
Part of a balanced diet
$
Verify with Terraform
terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
aws_vpc.testing_terraform: Refreshing state... (ID: vpc-091427c0ca8ed3c29)
...
aws_elb.web: Refreshing state... (ID: testing-terraform-elb)
------------------------------------------------------------------------
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
@nathenharvey
And all is well.
@nathenharvey
Meanwhile, at Team Shady….
@nathenharvey
An Innocent-Seeming Change…
@nathenharvey
An Innocent-Seeming Change…
$
Audit with Terraform
terraform plan
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
~ aws_instance.web[0]
vpc_security_group_ids.#: "3" => "2"
vpc_security_group_ids.1298918294: "sg-01eefd0164f2de498" => "sg-01eefd0164f2de498"
vpc_security_group_ids.35497876: "sg-0c6388fa3e956cc15" => ""
vpc_security_group_ids.645334896: "sg-03bca2a0e861c01e7" => "sg-03bca2a0e861c01e7”
Plan: 0 to add, 1 to change, 0 to destroy.
@nathenharvey
Detected the new security group
Will detach it
Is that enough?
Awesome! Terraform found the change!
@nathenharvey
It only audits what is known in the Terraform config
All change is drift (considered bad)
Only express what you want,
not what you don't
How does terraform plan fall short?
@nathenharvey
We need something else.
@nathenharvey
@nathenharvey
PART OF A PROCESS OF CONTINUOUS COMPLIANCE
Scan for
Compliance
Build & Test
Locally
Build & Test
CI/CD Remediate Verify
A SIMPLE EXAMPLE OF AN INSPEC CIS RULE
InSpec
▪ Translate compliance into Code
▪ Clearly express statements of policy
▪ Move risk to build/test from runtime
▪ Find issues early
▪ Write code quickly
▪ Run code anywhere
▪ Inspect machines, data and APIs
Turn security and
compliance into code
control 'cis-1.4.1' do
title '1.4.1 Enable SELinux in /etc/grub.conf'
desc '
Do not disable SELinux and enforcing in your GRUB
configuration. These are important security features that
prevent attackers from escalating their access to your systems.
For reference see …
'
impact 1.0
expect(grub_conf.param 'selinux').to_not eq '0'
expect(grub_conf.param 'enforcing').to_not eq '0'
end
$
InSpec Shell
inspec shell –t aws://
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
You are currently running on:
Name: aws
Families: cloud, api
Release: aws-sdk-v2.11.50
$
InSpec Shell
inspec shell –t aws://
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
You are currently running on:
Name: aws
Families: cloud, api
Release: aws-sdk-v2.11.50
Targeting AWS!
inspec>
InSpec Shell – Tab Completion
aws_<TAB>
aws_cloudtrail_trail aws_iam_access_keys aws_iam_users aws_security_group
aws_cloudtrail_trails aws_iam_group aws_kms_key aws_security_groups
aws_cloudwatch_alarm aws_iam_groups aws_kms_keys aws_sns_subscription
aws_cloudwatch_log_metric_filter aws_iam_password_policy aws_rds_instance aws_sns_topic
aws_config_delivery_channel aws_iam_policies aws_route_table aws_sns_topics
aws_config_recorder aws_iam_policy aws_route_tables aws_subnet
aws_ec2_instance aws_iam_role aws_s3_bucket aws_subnets
aws_ec2_instances aws_iam_root_user aws_s3_bucket_object aws_vpc
aws_iam_access_key aws_iam_user aws_s3_buckets aws_vpcs
inspec>
Find the shady security group
aws_security_group('sg-0c6388fa3e956cc15').group_name
=> "uat_executive"
inspec>
Check the Rules
aws_security_group('sg-0c6388fa3e956cc15').inbound_rules
=> [{:from_port=>22,
:ip_protocol=>"tcp",
:ip_ranges=>[{:cidr_ip=>"0.0.0.0/0"}],
:ipv_6_ranges=>[{:cidr_ipv_6=>"::/0"}],
:prefix_list_ids=>[],
:to_port=>22,
:user_id_group_pairs=>[]}]
inspec> describe aws_security_group('sg-0c6388fa3e956cc15') do
inspec> it { should_not allow_in ipv4_range: '0.0.0.0/0' }
inspec> end
Write a proper test
inspec> describe aws_security_group('sg-0c6388fa3e956cc15') do
inspec> it { should_not allow_in ipv4_range: '0.0.0.0/0' }
inspec> end
Profile: inspec-shell
Version: (not specified)
EC2 Security Group sg-0c6388fa3e956cc15
× should not allow in {}
expected `EC2 Security Group sg-0c6388fa3e956cc15.allow_in?({})` to
return false, got true
Test Summary: 0 successful, 1 failure, 0 skipped
Write a proper test
@nathenharvey
An InSpec Control
security_groups.rb
control 'Make sure unrestricted SSH is not permitted' do
# Loop over each of the security group IDs in the region
aws_security_groups.group_ids.each do |group_id|
# Examine a security group in detail
describe aws_security_group(group_id) do
# Examine Ingress rules, and complain if
# there is unrestricted SSH
it { should_not allow_in(port: 22, ipv4_range: '0.0.0.0/0') }
end
end
end
$
InSpec Shell
inspec exec –t aws:// secruity_groups.rb
Profile: tests from security_groups.rb (tests from security_groups.rb)
Version: (not specified)
Target: aws://
× Make sure unrestricted SSH is not permitted: EC2 Security Group sg-003262589de21dbf5 (15
failed)
✔ EC2 Security Group sg-003262589de21dbf5 should not allow in {}
✔ EC2 Security Group sg-00f0b54bd7c8d93a1 should not allow in {}
× EC2 Security Group sg-0c6388fa3e956cc15 should not allow in {}
expected `EC2 Security Group sg-0c6388fa3e956cc15.allow_in?({})` to return false, got
true
...
Profile Summary: 0 successful controls, 1 control failure, 0 controls skipped
Test Summary: 4 successful, 15 failures, 0 skipped
@nathenharvey
Where to next?
@nathenharvey
What else to validate?
Concern
Terraform
Plan
InSpec
Number and type of instances requested
All instances are part of our app
Right security groups created and attached
No security group allows in SSH
Only security group open to the world should
be port 80 for the ELB
ELB correctly configured
Should only be one ELB
@nathenharvey
Check instances
instances.rb
control "Should only have instances associated with my app" do
aws_ec2_instances.instance_ids.each do |instance_id|
describe aws_ec2_instance(instance_id) do
its('instance_type') { should cmp 't2.micro' }
its('tags') { should include(key:'X-Application', value:'Testing Terraform') }
end
end
end
@nathenharvey
More Security Groups
security_groups.rb
control "The only world-open security groups should be on the ELB" do
elb_sg_ids = aws_elbs.security_group_ids
aws_security_groups.group_ids.each do |sg_id|
sg = aws_security_group(sg_id)
if sg.allow_in? ipv4_range: '0.0.0.0/0'
describe sg do
its('group_id') { should be_in elb_sg_ids }
it { should allow_in_only port: 80 }
end
end
end
end
$
Put it all together with a profile
inspec init profile my_app
Create new profile at /Users/nathenharvey/projects/nathenharvey/testing-
terraform/inspec/profiles/my_app
* Create directory libraries
* Create file README.md
* Create directory controls
* Create file controls/example.rb
* Create file inspec.yml
* Create file libraries/.gitkeep
$
Put it all together with a profile
inspec exec -t aws:// my_app
Profile: tests from security_groups.rb (tests from security_groups.rb)
Version: (not specified)
Target: aws://
× Make sure unrestricted SSH is not permitted: EC2 Security Group sg-003262589de21dbf5 (15
failed)
✔ EC2 Security Group sg-003262589de21dbf5 should not allow in {}
✔ EC2 Security Group sg-00f0b54bd7c8d93a1 should not allow in {}
× EC2 Security Group sg-01b504b800f32e1ff should not allow in {}
expected `EC2 Security Group sg-01b504b800f32e1ff.allow_in?({})` to return false, got
true
...
Profile Summary: 0 successful controls, 3 control failures, 0 controls skipped
Test Summary: 43 successful, 65 failures, 0 skipped
@nathenharvey
Terraform: A Power Tool for the Cloud!
Terraform and InSpec?
InSpec: A Verification tool for OS's and API's
@nathenharvey
Terraform: A Power Tool for the Cloud!
Terraform and InSpec!
InSpec: A Verification tool for OS's and API's
@nathenharvey
Bonus Round
Iggy
$
Install InSpec-Iggy
gem install inspec-iggy
Successfully installed inspec-iggy-0.2.0
1 gem installed
$
Create a Profile from tfstate file
inspec terraform generate --tfstate terraform.tfstate > my_terra.rb
$
Run InSpec
inspec exec -t aws:// my_terra.rb
inspec exec -t aws:// my_terra.rb
Profile: tests from my_terra.rb (tests from my_terra.rb)
Version: (not specified)
Target: aws://
✔ aws_ec2_instance::i-03663e4b9cb2858d6: Iggy terraform.tfstate
aws_ec2_instance::i-03663e4b9cb2858d6
✔ EC2 Instance i-03663e4b9cb2858d6 should exist
...
Profile Summary: 8 successful controls, 0 control failures, 0 controls skipped
Test Summary: 32 successful, 0 failures, 0 skipped
@nathenharvey
Join us on Slack!
● http://community-slack.chef.io
● #general (for Chef stuff)
● #inspec
@nathenharvey
What questions can I answer for you?
https://github.com/nathenharvey/testing-terraform
Testing Terraform

More Related Content

PPTX
Advanced Weapons Training for the Empire
PDF
Gauntlt Rugged By Example
PDF
Small Python Tools for Software Release Engineering
PDF
ruxc0n 2012
PDF
Terraform - Taming Modern Clouds
PPTX
InSpec Workshop at Velocity London 2018
PDF
Nessus and Reporting Karma
PDF
Przemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy Terraform
Advanced Weapons Training for the Empire
Gauntlt Rugged By Example
Small Python Tools for Software Release Engineering
ruxc0n 2012
Terraform - Taming Modern Clouds
InSpec Workshop at Velocity London 2018
Nessus and Reporting Karma
Przemysław Iwanek - ABC AWS, budowanie infrastruktury przy pomocy Terraform

What's hot (20)

PPTX
Современные технологии и инструменты анализа вредоносного ПО_PHDays_2017_Pisk...
PPTX
How to add a new hypervisor to CloudStack:Lessons learned from Hyper-V effort
PDF
Attacking Oracle with the Metasploit Framework
PDF
FreeBSD: Dev to Prod
PPTX
BuildStuff.LT 2018 InSpec Workshop
PDF
IstSec'14 - İbrahim BALİÇ - Automated Malware Analysis
PDF
Threat stack aws
PDF
Embedded software development using BDD
PPTX
Security in PHP - 那些在滲透測試的小技巧
PDF
Meder Kydyraliev - Mining Mach Services within OS X Sandbox
PDF
Inspec one tool to rule them all
PDF
Terraform Introduction
PDF
infra-as-code
PPTX
2019 Chef InSpec Jumpstart Part 2 of 2
PDF
Infrastructure as Code with Terraform
PDF
(Un)safe Python
PPTX
So you want to be a security expert
PPTX
Adventures in Asymmetric Warfare
PDF
Node.js vs Play Framework
PPT
Defending Your Network
Современные технологии и инструменты анализа вредоносного ПО_PHDays_2017_Pisk...
How to add a new hypervisor to CloudStack:Lessons learned from Hyper-V effort
Attacking Oracle with the Metasploit Framework
FreeBSD: Dev to Prod
BuildStuff.LT 2018 InSpec Workshop
IstSec'14 - İbrahim BALİÇ - Automated Malware Analysis
Threat stack aws
Embedded software development using BDD
Security in PHP - 那些在滲透測試的小技巧
Meder Kydyraliev - Mining Mach Services within OS X Sandbox
Inspec one tool to rule them all
Terraform Introduction
infra-as-code
2019 Chef InSpec Jumpstart Part 2 of 2
Infrastructure as Code with Terraform
(Un)safe Python
So you want to be a security expert
Adventures in Asymmetric Warfare
Node.js vs Play Framework
Defending Your Network
Ad

Similar to Testing Terraform (20)

PPTX
RIMA-Infrastructure as a code with Terraform.pptx
PDF
Terraform introduction
PDF
Head in the Clouds: Testing Infra as Code - Config Management 2020
PDF
Compliance as Code with terraform-compliance
PDF
Getting Started with DevOps on AWS [Mar 2020]
PDF
DevOps Fest 2020. immutable infrastructure as code. True story.
PPTX
Adding Security and Compliance to Your Workflow with InSpec
PDF
Refactoring Infrastructure Code
PDF
Terraform Testing with InSpec Demo
PPTX
Effective Testing with Ansible and InSpec
PDF
Automating Security in Cloud Workloads with DevSecOps
PDF
Infrastructure as Code: Manage your Architecture with Git
PPTX
Will hall - Accelerating Infrastructure as Code and Configuration Management ...
PPTX
Accelerating Infrastructure as Code with CI in AWS.
PDF
AWS DevOps - Terraform, Docker, HashiCorp Vault
PDF
Refactoring terraform
PDF
CNCF London: Key Steps To a Good Quality Terraform Infrastructure Code
PDF
Atmosphere 2018: Yury Tsarev - TEST DRIVEN INFRASTRUCTURE FOR HIGHLY PERFORMI...
PDF
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
PPTX
An intro to Docker, Terraform, and Amazon ECS
RIMA-Infrastructure as a code with Terraform.pptx
Terraform introduction
Head in the Clouds: Testing Infra as Code - Config Management 2020
Compliance as Code with terraform-compliance
Getting Started with DevOps on AWS [Mar 2020]
DevOps Fest 2020. immutable infrastructure as code. True story.
Adding Security and Compliance to Your Workflow with InSpec
Refactoring Infrastructure Code
Terraform Testing with InSpec Demo
Effective Testing with Ansible and InSpec
Automating Security in Cloud Workloads with DevSecOps
Infrastructure as Code: Manage your Architecture with Git
Will hall - Accelerating Infrastructure as Code and Configuration Management ...
Accelerating Infrastructure as Code with CI in AWS.
AWS DevOps - Terraform, Docker, HashiCorp Vault
Refactoring terraform
CNCF London: Key Steps To a Good Quality Terraform Infrastructure Code
Atmosphere 2018: Yury Tsarev - TEST DRIVEN INFRASTRUCTURE FOR HIGHLY PERFORMI...
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
An intro to Docker, Terraform, and Amazon ECS
Ad

More from Nathen Harvey (13)

PDF
Accelerate Your DevOps Journey
PDF
Continuous Delivery - GDG Cloud Baltimore
PDF
Using Error Budgets to Prioritize Work
PPTX
Introduction to Test Kitchen and InSpec
PPTX
Introduction to Test Kitchen
PPTX
Effective Testing with Ansible and InSpec
PDF
DevOps Days India Keynote
PPTX
Compliance Automation with InSpec
PDF
Introduction to Infrastructure as Code & Automation / Introduction to Chef
PDF
Step AFK: Practical Advice for Career Adavancement
PDF
DevOp with Me!
PDF
Walk This Way - An Introduction to DevOps
PPTX
Mongo db at_customink
Accelerate Your DevOps Journey
Continuous Delivery - GDG Cloud Baltimore
Using Error Budgets to Prioritize Work
Introduction to Test Kitchen and InSpec
Introduction to Test Kitchen
Effective Testing with Ansible and InSpec
DevOps Days India Keynote
Compliance Automation with InSpec
Introduction to Infrastructure as Code & Automation / Introduction to Chef
Step AFK: Practical Advice for Career Adavancement
DevOp with Me!
Walk This Way - An Introduction to DevOps
Mongo db at_customink

Recently uploaded (20)

PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Electronic commerce courselecture one. Pdf
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Encapsulation theory and applications.pdf
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
cuic standard and advanced reporting.pdf
PDF
Spectral efficient network and resource selection model in 5G networks
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Electronic commerce courselecture one. Pdf
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
“AI and Expert System Decision Support & Business Intelligence Systems”
Building Integrated photovoltaic BIPV_UPV.pdf
Review of recent advances in non-invasive hemoglobin estimation
Agricultural_Statistics_at_a_Glance_2022_0.pdf
sap open course for s4hana steps from ECC to s4
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Chapter 3 Spatial Domain Image Processing.pdf
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
20250228 LYD VKU AI Blended-Learning.pptx
Unlocking AI with Model Context Protocol (MCP)
Encapsulation theory and applications.pdf
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
cuic standard and advanced reporting.pdf
Spectral efficient network and resource selection model in 5G networks

Testing Terraform

  • 2. @nathenharvey What am I talking about • Suppose you use a tool like Terraform to create your infrastructure • You're onboard with infrastructure as code • Code should be tested • How can we test Terraform?
  • 3. @nathenharvey 1. Deploy n-tier cloud infra 2. Deploy some app 3. Profit A Motivational Example Load Balancer VM Instance VM Instance ...
  • 4. @nathenharvey 1. Deploy n-tier cloud infra 2. Deploy some app ??? 3. Profit A Motivational Example Load Balancer VM Instance VM Instance ...
  • 5. @nathenharvey So how do you do that in Terraform?
  • 6. @nathenharvey Terraform on AWS: Define an Instance (VM) resource "aws_instance" "web" { count = 3 instance_type = "t2.micro" ami = "${lookup(var.aws_amis, var.aws_region)}" key_name = "${var.key_name}" subnet_id = "${aws_subnet.default.id}" vpc_security_group_ids = [ "${aws_security_group.lb_to_webservers.id}", "${aws_security_group.ssh_from_office.id}", ] ... }
  • 7. @nathenharvey Terraform on AWS: Define Load Balancer (ELB) resource "aws_elb" "web" { name = "testing-terraform-elb" subnets = ["${aws_subnet.default.id}"] security_groups = [ "${aws_security_group.world_to_elb.id}", "${aws_security_group.lb_to_webservers.id}", ] instances = ["${aws_instance.web.*.id}"] listener { instance_port = 80 instance_protocol = "http" lb_port = 80 lb_protocol = "http" } }
  • 8. @nathenharvey Terraform on AWS: Define a Firewall Rule resource "aws_security_group" "ssh_from_office" { name = "testing-terraform-ssh" vpc_id = "${aws_vpc.testing_terraform.id}" # SSH access from special office addresses ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = "${var.ssh_cidrs}" } # outbound internet access egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } }
  • 9. @nathenharvey Terraform on AWS: Define a Firewall Rule resource "aws_security_group" "ssh_from_office" { name = "testing-terraform-ssh" vpc_id = "${aws_vpc.testing_terraform.id}" # SSH access from special office addresses ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = "${var.ssh_cidrs}" } # outbound internet access egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } variable "ssh_cidrs" { default = [ "173.239.212.22/32", "12.130.117.75/32" ] }
  • 10. $ What's the plan, Phil? terraform plan -out plan.out Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. ... Plan: 11 to add, 0 to change, 0 to destroy. ------------------------------------------------------------------------ This plan was saved to: plan.out To perform exactly these actions, run the following command to apply: terraform apply "plan.out"
  • 11. $ Make it so! terraform apply "plan.out" aws_vpc.testing_terraform: Creating... assign_generated_ipv6_cidr_block: "" => "false" cidr_block: "" => "10.0.0.0/16" default_network_acl_id: "" => "<computed>" default_route_table_id: "" => "<computed>" default_security_group_id: "" => "<computed>” ... aws_elb.web: Creation complete after 25s (ID: testing-terraform-elb) Apply complete! Resources: 11 added, 0 changed, 0 destroyed. Outputs: address = testing-terraform-elb-1345186905.us-east-1.elb.amazonaws.com
  • 13. @nathenharvey Part of a balanced diet
  • 14. $ Verify with Terraform terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_vpc.testing_terraform: Refreshing state... (ID: vpc-091427c0ca8ed3c29) ... aws_elb.web: Refreshing state... (ID: testing-terraform-elb) ------------------------------------------------------------------------ No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed.
  • 19. $ Audit with Terraform terraform plan An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: ~ aws_instance.web[0] vpc_security_group_ids.#: "3" => "2" vpc_security_group_ids.1298918294: "sg-01eefd0164f2de498" => "sg-01eefd0164f2de498" vpc_security_group_ids.35497876: "sg-0c6388fa3e956cc15" => "" vpc_security_group_ids.645334896: "sg-03bca2a0e861c01e7" => "sg-03bca2a0e861c01e7” Plan: 0 to add, 1 to change, 0 to destroy.
  • 20. @nathenharvey Detected the new security group Will detach it Is that enough? Awesome! Terraform found the change!
  • 21. @nathenharvey It only audits what is known in the Terraform config All change is drift (considered bad) Only express what you want, not what you don't How does terraform plan fall short?
  • 24. @nathenharvey PART OF A PROCESS OF CONTINUOUS COMPLIANCE Scan for Compliance Build & Test Locally Build & Test CI/CD Remediate Verify A SIMPLE EXAMPLE OF AN INSPEC CIS RULE InSpec ▪ Translate compliance into Code ▪ Clearly express statements of policy ▪ Move risk to build/test from runtime ▪ Find issues early ▪ Write code quickly ▪ Run code anywhere ▪ Inspect machines, data and APIs Turn security and compliance into code control 'cis-1.4.1' do title '1.4.1 Enable SELinux in /etc/grub.conf' desc ' Do not disable SELinux and enforcing in your GRUB configuration. These are important security features that prevent attackers from escalating their access to your systems. For reference see … ' impact 1.0 expect(grub_conf.param 'selinux').to_not eq '0' expect(grub_conf.param 'enforcing').to_not eq '0' end
  • 25. $ InSpec Shell inspec shell –t aws:// Welcome to the interactive InSpec Shell To find out how to use it, type: help You are currently running on: Name: aws Families: cloud, api Release: aws-sdk-v2.11.50
  • 26. $ InSpec Shell inspec shell –t aws:// Welcome to the interactive InSpec Shell To find out how to use it, type: help You are currently running on: Name: aws Families: cloud, api Release: aws-sdk-v2.11.50 Targeting AWS!
  • 27. inspec> InSpec Shell – Tab Completion aws_<TAB> aws_cloudtrail_trail aws_iam_access_keys aws_iam_users aws_security_group aws_cloudtrail_trails aws_iam_group aws_kms_key aws_security_groups aws_cloudwatch_alarm aws_iam_groups aws_kms_keys aws_sns_subscription aws_cloudwatch_log_metric_filter aws_iam_password_policy aws_rds_instance aws_sns_topic aws_config_delivery_channel aws_iam_policies aws_route_table aws_sns_topics aws_config_recorder aws_iam_policy aws_route_tables aws_subnet aws_ec2_instance aws_iam_role aws_s3_bucket aws_subnets aws_ec2_instances aws_iam_root_user aws_s3_bucket_object aws_vpc aws_iam_access_key aws_iam_user aws_s3_buckets aws_vpcs
  • 28. inspec> Find the shady security group aws_security_group('sg-0c6388fa3e956cc15').group_name => "uat_executive"
  • 29. inspec> Check the Rules aws_security_group('sg-0c6388fa3e956cc15').inbound_rules => [{:from_port=>22, :ip_protocol=>"tcp", :ip_ranges=>[{:cidr_ip=>"0.0.0.0/0"}], :ipv_6_ranges=>[{:cidr_ipv_6=>"::/0"}], :prefix_list_ids=>[], :to_port=>22, :user_id_group_pairs=>[]}]
  • 30. inspec> describe aws_security_group('sg-0c6388fa3e956cc15') do inspec> it { should_not allow_in ipv4_range: '0.0.0.0/0' } inspec> end Write a proper test
  • 31. inspec> describe aws_security_group('sg-0c6388fa3e956cc15') do inspec> it { should_not allow_in ipv4_range: '0.0.0.0/0' } inspec> end Profile: inspec-shell Version: (not specified) EC2 Security Group sg-0c6388fa3e956cc15 × should not allow in {} expected `EC2 Security Group sg-0c6388fa3e956cc15.allow_in?({})` to return false, got true Test Summary: 0 successful, 1 failure, 0 skipped Write a proper test
  • 32. @nathenharvey An InSpec Control security_groups.rb control 'Make sure unrestricted SSH is not permitted' do # Loop over each of the security group IDs in the region aws_security_groups.group_ids.each do |group_id| # Examine a security group in detail describe aws_security_group(group_id) do # Examine Ingress rules, and complain if # there is unrestricted SSH it { should_not allow_in(port: 22, ipv4_range: '0.0.0.0/0') } end end end
  • 33. $ InSpec Shell inspec exec –t aws:// secruity_groups.rb Profile: tests from security_groups.rb (tests from security_groups.rb) Version: (not specified) Target: aws:// × Make sure unrestricted SSH is not permitted: EC2 Security Group sg-003262589de21dbf5 (15 failed) ✔ EC2 Security Group sg-003262589de21dbf5 should not allow in {} ✔ EC2 Security Group sg-00f0b54bd7c8d93a1 should not allow in {} × EC2 Security Group sg-0c6388fa3e956cc15 should not allow in {} expected `EC2 Security Group sg-0c6388fa3e956cc15.allow_in?({})` to return false, got true ... Profile Summary: 0 successful controls, 1 control failure, 0 controls skipped Test Summary: 4 successful, 15 failures, 0 skipped
  • 35. @nathenharvey What else to validate? Concern Terraform Plan InSpec Number and type of instances requested All instances are part of our app Right security groups created and attached No security group allows in SSH Only security group open to the world should be port 80 for the ELB ELB correctly configured Should only be one ELB
  • 36. @nathenharvey Check instances instances.rb control "Should only have instances associated with my app" do aws_ec2_instances.instance_ids.each do |instance_id| describe aws_ec2_instance(instance_id) do its('instance_type') { should cmp 't2.micro' } its('tags') { should include(key:'X-Application', value:'Testing Terraform') } end end end
  • 37. @nathenharvey More Security Groups security_groups.rb control "The only world-open security groups should be on the ELB" do elb_sg_ids = aws_elbs.security_group_ids aws_security_groups.group_ids.each do |sg_id| sg = aws_security_group(sg_id) if sg.allow_in? ipv4_range: '0.0.0.0/0' describe sg do its('group_id') { should be_in elb_sg_ids } it { should allow_in_only port: 80 } end end end end
  • 38. $ Put it all together with a profile inspec init profile my_app Create new profile at /Users/nathenharvey/projects/nathenharvey/testing- terraform/inspec/profiles/my_app * Create directory libraries * Create file README.md * Create directory controls * Create file controls/example.rb * Create file inspec.yml * Create file libraries/.gitkeep
  • 39. $ Put it all together with a profile inspec exec -t aws:// my_app Profile: tests from security_groups.rb (tests from security_groups.rb) Version: (not specified) Target: aws:// × Make sure unrestricted SSH is not permitted: EC2 Security Group sg-003262589de21dbf5 (15 failed) ✔ EC2 Security Group sg-003262589de21dbf5 should not allow in {} ✔ EC2 Security Group sg-00f0b54bd7c8d93a1 should not allow in {} × EC2 Security Group sg-01b504b800f32e1ff should not allow in {} expected `EC2 Security Group sg-01b504b800f32e1ff.allow_in?({})` to return false, got true ... Profile Summary: 0 successful controls, 3 control failures, 0 controls skipped Test Summary: 43 successful, 65 failures, 0 skipped
  • 40. @nathenharvey Terraform: A Power Tool for the Cloud! Terraform and InSpec? InSpec: A Verification tool for OS's and API's
  • 41. @nathenharvey Terraform: A Power Tool for the Cloud! Terraform and InSpec! InSpec: A Verification tool for OS's and API's
  • 43. $ Install InSpec-Iggy gem install inspec-iggy Successfully installed inspec-iggy-0.2.0 1 gem installed
  • 44. $ Create a Profile from tfstate file inspec terraform generate --tfstate terraform.tfstate > my_terra.rb
  • 45. $ Run InSpec inspec exec -t aws:// my_terra.rb inspec exec -t aws:// my_terra.rb Profile: tests from my_terra.rb (tests from my_terra.rb) Version: (not specified) Target: aws:// ✔ aws_ec2_instance::i-03663e4b9cb2858d6: Iggy terraform.tfstate aws_ec2_instance::i-03663e4b9cb2858d6 ✔ EC2 Instance i-03663e4b9cb2858d6 should exist ... Profile Summary: 8 successful controls, 0 control failures, 0 controls skipped Test Summary: 32 successful, 0 failures, 0 skipped
  • 46. @nathenharvey Join us on Slack! ● http://community-slack.chef.io ● #general (for Chef stuff) ● #inspec
  • 47. @nathenharvey What questions can I answer for you? https://github.com/nathenharvey/testing-terraform

Editor's Notes

  • #21: Config drift is different than scanning for a violation - it could just be here that a real change was intended