Hello! This tutorial will walk you through setting up a Terraform config to spin up an Amazon Web Services (AWS) EC2 instance using Inspec and Kitchen-Terraform from scratch.
(Note: these instructions are for Unix based systems only)
mkdir tf_aws_cluster
cd tf_aws_cluster
touch main.tf variables.tf output.tf testing.tfvars
Gemfile
vim Gemfile
ruby '>= 3.0'
source 'https://rubygems.org/' do
gem 'kitchen-terraform', '~> 7.0'
end
bundle install
.kitchen.yml
file:vim .kitchen.yml
.kitchen.yml
config file..kitchen.yml
file:---
driver:
name: terraform
variable_files:
- testing.tfvars
---
driver:
name: terraform
variable_files:
- testing.tfvars
provisioner:
name: terraform
---
driver:
name: terraform
variable_files:
- testing.tfvars
provisioner:
name: terraform
platforms:
- name: ubuntu
---
driver:
name: terraform
variable_files:
- testing.tfvars
provisioner:
name: terraform
platforms:
- name: ubuntu
verifier:
name: terraform
systems:
- name: default
controls:
- operating_system
backend: ssh
user: ubuntu
key_files:
- ~/path/to/your/private/aws/key.pem
hosts_output: public_dns
reporter:
- documentation
verifier:
name: terraform
systems:
- name: default
controls:
- operating_system
operating_system_spec.rb
within that group. backend: ssh
user: ubuntu
key_files:
- ~/path/to/your/private/aws/key.pem
hosts_output: public_dns
reporter:
- documentation
output.tf
in a bit. The user key specifies the username that kitchen terraform will use to ssh into the hostnames with. In this tutorial we are using Ubuntu instances and the default username is ubuntu. Finally the reporter key specifies the InSpec reporters for reporting test output. In this example, we are specifying documentation which shows the tests passed with a small summary at the end..kitchen.yml
file:---
driver:
name: terraform
variable_files:
- testing.tfvars
provisioner:
name: terraform
platforms:
- name: ubuntu
verifier:
name: terraform
systems:
- name: default
controls:
- operating_system
backend: ssh
user: ubuntu
key_files:
- ~/path/to/your/private/aws/key.pem
hosts_output: public_dns
reporter:
- documentation
suites:
- name: default
mkdir -p test/integration/default/controls
vim test/integration/default/inspec.yml
---
name: default
.kitchen.yml
is expecting an output of our test kitchen instances' hostnames within the output variable, public_dns. In order to have a hostname within that public_dns variable, we need to create an EC2 instance.vim main.tf
provider "aws" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
region = "${var.region}"
}
resource "aws_security_group" "allow_ssh" {
name = "allow_ssh"
description = "Allow SSH inbound traffic"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "example" {
ami = "${var.ami}"
instance_type = "${var.instance_type}"
key_name = "${var.key_name}"
security_groups = "${aws_security_group.allow_ssh.name]"
}
provider "aws" {
access_key = var.access_key
secret_key = var.secret_key
region = var.region
}
resource "aws_security_group" "allow_ssh" {
name = "allow_ssh"
description = "Allow SSH inbound traffic"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "example" {
ami = var.ami
instance_type = var.instance_type
key_name = var.key_name
security_groups = [aws_security_group.allow_ssh.name]
}
variables.tf
file.vim variables.tf
variable "access_key" {}
variable "secret_key" {}
variable "key_name" {}
variable "region" {}
variable "ami" {}
variable "instance_type" {}
testing.tfvars
file:vim testing.tfvars
access_key = "my_aws_access_key"
secret_key = "my_aws_secret_key"
key_name = "my_aws_key_pair_name"
region = "us-east-1"
ami = "ami-fce3c696"
instance_type = "m3.medium"
.kitchen.yml
output.tf
file.vim output.tf
output "public_dns" {
value = "${aws_instance.example.public_dns}"
}
bundle exec kitchen converge
Outputs:
public_dns = your_aws_instance_public_ip
bundle exec kitchen verify
Finished in 0.002 seconds (files took 2.54 seconds to load)
0 examples, 0 failures
vim test/integration/default/controls/operating_system_spec.rb
control 'operating_system' do
describe command('lsb_release -a') do
its('stdout') { should match (/Ubuntu/) }
end
end
bundle exec kitchen verify
Command: `lsb_release -a`
stdout
is expected to match /Ubuntu/
Finished in 0.23381 seconds (files took 2.62 seconds to load)
1 example, 0 failures
bundle exec kitchen destroy
vim testing.tfvars
region = "us-east-1"
instance_type = "m3.medium"
ami = "ami-fce3c696"
region = "us-east-1"
instance_type = "m3.medium"
ami = "ami-6869aa05"
bundle exec kitchen converge
bundle exec kitchen verify
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: 1 actions failed.
>>>>>> Verify failed on instance <default-ubuntu>. Please see
.kitchen/logs/default-ubuntu.log for more details
.kitchen/log/default-ubuntu.log
Parsing through the output, we see this:ERROR -- default-ubuntu: Message: Transport error, can't connect to
'ssh' backend: SSH session could not be established
.kitchen.yml
verifier:
name: terraform
systems:
- name: default
controls:
- operating_system
hostnames: public_dns
username: ubuntu
reporter:
- documentation
.kitchen.yml
should now look like this:verifier:
name: terraform
systems:
- name: default
controls:
- operating_system
backend: ssh
key_files:
- ~/.ssh/ncs-laptop.pem
hosts_output: public_dns
user: ec2-user
reporter:
- documentation
bundle exec kitchen verify
Command: `lsb_release -a`
stdout
is expected to match /Ubuntu/ (FAILED - 1)
Failures:
1) Command: `lsb_release -a` stdout is expected to match /Ubuntu/
Failure/Error: DEFAULT_FAILURE_NOTIFIER = lambda { |failure, _opts| raise failure }
expected "" to match /Ubuntu/
Diff:
@@ -1,2 +1,2 @@
-/Ubuntu/
+""
# ./test/integration/default/controls/operating_system_spec.rb:3:in `block (3 levels) in load_with_context'
Finished in 0.26506 seconds (files took 5.52 seconds to load)
1 example, 1 failure
Failed examples:
rspec # Command: `lsb_release -a` stdout is expected to match /Ubuntu/
.kitchen.yml
file and change the username back to ubuntuverifier:
name: terraform
systems:
- name: default
controls:
- operating_system
backend: ssh
key_files:
- ~/.ssh/ncs-laptop.pem
hosts_output: public_dns
user: ec2-user
reporter:
- documentation
testing.tfvars
file and switch back to an Ubuntu AMIregion = "us-east-1"
instance_type = "m3.medium"
ami = "ami-fce3c696"
bundle exec kitchen destroy
bundle exec kitchen converge
bundle exec kitchen verify
bundle exec kitchen destroy