Jumpstart your education on learning Chef InSpec to turn your DevOps into DevSecOps, by automating your integration testing and compliance/security scanning.
6. About you
• Hands up if you have Chef InSpec experience
• Keep it up if you have Chef Infra experience
7. About you
• Hands up if you have Chef InSpec experience
• Keep it up if you have Chef Infra experience
• Keep it up if you have at least 1 years experience
8. About you
• Hands up if you have Chef InSpec experience
• Keep it up if you have Chef Infra experience
• Keep it up if you have at least 1 years experience
• Keep it up if you have at least 2 years experience
9. About you
• Hands up if you have Chef InSpec experience
• Keep it up if you have Chef Infra experience
• Keep it up if you have at least 1 years experience
• Keep it up if you have at least 2 years experience
• Keep it up if you have at least 3 years experience
10. About you
• Hands up if you have Chef InSpec experience
• Keep it up if you have Chef Infra experience
• Keep it up if you have at least 1 years experience
• Keep it up if you have at least 2 years experience
• Keep it up if you have at least 3 years experience
• Well, you’ll all have at least one day’s experience
11. Agenda
• Introduction
• Introduction to Automated Testing
• Chef InSpec and Integration
Testing
• Chef InSpec Profiles
• Remote Scans
• Chef InSpec DSL - Deeper Dive
• Chef InSpec and Cloud
Infrastructure
• OSS Profiles
• Chef InSpec DSL and Compliance
Regulations
• Chef InSpec and Chef Automate
• Further Resources
12. Expectations
• This class focuses on Chef InSpec and assumes no previous
experience
• You will leave this class with the ability to
o Explain and create Chef InSpec profiles and controls
o Invoke Chef InSpec on local and remote target nodes, and cloud
infrastructure
o Use Chef Automate to scan your whole environment
o Run Chef to remediate non-compliances issues
13. Task Slides
If you see this on the top of a slide,
Then that’s your cue to get with the typey typey
TASK
15. File to Edit/Create on InSpec Workstation
Template
TASK
/filepath/file.rb
File contents here.
This template tells you to create or edit the specified file on your Workstation
16. What’s next…?
In the next section we’ll briefly look at types of automated testing, the
reasons for it, and the tooling used
19. Objectives
➢ After completing this lesson you will be able to:
o Discuss the types of testing that are prevalent in our industry
o Explain why automated testing is important
o Explain when each type of test gets run, and why
o Appreciate the distinction, and similarity, between integration tests and
compliance tests
o Explain what Chef InSpec is
20. Types of Testing
Code Correctness Unit Testing Integration Testing Compliance Scanning
● Foodcritic
● Cookstyle
(Rubocop)
● ChefSpec ● Test Kitchen
● Chef InSpec
● Chef Automate
● Chef InSpec
Is the code syntactically
correct & does it follow
style guidelines?
Do individual pieces of
code do what they’re
supposed to do?
Does the full application
work end to end?
Is the application (&
infrastructure it runs on)
secure and does it meet
regulations?
22. Many types of tests
Is web server listening on tcp/80?
Is web server delivering the correct content?
Using TLS or SSL?
SSH v2 Configured?
User ‘foo’ has read no write access to /myapp?
User ‘foo’ exists?
User ‘foo’ has read access to /myapp?
User ‘foo’ does not have sudo access?
User ‘foo’ does not have read access to /etc?
SSH v1 Configured?
23. Many types of tests
Is web server listening on tcp/80?
Is web server delivering the correct content?
Using TLS or SSL?
SSH v2 Configured?
User ‘foo’ has read no write access to /myapp?
User ‘foo’ exists?
User ‘foo’ has read access to /myapp?
User ‘foo’ does not have sudo access?
User ‘foo’ does not have read access to /etc?
SSH v1 Configured?
• There is zero consistency when testing
infrastructure
o All configuration files are proprietary
o All commands have different syntaxes &
command line switches
o They’re platform specific (RHEL, Debian,
Windows, …)
25. What is Chef InSpec
• Chef InSpec provides consistent DSL that is platform agnostic to
check status of any component:
o packages
o files
o users
o AWS IAM users
o AWS S3 buckets
o …
• Complex implementation code abstracted out
• Many Chef InSpec profiles exist in the community, and Chef
provides profiles matching specific compliance regulations
26. Bash vs Chef InSpec for testing
For example, SSH supports two different protocol versions. The
original version, SSHv1, was subject to a number of security issues.
Please use SSHv2 instead to avoid these.
27. Chef InSpec for any infrastructure
describe port(22) do
its('processes') { should include 'sshd' }
its('protocols') { should include 'tcp' }
its('addresses') { should include '0.0.0.0' }
end
• No agent, nor Ruby, required on target node
• Chef InSpec tests your servers’ actual state by executing the appropriate
command locally via SSH, via WinRM, via Docker API and so on
28. Chef InSpec for AWS
describe aws_iam_user(name: 'test_user') do
it { should have_mfa_enabled }
it { should have_console_password }
end
Chef InSpec for Azure
describe azure_virtual_machine(group_name: 'InSpec-Azure', name: 'Linux-Internal-VM') do
its('size') { should eq 'Standard_DS2_v2' }
its('location') { should eq 'westeurope' }
its('admin_settings') { should eq 'azure' }
end
29. Chef InSpec is cross platform
• One language • Chef InSpec for Windows
30. Chef InSpec is agentless
• Chef InSpec was born out of Rspec and ServerSpec
• No agent needs to be installed on the target node
• Requires
o SSH access for Linux nodes
o WinRM access for Windows
31. Integration (functional) vs Compliance (security)
Tests
Is web server listening on tcp/80? Integration Test
Is web server delivering the correct content? Integration Test
Using TLS or SSL? Compliance
Test
SSH v2 Configured? Integration
Test / Compliance Test
User ‘foo’ has read no write access to /myapp? Compliance Test
User ‘foo’ exists?
Integration Test
User ‘foo’ has read access to /myapp? Integration Test
User ‘foo’ does not have sudo access? Compliance Test
User ‘foo’ does not have read access to /etc? Compliance Test
SSH v1 Configured? Compliance
32. Integration (functional) vs Compliance (security)
Tests
Is web server listening on tcp/80? Integration Test
Is web server delivering the correct content? Integration Test
User ‘foo’ exists?
Integration Test
User ‘foo’ has read access to /myapp? Integration Test
SSH v2 Configured? Integration
Test / Compliance Test
Using TLS or SSL? Compliance
Test
User ‘foo’ has read no write access to /myapp? Compliance Test
User ‘foo’ does not have sudo access? Compliance Test
User ‘foo’ does not have read access to /etc? Compliance Test
SSH v1 Configured? Compliance
Integration Tests
(Does the thing work?)
● Tests usually
maintained within a
cookbook
● Invoked by Test
Kitchen
Compliance Scans
(Is the thing secure?)
● Tests collated in
InSpec profiles and
maintained
externally, e.g.,
GitHub,
Compliance server
● Invoked by ‘inspec’
cli or from Chef
Automate
33. Integration AND Compliance Tests — Two Separate Use
Cases
Use Case 1
Cookbook Integration Test
Is web server listening on tcp/80?
Is web server delivering the correct content?
User ‘foo’ exists?
User ‘foo’ has read access to /myapp?
We’ll look at this use case
briefly initially
Use Case 2
Server Compliance Scan
Using TLS or SSL?
User ‘foo’ has read no write access to /myapp?
User ‘foo’ does not have sudo access?
User ‘foo’ does not have read access to /etc?
SSH v1 Configured?
We’ll spend most of the workshop
looking at this use case
SSH v2
Configured?
34. Chef InSpec Integration vs Compliance
Testing
Same language — two distinct use cases
Chef InSpec Rules Integration tests Compliance scan
Types of Rules Governed by the application
(cookbook) requirements
Generic rules defined by industry security
requirements (not governed by the
application requirements)
Location of Rules Shipped with a cookbook Stored centrally (Compliance server,
GitHub)
Invocation Use Test Kitchen to provision a
sandbox environment to perform
functional tests of the cookbook
Use Chef InSpec DSL or Chef Automate to
perform compliance tests during
development, or in production
35. Key Takeaways
Chef InSpec has two separate very different use cases
1. Integration testing of Chef cookbooks within the Test Kitchen framework, and
2. Scanning your server estate for compliance reasons
What’s next… ?
In the next section we’ll get ourselves set up with a remote workstation to play
with...
39. Task: Log in to your workstation
The authenticity of host '12.34.56.78 (12.34.56.78)' can't be
established.ECDSA key fingerprint is
SHA256:GpuZBeC1yoO64HsyYseMnd/DRJSj0k/JqljtGX0aU9M.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '12.34.56.78' (ECDSA) to the list of
known hosts. chef@12.34.56.78's password: **********
Password = 123Chef321
$ ssh chef@12.34.56.78
TASK
40. Task: Ensure you’re in the correct VM
$ touch firstname-lastname
$ ls -l
<firstname-lastname> automate-credential.toml config.toml
chef-automate cookbooks deploy-chef-
automate.sh profiles
TASK
44. Use Case 1: Chef InSpec and
Integration Testing
Chef InSpec and TDD
45. Objectives
• After completing this lesson you will be able to:
o Navigate the Chef InSpec documentation
o Write custom Chef InSpec controls
o Use the “:skip” directive to skip tests
o Use Chef InSpec along with Test Kitchen for integration testing
o Read and understand Chef InSpec output
46. Chef InSpec and TDD
• We discussed earlier how Chef InSpec can be used for integration
testing as part of the CI/CD pipeline
• We will explore this in more detail using a Test Driven
Development (TDD) approach by way of example
• Our scenario is we need a web server to deliver some specific
content
47. Problem: We need a web server
• We will deploy this with Chef
using a TDD approach, i.e.,
o Write a test for your code
o Execute the test and watch it fail
o Write the code
o Rerun the test and watch it pass
We need to create a Nginx web server
48. What tests need to pass?
• We will be successful if http://localhost returns:
o 200 ok status code
o The content “inspec jumpstart”
o The correct content-Type header
49. What tests need to pass?
What tests need to pass?
• We will be successful if http://localhost returns:
o 200 ok status code
o The content “inspec jumpstart”
o The correct content-Type header
50. What tests need to pass?
Let’s look at the docs
What tests need to pass?
• We will be successful if http://localhost returns:
o 200 ok status code
o The content “inspec jumpstart”
o The correct content-Type header
54. Task: Template integration tests are
templated
We’ve pre-created the nginx cookbook
Note there is nothing in the recipe yet, so
nothing will be configured on the system
Using Chef is a workshop in itself - here
we’ll concentrate on InSpec
$ tree cookbooks/mynginx
TASK
55. Task: Append new InSpec test to
default_test.rb
NOTE: nano editor can be used instead of vi… $ nano ~/cookbooks/...
…
describe http('http://localhost', enable_remote_worker: true) do
its('status') { should cmp 200 }
its('body') { should cmp 'Inspec Jumpstart' }
its('headers.Content-Type') { should cmp 'text/html' }
end
What does this code mean?
cheat sheet
https://bit.ly/default_test
$ vi ~/cookbooks/mynginx/test/smoke/default/default_test.rb
TASK
56. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Control Contains
57. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Control Contains
- a describe
statement
58. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Control Contains
- a describe
statement
- a resource
59. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Control Contains
- a describe
statement
- a resource
- an optional
argument
60. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Control Contains
- a describe
statement
- a resource
- an optional
argument
- an optional
parameter
61. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Control Contains
- a describe
statement
- a resource
- an optional
argument
- an optional
parameter
- a do …. end block
62. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Control Contains
- a describe
statement
- a resource
- an optional
argument
- an optional
parameter
- a do …. end block
- one or more tests
63. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Test Contains
64. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Test Contains:
- one or more it
and/or its
statement
65. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Test Contains:
- one or more it
and/or its
statement
- an optional
property (its
statement)
66. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Test Contains:
- one or more it
and/or its
statement
- an optional
property (its
statement)
- each with a
condition
statement
67. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Test Contains:
- one or more it
and/or its
statement
- an optional
property (its
statement)
- each with a
condition
statement
Each Condition
Contains:
- a condition
68. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Test Contains:
- one or more it
and/or its
statement
- an optional
property (its
statement)
- each with a
condition
statement
Each Condition
Contains:
- a condition
- a matcher
69. Anatomy of a Chef InSpec test
describe http(‘http://localhost’, enable_remote_worker: true) do
its(‘status’) { should cmp 200 }
its(’body’) { should cmp ‘Inspec Jumpstart’ }
its(‘headers-Content-type’) { should cmp ‘text/html’ }
end
Each Test Contains:
- one or more it
and/or its
statement
- an optional
property (its
statement)
- each with a
condition
statement
Each Condition
Contains:
- a condition
- a matcher
- an expected result
70. Matchers
➢ Each Chef InSpec resource has a number of relevant matchers
you can use to check the status of that item
➢ For example, the file resource allows you to test the status of any
file (or directory) and as such relevant matchers are:
- exists
- be_readable
- content
- etc
➢ Whereas the package resource applicable matchers are
- version
- be_installed
- etc
71. Note skipped tests
Tests can be defined but skipped allowing for placeholders
$ cat ~/cookbooks/mynginx/test/smoke/default/default_test.rb
72. Problem: We need a web server
➢ We will deploy this with Chef
using a TDD approach, i.e.,
○ Write a test for your code
○ Execute the test and watch it fail
○ Write the code
○ Rerun the test and watch it pass
We need to create a web server
73. Introduction to Test Kitchen
➢ Now that we have created our tests, the second step is to execute
it and watch it fail
➢ We will use Test Kitchen to test our code
➢ Test Kitchen provides a harness to execute code on ephemeral
infrastructure - forms part of a CI/CD pipeline
74. Task: Navigate into cookbooks/mynginx
directory
We’ll remain in this directory for the remainder of this section
$ cd ~/cookbooks/mynginx
TASK
75. Task: View Test Kitchen Config file
This configuration file tells Test Kitchen to:
- spin up a centos-6.7 docker container (via ‘dokken’ driver)
- use Chef Zero to run this recipe - recipe[mynginx:default]
- then use InSpec to run the tests specified in test/smoke/default
$ cat .kitchen.yml
TASK
76. Task: Run Test Kitchen
kitchen verify
- spin up a centos-6.7 docker container
- use Chef Zero to run this recipe - recipe[mynginx:default] (recipe currently blank so does nothing)
- then use InSpec to run the tests specified in test/smoke/default
$ kitchen verify
TASK
77. Problem: We need a web server
➢ We will deploy this with Chef
using a TDD approach, i.e.,
○ Write a test for your code
○ Execute the test and watch it fail
○ Write the code
○ Rerun the test and watch it pass
We need to create a web server
78. Task: Create your recipe
include_recipe 'nginx::repo'
package 'nginx' do
action :install
end
remote_file '/usr/share/nginx/html/index.html' do
source 'https://inspec-jumpstart-2019.s3.amazonaws.com/web01.html'
end
service 'nginx' do
supports status: true, restart: true, reload: true
action [ :enable, :start ]
end
$ vi ~/cookbooks/mynginx/recipes/default.rb
TASK
cheat sheet
https://bit.ly/recipe_default
79. Test: run Test Kitchen
kitchen converge
- provisions a new server (or container in our case)
- installs Chef
- runs the recipe in the .kitchen.yml file
$ kitchen converge
TASK
80. Problem: We need a web server
➢ We will deploy this with Chef
using a TDD approach, i.e.,
○ Write a test for your code
○ Execute the test and watch it fail
○ Write the code
○ Rerun the test and watch it pass
We need to create a web server
82. Problem: We need a web server
➢ We will deploy this with Chef
using a TDD approach, i.e.,
○ Write a test for your code
○ Execute the test and watch it fail
○ Write the code
○ Rerun the test and watch it pass
We need to create a web server
83. Chef InSpec and TDD
➢ The key takeaway here is the Chef InSpec plugin for Test Kitchen
can be a valuable tool in the test driven development of Chef
cookbooks
➢ In that workflow the Chef InSpec controls are in control files
shipped along with the cookbook itself, as follows:
~/cookbooks/ <cookbook name>/test/smoke/default/control-filename_test.rb
➢ However, Chef InSpec is a standalone tool and can be used for
more general testing purposes, including compliance scanning
➢ Note: we will focus on using Chef InSpec for compliance scanning
for the remainder of the class
84. Key Takeaways
One very specific use case for Chef InSpec is for integration testing
of Chef cookbooks within the Test Kitchen framework
In this use case the Chef InSpec tests are shipped as .rb files
within the cookbook
In the next section we’ll look at the Chef InSpec tool itself,
creating Chef InSpec profiles, and the more general use case of
scanning infrastructure for compliance
What’s Next?
85.
86. Chef InSpec CLI, Profiles and
Compliance Scanning
Introduction to Chef InSpec CLI and creating and executing profiles
87. Objectives
➢ After completing this lesson you will be able to
➢ Describe Chef InSpec as a standalone tool
➢ Create & Navigate Chef InSpec profiles
➢ Identify the contents of an Chef InSpec profile
➢ Explain the structure of an Chef InSpec profile
➢ Invoke Chef InSpec tests on a local host
➢ Use formatters to format the output of an Chef InSpec test as
JSON, HTML, etc
88. Chef InSpec as a Standalone Tool
➢ We've seen how Chef InSpec controls may be shipped within Chef
cookbooks & invoked using Test Kitchen
○ Integration testing of Chef cookbooks use case
➢ For the remainder of the class we'll look at Chef InSpec as a
standalone tool to scan 1+ nodes for compliance using custom or
industry standard controls
○ This primary use case is unrelated to Test Kitchen and Chef – apart from
remediation cookbooks if necessary
89. Chef InSpec code is maintained in 'Profiles'
Chef InSpec organizes controls into versioned 'profiles'
A profile is a standalone structure containing
● control files
● documentation
● extension libraries
● dependencies
Lets look at profiles by way of an example
90. Problem Statement
➢ We need to ensure our web node is using SSH2 only and not
SSH1, as SSH1 has security vulnerabilities
➢ We will use InSpec to ensure the node is compliant
91. Problem: SSH v1 is Insecure
We need to ensure our web node is using SSH2 only and not SSH1,
as SSH1 has security vulnerabilities
The tasks are
1. Create a skeleton Chef InSpec profile for SSH
2. Review the technical requirements and create the Chef InSpec
control including the actual test
3. Execute the Chef InSpec profile to determine current system state
4. Correct the state and rerun Chef InSpec check
92. Chef InSpec Command Line Interface
➢ In this section we will use the Chef InSpec command line interface
(CLI) to help us create profiles and run audit tests against targets
➢ The Chef InSpec CLI commands can run audit tests against targets
using SSH, WinRM, locally, or on Docker containers
93. Chef InSpec Command Line Interface
➢ We'll be using inspec init, inspec check and inspec exec
➢ inspec check verifies the compliance profile code that you write
➢ inspec exec will run the tests against a system
Note: the Chef InSpec tests we executed in the previous section (using
Test Kitchen) were tied to the specific cookbook, and were used to
verify that cookbook
inspec exec can be used to scan for compliance – Test Kitchen isn't used
94. Task: Execute the 'inspec' command
● Chef InSpec has its own CLI for creating and executing profiles, amongst other things
● We will look more at the inspec command later – for now we'll use inspec init to create our new
profile
TASK
$ inspec
Commands:
inspec archive PATH # archive a profile to tar.gz (default) or zip
inspec artifact SUBCOMMAND ... # Sign, verify and install artifacts
inspec check PATH # verify all tests at the specified PATH
inspec compliance SUBCOMMAND ... # Chef Compliance commands
inspec detect # detect the target OS
inspec env # Output shell-appropriate completion configuration
inspec exec PATHS # run all test files at the specified PATH.
inspec habitat SUBCOMMAND ... # Commands for InSpec + Habitat Integration
inspec help [COMMAND] # Describe available commands or one specific command
inspec init TEMPLATE ... # Scaffolds a new project
inspec json PATH # read all tests in PATH and generate a JSON summary
inspec shell # open an interactive debugging shell
...
99. Anatomy of a Chef InSpec Profile
profiles/webnode_profile
│
├── inspec.yml
│
├── README.md
│
├── controls
│ └── example.rb
│
├── libraries
│
└── files
A Chef InSpec profile contains
● inspec.yml which includes the profile
description, dependencies, versioning, etc
100. The inspec.yml file
For those familiar with Chef, 'inspec.yml' is akin to 'metadata.rb'
TASK
$ cat ~/profiles/webnode_profile/inspec.yml
name: webnode_profile
title: InSpec Profile
maintainer: The Authors
copyright: The Authors
copyright_email: you@example.com
license: Apache-2.0
summary: An InSpec Compliance Profile
version: 0.1.0
supports:
platform: os
101. Anatomy of a Chef InSpec Profile
profiles/webnode_profile
│
├── inspec.yml
│
├── README.md
│
├── controls
│ └── example.rb
│
├── libraries
│
└── files
A Chef InSpec profile contains
● inspec.yml
● README.md
● controls directory in which all tests are
located. An example.rb file is stubbed with
sample controls
102. Sample Controls File
TASK
$ cat ~/profiles/webnode_profile/controls/example.rb
# encoding: utf-8
# copyright: 2018, The Authors
title 'sample section'
# you can also use plain tests
describe file('/tmp') do
it { should be_directory }
end
# you add controls here
control 'tmp-1.0' do # A unique ID for this control
impact 0.7 # The criticality, if this control fails.
title 'Create /tmp directory' # A human-readable title
desc 'An optional description...'
describe file('/tmp') do # The actual test
it { should be_directory }
end
end
103. Anatomy of a Chef InSpec Profile
profiles/webnode_profile
│
├── inspec.yml
│
├── README.md
│
├── controls
│ └── example.rb
│
├── libraries
│
└── files
A Chef InSpec profile contains
● inspec.yml
● README.md
● controls
● optional libraries directory in which optional
InSpec resource extensions are located
104. Anatomy of a Chef InSpec Profile
profiles/webnode_profile
│
├── inspec.yml
│
├── README.md
│
├── controls
│ └── example.rb
│
├── libraries
│
└── files
A Chef InSpec profile contains
● inspec.yml
● README.md
● Controls
● libraries
● optional files directory for additional files that
a profile can access
105. Problem: SSH v1 is Insecure
We need to ensure our web node is using SSH2 only and not SSH1,
as SSH1 has security vulnerabilities.
The tasks are
✓ Create a skeleton Chef InSpec profile for SSH
2. Review the technical requirements and create the Chef InSpec
control including the actual test
3. Execute the Chef InSpec profile to determine current system state
4. Correct the state and rerun Chef InSpec check
106. Back to our SSH problem - which resource shall we
use?
➢ We need to ensure our web node is using SSH2 only and not
SSH1, as SSH1 has security vulnerabilities.
➢ We'll use the ssh_config resource
107. Task: Create a new controls file ssh.rb within our profile
TASK
$ touch ~/profiles/webnode_profile/controls/ssh.rb
108. Task: Include some controls from OSS profile in our profile
TASK
$ vi ~/profiles/webnode_profile/controls/ssh.rb
title 'ssh'
control 'sshv2' do
impact 0.7
title 'Check SSH Version'
desc 'Only SSH version 2 should be enabled'
describe ssh_config do
its('Protocol') { should cmp 2 }
end
end cheat sheet
https://bit.ly/controls_ssh
109. Control Files
A profile contains one or more control
files, each containing a number of tests
• A control block contains at least
one describe block, but may
contain as many as required
• A describe block contains at least
one test
# encoding: utf-8
# copyright: 2018, The Authors
title 'sample section'
describe file('/tmp') do
it { should be_directory }
end
control 'tmp-1.0' do
tag 'tmp',
tag dir: '/tmp'
ref 'NSA-RH6 - Section 3.5.2.1'
impact 0.7
title 'Create /tmp directory'
desc 'An optional description...'
describe file('/tmp') do
it { should be_directory }
end
end
110. The Anatomy of a Control File
A control file within a profile contains
• Some boilerplate information and a title
# encoding: utf-8
# copyright: 2018, The Authors
title 'sample section'
describe file('/tmp') do
it { should be_directory }
end
control 'tmp-1.0' do
tag 'tmp',
tag dir: '/tmp'
ref 'NSA-RH6 - Section 3.5.2.1'
impact 0.7
title 'Create /tmp directory'
desc 'An optional description...'
describe file('/tmp') do
it { should be_directory }
end
end
111. The Anatomy of a Control File
A control file within a profile contains
• Some boilerplate information and a title
• One or more describe statements, each
containing one or more tests
# encoding: utf-8
# copyright: 2018, The Authors
title 'sample section'
describe file('/tmp') do
it { should be_directory }
end
control 'tmp-1.0' do
tag 'tmp',
tag dir: '/tmp'
ref 'NSA-RH6 - Section 3.5.2.1'
impact 0.7
title 'Create /tmp directory'
desc 'An optional description...'
describe file('/tmp') do
it { should be_directory }
end
end
112. The Anatomy of a Control File
A control file within a profile contains
• Some boilerplate information and a title
• One or more describe statements, each
containing one or more tests
• describe statements may be grouped
within control statements
# encoding: utf-8
# copyright: 2018, The Authors
title 'sample section'
describe file('/tmp') do
it { should be_directory }
end
control 'tmp-1.0' do
tag 'tmp',
tag dir: '/tmp'
ref 'NSA-RH6 - Section 3.5.2.1'
impact 0.7
title 'Create /tmp directory'
desc 'An optional description...'
describe file('/tmp') do
it { should be_directory }
end
end
113. The Anatomy of a Control File
A control file within a profile contains
• Some boilerplate information and a title
• One or more describe statements, each
containing one or more tests
• describe statements may be grouped
within control statements
• control statements may include extra
metadata defining for example
o a unique ID for this control
o the criticality, if this control fails.
o a human-readable title and
description
o reference documentation
# encoding: utf-8
# copyright: 2018, The Authors
title 'sample section'
describe file('/tmp') do
it { should be_directory }
end
control 'tmp-1.0' do
tag 'tmp',
tag dir: '/tmp'
ref 'NSA-RH6 - Section 3.5.2.1'
impact 0.7
title 'Create /tmp directory'
desc 'An optional description...'
describe file('/tmp') do
it { should be_directory }
end
end
114. Impact
➢ Impact is a measure of the importance of the compliance results
➢ The value ranges are:
○ 0.0 to <0.4 - these are controls with minor criticality
○ 0.4 to <0.7 - these are controls with major criticality
○ 0.7 to 1.0 - these are critical controls
➢ The impact value is configurable for each control
115. Chef InSpec Code Metadata
➢ Chef InSpec 'describe' statements abstract out the test implementation detail
➢ Compliance code contains further metadata pertaining to the compliance rule
Compliance DSL includes additional metadata around 'describe' statementsScripting Tools are platform specific
InSpec within a cookbook
116. Task: Update the profile's version number to 0.2.0
TASK
$ vi ~/profiles/webnode_profile/inspec.yml
name: webnode_profile
title: InSpec Profile
maintainer: The Authors
copyright: The Authors
copyright_email: you@example.com
license: Apache-2.0
summary: An InSpec Compliance Profile
version: 0.2.0
117. Task: Run 'inspec check' to check if profile is syntactically
correct
TASK
$ inspec check ~/profiles/webnode_profile
Location: /home/chef/profiles/webnode_profile
Profile: webnode_profile
Controls: 3
Timestamp: 2019-04-11T13:45:02+00:00
Valid: true
No errors or warnings
118. Problem: SSH v1 is Insecure
We need to ensure our web node is using SSH2 only and not SSH1,
as SSH1 has security vulnerabilities.
The tasks are
✓ Create a skeleton Chef InSpec profile for SSH
✓ Review the technical requirements and create the Chef InSpec
control including the actual test
3. Execute the Chef InSpec profile to determine current system state
4. Correct the state and rerun Chef InSpec check
119. Executing our code
We now need to execute our Chef InSpec profile
We will use inspec exec command to do this
120. Task: Run profile locally with Chef InSpec
command
TASK
$ inspec exec ~/profiles/webnode_profile
Profile: InSpec Profile (webnode_profile)
Version: 0.2.0
Target: local://
✔ tmp-1.0: Create /tmp directory
✔ File /tmp should be directory
× sshv2: Check SSH Version
× SSHD Configuration Protocol should cmp == 2
expected: 2
got: nil
(compared using `cmp` matcher)
File /tmp
✔ should be directory
Profile Summary: 1 successful control, 1 control failure, 0 controls skipped
Test Summary: 2 successful, 1 failure, 0 skipped
122. Why did our test fail?
# Protocol 2
It seems 'Protocol 2' line is commented out of our config file
Correcting it manually would not make sense, especially if you have
100's of nodes, so you would normally use Chef to configure this
But we'll just fix it manually for now
TASK
$ sudo grep 'Protocol' /etc/ssh/ssh_config
123. Problem: SSH v1 is Insecure
We need to ensure our web node is using SSH2 only and not SSH1,
as SSH1 has security vulnerabilities.
The tasks are
✓ Create a skeleton Chef InSpec profile for SSH
✓ Review the technical requirements and create the Chef InSpec
control including the actual test
✓ Execute the Chef InSpec profile to determine current system state
4. Correct the state and rerun Chef InSpec check
124. Task: Update the SSH Config File
...
# IdentityFile ~/.ssh/id_ecdsa
# IdentityFile ~/.ssh/id_ed25519
# Port 22
Protocol 2
# Cipher 3des
# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc
# MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
...
Manually update the SSH configuration file - uncomment the line to
enable SSH2 (line 42)
Usually this would be done by Chef
TASK
$ sudo vi /etc/ssh/ssh_config
125. Remember Test-Driven Development?
1. Write a test for your code
2. Execute the test and watch it fail
3. Write the code
4. Rerun the test and watch it pass
5. Repeat steps 1 through 4
126. Task: Again run profile locally with InSpec
command
Profile: InSpec Profile (webnode_profile)
Version: 0.2.0
Target: local://
✔ tmp-1.0: Create /tmp directory
✔ File /tmp should be directory
✔ sshv2: Check SSH Version
✔ SSH Configuration Protocol should cmp == 2
File /tmp
✔ should be directory
Profile Summary: 2 successful controls, 0 control failures, 0 controls skipped
Test Summary: 3 successful, 0 failures, 0 skipped
TASK
$ inspec exec ~/profiles/webnode_profile
127. Problem: SSH v1 is Insecure
We need to ensure our web node is using SSH2 only and not SSH1,
as SSH1 has security vulnerabilities.
The tasks are
✓ Create a skeleton Chef InSpec profile for SSH
✓ Review the technical requirements and create the Chef InSpec
control including the actual test
✓ Execute the Chef InSpec profile to determine current system state
✓ Correct the state and rerun Chef InSpec check
128. Executing specific controls files
➢ In some circumstances you may only wish to run those tests in a
specific control file in the profile
129. Task: Run just the controls in 'ssh.rb'
Profile: tests from profiles/webnode_profile/controls/ssh.rb (tests
from profiles.webnode_profile.controls.ssh.rb)
Version: (not specified)
Target: local://
✔ sshv2: Check SSH Version
✔ SSH Configuration Protocol should cmp == 2
Profile Summary: 1 successful control, 0 control failures, 0 controls
skipped
Test Summary: 1 successful, 0 failures, 0 skipped
TASK
$ inspec exec ~/profiles/webnode_profile/controls/ssh.rb
130. Executing specific controls
➢ In some circumstances you may wish to restrict the tests run to
specific controls within the profile
➢ In some circumstances you may only wish to run those tests in a
specific control file in the profile
● control tmp-1.0 in our example.rb control file
● control sshv2 in our ssh.rb controls file, and
control 'tmp-1.0' do
impact 0.7
title 'Create /tmp directory'
...
control 'sshv2' do
impact 0.7
title 'Check SSH Version'
...
131. Task: Use the --controls command line switch to run individual
controls
Profile: InSpec Profile (webnode_profile)
Version: 0.2.0
Target: local://
✔ tmp-1.0: Create /tmp directory
✔ File /tmp should be directory
Profile Summary: 1 successful controls, 0 control failures, 0 controls
skipped
Test Summary: 1 successful, 0 failures, 0 skipped
TASK
$ inspec exec ~/profiles/webnode_profile --controls tmp-1.0
132. Executing specific controls
➢ By default the inspec command returns results in human readable
format
➢ But you can use --reporter= flag to output in a number of other
formats, including
○ Documentation
○ Html
○ Progress
○ Json
○ Json-min
○ Json-rspec
○ Junit
○ cli (default)
➢ We'll look at a number of examples
136. Optional Task : Format the Output as JUnit
<?xml version='1.0'?>
<testsuites>
<testsuite name='webnode_profile' tests='1' failed='0'>
<testcase name='SSH Configuration Protocol should cmp == 2'
classname='webnode_profile.sshv2' time='0.000727831'/>
</testsuite>
</testsuites>
$ inspec exec ~/profiles/webnode_profile --reporter=junit
TASK
137. Takeaways
➢ A key primary Chef InSpec use case is for scanning machines for
regulatory compliance
➢ Used as such, Chef InSpec is used as a standalone tool (not within
Test Kitchen) and tests are maintained within Chef InSpec Profiles,
and executed using 'inspec exec' command
What’s next…?
In the next section we'll look at invoking Chef InSpec compliance
tests on remote hosts
141. Running Chef InSpec locally and remote
Up until now we’ve been running InSpec profiles on localhost
But the real power of InSpec is the ability to run it on remote targets
○ InSpec uses the appropriate transport mechanism to log into that target and
invoke the relevant command(s) — SSH or WinRM
○ Neither InSpec nor Ruby need to be installed on the remote target
142. Different ways to run Chef InSpec
Test your machine locally
> inspec exec profile .
Test a machine remotely via SSH
> inspec exec test.rb -i identify.key -t ssh://root@172.17.0.1 .
Test a machine remotely via WinRM
> inspec exec test.rb -t winrm://Admin@192.168.1.2 --password super .
Test a Docker container
> inspec exec test.rb -t docker://5cc8837bb6a8 .
We’ll run through a few examples
143. Pick the student
below you on the
spreadsheet!
TASK
https://bit.ly/student_ips
Find another Students Workstation IP
Address
144. Task: Execute control ‘sshv2’ from your profile on a remote
target
Note the ‘target’ is specified in the output
TASK
$ inspec exec ~/profiles/webnode_profile -t ssh://chef@<IP ADDRESS> --
password thepassword
Profile: InSpec Profile (webnode_profile)
Version: 0.2.0
Target: ssh://chef@52.90.72.1:22
✔ tmp-1.0: Create /tmp directory
✔ File /tmp should be directory
× sshv2: Check SSH Version
× SSH Configuration Protocol should cmp == 2
expected: 2
got:
(compared using `cmp` matcher)
File /tmp
✔ should be directory
Profile Summary: 1 successful control, 1 control failure, 0 controls skipped
Test Summary: 2 successful, 1 failure, 0 skipped
145. Task: Execute control ‘sshv2’ from your profile on a remote
target
This test may/not pass, depending on the target
selected, and if they completed the earlier lab.
TASK
$ inspec exec ~/profiles/webnode_profile -t ssh://chef@<IP ADDRESS> --
password thepassword --controls sshv2
Profile: InSpec Profile (webnode_profile)
Version: 0.2.0
Target: ssh://chef@52.90.72.1:22
× sshv2: Check SSH Version
× SSH Configuration Protocol should cmp == 2
expected: 2
got:
(compared using `cmp` matcher)
Profile Summary: 0 successful control, 1 control failure, 0 controls skipped
Test Summary: 2 successful, 1 failure, 0 skipped
146. Task: Determine the ID of your Docker container
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS
9d4fb40ed45e 177eec0ee5-default-centos-67:latest "sh -c 'trap exit 0 …" 3 hours ago Up 3 hours
We could run your InSpec profile against the Docker container created earlier by Test Kitchen
Run the command docker ps and copy the container ID.
If there is no container running, then first run kitchen converge from within the
cookbooks/mynginx directory$ cd ~/cookbooks/mynginx/
$ kitchen converge
Creating container 177eec0ee5-default-centos-67
Finished creating <default-centos-67> (0m0.55s).
-----> Kitchen is finished. (0m2.12s)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS
9d4fb40ed45e 177eec0ee5-default-centos-67:latest "sh -c 'trap exit 0 …" 3 hours ago Up 3 hours
$ cd ~
TASK
147. Task: Running InSpec on your Docker
container
TASK
$ inspec exec ~/profiles/webnode_profile/ -t docker://<CONTAINER ID> --
controls tmp-1.0
Profile: InSpec Profile (webnode_profile)
Version: 0.2.0
Target: ssh://chef@52.90.72.1:22
Target: docker://93c07bebf4a4a91c707ba3862c6297026b18a26833649c9bd7abcf940b3e4326
✔ tmp-1.0: Create /tmp directory
✔ File /tmp should be directory
Profile Summary: 1 successful controls, 0 control failure, 0 controls skipped
Test Summary: 1 successful, 0 failure, 0 skipped
148. Housekeeping:
Let’s copy our existing mynginx smoke test to within a control block in our profile
Task: Copy Chef InSpec test from mynginx cookbook into our
profile
TASK
$ cp ~/cookbooks/mynginx/test/smoke/default/default_test.rb
~/profiles/webnode_profile/controls/nginx.rb
149. Task: Tidy and format our nginx control file
1. Remove these placeholder
tests (these samples are
created automatically when
the cookbook is created)
1. Put the describe statement
into a control block called
mynginx-01
unless os.windows?
# This is an example test, replace with your own test.
describe user('root'), :skip do
it { should exist }
end
end
# This is an example test, replace it with your own test.
describe port(80), :skip do
it { should_not be_listening }
end
control 'mynginx-01' do
title 'Functional Tests'
desc 'Ensuring the web server is functioning correctly'
describe http('http://localhost', enable_remote_worker: true) do
its('status') { should cmp 200 }
its('body') { should cmp 'InSpec Jumpstart' }
its('headers.Content-Type') { should cmp 'text/html' }
end
end
TASK
$ vi ~/profiles/webnode_profile/controls/nginx.rb
150. Housekeeping:
Let’s remove the example.rb file that was stubbed, just to reduce output.
Task: Remove example.rb
TASK
$ rm ~/profiles/webnode_profile/controls/example.rb
151. Task: Running InSpec on your Docker
container
TASK
$ inspec exec ~/profiles/webnode_profile/ -t docker://<CONTAINER ID>
Profile: InSpec Profile (webnode_profile)
Version: 0.2.0
Target: docker://93c07bebf4a4a91c707ba3862c6297026b18a26833649c9bd7abcf940b3e4326
↺ sshv2: Check SSH Version
↺ Can't find file: /etc/ssh/ssh_config
✔ mynginx-01: http GET on http://localhost
✔ http GET on http://localhost status should cmp == 200
✔ http GET on http://localhost body should cmp == "InSpec Jumpstart"
✔ http GET on http://localhost headers.Content-Type should cmp == "text/html"
Profile Summary: 1 successful controls, 0 control failure, 1 controls skipped
Test Summary: 3 successful, 0 failure, 1 skipped
152. Task: Run ‘inspec detect’ to see OS details
== Operating System Details
Name: centos
Family: redhat
Release: 7.4.1708
Arch: x86_64
Before we run inspec exec, we can run inspec detect to get OS information.
This can help you identify what profiles should be executed on a remote target.
TASK
$ inspec detect -t ssh://chef@<IP ADDRESS> --password thepassword
153. Task: Run ‘inspec detect’ on Docker container
== Operating System Details
Name: centos
Family: redhat
Release: 7.4.1708
Arch: x86_64
--target= EQUALS -t
TASK
$ inspec detect --target=docker://<containerID>
154. Takeaways
➢ Chef InSpec uses SSH or WinRM to log onto a target and invoke
relevant command(s) to invoke the Chef InSpec code
➢ Neither Chef InSpec or Ruby need to be installed on the remote
target
What’s next…?
In the next section we’ll look at the InSpec DSL in a little more
detail, and see how we can use some more advanced Chef InSpec
constructs and Ruby in our profiles