Jumpstart your education on learning Chef InSpec to turn your DevOps into DevSecOps, by automating your integration testing and compliance/security scanning.
3. Objectives
➢ After completing this lesson you will be able to:
➢ Describe and invoke the Chef InSpec Shell
➢ Explain and use ‘describe.one’ and ‘only_if’ directives
➢ Abstract hardcoded data into a YAML file and iterate over it within a
control file
4. Chef InSpec Advanced Constructs & Tools
➢ Chef InSpec is based on Ruby, so we can utilize the full power of
Ruby in our control files.
➢ There are also a number of built in features to simplify tests, and
avoid repetition to make the profiles ‘DRY’.
➢ Chef InSpec comes with its own REPL (Read-Eval-Print-Loop)
interactive shell, which can be a powerful troubleshooting tool.
➢ First we will use Chef InSpec Shell to determine the state of our
Docker container running Nginx, that we created earlier.
5. 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 ran this step in the last section; if you did not retain the container ID, run the commands again.
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
6. Task: Open an inspec shell session in our container
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
1. You are currently running on:
Name: centos
Families: redhat, linux, unix, os
Release: 6.7
Arch: x86_64
inspec>
You can use the command inspec shell to open a REPL session on the local machine, but
here we are opening a session within our ‘remote’ container.
We can then use the InSpec language to view the status of the machine and the CLI.
TASK
$ inspec shell -t docker://<CONTAINER ID>
7. Task: Exploring inspec shell
...
- mysql_session
- nginx
- nginx_conf
- npm
- ntp_conf
- oneget
- oracledb_session
- os
- os_env
- package
...
You can see that InSpec has built-in resources specifically for Nginx.
Of course, you can see all these in http://www.inspec.io/docs/, but we’re just exploring
inspec shell here.
TASK
inspec> help resources
8. Task: Exploring nginx resource methods
...
:version,
:prefix,
:bin_dir,
:params,
:modules,
:service,
:openssl_version,
:compiler_info,
:support_info,
...
InSpec is a Ruby DSL, and as such, matchers are implemented as Ruby methods.
So, you use the syntax resource.methods within the shell to get a list of the matchers
for a particular resource.
TASK
inspec> nginx.methods
9. Task: Using inspec shell to determine Nginx modules
installed
=> ["http_addition",
"http_auth_request",
"http_dav",
"http_flv",
"http_gunzip",
"http_gzip_static",
...
So you can see we can get the information on Nginx using the nginx resource. Now lets
put this into an InSpec control document by way of an example.
NOTE: Type ‘exit’ to quit InSpec shell.
inspec> nginx.version
=> "1.12.2"=> "1.16.0"
TASK
inspec> nginx.modules
10. Problem Statement
We need to ensure:
➢ The version of Nginx running in our container is greater than 1.10.2
➢ Nginx has the following modules installed:
○ http_ssl
○ stream_ssl
○ mail_ssl
➢ Nginx should have module nginx-http-sysguard installed ONLY if it is
running on Debian
➢ Nginx should have EITHER of these modules installed
○ nginx-auth-ldap
○ http_auth_request
11. Checking for version
➢ The first requirement is to check if the version of Nginx installed is correct.
➢ We can implement this using the version matcher and the cmp comparator.
12. Task: Open the control file nginx.rb in your profile for editing
…
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 'Hello ChefConf' }
its('headers.Content-Type') { should cmp 'text/html' }
end
end
control 'mynginx-02' do
title 'Nginx Version'
desc 'Checking Nginx Version'
describe nginx do
its('version') { should cmp >= '1.10.2' }
end
end
TASK
cheat sheet
https://bit.ly/control-nginx-02
$ vi ~/profiles/webnode_profile/controls/nginx.rb
13. Task: Running InSpec on your Docker container
Profile: InSpec Profile (profiles/webnode_profile)
Version: 0.1.0
Target: docker://c280c4cfdcc3d32c4edd0e9a122179e07c59aafad1fa81ee24c29657987eac48
↺ sshv2: Check SSH Version
↺ Can't find file: /etc/ssh/ssh_config
✔ mynginx-01: http GET on http://localhost status should cmp == 200; http ...
✔ http GET on http://localhost status should cmp == 200
✔ http GET on http://localhost body should cmp == "Hello ChefConf"
✔ http GET on http://localhost headers.Content-Type should cmp == "text/html"
✔ mynginx-02: Nginx Environment version should cmp >= "1.10.2"
✔ Nginx Environment version should cmp >= "1.10.2"
Profile Summary: 2 successful controls, 0 control failures, 1 controls skipped
Test Summary: 4 successful, 0 failures, 1 skipped
TASK
$ inspec exec ~/profiles/webnode_profile/ -t docker://<CONTAINER ID>
14. Problem Statement
We need to ensure:
✓ The version of Nginx running in our container is greater than 1.10.2
➢ Nginx has the following modules installed:
○ http_ssl
○ stream_ssl
○ mail_ssl
➢ Nginx should have module nginx-http-sysguard installed ONLY if it is
running on Debian
➢ Nginx should have EITHER of these modules installed
○ nginx-auth-ldap
○ http_auth_request
15. Checking for modules
➢ The second requirement is to check if these modules are installed.
○ http_ssl
○ stream_ssl
○ mail_ssl
➢ We can implement this using the modules matcher.
16. Task: Add tests for modules installed
…
control 'mynginx-03' do
title 'Mandatory modules'
desc 'Checking mandatory modules'
describe nginx do
its('modules') { should include 'http_ssl' }
its('modules') { should include 'stream_ssl' }
its('modules') { should include 'mail_ssl' }
end
end
TASK
cheat sheet
https://bit.ly/control-nginx-02
$ vi ~/profiles/webnode_profile/controls/nginx.rb
17. Task: Run InSpec again
Profile: InSpec Profile (profiles/webnode_profile)
Version: 0.1.0
Target: docker://c280c4cfdcc3d32c4edd0e9a122179e07c59aafad1fa81ee24c29657987eac48
↺ sshv2: Check SSH Version
↺ Can't find file: /etc/ssh/ssh_config
✔ mynginx-01: http GET on http://localhost status should cmp == 200; http ...
✔ http GET on http://localhost status should cmp == 200
✔ http GET on http://localhost body should cmp == "Hello ChefConf"
✔ http GET on http://localhost headers.Content-Type should cmp == "text/html"
✔ mynginx-02: Nginx Environment version should cmp >= "1.10.2"
✔ Nginx Environment version should cmp >= "1.10.2"
✔ mynginx-03: Nginx Environment modules should include "http_ssl"; Nginx E...
✔ Nginx Environment modules should include "http_ssl"
✔ Nginx Environment modules should include "stream_ssl"
✔ Nginx Environment modules should include "mail_ssl"
Profile Summary: 3 successful controls, 0 control failures, 1 controls skipped
Test Summary: 7 successful, 0 failures, 1 skipped
TASK
$ inspec exec ~/profiles/webnode_profile/ -t docker://<CONTAINER ID>
18. Problem Statement
We need to ensure:
✓ The version of Nginx running in our container is greater than 1.10.2
✓ Nginx has the following modules installed:
○ http_ssl
○ stream_ssl
○ mail_ssl
➢ Nginx should have module nginx-http-sysguard installed ONLY if it is
running on Debian
➢ Nginx should have EITHER of these modules installed
○ nginx-auth-ldap
○ http_auth_request
19. Checking for modules
➢ The third requirement is Nginx should have module nginx-http-sysguard
installed, but ONLY if its running on Debian.
➢ We can implement this using the modules matcher along with the only_if
directive.
20. Task: Add the test for nginx-http-sysguard if Debian
…
control 'mynginx-04' do
title 'nginx-http-sysguard check'
desc 'Checking for nginx-http-sysguard '
describe nginx do
its('modules') { should include 'nginx-http-sysguard ' }
end
only_if { os.debian? }
end
TASK
cheat sheet
https://bit.ly/control-nginx-02
$ vi ~/profiles/webnode_profile/controls/nginx.rb
21. Task: Test new code
...
✔ mynginx-01: http GET on http://localhost status should cmp == 200; http ...
✔ http GET on http://localhost status should cmp == 200
✔ http GET on http://localhost body should cmp == "Hello ChefConf"
✔ http GET on http://localhost headers.Content-Type should cmp == "text/html"
✔ mynginx-02: Nginx Environment version should cmp >= "1.10.2"
✔ Nginx Environment version should cmp >= "1.10.2"
✔ mynginx-03: Nginx Environment modules should include "http_ssl"; Nginx E...
✔ Nginx Environment modules should include "http_ssl"
✔ Nginx Environment modules should include "stream_ssl"
✔ Nginx Environment modules should include "mail_ssl"
↺ mynginx-04: Operating System Detection
↺ Skipped control due to only_if condition.
Profile Summary: 3 successful controls, 0 control failures, 2 control skipped
Test Summary: 7 successful, 0 failures, 2 skipped
We see our control has been skipped, as its running a RHEL container.
TASK
$ inspec exec ~/profiles/webnode_profile/ -t docker://<CONTAINER ID>
22. Problem Statement
We need to ensure:
✓ The version of Nginx running in our container is greater than 1.10.2
✓ Nginx has the following modules installed:
○ http_ssl
○ stream_ssl
○ mail_ssl
✓ Nginx should have module nginx-http-sysguard installed ONLY if it is
running on Debian
➢ Nginx should have EITHER of these modules installed
○ nginx-auth-ldap
○ http_auth_request
23. Checking for modules
➢ The fourth requirement states Nginx should have EITHER of these modules
installed:
○ nginx-auth-ldap
○ http_auth_request
➢ Chef InSpec provides a describe.one directive to check if at least one of a
collection of checks is TRUE.
24. Task: Add the test for an ‘auth’ module
…
control 'mynginx-05' do
title 'Auth module'
desc 'Checking for an auth module'
describe.one do
describe nginx do
its('modules') { should include 'http_auth_request' }
end
describe nginx do
its('modules') { should include 'nginx-auth-ldap' }
end
end
end
If either of these conditions
pass, then the control passes
TASK
cheat sheet
https://bit.ly/control-nginx-02
$ vi ~/profiles/webnode_profile/controls/nginx.rb
25. Task: Test new code
...
✔ mynginx-01: http GET on http://localhost status should cmp == 200; http ...
✔ http GET on http://localhost status should cmp == 200
✔ http GET on http://localhost body should cmp == "Hello ChefConf"
✔ http GET on http://localhost headers.Content-Type should cmp == "text/html"
✔ mynginx-02: Nginx Environment version should cmp >= "1.10.3"
✔ Nginx Environment version should cmp >= "1.10.3"
✔ mynginx-03: Nginx Environment modules should include "http_ssl"; Nginx E...
✔ Nginx Environment modules should include "http_ssl"
✔ Nginx Environment modules should include "stream_ssl"
✔ Nginx Environment modules should include "mail_ssl"
↺ mynginx-04: Operating System Detection
↺ Skipped control due to only_if condition.
✔ mynginx-05: Nginx Environment modules should include "http_auth_request"
✔ Nginx Environment modules should include "http_auth_request"
Profile Summary: 4 successful controls, 0 control failures, 2 control skipped
Test Summary: 8 successful, 0 failures, 2 skipped
The module http_auth_request exists so we see the control passes.
TASK
$ inspec exec ~/profiles/webnode_profile/ -t docker://<CONTAINER ID>
26. Problem Statement
We need to ensure:
✓ The version of Nginx running in our container is greater than 1.10.2
✓ Nginx has the following modules installed:
○ http_ssl
○ stream_ssl
○ mail_ssl
✓ Nginx should have module nginx-http-sysguard installed ONLY if it is
running on Debian
✓ Nginx should have EITHER of these modules installed
○ nginx-auth-ldap
○ http_auth_request
27. Refactoring our Profile
➢ We have solved our problem statement, but the control file isn’t ideal
○ It is quite repetitive
○ It may become high maintenance, especially if there are many Nginx
modules
○ If we remove or add a new module we’d have to edit our code
➢ In general you should not use hard coded values in controls
○ Ideally the control files should contain logic, and the data held elsewhere
➢ It would be nice if we could maintain a list of such modules and version
numbers separately in a data file, and read it into a control
28. Problem Statement
➢ We need to refactor our control file to remove hardcoded values
and make it DRY.
29. Task: Create a files directory in your profile
TASK
$ mkdir -p ~/profiles/webnode_profile/files
30. Task: Create a data file for our profile
nginx_version: 1.10.3
mandatory_modules:
- http_ssl
- stream_ssl
- mail_ssl
auth_modules:
- http_auth_request
- nginx-auth-ldap
debian_modules:
- nginx-http-sysguard
TASK
cheat sheet
https://bit.ly/files-conf
$ vi ~/profiles/webnode_profile/files/conf.yml
31. Task: Refactor Control to read in conf.yml file
# # encoding: utf-8
# Inspec test for recipe mynginx::default
# The Inspec reference, with examples and extensive documentation, can be
# found at http://inspec.io/docs/reference/resources/
myconf = yaml(content: inspec.profile.file('conf.yml')).params
...
We load the contents of datafile conf.yml into a variable called myconf
TASK
$ vi ~/profiles/webnode_profile/controls/nginx.rb
32. Task: Refactor Control mynginx-02 and mynginx-03
…
control 'mynginx-02' do
title 'Nginx Version'
desc 'Checking Nginx Version'
describe nginx do
its('version') { should cmp >= myconf['nginx_version'] }
end
end
control 'mynginx-03' do
title 'Mandatory modules'
desc 'Checking mandatory modules'
describe nginx do
myconf['mandatory_modules'].each do |mod|
its('modules') { should include mod }
end
end
end
...
.
We use the variable myconf in our
describe statement
Iterate over the installed_modules
array within myconf in our describe
statement and execute the test on each
value
TASK
$ vi ~/profiles/webnode_profile/controls/nginx.rb
33. Task: Refactor Control mynginx-04
…
control 'mynginx-04' do
title 'nginx-http-sysguard check'
desc 'Checking for nginx-http-sysguard '
describe nginx do
myconf['debian_modules'].each do |mod|
its('modules') { should include mod }
end
end
only_if { os.debian? }
end
In mynginx-04 we want multiple tests
within a single describe statement,
so .each statement surrounds the
its statement
TASK
$ vi ~/profiles/webnode_profile/controls/nginx.rb
34. Task: Refactor Control mynginx-05
…
control 'mynginx-05' do
title 'Auth module'
desc 'Checking for an auth module'
describe.one do
myconf['auth_modules'].each do |mod|
describe nginx do
its('modules') { should include mod }
end
end
end
end
In mynginx-05 we want one
describe statement for each value of
myconf['auth_modules'] so
.each statement surrounds the
describe statement
TASK
Cheat Sheet
https://bit.ly/refactor-nginx
$ vi ~/profiles/webnode_profile/controls/nginx.rb
35. Task: Run the newly factored InSpec profile on your Docker
container
...
✔ mynginx-01: http GET on http://localhost status should cmp == 200; http ...
✔ http GET on http://localhost status should cmp == 200
✔ http GET on http://localhost body should cmp == "Hello ChefConf"
✔ http GET on http://localhost headers.Content-Type should cmp == "text/html"
✔ mynginx-02: Nginx Environment version should cmp >= "1.10.3"
✔ Nginx Environment version should cmp >= "1.10.3"
✔ mynginx-03: Nginx Environment modules should include "http_ssl"; Nginx E...
✔ Nginx Environment modules should include "http_ssl"
✔ Nginx Environment modules should include "stream_ssl"
✔ Nginx Environment modules should include "mail_ssl"
↺ mynginx-04: Operating System Detection
↺ Skipped control due to only_if condition.
✔ mynginx-05: Nginx Environment modules should include "http_auth_request"
✔ Nginx Environment modules should include "http_auth_request"
Profile Summary: 4 successful controls, 0 control failures, 1 control skipped
Test Summary: 8 successful, 0 failures, 1 skipped
Result is the same as before, but the code is more succinct with no hardcoding.
TASK
$ inspec exec ~/profiles/webnode_profile/ -t docker://<CONTAINER ID>
36. Chef InSpec and Ruby
➢ You can also use other Ruby constructs within and outside a
control
○ For example, when the OS is not Windows, a user named root should
exist.
unless os.windows?
describe user('root') do
it { should exist }
end
end
37. Problem Statement
✓ We need to refactor our control file to remove hardcoded values
and make it DRY.
38. Wow, that was a lot of info...
✓ Let’s recap and let this settle in...
39. Key takeaways
Chef InSpec DSL can use some more advanced Chef InSpec
constructs and Ruby in profiles, and has some built-in resources for
advanced testing (describe.one, only_if, etc.)
What’s next…?
In the next section we’ll look at how we can use Chef InSpec to test our
cloud infrastructure.
40.
41. Chef InSpec & Cloud
Infrastructure
Using Chef InSpec against Azure and AWS
42. Objectives
➢ After completing this lesson you will be able to
○ Set up and use inSpec to run tests against your cloud infrastructure
43. Cloud Infrastructure Support
➢ Chef InSpec supports auditing of your cloud AWS and/or Azure Infrastructure
➢ Chef InSpec needs ‘programmatic’ access your accounts
○ For example in AWS you need to create a user with IAM Profile named ‘ReadOnlyAccess’
➢ We will go through an example for AWS - Azure is similar
➢ Earlier in the class we used some content from S3 for our Nginx application
➢ Let’s check if that S3 content is available, and also ensure an EC2 instance is
running
remote_file '/usr/share/nginx/html/index.html' do
source 'https://s3.amazonaws.com/inspec-jumpstart/web01.html'
end
44. Problem Statement
We need to ensure that
➢ An EC2 instance with a specific intance_id value is running
➢ This file web01.html in the S3 bucket inspec-jumpstart exists and is
publicly readable
The tasks are
➢ Configure workstation to access AWS
➢ Create a skeleton Chef InSpec profile called ‘myaws’ containing a
control file called ‘aws.rb’
➢ Review the technical requirements and create a separate control for the
EC2 instance check and the S3 bucket check containing the actual test
➢ Execute the Chef InSpec profile to determine current system state
45. Problem Statement
Tips:
○ Use the docs at inspec.io to formulate the correct Chef InSpec controls
○ You can get the instance_id of another node from someone in the class
from this spreadsheet: https://bit.ly/student_ips
○ You can use ‘ohaiec2/instance_id’ on your workstation to get your own
instance_id
46. TASK
Your instructor will give you temporary keys to use
$ mkdir -p ~/.aws
$ touch ~/.aws/credentials
Task: Create AWS Credentials File
50. Problem Statement
We need to ensure that
➢ An EC2 instance with a specific intance_id value is running
➢ This file web01.html in the S3 bucket inspec-jumpstart exists and is
publicly readable
The tasks are
✓ Configure workstation to access AWS
✓ Create a skeleton Chef InSpec profile called ‘myaws’ containing a
control file called ‘aws.rb’
➢ Review the technical requirements and create a separate control for the
EC2 instance check and the S3 bucket check containing the actual test
➢ Execute the Chef InSpec profile to determine current system state
51. What Resources Shall We Use?
We will use in the Inspec
Resources:
○ aws_ec2_instance
○ aws_s3_bucket_object
52. TASK
[2018-04-18T13:16:48+00:00] INFO: The plugin path /etc/chef/ohai/plugins does not exist. Skipping...
[
"i-0233633e0c7c66111
"
]
We’re just using Ohai to get the instance_id, as we don’t have access to the AWS UI
$ ohai ec2/instance_id
Task: Get your workstation’s instance_id
53. TASK
control 'myaws-01' do
title 'AWS Verification'
desc 'Testing AWS'
describe aws_ec2_instance('i-0233633e0c7c66111') do
it { should exist }
it { should be_running}
end
describe aws_s3_bucket_object(bucket_name: 'inspec-jumpstart-2019', key: 'web01.html') do
it { should exist }
it { should be_public }
end
end
cheat sheet
https://bit.ly/control-aws
$ vi ~/profiles/myaws/controls/aws.rb
Task: Create Control File aws.rb and add
Controls
54. Problem Statement
We need to ensure that
✓ An EC2 instance with a specific intance_id value is running
✓ This file web01.html in the S3 bucket inspec-jumpstart exists and is
publicly readable
The tasks are
✓ Configure workstation to access AWS
✓ Create a skeleton Chef InSpec profile called ‘myaws’ containing a
control file called ‘aws.rb’
✓ Review the technical requirements and create a separate control for the
EC2 instance check and the S3 bucket check containing the actual test
➢ Execute the Chef InSpec profile to determine current system state
55. TASK
Profile: tests from /home/chef/profiles/myaws/controls/aws.rb (tests from
.home.chef.profiles.myaws.controls.aws.rb)
Version: (not specified)
Target: aws://us-east-1
✔ myaws-01: AWS Verification
✔ EC2 Instance i-0262f0022bb004bc0 should exist
✔ EC2 Instance i-0262f0022bb004bc0 should be running
✔ s3://inspec-jumpstart/web01.html should exist
✔ s3://inspec-jumpstart/web01.html should be public
Profile Summary: 1 successful control, 0 control failures, 0 controls skipped
Test Summary: 4 successful, 0 failures, 0 skipped
$ inspec exec ~/profiles/myaws/controls/aws.rb -t aws://us-west-2/inspec
Task: Execute Your Profile
56. Problem Statement
We need to ensure that
✓ An EC2 instance with a specific intance_id value is running
✓ This file web01.html in the S3 bucket inspec-jumpstart exists and is
publicly readable
The tasks are
✓ Configure workstation to access AWS
✓ Create a skeleton Chef InSpec profile called ‘myaws’ containing a
control file called ‘aws.rb’
✓ Review the technical requirements and create a separate control for the
EC2 instance check and the S3 bucket check containing the actual test
✓ Execute the Chef InSpec profile to determine current system state
57. Key Takeaways
➢ Chef InSpec can not only be used to scan your servers, but has
custom resources to scan your AWS and Azure cloud infrastructure
What’s next…?
➢ In the next section we’ll look at how to access open source Chef
InSpec profiles
60. Objectives
➢ After completing this lesson you will be able to
○ Locate and utilize open source Chef InSpec profiles
○ Execute remote profiles on local hosts
○ Execute remote profiles on remote hosts
○ Use the ‘dependencies’ & ‘supports’ directives
○ Describe the inspeck.lock file
61. OSS Profiles
➢ Chef InSpec is open source, so there are number of community profiles
available
➢ Most are stored on GitHub, but you can access them via Chef Supermarket
○ In particular, there are a number of a public baseline profiles available at
http://github.com/dev-sec
63. TASK
== Available profiles
* apache2-compliance-test-tthompson thompsontelmate/apache2-compliance-test-tthompson
* Apache DISA STIG som3guy/apache-disa-stig
* chef-alfresco-inspec-mysql alfresco/chef-alfresco-inspec-mysql
* chef-alfresco-inspec-tomcat alfresco/chef-alfresco-inspec-tomcat
* chef-client-hardening sliim/chef-client-hardening
* CIS Distribution Independent Linux Benchmark dev-sec/cis-linux-benchmark
* CIS Docker Benchmark dev-sec/cis-docker-benchmark
* CIS Kubernetes Benchmark dev-sec/cis-kubernetes-benchmark
* CVE-2016-5195 ndobson/cve-2016-5195
* DevSec Apache Baseline dev-sec/apache-baseline
* DevSec Linux Baseline dev-sec/linux-baseline
* DevSec Linux Patch Baseline dev-sec/linux-patch-baseline
* DevSec MySQl Baseline dev-sec/mysql-baseline
* DevSec Nginx Baseline dev-sec/nginx-baseline
* DevSec PHP Baseline dev-sec/php-baseline
...
$ inspec supermarket profiles
Task: Let’s have a closer look at dev-sec/linux-baseline
profile
64. TASK
name: linux-baseline
owner: dev-sec
url: https://github.com/dev-sec/linux-baseline
description: Linux compliance profile, used for Security + DevOps. More information is available at http://dev-sec.io
$ inspec supermarket info dev-sec/linux-baseline
Task: View dev-sec/linux-baseline profile on Supermarket &
GitHub
65. Running OSS Profiles
➢ You can execute open source profiles directly from either
GitHub or Supermarket
➢ Let’s run through a few examples
66. TASK
...
× sysctl-30: Magic SysRq
× Kernel Parameter kernel.sysrq value should eq 0
expected: 0
got: 16
(compared using ==)
✔ sysctl-31a: Secure Core Dumps - dump settings
✔ Kernel Parameter fs.suid_dumpable value should cmp == /(0|2)/
↺ sysctl-31b: Secure Core Dumps - dump path
↺ Skipped control due to only_if condition.
✔ sysctl-32: kernel.randomize_va_space
✔ Kernel Parameter kernel.randomize_va_space value should eq 2
✔ sysctl-33: CPU No execution Flag or Kernel ExecShield
✔ /proc/cpuinfo Flags should include NX
Profile Summary: 26 successful controls, 27 control failures, 1 control skipped
Test Summary: 70 successful, 55 failures, 1 skipped
$ inspec supermarket exec dev-sec/linux-baseline
Task: You can Run dev-sec/linux-baseline profile locally from
Supermarket
67. TASK
...
× sysctl-30: Magic SysRq
× Kernel Parameter kernel.sysrq value should eq 0
expected: 0
got: 16
(compared using ==)
✔ sysctl-31a: Secure Core Dumps - dump settings
✔ Kernel Parameter fs.suid_dumpable value should cmp == /(0|2)/
↺ sysctl-31b: Secure Core Dumps - dump path
↺ Skipped control due to only_if condition.
✔ sysctl-32: kernel.randomize_va_space
✔ Kernel Parameter kernel.randomize_va_space value should eq 2
✔ sysctl-33: CPU No execution Flag or Kernel ExecShield
✔ /proc/cpuinfo Flags should include NX
Profile Summary: 26 successful controls, 27 control failures, 1 control skipped
Test Summary: 70 successful, 55 failures, 1 skipped
$ inspec exec https://github.com/dev-sec/linux-baseline
Task: You can Run dev-sec/linux-baseline profile locally from GitHub
68. Running OSS Profiles
➢ You can execute open source profiles directly from either
GitHub or Supermarket on remote machines
➢ Let’s run through a few examples
69. Pick the student
below you on the
spreadsheet!
TASK
https://bit.ly/student_ips
Find another Students Workstation IP
Address
70. TASK
...
× sysctl-30: Magic SysRq
× Kernel Parameter kernel.sysrq value should eq 0
expected: 0
got: 16
(compared using ==)
✔ sysctl-31a: Secure Core Dumps - dump settings
✔ Kernel Parameter fs.suid_dumpable value should cmp == /(0|2)/
↺ sysctl-31b: Secure Core Dumps - dump path
↺ Skipped control due to only_if condition.
✔ sysctl-32: kernel.randomize_va_space
✔ Kernel Parameter kernel.randomize_va_space value should eq 2
✔ sysctl-33: CPU No execution Flag or Kernel ExecShield
✔ /proc/cpuinfo Flags should include NX
Profile Summary: 26 successful controls, 27 control failures, 1 control skipped
Test Summary: 70 successful, 55 failures, 1 skipped
$ inspec supermarket exec dev-sec/linux-baseline --
target=ssh://chef@52.90.72.1 --password thepassword
Task: You can Run dev-sec/linux-baseline profile on a remote target from
Supermarket
71. TASK
...
× sysctl-30: Magic SysRq
× Kernel Parameter kernel.sysrq value should eq 0
expected: 0
got: 16
(compared using ==)
✔ sysctl-31a: Secure Core Dumps - dump settings
✔ Kernel Parameter fs.suid_dumpable value should cmp == /(0|2)/
↺ sysctl-31b: Secure Core Dumps - dump path
↺ Skipped control due to only_if condition.
✔ sysctl-32: kernel.randomize_va_space
✔ Kernel Parameter kernel.randomize_va_space value should eq 2
✔ sysctl-33: CPU No execution Flag or Kernel ExecShield
✔ /proc/cpuinfo Flags should include NX
Profile Summary: 26 successful controls, 27 control failures, 1 control skipped
Test Summary: 70 successful, 55 failures, 1 skipped
$ inspec exec https://github.com/dev-sec/linux-baseline
--target=ssh://chef@52.90.72.1 --password thepassword
Task: You can Run dev-sec/linux-baseline profile on a remote target from GitHub
72. Dependencies
➢ One profile can have an explicit dependency upon another, and
when the dependent profile is run, then some or all of the controls
from the dependency can be invoked
➢ A common use case for this is to use open source profiles along
side your own custom ones
➢ Let’s run through a few examples
73. TASK
• DevSec Nginx Baseline dev-sec/nginx-baseline
$ inspec supermarket info dev-sec/nginx-baseline
name: nginx-baseline
owner: dev-sec
url: https://github.com/dev-sec/nginx-baseline
description: NGINX compliance profile, used for Security + DevOps. More
information is available at http://dev-sec.io
So there is an OSS Nginx profile we can use
$ inspec supermarket profiles | grep -i nginx
Task: Locate an nginx profile on supermarket & find
details
74. Problem Statement
➢ We need to include controls nginx-01 and nginx-02 from the nginx-
baseline profile within our custom webnode_profile profile
➢ We need to reset the impact of nginx-02 to 0.6
76. TASK
---
lockfile_version: 1
depends : []
You will notice a new inspec.lock file has appeared in your profile.
When you execute a profile, the InSpec will source any profile dependencies and cache
them locally and generate an inspec.lock file.
If you add or update dependencies in inspec.yml. Dependencies may be re-vendored and
the lock file updated with the command inspec vendor --overwrite
$ cat ~/profiles/webnode_profile/inspec.lock
Task: First let’s look at the inspec.lock file
77. TASK
end
end
end
require_controls 'nginx-baseline' do
control 'nginx-01'
control 'nginx-02' do
impact 0.6
end
end
We use the require_controls to access controls from another profile
$ vi ~/profiles/webnode_profile/controls/nginx.rb
Task: Include some controls from OSS profile in our
profile
78. We will use the highlighted method
…
depends:
- name: profile_name
path: path/to/profile
- name: profile_name
url: https://github.com/repo/profile_name/archive/0.1.0.tar.gz
- name: profile_name
git: https://github.com/repo/profile_name
branch: master
tag:
version:
- name: profile_name
supermarket: origin/profile_name
- name: profile_name
Compliance: origin/profile_name
Profile Dependencies are defined in inspec.yml
79. TASK
…
license: Apache-2.0
summary: An InSpec Compliance Profile
version: 0.3.0
supports:
- os-family: redhat
depends:
- name: nginx-baseline
supermarket: dev-sec/nginx-baseline
Here we declare an explicit dependency between our webnode_profile
profile and the nginx-baseline profile
$ vi ~/profiles/webnode_profile/inspec.yml
Task: Update inspec.yml file to include a dependency on other
profile
81. TASK
[2018-04-18T09:12:51+00:00] WARN: URL target https://github.com/dev-sec/nginx-baseline transformed to
https://github.com/dev-sec/nginx-baseline/archive/master.tar.gz. Consider using the git fetcher
Dependencies for profile /home/chef/profiles/webnode_profile/ successfully vendored to
/home/chef/profiles/webnode_profile/vendor
$ inspec vendor ~/profiles/webnode_profile
Task: Vendor the profile
82. TASK
[2018-04-18T09:12:51+00:00] WARN: URL target https://github.com/dev-sec/nginx-baseline transformed to
https://github.com/dev-sec/nginx-baseline/archive/master.tar.gz. Consider using the git fetcher
Ignoring `enable_remote_worker` option, the `http` resource
remote worker is enabled by default for remote targets and
cannot be disabled
Location: /home/chef/profiles/webnode_profile
Profile: webnode_profile
Controls: 10
Timestamp: 2018-04-18T09:12:50+00:00
Valid: true
No errors or warnings
$ inspec check ~/profiles/webnode_profile
Task: Recheck the profile
83. TASK
…
✔ Nginx Environment modules should include "http_auth_request"
Profile: DevSec Nginx Baseline (nginx-baseline)
Version: 2.1.0
Target: docker://c280c4cfdcc3d32c4edd0e9a122179e07c59aafad1fa81ee24c29657987eac48
✔ nginx-01: Running worker process as non-privileged user
✔ User nginx should exist
✔ Parse Config File /etc/nginx/nginx.conf user should eq "nginx"
✔ Parse Config File /etc/nginx/nginx.conf group should not eq "root"
∅ nginx-02: Check NGINX config file owner, group and permissions. (1 failed)
✔ File /etc/nginx/nginx.conf should be owned by "root"
✔ File /etc/nginx/nginx.conf should be grouped into "root"
× File /etc/nginx/nginx.conf should not be readable by others
expected File /etc/nginx/nginx.conf not to be readable by others
✔ File /etc/nginx/nginx.conf should not be writable by others
✔ File /etc/nginx/nginx.conf should not be executable by others
Profile Summary: 5 successful controls, 1 control failure, 1 control skipped
Test Summary: 15 successful, 1 failure, 1 skipped
Note: You may need to do ‘docker ps’
to get your docker id.
$ inspec exec ~/profiles/webnode_profile/ -t docker://<containerID>
Task: Execute the profile
84. TASK
---
lockfile_version: 1
depends:
- name: nginx-baseline
resolved_source:
url: https://github.com/dev-sec/nginx-baseline/archive/master.tar.gz
sha256: f155c55124d259024a37134166d50045d5cfa853bf2e829e1d2a8e1846afb578
version_constraints: "[]"
You will notice the inspec.lock file has been updated with the new dependency
$ cat ~/profiles/webnode_profile/inspec.lock
Task: Look again at the inspec.lock file
85. Key Takeaways
➢ Chef InSpec is Open Source and many profiles are maintained by
the community. These OSS profiles may be used in whole or part
to scan your infrastructure.
What’s next…?
➢ In the next section we’ll look at how Chef InSpec feeds into
industry-specific compliance regulations
86.
87. Chef InSpec DSL & Compliance
Regulations
Chef InSpec DSL & CIS Profiles
88. Objectives
➢ After completing this lesson you will be able to:
○ Explain the importance of Chef InSpec with respect to industry-specific
compliance regulations
○ List compliance regulations and bodies and CIS profiles
○ Map specific compliance regulations to individual Chef InSpec profiles
and controls
○ Create a Chef InSpec profile for a given compliance regulation document
89. Chef InSpec takes Compliance to the next
level
Many industries are bound by regulations maintained by external bodies
○ Sarbanes Oxley
○ PCI
○ HIPPA
○ GDPR
○ STIG
○ etc
Many of these rules relate to technical requirements in their application
and infrastructure that they must comply with
90. Center for Internet Security
'Center for Internet Security' provides
benchmarks for secure configuration of many
platforms and applications
e.g. https://learn.cisecurity.org/benchmarks
Regulatory bodies can refer to these
guidelines for their rules
91. 5.2.2 Ensure SSH Protocol is set to 2
"SSH supports two different and incompatible
protocols: SSH1 and SSH2. SSH1 was the
original protocol and was subject to security
issues. SSH2 is more advanced and secure."
92. control 'ssh-5.2.2' do
impact 1.0
title 'Ensure SSH Protocol is set...'
desc "
SSH supports two different ...
"
describe sshd_config do
its('Protocol') { should cmp('2') }
end
end
Chef InSpec ControlCIS Requirement
Each control statement relates to a
specific compliance regulation.
Mapping Compliance Document to Chef InSpec
93. Mapping Compliance Document to InSpec
control 'ssh-5.2.2' do
impact 1.0
title 'Ensure SSH Protocol is
set...'
desc "
SSH supports two different ...
"
describe sshd_config do
its('Protocol') { should cmp('2')
}
end
end
94. Mapping Compliance Document to InSpec
control 'ssh-5.2.2' do
impact 1.0
title 'Ensure SSH Protocol is
set...'
desc "
SSH supports two different ...
"
describe sshd_config do
its('Protocol') { should cmp('2')
}
end
end
95. Mapping Compliance Document to InSpec
control 'ssh-5.2.2' do
impact 1.0
title 'Ensure SSH Protocol is
set...'
desc "
SSH supports two different ...
"
describe sshd_config do
its('Protocol') { should cmp('2')
}
end
end
96. Mapping Compliance Document to InSpec
control 'ssh-5.2.2' do
impact 1.0
title 'Ensure SSH Protocol is
set...'
desc "
SSH supports two different ...
"
describe sshd_config do
its('Protocol') { should cmp('2')
}
end
end
97. control 'ssh-5.2.2' do
impact 1.0
title 'Ensure SSH Protocol is
set...'
desc "
SSH supports two different ...
"
describe sshd_config do
its('Protocol') { should cmp('2')
}
end
end
Mapping Compliance Document to InSpec
CIS doc even gives details for
a remediation cookbook!
98. Takeaways
The format of the Chef InSpec DSL fits neatly with the documents
created by industry-specific compliance regulatory bodies
What’s next…?
In the next section we'll look at how Chef InSpec works along with Chef
Automate to automatically Detect and Correct your infrastructure
101. Objectives
➢ After completing this lesson you will be able to:
○ Login and navigate the Chef Automate UI
○ Upload a custom Chef InSpec profile to Chef Automate
○ Copy one of the “shipped” available compliance profiles to the Profiles tab
of the Chef Automate UI
○ Invoke a compliance scan via the Chef Automate UI and view the results
○ Remediate a compliance failure using Chef
102. What is Chef Automate?
➢ Chef Automate allows you to monitor and visualize node status and
convergence events from any servers or nodes that you are
managing
➢ Chef Automate enables you to directly run scans (i.e., execute
Chef InSpec profiles) to determine the compliance state of your
whole environment
➢ It also facilitates remediation on those nodes using Chef in a
prescribed workflow
➢ Let’s get started with Chef Automate
104. Task: Log in to your server
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
TASK
$ ssh chef@12.34.56.78
105. Task: Ensure you’re in the correct VM
Do this on the Chef Automate machine
TASK
$ touch firstname-lastname
$ ls -l
firstname-lastname cookbooks Berksfile profiles
nodes Berksfile.lock config.json
108. Task: Browse to the login screen
Browse to the url in automate-credentials.toml
TASK
…
url = "https://1.2.3.4"
username = "admin"
password = "some long string"
109. Task: Log In to Chef Automate
Login using credentials from automate-credentials.toml
TASK
…
url = "https://1.2.3.4"
username = "admin"
password = "some long string"
110. Task: Apply licensing
Fill in the form…
• If you’d like Chef to be in
touch, then real info…
• Else, fake info works too!
TASK
112. Task: View pre-baked Profiles
Click on the 149 available to display the pre-
baked profiles. You can also upload your
own. Any profiles in Chef Automate can be
used in manual or automated scans across
your environment
TASK
113. Problem Statement
➢ We need to run compliance scans across a number of targets using
the following profiles:
o one webnode_profile that we created in this class
o ‘CIS CentOS Linux 7 Benchmark Level 2’ Profile
➢ The tasks are
o Upload webnode_profile to Chef Automate
o Make the relevant CIS profile available for scans
o Add your workstation as a scan target
o Assign the profiles to the target
o Scan the target node and view results
114. Uploading profiles to compliance server
Our first task is to upload webnode_profile to Chef Automate
The Chef InSpec CLI includes REST API functionality that allows us to log
into a Chef Automate server via command line and upload files
The command to log into Chef Automate is:
inspec compliance login http://<URL> --insecure --user=’USER’ --
ent=’ENT’ --token=’TOKEN’
e..g.
inspec compliance login http://52.204.216.243 --insecure --
user=’admin’ --ent=’demo’ --token='7rI0l71oIpBW1JGmCiQkyo'
You’ll first need to retrieve a TOKEN before logging in
117. Task: Log into Chef Automate from
workstation
$ Stored configuration for Chef Automate: https://54.175.197.216/compliance'
with user: 'admin'
TOP TIP1: You might want to formulate the command string in a text editor before
pasting it to the command line
TOP TIP2: Use the url from automate-credentials.toml
TASK
$ inspec compliance login http://<URL> --insecure --user='admin' --
ent='Demo' --dctoken='<PASTE TOKEN VALUE>'
118. Task: Upload webnode profile to Compliance
server
TASK
Profile is already vendored. Use --overwrite.
I, [2018-04-13T12:51:17.132757 #4825] INFO -- : Checking profile in profiles/webnode_profile
I, [2018-04-13T12:51:17.133676 #4825] INFO -- : Metadata OK.
I, [2018-04-13T12:51:17.420101 #4825] INFO -- : Found 8 controls.
I, [2018-04-13T12:58:50.401191 #9099] INFO -- : Control definitions OK.
Profile is valid
Generate temporary profile archive at /tmp/webnode_profile20180413-4825-1fi5adr.tar.gz
I, [2018-04-13T12:51:17.430258 #4825] INFO -- : Generate archive
/tmp/webnode_profile20180413-4825-1fi5adr.tar.gz.
I, [2018-04-13T12:51:17.434434 #4825] INFO -- : Finished archive generation.
Start upload to admin/webnode_profile
Uploading to Chef Automate
Successfully uploaded profile
$ inspec compliance upload ~/profiles/webnode_profile
119. Task: Verify Profiles on the Automate Server
You can click on the profile to view the code
You’ll notice the profile is name-spaced with the
user who uploaded it - there are CRUD rules
around which the user can upload and use
which profiles
image has to be updated to
TASK
$ inspec compliance profiles
== Available profiles:
* InSpec Profile v0.3.0 (admin/webnode_profile)
120. Problem Statement
➢ We need to run compliance scans across a number of targets using
the following profiles:
o one webnode_profile that we created in this class
o ‘CIS CentOS Linux 7 Benchmark Level 2’ Profile
➢ The tasks are
✓ Upload webnode_profile to Chef Automate
o Make the relevant CIS profile available for scans
o Add your workstation as a scan target
o Assign the profiles to the target
o Scan the target node and view results
121. Task: Copy profile into your workspace
1
2
4
Start entering the desired Profile or scroll to locate1
2
3
CLICK
TASK
122. The 2 required profiles should now be available for use
Available profiles
123. Task: Verify profiles on the Automate server
TASK
$ inspec compliance profiles
== Available profiles:
* CIS CentOS Linux 7 Benchmark Level 2 v1.1.0-3 (admin/cis-centos7-level2)
* InSpec Profile v0.3.0 (admin/webnode_profile)
124. Problem Statement
➢ We need to run compliance scans across a number of targets using
the following profiles:
o one webnode_profile that we created in this class
o ‘CIS CentOS Linux 7 Benchmark Level 2’ Profile
➢ The tasks are
✓ Upload webnode_profile to Chef Automate
✓ Make the relevant CIS profile available for scans
o Add your workstation as a scan target
o Assign the profiles to the target
o Scan the target node and view results
125. • You’ll notice that this Chef Automate server does not have any
nodes associated with it yet
• There are a number of ways nodes can be added, but we’ll add
our node manually
• Before we can add a node we must define login credentials to
assign to it
Adding target nodes
130. Task: Step 2-Add a new target node
1
2 Click on
3 Click on
Enter fields on left and click
TASK
1
2
3
4
5
131. Task: Verify the node is reachable
1
2 Click on
3 Click on
Enter fields on left and click
TASK
132. • Now that we have a target node on the system, and profiles in our
workspace, we can create a scan job
• A scan job associates one or more target nodes with one or more
profiles
• A job can then be invoked manually or on a schedule
Creating a scan job
133. Task: Create a new scan job (1)
1
2 Click on
3 Click on
Enter fields on left and click
1
2
TASK
1
2
134. Task: Create a new scan job (2)
1
2 Click on
3 Click on
Enter fields on left and click
1
2
1
Click on
2
Click on
TASK
1
2
135. Task: Create a new scan job (3)
1
2 Click on
3 Click on
Enter fields on left and click
1
2
1
Click on
2
Click on
1
Select Profiles for Scan
2
TASK
1
2
136. Task: Create a new scan job (3)
1
2 Click on
3 Click on
Enter fields on left and click
1
2
1
Click on
2
Click on
1
Select Profiles for Scan
2
1
Name the job
2
click
save
1
2
TASK
137. Task: Running a new scan job
1
2 Click on
3 Click on
Enter fields on left and click
1
2
1
Click on
2
Click on
1
Select Profiles for Scan
2
1
Name the job
2
click
save
TASK
138. Task: Viewing the results of the scan job(1)
1
2 Click on
3 Click on
Enter fields on left and click
1
2
1
Click on
2
Click on
1
Select Profiles for Scan
2
1
Name the job
2
click
save
1
TASK
139. Task: Viewing the results of the scan job(2)
1
2 Click on
3 Click on
Enter fields on left and click
1
2
1
Click on
2
Click on
1
Select Profiles for Scan
2
1
Name the job
2
click
save
TASK
140. Review
➢ We need to run compliance scans across a number of targets using
the following profiles:
○ one webnode_profile that we created in this class
○ ‘CIS CentOS Linux 7 Benchmark Level 2’ Profile
➢ The tasks are
✓ Upload webnode_profile to Chef Automate
✓ Make the relevant CIS profile available for scans
✓ Add your workstation as a scan target
✓ Assign the profiles to the target
✓ Scan the target node and view results
141. Problem Statement
➢ Our webnode_profile is failing. We need to fix the node to make it
pass
➢ The tasks are
o Run the recipe - recipe[mynginx::default] on the node
o Re-scan the target node with webnode_profile profile and view results
142. Detect and Correct
➢ Chef Automate not only allows you to invoke compliance scans across
your estate but it also facilitates remediation
➢ Chef will be building out remediation cookbooks for all Chef InSpec
profiles on Chef Automate
➢ For simplicity now, and since we have no Chef Server configured, we will
run the remediation cookbook for our webnode Chef InSpec profile (i.e.,
our custom mynginx cookbook) on the node in local mode
144. • We need to install some dependencies from our mynginx cookbook
• Here we are pulling the mynginx cookbook and its dependencies into a
new cookbooks directory
• This is just some Chef housekeeping - we can explain late if we have
time available
Task: Install mynginx cookbook
dependencies
TASK
$ cd ~/cookbooks/mynginx/
$ berks vendor ../../vendor/cookbooks
[output truncated]
$ cd ../../vendor/
145. Task: Execute recipe 'mynginx' on
workstation
$ sudo chef-client -zr 'recipe[mynginx]'
TASK
...
-<p><em>Thank you for using nginx.</em></p>
-</body>
-</html>
+InSpec Jumpstart
- restore selinux security context
* service[nginx] action enable
- enable service service[nginx]
* service[nginx] action start
- start service service[nginx]
Running handlers:
Running handlers complete
Chef Client finished, 9/12 resources updated in 09 seconds
146. Problem Statement
➢ Our webnode_profile is failing. We need to fix the node to make it
pass
➢ The tasks are
✓ Run the recipe - recipe[mynginx::default] on the node
o Re-scan the target node with webnode_profile profile and view results
147. Task: Create a new scan job
● Click the
Compliance tab at
the top then the
Scanner tab on the
left
● Click Create new job
● For this scan just
select InSpec Profile
v0.3.0
● Click Create job
TASK
148. Task: View results for InSpec Profile v0.3.0
● Click the Scanner tab on the
left
● Click Report next to the
most recent scan
● You will see that the node is
now compliant with respect
to your webnode_profile
Profile
TASK
149. Review
➢ Our webnode_profile is failing. We need to fix the node to make it
pass
➢ The tasks are
✓ Run the recipe - recipe[mynginx::default] on the node
✓ Re-scan the target node with webnode_profile profile and view results
150. The Audit Cookbook
• As we’ve seen, Chef Automate proactively scans hosts, either
manually or on a scheduled basis
• Alternatively, the Chef ‘Audit Cookbook’ can be used to run scans at
the end of a chef-client run, and report the results back to Chef
Automate
151. Remediation Cookbooks
• Chef Automate comes pre-loaded with a number of Chef InSpec
profiles for many applications and multiple platforms
• Chef will also be building out corresponding remediation cookbooks to
solidify these patterns and applications
152. Key Takeaways
• Chef InSpec works along with Chef Automate to automatically
Detect and Correct your entire infrastructure, run reports, schedule
scans, etc.
• As a Chef Automate customer you get access to proprietary Chef
InSpec profiles helping you to become compliant with respect to
PCI, HIPAA, SOX, GDPR, etc
● Save your work! Make a github repo or copy it somewhere for
later!
● In the next section we’ll look at how to access from further
resources as you continue on your path with Chef InSpec
What’s Next?
154. Resources to Continue What You’ve Started
• Chef Workstation - includes Chef InSpec, Test Kitchen, etc.
https://downloads.chef.io/chef-workstation/
• Chef InSpec Website, includes tutorials and docks -
https://www.chef.io/products/chef-inspec/
• Chef Automate docs with 30-day demo license
https://automate.chef.io/docs/install/
• #inspec channel of the Chef Community Slack - http://community-
slack.chef.io/
• Open Source Project - https://github.com/chef/inspec