Use terraform environments to avoid integration test collisions

* When running integration tests with Rakefile use terraform environment based on environment variable INSPEC_TERRAFORM_ENV
** If INSPEC_TERRAFORM_ENV is not provided, a random string will be used
* Use terraform environment as a namespace for AWS artifacts
* Use attribute file for inspec to be aware of the terraform environment used

Signed-off-by: Miles Tjandrawidjaja <miles@tjandrawidjaja.com>
This commit is contained in:
Miles 2017-04-29 19:46:53 -04:00 committed by Miles Tjandrawidjaja
parent 5581762c64
commit 69434fec48
6 changed files with 88 additions and 18 deletions

8
.gitignore vendored
View file

@ -1,4 +1,8 @@
.attribute.yml
.bundle/
.terraform/
inspec.lock
Gemfile.lock
terraform.tfstate
terraform.tfstate.backup
terraform.tfstate*
terraform.tfstate.backup

View file

@ -97,7 +97,7 @@ bundle exec rake test
### Integration tests
To run the integration tests, please make sure all required environment variables like `AWS_ACCESS_KEY_ID`
, `AWS_SECRET_ACCESS_KEY` and `AWS_DEFAULT_REGION` are set properly. (`AWS_DEFAULT_REGION` **must** be set to **us-east-1** when running the integration tests.) We use terraform to create the AWS setup and InSpec to verify the all aspects. Integration tests can be executed via:
, `AWS_SECRET_ACCESS_KEY` and `AWS_DEFAULT_REGION` are set properly. (`AWS_DEFAULT_REGION` **must** be set to **us-east-1** when running the integration tests.) We use terraform to create the AWS setup and InSpec to verify the all aspects. If you want to use a specific terraform environment, set environment variable `INSPEC_TERRAFORM_ENV`. Integration tests can be executed via:
```
bundle exec rake test:integration
@ -105,9 +105,11 @@ bundle exec rake test:integration
This task sets up test AWS resources, runs the integration tests, and then cleans up the resources. To perform these tasks independently, please call them individually:
* `bundle exec rake test:configure_test_environment`
* `bundle exec rake test:setup_integration_tests`
* `bundle exec rake test:run_integration_tests`
* `bundle exec rake test:cleanup_integration_tests`
* `bundle exec rake test:destroy_test_environment`
## Kudos

View file

@ -3,6 +3,7 @@
require 'rake/testtask'
require 'rubocop/rake_task'
require 'securerandom'
# Rubocop
desc 'Run Rubocop lint checks'
@ -25,23 +26,36 @@ task lint: [:rubocop]
task default: [:lint, :test]
namespace :test do
integration_dir = "test/integration"
terraform_env = ENV['INSPEC_TERRAFORM_ENV'] || SecureRandom.urlsafe_base64(5)
project_dir = File.dirname(__FILE__)
attribute_file = File.join(project_dir, ".attribute.yml")
integration_dir = File.join(project_dir, "test/integration")
# run inspec check to verify that the profile is properly configured
task :check do
dir = File.join(File.dirname(__FILE__))
sh("bundle exec inspec check #{dir}")
sh("bundle exec inspec check #{project_dir}")
end
task :configure_test_environment do
puts "----> Creating terraform environment"
sh("cd #{integration_dir}/build/ && terraform env new #{terraform_env}")
end
task :setup_integration_tests do
puts "----> Setup"
sh("cd #{integration_dir}/build/ && terraform plan")
sh("cd #{integration_dir}/build/ && terraform apply")
sh("cd #{integration_dir}/build/ && terraform output > #{attribute_file}")
raw_output = File.read(attribute_file)
yaml_output = raw_output.gsub(" = ", " : ")
File.open(attribute_file, "w") {|file| file.puts yaml_output}
end
task :run_integration_tests do
puts "----> Run"
sh("bundle exec inspec exec #{integration_dir}/verify")
sh("bundle exec inspec exec #{integration_dir}/verify --attrs #{attribute_file}")
end
task :cleanup_integration_tests do
@ -49,10 +63,18 @@ namespace :test do
sh("cd #{integration_dir}/build/ && terraform destroy -force")
end
task :destroy_test_environment do
puts "----> Destroying terraform environment"
sh("cd #{integration_dir}/build/ && terraform env select default")
sh("cd #{integration_dir}/build && terraform env delete #{terraform_env}")
end
task :integration do
Rake::Task["test:configure_test_environment"].execute
Rake::Task["test:cleanup_integration_tests"].execute
Rake::Task["test:setup_integration_tests"].execute
Rake::Task["test:run_integration_tests"].execute
Rake::Task["test:cleanup_integration_tests"].execute
Rake::Task["test:destroy_test_environment"].execute
end
end

View file

@ -5,17 +5,17 @@ resource "aws_instance" "example" {
instance_type = "t2.micro"
tags {
Name = "Example"
Name = "${terraform.env}.Example"
X-Project = "inspec"
}
}
resource "aws_iam_user" "mfa_not_enabled_user" {
name = "mfa_not_enabled_user"
name = "${terraform.env}.mfa_not_enabled_user"
}
resource "aws_iam_user" "console_password_enabled_user" {
name = "console_password_enabled_user"
name = "${terraform.env}.console_password_enabled_user"
force_destroy = true
}
@ -23,3 +23,19 @@ resource "aws_iam_user_login_profile" "u" {
user = "${aws_iam_user.console_password_enabled_user.name}"
pgp_key = "${var.login_profile_pgp_key}"
}
output "mfa_not_enabled_user" {
value = "${aws_iam_user.mfa_not_enabled_user.name}"
}
output "console_password_enabled_user" {
value = "${aws_iam_user.console_password_enabled_user.name}"
}
output "example_ec2_name" {
value = "${aws_instance.example.tags.Name}"
}
output "example_ec2_id" {
value = "${aws_instance.example.id}"
}

View file

@ -1,4 +1,20 @@
describe aws_ec2(name: 'Example') do
example_ec2_id = attribute(
'example_ec2_id',
default: 'default.example_ec2_id',
description: 'ID of example ec2 instance')
example_ec2_name = attribute(
'example_ec2_name',
default: 'default.Example',
description: 'Name of exapmle ec2 instance')
describe aws_ec2(name: example_ec2_name) do
it { should exist }
its('image_id') { should eq 'ami-0d729a60' }
its('instance_type') { should eq 't2.micro' }
end
describe aws_ec2(example_ec2_id) do
it { should exist }
its('image_id') { should eq 'ami-0d729a60' }
its('instance_type') { should eq 't2.micro' }

View file

@ -1,8 +1,18 @@
describe aws_iam_user('mfa_not_enabled_user') do
its('has_mfa_enabled?') { should be false }
its('has_console_password?') { should be false }
end
describe aws_iam_user('console_password_enabled_user') do
its('has_console_password?') { should be true }
mfa_not_enabled_user = attribute(
'mfa_not_enabled_user',
default: 'default.mfa_not_enabled_user',
description: 'Name of IAM user mfa_not_enabled_user')
console_password_enabled_user = attribute(
'console_password_enabled_user',
default: 'default.console_password_enabled_user',
description: 'Name of IAM user console_password_enabled_user')
describe aws_iam_user(mfa_not_enabled_user) do
its('has_mfa_enabled?') { should be false }
its('has_console_password?') { should be false }
end
describe aws_iam_user(console_password_enabled_user) do
its('has_console_password?') { should be true }
end