Test Driven
InfraStructure
Compliance as Code
by
Joaquín Menchaca
À propos de moi
About ME
Rocket LAWYER
SENIOR DEVOPS BUILD/RELEASE ENGINEER
aka
Linux Ninja Pants Automation Engineering Mutant
actual photo
AGENDA
- Setup
- Context
- Chef + InSpec
- Ansible + InSpec
- Bonus
SETUP
ThE CODE
git clone \
https://github.com/darkn3rd/lisa18_test_driven_infra
cd lisa18_test_driven_infra
# Using Virtual Workstation
vagrant up
vagrant ssh
cd lisa18_test_driven_infra
# Using Host (MacOS X or Linux)
#### Install Requirements
# Using Host (Windows)
#### Install Rrequiremnts
#### Warning: Might not work, had success w/ Chef
CODE
SETUP
The HoST
must be able to run
Docker
or
Vagrant
Minimum ReqUIRED
ChefDK - bundles ruby, test kitchen, inspec
Docker - fastest way to run stuff (virtual virtual machines)
DOCKER
Easiest Path is Docker Desktop
choco install docker-for-windows
brew cask install docker
https://chocolatey.org/
https://brew.sh/
https://www.docker.com/products/docker-desktop
DirecT DOWNLOAD
Package Managers
DOCKER
sudo apt-get update -qq
sudo apt-get install -y apt-transport-https \
curl ca-certificates software-properties-common
DOCKER_REPO="https://download.docker.com/linux/ubuntu"
curl -fsSL ${DOCKER_REPO}/gpg | \
sudo apt-key add -
sudo add-apt-repository \
"deb [arch=amd64] ${DOCKER_REPO} \
$(lsb_release -cs) \
stable"
sudo apt-get update -qq
sudo apt-get install -y docker-ce
sudo usermod -aG docker $USER
Debian Package on Ubuntu
DOCKER
CHEFDK
Easiest Way to Get Test Kitchen and InSpec
choco install chefdk
chef gem install kitchen-ansible
chef gem install kitchen-docker
brew tap chef/chef
brew cask install chefdk
chef gem install kitchen-ansible
chef gem install kitchen-docker
https://chocolatey.org/
https://brew.sh/
https://downloads.chef.io/chefdk/
DirecT DOWNLOAD
Package Managers
CHEFDK
VER=3.2.30
PKG=chefdk_${VER}-1_amd64.deb
PREFIX=https://packages.chef.io/files/stable/chefdk/
# Fetch and Install
wget --quiet ${PREFIX}/${VER}/ubuntu/16.04/${PKG}
sudo dpkg -i ${PKG}
# Local ChefDK Ruby Gems
chef gem install kitchen-ansible
chef gem install kitchen-docker
Debian Package on Ubuntu
CHEFDK
CONTEXT
WHY?
WHY?
We Code
SYSTEMS
We Code
PLATFORMS
We Code INFRASTRUCTURE
WHY?
WHY?
- Disaster Recovery, Rollback
- Migrate/Replicate New Environments
- Swap out components, Experiment
- Rapid (Like Seriously) Development
Destroy and Recreate with Ease
Because Tests…
WHEN?
WHEN
You have
an
Artifact?
What?
WHAT TO TEST?
HOW?
ABOUT THE
TOOLS
TEST KITCHEN
Create (Vagrant)→Converge(Chef)→Verify(InSpec)
TEST KITCHEN: Vagrant
---
driver:
name: vagrant
provider: hyperv
provisioner:
name: chef_zero
verifier:
name: inspec
platforms:
- name: ubuntu-16.04
suites:
- name: default
Create (Docker)→Converge(Ansible)→Verify(InSpec)
TEST KITCHEN
---
driver:
name: docker
provisioner:
name: ansible_playbook
verifier:
name: inspec
platforms:
- name: ubuntu-16.04
suites:
- name: default
TEST KITCHEN: DOCKER
control 'ez_apache-contract-01' do
describe port(80) do
it { should be_listening }
end
end
control 'ez_mysql-security-conf-01' do
describe file(mysql_data_path) do
it { should be_directory }
it { should be_owned_by 'mysql' }
it { should be_grouped_into 'mysql' }
end
end
INSPEC
package 'apache2'
service 'apache2' do
action %i(enable start)
supports(
status: true,
restart: true,
reload: true
)
end
cookbook_file "#{node['docroot']}/index.html" do
source 'index.html'
action :create
end
CHEF
- name: "Install Web Service"
package:
name: apache2
state: present
- name: "Start Web Service"
service:
name: apache2
state: started
enabled: yes
- name: "Copy Content"
copy:
src: "{{ role_path }}/files/index.html"
dest: "{{ docroot }}/index.html"
ANSIBLE
InSPEC
CHEF
CookBOOK STRUCTURE
./chef/cookbooks/ez_mysql
├── attributes
│ └── default.rb
├── Berksfile
├── kitchen.docker.yml
├── kitchen.hyperv.yml
├── kitchen.vbox.yml
├── metadata.rb
├── README.md
├── recipes
│ ├── client.rb
│ ├── database.rb
│ ├── default.rb
│ ├── harden.rb
│ ├── install.rb
│ └── service.rb
├── templates
│ └── security.cnf.erb
└── test -> ../../../inspec/ez_mysql/test
TEST STRUCTURE
./inspec/ez_mysql
└── test
└── integration
└── default
├── ansible.cfg
├── conform_test.rb
├── contract_test.rb
├── default.yml
└── security_test.rb
Shared Test for ANY change configuration, e.g.
CAPS (Chef, Ansible, Puppet, Salt Stack), or other automation
THE STEPS
# Setup (tell kitchen to use docker)
export KITCHEN_YAML=kitchen.docker.yml
# Create Environment
kitchen create
# (optional) Login into environment
kitchen login
# Converge to Desired State
kitchen converge
# Verify Environment
kitchen verify
WORKED FINE?
THE STEPS
include_recipe 'ez_mysql::install'
include_recipe 'ez_mysql::service'
# include_recipe 'ez_mysql::database'
include_recipe 'ez_mysql::harden'
THE STEPS
include_recipe 'ez_mysql::install'
include_recipe 'ez_mysql::service'
include_recipe 'ez_mysql::database'
include_recipe 'ez_mysql::harden'
WHEN CODE WORKS
ANSIBLE
InSPEC
ROLE STRUCTURE
./ansible/roles/ez_mysql
├── defaults
│ └── main.yml
├── handlers
│ └── main.yml
├── kitchen.docker.yml
├── kitchen.hyperv.yml
├── kitchen.vbox.yml
├── meta
│ └── main.yml
├── tasks
│ ├── client.yml
│ ├── database.yml
│ ├── harden.yml
│ ├── install.yml
│ ├── main.yml
│ └── service.yml
├── templates
│ └── security.cnf.j2
└─── test -> ../../../inspec/ez_mysql/test
TEST STRUCTURE
./inspec/ez_mysql
└── test
└── integration
└── default
├── ansible.cfg
├── conform_test.rb
├── contract_test.rb
├── default.yml
└── security_test.rb
Shared Test for ANY change configuration, e.g.
CAPS (Chef, Ansible, Puppet, Salt Stack), or other automation
THE STEPS
# Setup (tell kitchen to use docker)
export KITCHEN_YAML=kitchen.docker.yml
# Create Environment
kitchen create
# (optional) Login into environment
kitchen login
# Converge to Desired State
kitchen converge
# Verify Environment
kitchen verify
WORKED FINE?
THE STEPS
- include: install.yml
- include: config.yml
- include: service.yml
# - include: harden.yml
THE STEPS
- include: install.yml
- include: config.yml
- include: service.yml
- include: harden.yml
WHEN CODE WORKS
EXTRA STUFF
(tba)
(secret)
FINAL NOTES
(for reference)
TESTED PLATFORMS
Mac OS HOST
LINUX GUEST
WINDOWS HOST
☑ Mac/Vagrant (Virtualbox) / TestKitchen (Docker) / Chef
☑ Mac/Vagrant (Virtualbox)/ TestKitchen (Docker) / Ansible
☑ Win/Vagrant (HyperV) / TestKitchen (Docker) / Chef
☐ Win/Vagrant (HyperV)/ TestKitchen (Docker) / Ansible
☑ TestKitchen (HyperV) / Chef
☒ TestKitchen (HyperV) / Ansible
☐ TestKitchen (Docker) / Chef
☐ TestKitchen (Docker) / Ansible
☑ TestKitchen (Virtualbox) / Chef
☑ TestKitchen (Virtualbox) / Ansible
☑ TestKitchen (Docker) / Chef
☑ TestKitchen (Docker) / Ansible
FURTHER READING
TEST KITCHEN RESROUCES
- Test Kitchen: https://kitchen.ci/
- Ansible Provisioner: https://github.com/neillturner/kitchen-ansible
- Vagrant Driver: https://github.com/test-kitchen/kitchen-vagrant
- Docker Driver: https://github.com/test-kitchen/kitchen-docker
- InSpec Verifier: https://github.com/inspec/kitchen-inspec
- GCP Driver: https://github.com/test-kitchen/kitchen-google
- AWS Driver: https://github.com/test-kitchen/kitchen-ec2
-
Kubernetes Driver: https://github.com/coderanger/kitchen-kubernetes
Vagrant
- HashiCorp Vagrant: https://www.vagrantup.com/
DOCKER
- Docker: https://www.docker.com/
FURTHER READING
INSPEC
- InSpec: https://www.inspec.io/
- inspec-gcp: https://github.com/inspec/inspec-gcp
- inspec-gcp blog: https://blog.chef.io/2018/06/19/inspec-gcp-deep-dive/
KUBERNETES
- Sonobuoy: https://github.com/heptio/sonobuoy
TERRAFORM
- Terratest: https://github.com/gruntwork-io/terratest
- kitchen-terraform: https://github.com/newcontext-oss/kitchen-terraform
THE END
LISA18: Test Driven Infrastructure
By Joaquín Menchaca
LISA18: Test Driven Infrastructure
Original LISA18 Slide Deck w/o Extras (Inspec, GCP, Kubernetes)
- 1,169