Add regular page content and images

Signed-off-by: IanMadd <imaddaus@chef.io>
This commit is contained in:
IanMadd 2020-07-07 17:44:59 -07:00
parent c93a515c6f
commit ab17f16b0a
25 changed files with 4693 additions and 0 deletions

View file

@ -0,0 +1,55 @@
+++
title = "An Overview of Chef InSpec"
draft = false
[menu]
[menu.inspec]
title = "Chef InSpec Overview"
identifier = "inspec/_index.md Chef InSpec Overview"
parent = "inspec"
weight = 10
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/_index.md)
Chef InSpec is an open-source framework for testing and auditing your applications and infrastructure. Chef InSpec works by comparing the actual state of your system with the desired state that you express in easy-to-read and easy-to-write Chef InSpec code. Chef InSpec detects violations and displays findings in the form of a report, but puts you in control of remediation.
{{< note >}}
Versions of Chef InSpec 4.0 and later require accepting the EULA. Please
visit the [license acceptance page](/chef_license_accept/) for more information.
{{< /note >}}
## Getting started with Chef InSpec
Below are some of the core concepts that make up Chef InSpec.
### Create a profile
[Profiles](/inspec/profiles/) are the core of the Chef InSpec testing experience. Use Chef InSpec
profiles to manage everything you need to run a security or compliance scan--attributes,
metadata, and the tests themselves.
### Add your tests
You can create tests three different ways: By composing your own tests, by
including tests from the [Chef Supermarket](https://supermarket.chef.io/)
or by adding tests from the [Dev-Sec Project](http://dev-sec.io/) as dependencies.
You can also customize your tests--pulling in the tests from our Supermarket and
change them to suit your unique needs with the easy-to-read and easy-to-write Chef
InSpec domain specific language.
### Target your system
Run your tests wherever your infrastructure is--locally or in the cloud. Chef
InSpec is designed for platforms and treats operating systems as special cases.
Chef InSpec helps you, whether you use Windows Server on your own hardware or
run Linux in Docker containers in the cloud. As for the cloud, you can use Chef
InSpec to target applications and services running on AWS and Azure.
### Resources
Chef InSpec has 80+ [resources](/inspec/resources/) ready use--apache to zfs pool.
If you need a solution that we havent provided, you can write your own [custom
resource](/inspec/dsl_resource/).

525
www/content/inspec/cli.md Normal file
View file

@ -0,0 +1,525 @@
+++
title = "InSpec CLI"
draft = false
[menu]
[menu.inspec]
title = "InSpec Executable"
identifier = "inspec/reference/cli.md InSpec Executable"
parent = "inspec/reference"
weight = 10
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/cli.md)
Use the InSpec CLI to run tests and audits against targets using local, SSH, WinRM, or Docker connections.
## archive
Archive a profile to tar.gz (default) or zip
### Syntax
This subcommand has the following syntax:
```bash
inspec archive PATH
```
### Options
This subcommand has additional options:
* ``--airgap``, ``--no-airgap``
Fallback to using local archives if fetching fails.
* ``--ignore-errors``, ``--no-ignore-errors``
Ignore profile warnings.
* ``-o``, ``--output=OUTPUT``
Save the archive to a path
* ``--overwrite``, ``--no-overwrite``
Overwrite existing archive.
* ``--profiles-path=PROFILES_PATH``
Folder which contains referenced profiles.
* ``--tar``, ``--no-tar``
Generates a tar.gz archive.
* ``--vendor-cache=VENDOR_CACHE``
Use the given path for caching dependencies. (default: ~/.inspec/cache)
* ``--zip``, ``--no-zip``
Generates a zip archive.
## check
Verify all tests at the specified path
### Syntax
This subcommand has the following syntax:
```bash
inspec check PATH
```
### Options
This subcommand has additional options:
* ``--format=FORMAT``
* ``--profiles-path=PROFILES_PATH``
Folder which contains referenced profiles.
* ``--vendor-cache=VENDOR_CACHE``
Use the given path for caching dependencies. (default: ~/.inspec/cache)
## detect
Detect the target os
### Syntax
This subcommand has the following syntax:
```bash
inspec detect
```
### Options
This subcommand has additional options:
* ``-b``, ``--backend=BACKEND``
Choose a backend: local, ssh, winrm, docker.
* ``--bastion-host=BASTION_HOST``
Specifies the bastion host if applicable
* ``--bastion-port=BASTION_PORT``
Specifies the bastion port if applicable
* ``--bastion-user=BASTION_USER``
Specifies the bastion user if applicable
* ``--config=CONFIG``
Read configuration from JSON file (`-` reads from stdin).
* ``--enable-password=ENABLE_PASSWORD``
Password for enable mode on Cisco IOS devices.
* ``--format=FORMAT``
* ``--host=HOST``
Specify a remote host which is tested.
* ``--insecure``, ``--no-insecure``
Disable SSL verification on select targets
* ``-i``, ``--key-files=one two three``
Login key or certificate file for a remote scan.
* ``--password=PASSWORD``
Login password for a remote scan, if required.
* ``--path=PATH``
Login path to use when connecting to the target (WinRM).
* ``-p``, ``--port=N``
Specify the login port for a remote scan.
* ``--proxy-command=PROXY_COMMAND``
Specifies the command to use to connect to the server
* ``--self-signed``, ``--no-self-signed``
Allow remote scans with self-signed certificates (WinRM).
* ``--shell``, ``--no-shell``
Run scans in a subshell. Only activates on Unix.
* ``--shell-command=SHELL_COMMAND``
Specify a particular shell to use.
* ``--shell-options=SHELL_OPTIONS``
Additional shell options.
* ``--ssl``, ``--no-ssl``
Use SSL for transport layer encryption (WinRM).
* ``--sudo``, ``--no-sudo``
Run scans with sudo. Only activates on Unix and non-root user.
* ``--sudo-command=SUDO_COMMAND``
Alternate command for sudo.
* ``--sudo-options=SUDO_OPTIONS``
Additional sudo options for a remote scan.
* ``--sudo-password=SUDO_PASSWORD``
Specify a sudo password, if it is required.
* ``-t``, ``--target=TARGET``
Simple targeting option using URIs, e.g. ssh://user:pass@host:port
* ``--target-id=TARGET_ID``
Provide a ID which will be included on reports
* ``--user=USER``
The login user for a remote scan.
* ``--winrm-basic-auth-only``, ``--no-winrm-basic-auth-only``
Whether to use basic authentication, defaults to false (WinRM).
* ``--winrm-disable-sspi``, ``--no-winrm-disable-sspi``
Whether to use disable sspi authentication, defaults to false (WinRM).
* ``--winrm-transport=WINRM_TRANSPORT``
Specify which transport to use, defaults to negotiate (WinRM).
## env
Output shell-appropriate completion configuration
### Syntax
This subcommand has the following syntax:
```bash
inspec env
```
## exec
Run all test files at the specified locations.
loads the given profile(s) and fetches their dependencies if needed. then
connects to the target and executes any controls contained in the profiles.
one or more reporters are used to generate output.
```
exit codes:
0 normal exit, all tests passed
1 usage or general error
2 error in plugin system
3 fatal deprecation encountered
100 normal exit, at least one test failed
101 normal exit, at least one test skipped but none failed
172 chef license not accepted
```
below are some examples of using `exec` with different test locations:
automate:
```
inspec compliance login
inspec exec compliance://username/linux-baseline
```
supermarket:
```
inspec exec supermarket://username/linux-baseline
```
local profile (executes all tests in `controls/`):
```
inspec exec /path/to/profile
```
local single test (doesn't allow inputs or custom resources)
```
inspec exec /path/to/a_test.rb
```
git via ssh
```
inspec exec git@github.com:dev-sec/linux-baseline.git
```
git via https (.git suffix is required):
```
inspec exec https://github.com/dev-sec/linux-baseline.git
```
private git via https (.git suffix is required):
```
inspec exec https://api_token@github.com/dev-sec/linux-baseline.git
```
private git via https and cached credentials (.git suffix is required):
```
git config credential.helper cache
git ls-remote https://github.com/dev-sec/linux-baseline.git
inspec exec https://github.com/dev-sec/linux-baseline.git
```
web hosted fileshare (also supports .zip):
```
inspec exec https://webserver/linux-baseline.tar.gz
```
web hosted fileshare with basic authentication (supports .zip):
```
inspec exec https://username:password@webserver/linux-baseline.tar.gz
```
### Syntax
This subcommand has the following syntax:
```bash
inspec exec LOCATIONS
```
### Options
This subcommand has additional options:
* ``--attrs=one two three``
Legacy name for --input-file - deprecated.
* ``-b``, ``--backend=BACKEND``
Choose a backend: local, ssh, winrm, docker.
* ``--backend-cache``, ``--no-backend-cache``
Allow caching for backend command output. (default: true)
* ``--bastion-host=BASTION_HOST``
Specifies the bastion host if applicable
* ``--bastion-port=BASTION_PORT``
Specifies the bastion port if applicable
* ``--bastion-user=BASTION_USER``
Specifies the bastion user if applicable
* ``--config=CONFIG``
Read configuration from JSON file (`-` reads from stdin).
* ``--controls=one two three``
A list of control names to run, or a list of /regexes/ to match against control names. Ignore all other tests.
* ``--create-lockfile``, ``--no-create-lockfile``
Write out a lockfile based on this execution (unless one already exists)
* ``--distinct-exit``, ``--no-distinct-exit``
Exit with code 101 if any tests fail, and 100 if any are skipped (default). If disabled, exit 0 on skips and 1 for failures.
* ``--enable-password=ENABLE_PASSWORD``
Password for enable mode on Cisco IOS devices.
* ``--host=HOST``
Specify a remote host which is tested.
* ``--input=name1=value1 name2=value2``
Specify one or more inputs directly on the command line, as --input NAME=VALUE. Accepts single-quoted YAML and JSON structures.
* ``--input-file=one two three``
Load one or more input files, a YAML file with values for the profile to use
* ``--insecure``, ``--no-insecure``
Disable SSL verification on select targets
* ``-i``, ``--key-files=one two three``
Login key or certificate file for a remote scan.
* ``--password=PASSWORD``
Login password for a remote scan, if required.
* ``--path=PATH``
Login path to use when connecting to the target (WinRM).
* ``-p``, ``--port=N``
Specify the login port for a remote scan.
* ``--profiles-path=PROFILES_PATH``
Folder which contains referenced profiles.
* ``--proxy-command=PROXY_COMMAND``
Specifies the command to use to connect to the server
* ``--reporter=one two:/output/file/path``
Enable one or more output reporters: cli, documentation, html, progress, json, json-min, json-rspec, junit, yaml
* ``--reporter-backtrace-inclusion``, ``--no-reporter-backtrace-inclusion``
Include a code backtrace in report data (default: true)
* ``--reporter-message-truncation=REPORTER_MESSAGE_TRUNCATION``
Number of characters to truncate failure messages in report data to (default: no truncation)
* ``--self-signed``, ``--no-self-signed``
Allow remote scans with self-signed certificates (WinRM).
* ``--shell``, ``--no-shell``
Run scans in a subshell. Only activates on Unix.
* ``--shell-command=SHELL_COMMAND``
Specify a particular shell to use.
* ``--shell-options=SHELL_OPTIONS``
Additional shell options.
* ``--show-progress``, ``--no-show-progress``
Show progress while executing tests.
* ``--silence-deprecations=all|GROUP GROUP...``
Suppress deprecation warnings. See install_dir/etc/deprecations.json for list of GROUPs or use 'all'.
* ``--ssl``, ``--no-ssl``
Use SSL for transport layer encryption (WinRM).
* ``--sudo``, ``--no-sudo``
Run scans with sudo. Only activates on Unix and non-root user.
* ``--sudo-command=SUDO_COMMAND``
Alternate command for sudo.
* ``--sudo-options=SUDO_OPTIONS``
Additional sudo options for a remote scan.
* ``--sudo-password=SUDO_PASSWORD``
Specify a sudo password, if it is required.
* ``-t``, ``--target=TARGET``
Simple targeting option using URIs, e.g. ssh://user:pass@host:port
* ``--target-id=TARGET_ID``
Provide a ID which will be included on reports
* ``--user=USER``
The login user for a remote scan.
* ``--vendor-cache=VENDOR_CACHE``
Use the given path for caching dependencies. (default: ~/.inspec/cache)
* ``--waiver-file=one two three``
Load one or more waiver files.
* ``--winrm-basic-auth-only``, ``--no-winrm-basic-auth-only``
Whether to use basic authentication, defaults to false (WinRM).
* ``--winrm-disable-sspi``, ``--no-winrm-disable-sspi``
Whether to use disable sspi authentication, defaults to false (WinRM).
* ``--winrm-transport=WINRM_TRANSPORT``
Specify which transport to use, defaults to negotiate (WinRM).
## help
Describe available commands or one specific command
### Syntax
This subcommand has the following syntax:
```bash
inspec help [COMMAND]
```
## json
Read all tests in path and generate a json summary
### Syntax
This subcommand has the following syntax:
```bash
inspec json PATH
```
### Options
This subcommand has additional options:
* ``--controls=one two three``
A list of controls to include. Ignore all other tests.
* ``-o``, ``--output=OUTPUT``
Save the created profile to a path
* ``--profiles-path=PROFILES_PATH``
Folder which contains referenced profiles.
* ``--vendor-cache=VENDOR_CACHE``
Use the given path for caching dependencies. (default: ~/.inspec/cache)
## nothing
Does nothing
### Syntax
This subcommand has the following syntax:
```bash
inspec nothing
```
## schema
Print the json schema
### Syntax
This subcommand has the following syntax:
```bash
inspec schema NAME
```
## shell
Open an interactive debugging shell
### Syntax
This subcommand has the following syntax:
```bash
inspec shell
```
### Options
This subcommand has additional options:
* ``-b``, ``--backend=BACKEND``
Choose a backend: local, ssh, winrm, docker.
* ``--bastion-host=BASTION_HOST``
Specifies the bastion host if applicable
* ``--bastion-port=BASTION_PORT``
Specifies the bastion port if applicable
* ``--bastion-user=BASTION_USER``
Specifies the bastion user if applicable
* ``-c``, ``--command=COMMAND``
A single command string to run instead of launching the shell
* ``--config=CONFIG``
Read configuration from JSON file (`-` reads from stdin).
* ``--depends=one two three``
A space-delimited list of local folders containing profiles whose libraries and resources will be loaded into the new shell
* ``--distinct-exit``, ``--no-distinct-exit``
Exit with code 100 if any tests fail, and 101 if any are skipped but none failed (default). If disabled, exit 0 on skips and 1 for failures.
* ``--enable-password=ENABLE_PASSWORD``
Password for enable mode on Cisco IOS devices.
* ``--host=HOST``
Specify a remote host which is tested.
* ``--insecure``, ``--no-insecure``
Disable SSL verification on select targets
* ``--inspect``, ``--no-inspect``
Use verbose/debugging output for resources.
* ``-i``, ``--key-files=one two three``
Login key or certificate file for a remote scan.
* ``--password=PASSWORD``
Login password for a remote scan, if required.
* ``--path=PATH``
Login path to use when connecting to the target (WinRM).
* ``-p``, ``--port=N``
Specify the login port for a remote scan.
* ``--proxy-command=PROXY_COMMAND``
Specifies the command to use to connect to the server
* ``--reporter=one two:/output/file/path``
Enable one or more output reporters: cli, documentation, html, progress, json, json-min, json-rspec, junit
* ``--self-signed``, ``--no-self-signed``
Allow remote scans with self-signed certificates (WinRM).
* ``--shell``, ``--no-shell``
Run scans in a subshell. Only activates on Unix.
* ``--shell-command=SHELL_COMMAND``
Specify a particular shell to use.
* ``--shell-options=SHELL_OPTIONS``
Additional shell options.
* ``--ssl``, ``--no-ssl``
Use SSL for transport layer encryption (WinRM).
* ``--sudo``, ``--no-sudo``
Run scans with sudo. Only activates on Unix and non-root user.
* ``--sudo-command=SUDO_COMMAND``
Alternate command for sudo.
* ``--sudo-options=SUDO_OPTIONS``
Additional sudo options for a remote scan.
* ``--sudo-password=SUDO_PASSWORD``
Specify a sudo password, if it is required.
* ``-t``, ``--target=TARGET``
Simple targeting option using URIs, e.g. ssh://user:pass@host:port
* ``--target-id=TARGET_ID``
Provide a ID which will be included on reports
* ``--user=USER``
The login user for a remote scan.
* ``--winrm-basic-auth-only``, ``--no-winrm-basic-auth-only``
Whether to use basic authentication, defaults to false (WinRM).
* ``--winrm-disable-sspi``, ``--no-winrm-disable-sspi``
Whether to use disable sspi authentication, defaults to false (WinRM).
* ``--winrm-transport=WINRM_TRANSPORT``
Specify which transport to use, defaults to negotiate (WinRM).
## supermarket
Supermarket commands
### Syntax
This subcommand has the following syntax:
```bash
inspec supermarket SUBCOMMAND ...
```
## vendor
Download all dependencies and generate a lockfile in a `vendor` directory
### Syntax
This subcommand has the following syntax:
```bash
inspec vendor PATH
```
### Options
This subcommand has additional options:
* ``--overwrite``, ``--no-overwrite``
Overwrite existing vendored dependencies and lockfile.
## version
Prints the version of this tool
### Syntax
This subcommand has the following syntax:
```bash
inspec version
```
### Options
This subcommand has additional options:
* ``--format=FORMAT``

View file

@ -0,0 +1,125 @@
+++
title = "InSpec Configuration File"
draft = false
[menu]
[menu.inspec]
title = "Configuration"
identifier = "inspec/reference/config.md Configuration"
parent = "inspec/reference"
weight = 60
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/config.md)
This documents the Chef InSpec configuration file format introduced in version 3.5 of InSpec and extended in later versions.
## Config File Location
By default, Chef InSpec looks for a config file in `~/.inspec/config.json`. Chef InSpec does not need a configuration file to run.
You may also specify the location using `--config`. For example, to run the shell using a config file in `/etc/inspec`, use `inspec shell --config /etc/inspec/config.json`.
## Config File Format Versions
Config files must contain a top-level key, `version`, which indicates the file format. This allows us to add new fields without breaking old installations.
## Version 1.1
### Complete Example
```
{
"version": "1.1",
"cli_options":{
"color": "true"
},
"credentials": {
"ssh": {
"my-target": {
"host":"somewhere.there.com",
"user":"bob"
}
}
},
"reporter": {
"automate" : {
"stdout" : false,
"url" : "https://YOUR_A2_URL/data-collector/v0/",
"token" : "YOUR_A2_API_TOKEN",
"insecure" : true,
"node_name" : "inspec_test_node",
"environment" : "prod"
}
}
}
```
version
: Should have the value '1.1'.
cli_options
: Any long-form command line option, without the leading dashes.
credentials
: Train-transport-specific options. Store the options keyed first by transport name, then by a name you'll use later on. The combination of transport name and your chosen name can be used in the `--target` option to `inspec exec`, as `--target transport-name://connection-name`.
For example, if the config file contains:
```
{
"credentials": {
"winrm": {
"myconn": {
"user": "Administrator",
"host": "prod01.east.example.com",
"disable_sspi": true,
"connection_retries": 10
}
}
}
}
```
Then use `-t winrm://myconn` to connect to the host, with the given extra options.
Each Train transport offers a variety of options. By using the credential set facility, you are able to easily set options that are not accessible via the Train URI.
You may have as many credential sets in the config file as you require.
If you use a target URI and the portion after the `://` cannot be matched to credential set name, Chef InSpec will send the URI to Train to be parsed as a Train URI. Thus, you can still do `ssh://someuser@myhost.com`.
You can use a credential set, and then override individual options using command line options.
Credential sets are intended to work hand-in-hand with the underlying credentials storage facility of the transport. For example, if you have a `~/.ssh/config` file specifying that the sally-key.pem file should be used with the host `somehost.com`, and you have a credential set that specifies that host, then when Train tries to connect to that host, the SSH library will automatically use the SSH config file to use the indicated key.
### reporter
You may also set output (reporter) options in the config file. See the [Reporters Page](/inspec/reporters/) for details.
## Version 1.2
Version 1.2 adds a top-level field, "plugins".
### plugins
Use the `plugins` top-level configuration field to provide configuration settings to plugins that you use with Chef InSpec. Refer to the documentation of the plugin you are using for details regarding what settings are available.
To use this new feature, add a new top-level key in your config file named `plugins`. Then create a sub-key named for each plugin you wish to configure. Each plugin will have a key-value are that it may use as it sees fit - Chef Inspec does not specify the structure. Here is an example, using contrived plugins:
```
{
"version":"1.2",
"plugins": {
"inspec-training-wheels": {
"diameter": "4 inches"
},
"inspec-input-secrets": {
"security-tokens: [
"123456789".
"abcdef252875"
]
}
}
}
```

View file

@ -0,0 +1,421 @@
+++
title = "Chef InSpec DSL"
draft = false
[menu]
[menu.inspec]
title = "Chef InSpec DSL"
identifier = "inspec/reference/dsl_inspec.md Chef InSpec DSL"
parent = "inspec/reference"
weight = 70
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/dsl_inspec.md)
Chef InSpec is a run-time framework and rule language used to specify compliance,
security, and policy requirements. It includes a collection of resources that help
you write auditing controls quickly and easily. The syntax used by both open source
and [Chef compliance](/compliance/) auditing is the same. The open source [Chef InSpec resource](/inspec/resources/)
framework is compatible with [Chef compliance](/compliance/).
The Chef InSpec DSL is a Ruby DSL for writing audit controls, which includes audit resources that you can invoke.
The following sections describe the syntax and show some simple examples of using the Chef InSpec resources.
## Syntax
The following resource tests |ssh| server configuration. For example, a simple control may described as:
```ruby
describe sshd_config do
its('Port') { should cmp 22 }
end
```
In various use cases like implementing IT compliance across different departments, it becomes handy to extend the control with metadata. Each control may define an additional ``impact``, ``title`` or ``desc``. An example looks like:
```ruby
control 'sshd-8' do
impact 0.6
title 'Server: Configure the service port'
desc 'Always specify which port the SSH server should listen.'
desc 'rationale', 'This ensures that there are no unexpected settings' # Requires Chef InSpec >=2.3.4
tag 'ssh','sshd','openssh-server'
tag cce: 'CCE-27072-8'
ref 'NSA-RH6-STIG - Section 3.5.2.1', url: 'https://www.nsa.gov/ia/_files/os/redhat/rhel5-guide-i731.pdf'
describe sshd_config do
its('Port') { should cmp 22 }
end
end
```
where
* `'sshd-8'` is the name of the control
* `impact`, `title`, and `desc` define metadata that fully describes the importance of the control, its purpose, with a succinct and complete description
* `desc` when given only one argument it sets the default description. As of Chef InSpec 2.3.4, when given 2 arguments (see: `'rationale'`) it will use the first argument as a header when rendering in Automate
* `impact` is a string, or numeric that measures the importance of the compliance results.
Valid strings for impact are `none`, `low`, `medium`, `high`, and `critical`. The values are based off CVSS 3.0.
A numeric value must be between `0.0` and `1.0`. The value ranges are:
* `0.0 to <0.01` these are controls with no impact, they only provide information
* `0.01 to <0.4` these are controls with low impact
* `0.4 to <0.7` these are controls with medium impact
* `0.7 to <0.9` these are controls with high impact
* `0.9 to 1.0` these are critical controls
* `tag` is optional meta-information with with key or key-value pairs
* `ref` is a reference to an external document
* `describe` is a block that contains at least one test. A `control` block must contain at least one `describe` block, but may contain as many as required
* `sshd_config` is a Chef InSpec resource. For the full list of Chef InSpec resources, see Chef InSpec resource documentation
* `its('Port')` is the matcher; `{ should eq '22' }` is the test. A `describe` block must contain at least one matcher, but may contain as many as required
## Advanced concepts
### Checking if at least one condition passes with `describe.one`
With Chef InSpec, you can check if at least one of a collection of checks is true.
For example, if you configure a setting in two different locations, then you may want to test if either configuration A or configuration B is set.
Do this task with the `describe.one` block.
`describe.one` defines a set of `describe` blocks where only one block needs to pass.
```ruby
describe.one do
describe ConfigurationA do
its('setting_1') { should eq true }
end
describe ConfigurationB do
its('setting_2') { should eq true }
end
end
```
#### `describe.one` usage notes
* A `describe.one` block passes if one of its nested `describe` blocks has all assertions passing. A `describe.one` block needs an entire `describe` block to pass and not just a single assertion.
* Chef InSpec will always evaluate all the tests contained within `describe.one`. It does not short-circuit upon evaluating a passing `describe` block.
* Nesting a `describe.one` block inside another `describe.one` block is not supported.
### Sensitive resources
In some scenarios, you may be writing checks that involve resources with sensitive content, such as a file resource.
In case of failures, you may desire to suppress output.
Do this task by adding the `:sensitive` flag to the resource definition:
```ruby
describe file('/tmp/mysecretfile'), :sensitive do
its('content') { should match /secret_info/ }
end
```
## Examples
The following examples show simple compliance tests using a single `control` block.
### Test System Event Log
The following test shows how to audit machines running Windows 2012 R2 that password complexity is enabled:
```ruby
control 'windows-account-102' do
impact 'critical'
title 'Windows Password Complexity is Enabled'
desc 'Password must meet complexity requirement'
describe security_policy do
its('PasswordComplexity') { should cmp 1 }
end
end
```
### Test if PostgreSQL passwords are empty
The following test shows how to audit machines running PostgreSQL to ensure that passwords are not empty.
```ruby
control 'postgres-7' do
impact 1.0
title "Don't allow empty passwords"
describe postgres_session('user', 'pass').query("SELECT * FROM pg_shadow WHERE passwd IS NULL;") do
its('output') { should cmp '' }
end
end
```
### Test if MySQL passwords are in ENV
The following test shows how to audit machines running MySQL to ensure that passwords are not stored in `ENV`:
```ruby
control 'mysql-3' do
impact 1.0
title 'Do not store your MySQL password in your ENV'
desc '
Storing credentials in your ENV may easily expose
them to an attacker. Prevent this at all costs.
'
describe command('env') do
its('stdout') { should_not match /^MYSQL_PWD=/ }
end
end
```
### Test if `/etc/ssh` is a Directory
The following test shows how to audit machines to ensure that `/etc/ssh` is a directory:
```ruby
control 'basic-1' do
impact 1.0
title '/etc/ssh should be a directory'
desc '
In order for OpenSSH to function correctly, its
configuration path must be a folder.
'
describe file('/etc/ssh') do
it { should be_directory }
end
end
```
### Test if Apache running
The following test shows how to audit machines to ensure that Apache is enabled and running:
```ruby
control 'apache-1' do
impact 'medium'
title 'Apache2 should be configured and running'
describe service(apache.service) do
it { should be_enabled }
it { should be_running }
end
end
```
### Test if insecure packages are installed
The following test shows how to audit machines for insecure packages:
```ruby
control 'cis-os-services-5.1.3' do
impact 0.7
title '5.1.3 Ensure rsh client is not installed'
describe package('rsh') do
it { should_not be_installed }
end
describe package('rsh-redone-client') do
it { should_not be_installed }
end
end
```
### Test Windows Registry Keys
The following test shows how to audit machines to ensure Safe DLL Search Mode is enabled:
```ruby
control 'windows-base-101' do
impact 1.0
title 'Safe DLL Search Mode is Enabled'
desc '
@link: https://msdn.microsoft.com/en-us/library/ms682586(v=vs.85).aspx
'
describe registry_key('HKLM\\System\\CurrentControlSet\\Control\\Session Manager') do
it { should exist }
it { should_not have_property_value('SafeDllSearchMode', :type_dword, '0') }
end
end
```
### Use `only_if` to exclude a specific control
This example shows how to allow skipping certain controls if conditions are not
met by using `only_if`. In this example, the control will not be performed if
the `redis-cli` command does not exist. A optional message can say why it was skipped.
```ruby
control 'nutcracker-connect-redis-001' do
impact 'critical'
title 'Check if nutcracker can pass commands to redis'
desc 'execute redis-cli set key command, to check connectivity of the service'
only_if('redis is not installed.') do
command('redis-cli').exist?
end
describe command('redis-cli SET test_inspec "HELLO"') do
its('stdout') { should match /OK/ }
end
end
```
Mixing this with other conditionals, such as checking existence of the files, can
help to test different test paths using Chef InSpec. With this way, you can skip
certain controls, which would 100% fail due to the way servers are prepared, but
you know that the same control suites are reused later in different circumstances
by different teams.
Some notes about `only_if`:
- `only_if` applies to the entire `control`. If the results of the `only_if`
block evaluate to false, any Chef InSpec resources mentioned as part of a
`describe` block will not be run. Additionally, the contents of the describe
blocks will not be run. However, bare Ruby expressions and bare Chef InSpec
resources (not assocated with a describe block) preceding the only_if statement
will run
To illustrate:
```ruby
control "whatruns" do
command("do_something") # This will ALWAYS run
describe command("do_another_thing") do # This will not run
command("do_yet_another_thing") # This will not run
end
only_if { false }
command("do_something_else") # This will not run
end
```
* Only one `only_if` is permitted per `control` block. If multiple `only_if` blocks are present, only the last `only_if` block will be honored
* If used outside a control block, `only_if` skips all controls in the current file
* To implement complex logic, use Ruby 'or' (`||`) and 'and' (`&&`) inside your `only_if` block:
```ruby
only_if('ready for launch') do
rocket_is_ready && weather_is_clear
end
```
### Additional metadata for controls
The following example illustrates various ways to add tags and references to `control`
```ruby
control 'ssh-1' do
impact 1.0
title 'Allow only SSH Protocol 2'
desc '
Only SSH protocol version 2 connections should be permitted.
The default setting in /etc/ssh/sshd_config is correct, and can be
verified by ensuring that the following line appears: Protocol 2
'
tag 'production','development'
tag 'ssh','sshd','openssh-server'
tag cce: 'CCE-27072-8'
tag disa: 'RHEL-06-000227'
tag remediation: 'stig_rhel6/recipes/sshd-config.rb'
tag remediation: 'https://supermarket.chef.io/cookbooks/ssh-hardening'
ref 'NSA-RH6-STIG - Section 3.5.2.1', url: 'https://www.nsa.gov/ia/_files/os/redhat/rhel5-guide-i731.pdf'
ref 'http://people.redhat.com/swells/scap-security-guide/RHEL/6/output/ssg-centos6-guide-C2S.html'
describe ssh_config do
its('Protocol') { should cmp 2 }
end
end
```
## Using Ruby in InSpec
The Chef InSpec DSL is a Ruby based language. This allows you to be flexible with
Ruby code in controls:
```ruby
json_obj = json('/file.json')
json_obj['keys'].each do |value|
..
end
```
Ruby allows a lot of freedoms, but should be limited in controls so that they
remain portable and easy to understand. Please see our [profile style guide](/inspec/style/).
Core and custom resources are written as regular Ruby classes which inherit from
`Inspec.resource`.
### Interactive Debugging with Pry
Here's a sample Chef InSpec control that uses Ruby variables to instantiate
a Chef InSpec resource once and use the content in multiple tests.
```ruby
control 'check-perl' do
impact 0.3
title 'Check perl compiled options and permissions'
perl_out = command('perl -V')
#require 'pry'; binding.pry;
describe perl_out do
its('exit_status') { should eq 0 }
its('stdout') { should match /USE_64_BIT_ALL/ }
its('stdout') { should match /useposix=true/ }
its('stdout') { should match /-fstack-protector/ }
end
# extract an array of include directories
perl_inc = perl_out.stdout.partition('@INC:').last.strip.split("\n")
# ensure include directories are only writable by 'owner'
perl_inc.each do |path|
describe directory(path.strip) do
it { should_not be_writable.by 'group' }
it { should_not be_writable.by 'other' }
end
end
end
```
An **advanced** but very useful Ruby tip. In the previous example, I
commented out the `require 'pry'; binding.pry;` line. If you remove the
`#` prefix and run the control, the execution will stop at that line and
give you a `pry` shell. Use that to troubleshoot, print variables, see
methods available, etc. For the above example:
```ruby
[1] pry> perl_out.exit_status
=> 0
[2] pry> perl_out.stderr
=> ""
[3] pry> ls perl_out
Inspec::Plugins::Resource#methods: inspect
Inspec::Resources::Cmd#methods: command exist? exit_status result stderr stdout to_s
Inspec::Resource::Registry::Command#methods: inspec
instance variables: @__backend_runner__ @__resource_name__ @command @result
[4] pry> perl_out.stdout.partition('@INC:').last.strip.split("\n")
=> ["/Library/Perl/5.18/darwin-thread-multi-2level",
" /Library/Perl/5.18",
...REDACTED...
[5] pry> exit # or abort
```
You can use `pry` inside both the controls DSL and resources. Similarly,
for dev and test, you can use `inspec shell` which is based on `pry`,
for example:
```ruby
$ inspec shell
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
inspec> command('ls ~/projects/github/inspec/docs').stdout
=> "README.md\nconfig.md\ndev\ndsl_inspec.md\ndsl_resource.md\nglossary.md\nhabitat.md\ninputs.md\ninspec_and_friends.md\nmatchers.md\nmigration.md\nplatforms.md\nplugin_kitchen_inspec.md\nplugins.md\nprofiles.md\nreporters.md\nresources\nshared\nshell.md\nstyle.md\nwaivers.md\n"
inspec> command('ls ~/projects/github/inspec/docs').stdout.split("\n").first
=> "README.md"
inspec> help command
Name: command
Description:
Use the command InSpec audit resource to test an arbitrary command that is run on the system.
Example:
describe command('ls -al /') do
it { should exist }
its('stdout') { should match /bin/ }
its('stderr') { should eq '' }
its('exit_status') { should eq 0 }
end
```

View file

@ -0,0 +1,137 @@
+++
title = "Resource DSL"
draft = false
[menu]
[menu.inspec]
title = "Custom Resources"
identifier = "inspec/reference/dsl_resource.md Custom Resources"
parent = "inspec/reference"
weight = 90
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/dsl_resource.md)
Chef InSpec provides a mechanism for defining custom resources. These become
available with their respective names and provide easy functionality to
profiles.
## Resource location
Resources may be added to profiles in the libraries folder:
```bash
$ tree examples/profile
examples/profile
...
├── libraries
│   └── example_config.rb
```
## Resource structure
The smallest possible resource takes this form:
```ruby
class Tiny < Inspec.resource(1)
name 'tiny'
end
```
Resources are written as a regular Ruby class which inherits from
Inspec.resource. The number (1) specifies the version this resource
plugin targets. As Chef InSpec evolves, this interface may change and may
require a higher version.
The following attributes can be configured:
- name - Identifier of the resource (required)
- desc - Description of the resource (optional)
- example - Example usage of the resource (optional)
- supports - (Chef InSpec 2.0+) Platform restrictions of the resource (optional)
The following methods are available to the resource:
- inspec - Contains a registry of all other resources to interact with the operating system or target in general.
- skip\_resource - A resource may call this method to indicate that requirements aren't met. All tests that use this resource will be marked as skipped.
The following example shows a full resource using attributes and methods
to provide simple access to a configuration file:
```ruby
class ExampleConfig < Inspec.resource(1)
name 'example_config'
# Restrict to only run on the below platforms (if none were given, all OS's supported)
supports platform_family: 'fedora'
supports platform: 'centos', release: '6.9'
# Supports `*` for wildcard matcher in the release
supports platform: 'centos', release: '7.*'
desc '
Resource description ...
'
example '
describe example_config do
its("signal") { should eq "on" }
end
'
# Load the configuration file on initialization
def initialize(path = nil)
@path = path || '/etc/example.conf'
@params = SimpleConfig.new( read_content )
end
# Expose all parameters of the configuration file.
def method_missing(name)
@params[name]
end
private
def read_content
f = inspec.file(@path)
# Test if the path exist and that it's a file
if f.file?
# Retrieve the file's contents
f.content
else
# If the file doesn't exist, skip all tests that use example_config
raise Inspec::Exceptions::ResourceSkipped, "Can't read config at #{@path}"
end
end
end
```
For a full example, see our [example resource](https://github.com/chef/inspec/blob/master/examples/profile/libraries/example_config.rb).
## Lazy Loading
Prior to InSpec v4.16, resources were pre-loaded for every invocation
of `inspec`. This was a heavy and unnecessary burden on the system and
exacerbated startup times (especially on Windows).
As of InSpec v4.16, resources are lazily loaded into the `inspec`
process upon use. This greatly speeds up the initial startup costs of
the `inspec` process and only loads what you need to use. For example, `inspec
--version` no longer runs for 10 seconds!.
### Overriding Core Resources
Lazy loading does change the way the resource registry is handled in
ways that might break some assumptions. Specifically,
`inspec.<resource>` isn't pre-populated with the core resources that
InSpec ships with. If you make a local/custom resource of the same
name, referring to the core resource via `inspec.<resource>` will not
resolve to the core resource.
As such, overriding core resources is not recommended best practice.
If you really do need to do this, it is easiest to make a local
resource with a new name and refer to the core resource directly.
Otherwise, you need to ensure that the core resource you want is
registered (via `require "inspec/resource/<name>"`) _before_ your
profile is run to ensure it is eagerly loaded and in the global
resource registry.

View file

@ -0,0 +1,399 @@
+++
title = "Chef InSpec Glossary"
draft = false
[menu]
[menu.inspec]
title = "Chef InSpec Glossary"
identifier = "inspec/glossary.md Chef InSpec Glossary"
parent = "inspec"
weight = 50
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/glossary.md)
This document should help you become familiar with some of the terminology used by the Chef InSpec project.
There are two ways to use it:
- A [text glossary](#text-glossary). Learn the meaning of a word you have encountered.
- A [visual glossary](#visual-glossary). Look at examples and see how the parts are labelled. You can then use the text glossary to read details of each concept.
## Visual Glossary
### Motivating Example
Suppose we are interested in auditing cars. Let's suppose we have two Chef InSpec resources for auditing: `cars`, which searches for and filters groups of cars, and `car`, which performs detailed auditing of a single car.
### Basic Syntax
Let's look at some simple examples.
### Singular Resource Example
```inspec
describe car(owner: 'Tony Clifton') do
it { should exist }
its('license_plate') { should cmp 'MOONMAN' }
it { should be_classy }
it { should_not have_check_engine_light_on }
end
```
#### describe car(owner: 'Tony Clifton') do
_car_ is a [resource](#resource). Since we are talking about only one car, it is a [singular resource](#singular-resource).
#### describe car(_owner: 'Tony Clifton'_)
_owner_ is a [resource parameter](#resource-parameter) and _'Tony Clifton'_ is a resource parameter value.
#### _it { should exist }_
Each line within the resource block beginning with `it` or `its` is a [test](#test). Use [it](#it) to access [resource-specific matchers](#resource-specific-matcher), and use [its](#its) to access [properties](#property) of the [resource](#resource), which are in turn used with [universal matchers](#universal-matcher).
#### its('_license\_plate_') { should cmp 'MOONMAN' }
_license\_plate_ is a [property](#property) belonging to the [resource](#resource). Properties expose testable information about the resource. Some properties are numbers, some (like this one) are text, some are lists, and some are more complex objects. Properties are always used with [universal matchers](#universal-matcher).
#### its('license\_plate') { should _cmp_ 'MOONMAN' }
_cmp_ is a [universal matcher](#universal-matcher). `cmp` is a very flexible, loosely typed equality operator; here it checks to see if the license plate text is the same as the text 'MOONMAN'. Notice that the test operates on the license plate text (the property value) and not on the resource. You can find the full list of supported universal matchers on the [Universal Matcher page](/inspec/matchers/).
#### its('license\_plate') { should cmp _'MOONMAN'_ }
_'MOONMAN'_ is an [expected result](#expected-result). Some matchers take an expected result; others do not.
#### it { should _be\_classy_ }
_be\_classy_ is a [resource-specific matcher](#resource-specific-matcher). It returns a yes-or-no value, based on whether Tony's car is classy or not. (It is. Tony is a classy guy.)
#### it { _should\_not_ have\_check\_engine\_light\_on }
_should\_not_ indicates this is a negated test. So, this test passes if the matcher says "no".
### Plural Resource Example
```inspec
describe cars.where(color: /^b/) do
it { should exist }
its('manufacturers') { should include 'Cadillac' }
its('count') { should be >= 10 }
end
```
#### describe _cars_.where(color: /^b/) do
_cars_ is a [resource](#resource). Since we are potentially talking about many cars, it is a [plural resource](#plural-resource).
#### describe cars._where(color: /^b/)_ do
_where(color: /^b/)_ is a [filter statement](#filter-statement). Without a filter statement, `cars` simply selects all the cars in the world.
#### describe cars.where(_color: /^b/_) do
_color_ is a [filter criterion](#filter-criteria) along with its filter value, _/^b/_. Here, the criterion expresses that we want to select all cars whose colors begin with the letter 'b' - blue, brown, burgundy, etc.
#### _it { should exist }_
Each line within the resource block beginning with `it` or `its` is a [test](#test). Use [it](#it) to access [resource-specific matchers](#resource-specific-matcher), and use [its](#its) to access [properties](#property) of the [resource](#resource), which are in turn used with [universal matchers](#universal-matcher).
With plural resources, `exist` has a special meaning: did the filter match anything?
#### its('_manufacturers_') { should include 'Cadillac' }
_manufacturers_ is a [property](#property) of the [resource](#resource). Properties expose testable information about the resource. On plural resources, properties are almost always names in the plural, and almost always return a list of values. Here, the test returns a list of the car manufacturer names. Some list properties are de-duplicated; for example, you might have 10 cars, but if they are all Subarus and Cadillacs, it returns only two entries in the `manufacturers` property. Be sure to check the documentation for your resource.
#### its('manufacturers') { should _include_ 'Cadillac' }
_include_ is a [universal matcher](#universal-matcher). `include` works with lists, and checks to see if an expected result is present. Here, it checks to see if the list of manufacturers contains an entry with the text 'Cadillac'. Notice it operates on the manufacturers list (the property value) and not on the resource. You can find the full list of supported universal matchers on the [Universal Matcher page](/inspec/matchers/).
#### its('manufacturers') { should include '_Cadillac_' }
_'Cadillac'_ is an [expected result](#expected-result). Some matchers take an expected result; others do not.
#### its('count') { should _be >=_ 10 }
_be >=_ is an [operator matcher](#operator matcher). It allows you to perform numeric comparisons. All plural resources have a `count` property.
## Text Glossary
### attribute
Deprecated name for [input](#input).
### control
### control block
The _`control`_ keyword is used to declare a _`control block`_. Here, the word 'control' means a 'regulatory control, recommendation, or requirement' - not a software engineering construct. A `control block` has a name (which usually refers to the assigned ID of the regulatory recommendation it implements), metadata such as descriptions, references, and tags, and finally groups together related [describe blocks](#describe-block) to implement the checks.
### core resource
A [resource](#resource) that is included with InSpec; you are not required to install additional [plugins](#plugin) or depend on a [resource pack](#resource pack) to use the resource.
### custom resource
A [resource](#resource) that is _not_ included with InSpec. It may be a resource of your own creation, or one you obtain by depending on a [resource pack](#resource pack).
### describe
### describe block
The _`describe`_ keyword is used with a _`describe block`_ to refer to a Chef InSpec resource. You use the `describe` keyword along with the name of a [resource](#resource) to enclose related [tests](#test) that apply to the resource. Multiple describe blocks are usually grouped together in a [control](#control), but you can also use them outside of a control.
```Ruby
control 'Rule 1.1 - Color restrictions' do
# Count only blue cars
describe cars.where(color: 'blue') do
its('count') { should eq 20 }
end
end
```
### DSL
_DSL_ is an acronym for _Domain Specific Language_. It refers to the language extensions Chef InSpec provides to make authoring resources and controls easier. While Chef InSpec control files are use Ruby, the _Control DSL_ makes it easy to write controls without knowledge of Ruby by providing DSL keywords such as [describe](#describe), [control](#control), [it](#it) and [its](#its). See the [Chef InSpec DSL page](/inspec/dsl_inspec/) for details about keywords available to control authors.
For [custom resource](#custom-resource) authors, an additional DSL is available - see the [Resource DSL page](/inspec/dsl_resource/).
### expected result
When using a [matcher](#matcher), the _`expected result`_ is the value the matcher will compare against the [property](#property) being accessed.
In this example, the [`cmp`](/inspec/matchers/#cmp) matcher is being used to compare the `color` property to the expected result 'black'.
```Ruby
describe car(owner: 'Bruce Wayne') do
its('color') { should cmp 'black' }
end
```
### filter statement
When using a [plural resource](#plural-resource), a _`filter statement`_ is used to select individual test subjects using [filter criteria](#filter-criteria). A filter statement almost always is indicated by the keyword `where`, and may be repeated using method chaining.
A filter statement may use method call syntax (which allows basic criteria operations, such as equality, regex matching, and ruby `===` comparison) or block syntax (which allows arbitrary code).
In this example, `where(...)` is the filter statement.
```Ruby
# Count only blue cars
describe cars.where(color: 'blue') do
its('count') { should eq 20 }
end
```
### filter criterion
### filter criteria
When using a [plural resource](#plural-resource), a _`filter criterion`_ is used to select individual test subjects within a [filter statement](#filter-statement). You may use multiple _`filter criteria`_ in a single filter statement.
When method-call syntax is used with the filter statement, you provide filter criteria as a Hash, with filter criteria names as keys, and conditions as the Hash values. You may provide test, true/false, or numbers, in which case the comparison is equality; or you may provide a regular expression, in which case a match is performed.
Here, `(color: blue)` is a single filter criterion being used with a filter statement in method-call syntax.
```Ruby
# Count only blue cars
describe cars.where(color: 'blue') do
its('count') { should eq 20 }
end
```
When block-method syntax is used with the filter statement, you provide a block. The block may contain arbitrary code, and each filter criteria will be available as an accessor. The block will be evaluated once per row, and each block that evaluates to a truthy value will pass the filter.
Here, `{ engine_cylinders >= 6 }` is a block-syntax filter statement referring to one filter criterion.
```Ruby
# Vroom!
describe cars.where { engine_cylinders >= 6 } do
its('city_mpg_ratings') { should_not include '4-star' }
end
```
### input
An _`input`_ is a value that Chef InSpec can source from a number of providers, including from the command line, profile metadata, or within the control file DSL itself. You can use this feature either to change a [profile's](#profile) behavior by passing different attribute files or to store secrets that should not be directly present in a profile.
Inputs were formerly known as `attributes`. Chef InSpec inputs are unrelated to Chef Infra attributes.
The CLI syntax for inputs is documented under the [`inspec exec`](/inspec/cli/#exec) command.
Inputs are documented in detail in the [input documentation](/inspec/inputs/).
### it
Within a [describe block](#describe), _`it`_ declares an individual [test](#test) directly against the [resource](#resource) (as opposed to testing against one of the resource's [properties](#property), as [its](#its) does). Though it is possible to use [universal matchers](#universal-matcher) with `it`, it is much more typical to use [resource-specific matchers](#resource-specific-matchers).
`it` may be used with `should`, or negated using `should_not`.
Here, `it { should ... }` declares a test, calling the `classy?` matcher on Tony Clifton's car.
```Ruby
describe car(owner: 'Tony Clifton') do
it { should be_classy }
end
```
### its
Within a [describe block](#describe), _`its`_ declares an individual [test](#test) against a property of the [resource](#resource) (as opposed to testing directly against the resource itself, as [it](#it) does). You must use [universal matchers](#universal-matcher) with `its`; you cannot use [resource-specific matchers](#resource-specific-matchers).
`its` may be used with `should`, or negated using `should_not`.
The property to access is passed as a single string argument to `its`. As an advanced usage, if the property has methods you are interested in, you can call them using '`.`' within the string; even more advanced calling patterns are possible - see [the rspec-its documentation](https://github.com/rspec/rspec-its#usage).
Here, `its('fuzzy_dice') { should ... }` declares a test, testing against the `fuzzy_dice` property of Tony Clifton's car. Let's assume - Tony being Tony - that `fuzzy_dice` will return an Array.
```Ruby
describe car(owner: 'Tony Clifton') do
its('fuzzy_dice') { should_not be_empty }
its('fuzzy_dice.count') { should be >= 2 }
its('fuzzy_dice.first.fuzziness') { should cmp 'outlandishly so' }
end
```
### matcher
A _`matcher`_ performs the actual assertions against [resources](#resource) or the [properties](#property) of resources. Matchers always return a true/false value. Matchers fall into two camps:
* [resource-specific matchers](#resource-specific-matchers), which operate directly on the resource, are used with [it](#it), and tend to be highly customized to the auditing needs of the resource
* [universal matchers](#universal-matchers), which operate on the properties of the resource, are used with [its](#its), and tend to be very generic, operating on text, numbers, and lists
Some matchers accept parameters, called [expected results](#expected-results).
For information on how RSpec matchers are related o Chef InSpec matchers, see [Chef InSpec and RSpec](/inspec/inspec_and_friends/#rspec).
Here, `be_classy` is a resource-specific matcher operating directly on the `car`, while `cmp` is a universal matcher operating on the `manufacturer` property.
```Ruby
describe car(owner: 'Tony Clifton') do
it { should be_classy }
its('manufacturer') { should cmp 'Cadillac' }
end
```
### plural resource
A _`plural resource`_ is a [resource](#resource) that specializes in performing searches and represents multiple occurrences of the resource on the [target](#target) platform. Plural resources are used to audit counts, inspect group properties, and have the unique ability to enforce negative tests ("nothing like this should exist") often required by compliance standards. Plural resources are not intended to perform in-depth auditing of an individual; use [singular resources](#singular-resource) for that.
Plural resources nearly always have a name that ends in 's': `processes`, `aws_security_groups`, `cars`. Plural resources generally do not have [resource-specific matchers](#resource-specific-matcher). If they have properties, they are almost always list properties, meaning that they return a list of values, which may or may not be de-duplicated.
Plural resources support [filter statements](#filter-statement). See the [resource documentation](/inspec/resources/) for details regarding which [filter criteria](#filter-criteria) are supported on each resource.
Here, `cars` is a plural resource.
```Ruby
describe cars.where(color: 'blue') do
its('count') { should eq 20 }
its('license_plates') { should include 'AUTOAZUL' }
# License plates are unique, should have 20
its('license_plates.count') { should cmp 20 }
# Manufacturers are de-duplicated
its('manufacturers') { should include 'Subaru' }
its('manufacturers.count') { should be < 10 }
end
```
### profile
A _`profile`_ is a set of related [controls](#control) in a distributable form. You might have a locally-developed profile that your organization uses to define baseline security on all machines, or you might use a pre-defined profile that implements the requirements of a specific compliance standard. For full details about the capabilities of a profile, see the [profile documentation](/inspec/profiles/).
Profiles may be distributed locally as a directory tree, as a tarball or zipfile at a URL, as a git repo, and several other ways. Profiles contain metadata, including versioning, and can setup dependency relationships with other profiles.
Aside from controls, profiles can also contain [custom resources](#custom-resource). If the profile contains only custom resources and no controls, we call it a [resource pack](#resource-pack).
### property
A fact about a [resource](#resource). Typically, you use the [its](#its) keyword to access the property and write a [test](#test) within a [describe block](#describe-block), and then use a [universal matcher](#universal-matcher) to make assertions about the value of the property.
Each resource has different properties. See the [resource documentation](/inspec/resources/) for details.
Here, `manufacturer` is a property of the `car` resource.
```Ruby
describe car(owner: 'Tony Clifton') do
its('manufacturer') { should cmp 'Cadillac' }
end
```
### reporter
An output format for the `inspec exec` command line. Several reporters are available, including JSON and JUnit; see the [inspec exec documentation](/inspec/cli/#exec).
### resource
A _`resource`_ represents a category of things on the [target](#target) you wish to examine. For example, to check for the existence and permissions of a file, you would use the [`file`](/inspec/resources/file/) resource. Chef InSpec offers dozens of different resources, from the highly specialized (such as `aws_security_group`, which examines firewall rules in AWS) to the very general (such as `command`, which runs a command and lets you examine its output).
Resources are generally categorized as either [singular](#singular-resource) or [plural](#plural-resource), though there are some irregular resources that cannot be cleanly considered one or the other.
Resources are used within a [describe block](#describe-block) to perform [tests](#test).
Here, `car` is a resource.
```Ruby
describe car(owner: 'Tony Clifton') do
it { should be_classy }
end
```
### resource pack
A _resource pack_ is a type of [profile](#profile) that is used to distribute [custom resources](#custom-resource). This specialized type of profile contains no [controls](#control), but it does contain a `libraries` directory within which Ruby files define custom resources.
### resource parameter
_`resource parameters`_ are information passed to the resource when they are declared. Typically, resource parameters provide identifying information or connectivity information. Resource parameters are not the same as a [filter statement](#filter-statement).
Resource parameters vary from resource to resource; refer to the [resource documentation](/inspec/resources/) for details.
Here, `owner: 'Tony Clifton'` is a resource parameter.
```Ruby
describe car(owner: 'Tony Clifton') do
it { should be_classy }
end
```
### resource-specific matcher
A [matcher](#matcher) that operates directly on the [resource](#resource), as opposed to operating on a property as a [universal matcher](#universal matcher) does.
Resource-specific matchers often provide highly customized behavior. Check the [resource documentation](#/inspec/resources/) to discover which resource-specific matchers are available for your resource.
For example, the hypothetical `car` resource defines a `classy?` method, which is exposed as the `be_classy` matcher in Chef InSpec tests.
```Ruby
describe car(owner: 'Tony Clifton') do
it { should be_classy }
end
```
### singular resource
A [resource](#resource) intended to uniquely identify a single object on the [target](#target). Singular resources specialize in providing richer auditing capabilities via resource-specific matchers. Compare to [plural resources](#plural-resource).
### target
The _`target`_ is the OS or API on which Chef InSpec is performing audits. In Chef InSpec 1.x, this was always an operating system target (a bare metal machine, VM, or container). In Chef InSpec 2.x and later, this can be an OS target, or an API target, including cloud providers such as AWS. Chef InSpec is agentless, meaning that the Chef InSpec code and profiles remain on your workstation, and the target is remotely interrogated without installing anything.
### test
A _`test`_ is an individual assertion about the state of the [resource](#resource) or one of its [properties](#property). All tests begin with the keyword [it](#it) or [its](#its). Tests are grouped within a [describe block](#describe-block).
### universal matcher
A _universal matcher_ is a [matcher](#matcher) that can be used on the [properties](#property) of any type of [resource](#resource). For example, you can use the `cmp` matcher to check the value of properties without having to worry about Ruby type-casting. Universal matchers are almost always used with the [its](#its) keyword.
Universal matchers are documented on the [Universal Matchers](/inspec/matchers/) page.
Here, we access the 'color' property, then use the `cmp` universal matcher to compare the property to the 'black' [expected result](#expected-result).
```Ruby
describe car(owner: 'Bruce Wayne') do
its('color') { should cmp 'black' }
end
```

View file

@ -0,0 +1,231 @@
+++
title = "Chef InSpec Integration with Chef Habitat"
draft = false
[menu]
[menu.inspec]
title = "Chef Habitat Integration"
identifier = "inspec/reference/habitat.md Habitat Integration"
parent = "inspec/reference"
weight = 120
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/habitat.md)
Chef InSpec provides an easy method to create an executable Chef Habitat package for a Chef InSpec profile. When run via the Chef Habitat Supervisor, the package will run Chef InSpec with your profile and write out its findings to the supervisor log. This provides the ability to ship your compliance controls alongside your Chef Habitat-packaged application and continuously run InSpec, providing you *Continuous Compliance.*
## What is Chef Habitat
Chef Habitat by Chef Software is our new Application Automation tool that aims
to make it easy, safe, and fast to build, deploy, and manage applications. From
build dependencies, runtime dependencies, dynamic configuration, and service
discovery (just to name a few), Chef Habitat packages the automation with the
application instead of relying on an underlying platform.
To learn more about Chef Habitat and try our demos and tutorials, visit
[https://www.habitat.sh](https://www.habitat.sh).
## Using the Chef Habitat Integration
After creating a Chef Habitat package for a Chef InSpec profile (see CLI commands
below) and uploading the package to a Chef Habitat Depot or manually distributing
to a host, start the Chef Habitat Supervisor with your package:
```bash
hab start effortless/audit-baseline
```
The Chef Habitat Supervisor will install Chef InSpec and execute your profile in
a loop. The loop is controlled by two variables: the `interval` and the `splay`.
The `interval` is a set time you want InSpec to run and its default is `1800`
seconds. The `splay` is a randomly generated sleep time that prevents a thundering
herd problem, or resource starvation scenario, when sending your report to an
external server like Chef Automate. The default for the `splay` is also `1800`
seconds. Alternatively, the `splay_first_run` can be set to wait a random period
of time between 0 and the number set for the `splay_first_run` before running
InSpec when your Habitat package is started or updated. The default of the
`splay_first_run` is `0` seconds.
```bash
HAB_INSPEC_PROFILE_FRONTEND1="interval = 60" hab start effortless/audit-baseline
```
The Chef Habitat Supervisor will display output like this:
```text
hab start effortless/audit-baseline
∵ Missing package for core/hab-sup/0.17.0
» Installing core/hab-sup/0.17.0
↓ Downloading core/hab-sup/0.17.0/20170214235450
1.68 MB / 1.68 MB - [=========================================================================] 100.00 % 7.43 MB/s
... more Chef Habitat output here ...
hab-sup(MN): Starting effortless/audit-baseline/0.1.0/20170328173005
hab-sup(CS): effortless/audit-baseline/0.1.0/20170328173005 is not installed
↓ Downloading adamleff-20160617201047 public origin key
79 B / 79 B | [===============================================================================] 100.00 % 2.64 MB/s
☑ Cached adamleff-20160617201047 public origin key
↓ Downloading chef/inspec/1.17.0/20170321214949
16.93 MB / 16.93 MB / [======================================================================] 100.00 % 10.49 MB/s
... more Chef Habitat output here ...
★ Install of effortless/audit-baseline/0.1.0/20170328173005 complete with 9 new packages installed.
hab-sup(MR): Butterfly Member ID d9bd761e18c144469d755b1b97406eb2
hab-sup(MR): Starting butterfly on 0.0.0.0:9638
hab-sup(MR): Starting http-gateway on 0.0.0.0:9631
inspec-profile-frontend1.default(SR): Initializing
inspec-profile-frontend1.default(SV): Starting process as user=hab, group=hab
inspec-profile-frontend1.default(O): Executing InSpec effortless/audit-baseline
inspec-profile-frontend1.default(O): InSpec run completed successfully.
inspec-profile-frontend1.default(O): sleeping for 2134 seconds
```
The above sample output shows the supervisor starting, downloading the necessary dependencies for the supervisor and the Chef InSpec profile, and then shows the supervisor running Chef InSpec successfully.
Chef InSpec will write a JSON file in the `${svc_var_path}/inspec_results` directory containing the results of the last Chef InSpec run. For example, for the `effortless/audit-baseline` package, the Chef InSpec results will be at:
```text
/hab/svc/inspec-profile-frontend1/var/inspec_results/inspec-profile-frontend1.json
```
## Chef InSpec Chef Habitat CLI Commands
### inspec habitat profile create
Create a Chef Habitat package for a Chef InSpec profile. Chef InSpec will
validate the profile, fetch and vendor any dependencies (if necessary), and build
the Chef Habitat package with a dependency on the latest InSpec. The resulting
package will be saved to the current working directory.
The package can then be manually uploaded to a Chef Habitat Depot or manually
distributed to a host and installed via `hab pkg install`.
The package file will be named:
```text
HABITAT_ORIGIN-inspec-profile-PROFILE_NAME-PROFILE_VERSION-BUILD_ID-x86_64-linux.hart
```
For example:
```text
adamleff-inspec-profile-frontend1-0.1.0-20170328173005-x86_64-linux.hart
```
#### Syntax
```bash
inspec habitat profile create PROFILE_DIRECTORY
```
#### Example
```bash
inspec habitat profile create ~/profiles/frontend1
```
#### Example Output
```text
$ habitat profile create ~/profiles/frontend1
[2017-03-28T13:29:32-04:00] INFO: Creating a Habitat artifact for profile: /Users/aleff/profiles/frontend1
[2017-03-28T13:29:32-04:00] INFO: Checking to see if Habitat is installed...
[2017-03-28T13:29:32-04:00] INFO: Copying profile contents to the work directory...
[2017-03-28T13:29:32-04:00] INFO: Generating Habitat plan at /var/folders/v5/z54gb76j2rs3wrn65hmtyf1r0000gp/T/inspec-habitat-exporter20170328-4932-kg2ltd/habitat/plan.sh...
[2017-03-28T13:29:32-04:00] INFO: Generating a Habitat run hook at /var/folders/v5/z54gb76j2rs3wrn65hmtyf1r0000gp/T/inspec-habitat-exporter20170328-4932-kg2ltd/habitat/hooks/run...
[2017-03-28T13:29:32-04:00] INFO: Generating Habitat's default.toml configuration...
[2017-03-28T13:29:32-04:00] INFO: Building our Habitat artifact...
hab-studio: Destroying Studio at /hab/studios/src (default)
hab-studio: Creating Studio at /hab/studios/src (default)
hab-studio: Importing adamleff secret origin key
» Importing origin key from standard input
★ Imported secret origin key adamleff-20160617201047.
» Installing core/hab-backline
↓ Downloading core/hab-backline/0.19.0/20170311034116
2.17 KB / 2.17 KB / [=========================================================================] 100.00 % 4.33 MB/s
... more Chef Habitat output here...
[2017-03-28T13:30:18-04:00] INFO: Copying artifact to /Users/aleff...
```
### inspec habitat profile setup
Create a Chef Habitat directory that includes a plan file in a profile directory.
This is the same process that is used by `inspec habitat profile create` - but
this adds the generated Chef Habitat directory and file to your system so that
you can commit them to source control. If you commit these files to GitHub, you
can connect that plan to the [Chef Habitat Builder Service](https://www.habitat.sh/docs/using-builder/).
#### Syntax
```bash
inspec habitat profile setup PROFILE_DIRECTORY
```
#### Example
```bash
inspec habitat profile setup ~/profiles/frontend1
```
#### Example Output
```bash
[2018-10-31T23:45:59+00:00] INFO: Setting up profile at /home/nell/profiles/frontend1/ for Habitat...
[2018-10-31T23:45:59+00:00] INFO: Checking to see if the profile is valid...
[2018-10-31T23:45:59+00:00] INFO: Profile is valid.
[2018-10-31T23:45:59+00:00] INFO: Profile's dependencies are already vendored, skipping vendor process.
[2018-10-31T23:45:59+00:00] INFO: Generating Habitat plan at /home/nell/profiles/frontend1/habitat/plan.sh...
```
### inspec habitat profile upload
Create and then upload a Chef Habitat package for a Chef InSpec profile. Like
the `inspec habitat profile create` command, Chef InSpec will validate the profile,
fetch and vendor any dependencies (if necessary), and build the Chef Habitat
package with a dependency on the latest InSpec. However, instead of saving the
package locally to the workstation, Chef InSpec will upload it to the depot
defined in the `HAB_DEPOT` environment variable. If `HAB_DEPOT` is not defined,
the package will be uploaded to the public Chef Habitat depot at
[https://app.habitat.sh](https://app.habitat.sh).
#### Syntax
```bash
inspec habitat profile upload PROFILE_DIRECTORY
```
#### Example
```bash
inspec habitat profile upload ~/profiles/frontend1
```
#### Example Output
```text
[2017-03-28T13:29:32-04:00] INFO: Creating a Habitat artifact for profile: /Users/aleff/profiles/frontend1
[2017-03-28T13:29:32-04:00] INFO: Checking to see if Habitat is installed...
[2017-03-28T13:29:32-04:00] INFO: Copying profile contents to the work directory...
[2017-03-28T13:29:32-04:00] INFO: Generating Habitat plan at /var/folders/v5/z54gb76j2rs3wrn65hmtyf1r0000gp/T/inspec-habitat-exporter20170328-4932-kg2ltd/habitat/plan.sh...
[2017-03-28T13:29:32-04:00] INFO: Generating a Habitat run hook at /var/folders/v5/z54gb76j2rs3wrn65hmtyf1r0000gp/T/inspec-habitat-exporter20170328-4932-kg2ltd/habitat/hooks/run...
[2017-03-28T13:29:32-04:00] INFO: Generating Habitat's default.toml configuration...
[2017-03-28T13:29:32-04:00] INFO: Building our Habitat artifact...
hab-studio: Destroying Studio at /hab/studios/src (default)
hab-studio: Creating Studio at /hab/studios/src (default)
hab-studio: Importing adamleff secret origin key
» Importing origin key from standard input
★ Imported secret origin key adamleff-20160617201047.
» Installing core/hab-backline
↓ Downloading core/hab-backline/0.19.0/20170311034116
2.17 KB / 2.17 KB / [=========================================================================] 100.00 % 4.33 MB/s
... more Chef Habitat output here...
[2017-03-28T13:30:18-04:00] INFO: Uploading the Habitat artifact to our Depot...
[2017-03-28T13:30:23-04:00] INFO: Upload complete!
```

View file

@ -0,0 +1,422 @@
+++
title = "Chef InSpec Inputs"
draft = false
[menu]
[menu.inspec]
title = "Inputs"
identifier = "inspec/reference/inputs.md Inputs"
parent = "inspec/reference"
weight = 30
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/inputs.md)
## What are Inputs?
Inputs are the "knobs" you can use to customize the behavior of Chef InSpec profiles.
If a profile supports inputs, you can set the inputs in a variety of ways, allowing
flexibility. Profiles that include other profiles can set inputs in the included
profile, enabling a multi-layered approach to configuring profiles.
### A Simple Example
Suppose you have a profile named `rock_critic`. In its profile metadata file (inspec.yml):
```yaml
# Optionally declare inputs in the profile metadata
# This lets you set up things like type checking, etc.
inputs:
- name: amplifier_max_volume
description: How loud the amplifiers can go
type: numeric
# More options, including value: and priority: are possible here
```
In the profile's control code:
```ruby
# Set a default value for an input. This is optional.
input('amplifier_max_volume', value: 10)
control 'Big Rock Show' do
describe input('amplifier_max_volume') do # This line reads the value of the input
it { should cmp 11 } # The UK'S LOUDEST BAND
end
end
```
When the above profile is executed by using `inspec exec rock_critic`, you would see something like:
```
× Big Rock Show: 10
× 10 is expected to cmp == 11
expected: 11
got: 10
(compared using `cmp` matcher)
Profile Summary: 0 successful controls, 1 control failure, 0 controls skipped
```
That result clearly won't do. Let's override the input's default value.
We can now run that profile with `inspec exec rock_critic --input amplifier_max_volume=11`:
```
✔ Big Rock Show: 11
✔ 11 is expected to cmp == 11
Profile Summary: 1 successful control, 0 control failures, 0 controls skipped
```
### Which profiles support inputs?
The best way for a profile to indicate it supports inputs is to list them in the
metadata file, `inspec.yml`. Any profile that has an `inputs` (or the deprecated
`attributes`) section in its `inspec.yml` metadata file is
[configuring](#configuring-inputs-in-profile-metadata) inputs.
That said, any profile that uses the DSL keyword `input()` (or the deprecated
`attribute()`) in the control source code supports inputs. These profiles are
*reading* (and possibly setting) input values and using them to make decisions.
### How can I set Inputs?
As installed (without specialized plugins), Chef InSpec supports several ways of setting inputs:
- Inline in control code, using `input('input_name', value: 42)`.
- In profile `inspec.yml` metadata files
- Using the CLI option `--input name1=value1 name2=value2...` to read directly from the command line
- Using the CLI option `--input-file somefile.yaml` to read inputs from files
- In kitchen-inspec, using the `verifier/inputs` settings
- In the Audit Cookbook, using the `node[:audit][:inputs]`
In addition, Chef InSpec supports Input Plugins, which can provide optional integrations to specific key-value stores.
### How does Input precedence work?
#### Simple Precedence
Briefly:
inline DSL < metadata < ( cli-input-file or kitchen-inspec or audit-cookbook ) < cli --input
In addition, for inherited profiles:
dependent profile metadata < wrapper profile metadata
This precedence lets you override input values on the command line, as well as
override child profile inline values from the parent profile.
This description matches the general behavior of InSpec v3, while also making
some edge cases easier to reason.
#### The Details of Input Precedence
Whenever an input provider sets a value on an input, a *priority value* is
assigned to the operation. Over the life of the input, multiple assignments with
varying priority values may occur. When the input is evaluated, the current value
is determined by finding the setting event with the highest priority.
Note that this approach does not rely on execution order, nor does it rely on
multiple named precedence levels. Each setting operation is preserved and this
allows the user to [debug](#debugging-inputs-with-the-event-log) the history of
the input values.
Some input providers allow you to set a priority when you set the value. For
example, to set a priority of 50 in a metadata file, use:
```yaml
inputs:
- name: very_important_input
value: 12
priority: 50
```
To set a priority in DSL, use:
```ruby
input('also_important', value: 42, priority: 45)
```
As packaged, Chef InSpec uses the following priority values:
| Input Provider | Priority | May change priority |
| -------------------------------------- | -------- | ------------------- |
| Inline DSL | 20 | Yes |
| Metadata | 30 | Yes |
| Metadata in a wrapper cookbook | 35 | Yes |
| CLI `--input-file` option | 40 | No |
| inspec-kitchen `inputs:` section | 40 | No |
| audit cookbook `node[:audit][:inputs]` | 40 | No |
| CLI `--input` option | 50 | No |
### What happened to "Attributes"?
When originally introduced, the Input facility was named *Attributes*. This name
was problematic, because:
- The Chef Infra tool uses the same word to describe its parameterization system.
- Chef Infra attributes have a completely different and much more complex precedence system.
- This caused confusion about passing Chef Infra attributes into InSpec when using Audit Cookbook and kitchen-inspec.
Based on these concerns, InSpec attributes have been renamed to InSpec inputs in Chef InSpec v4.
Support for using the DSL keyword `attribute()`, the metadata field `attributes:`, and the corresponding kitchen-inspec and audit cookbook values are anticipated to continue through Chef InSpec v5.
## Working with Inputs in Control Code
### Input Scope
Inputs are available throughout the InSpec profile DSL. You can use them anywhere.
```ruby
# some_controls.rb
input('outer_input', value: 1) # here
control 'control-1' do
input('control_dsl_input', value: 2) # here too
describe some_resource do
input('test_dsl_input', value: 3) # even here
it { should cmp input('expectation_dsl_input') } # and yes here too
end
end
```
### Setting Inputs in Control DSL
When you write `input('some_name', value: 'some_value')`, you are *setting* an
input value in the DSL. Because the `value:` option is present, a new value will
be set. You may also pass any other option listed in the
[input option reference](#input-options-reference).
### Reading Inputs in Control DSL
When you call `input('some_name')`, with or without additional options, the value
of the input will be resolved and returned. Note that this process may involve
sourcing the value from another provider, using the value set in DSL, or overriding
the value provided in the same call.
```ruby
# You can use the value in a Ruby variable
some_var = input('some_input_name')
# Or more directly in a resource parameter
describe file(input('important_path')) do
it { should exist }
end
# Or as the resource itself (this could be a string, here)
describe input('some_setting') do
it { should cmp 'correct_value' }
end
# Or as the expected value
describe file('/etc/httpd/httpd.conf') do
its('owner') { should_not cmp input('webserver_user') }
end
```
The value returned can be used anywhere a Ruby value is used.
## Configuring Inputs in Profile Metadata
Each Chef InSpec profile has a metadata file at the top level named `inspec.yml`.
In that file, you may add a section for inputs. You may define inputs there,
clearly setting options including values, type checking, and whether the input is
required.
```yaml
name: my_profile
inputs:
- name: webserver_user # Name is the only required field
- name: favorite_fruit
value: banana # You can set a value; priority is 30 for metadata
- name: meaning_of_life
type: Numeric
value: 42
required: true
priority: 70
```
All [input options](#input-options-reference) are supported in metadata files.
There are two major advantages to defining inputs in profile metadata:
1. The inputs and their configuration are listed explicitly in simple YAML in
one place - a consumer of your profile does not need to read through the control
code to find the inputs.
1. You can set inputs in other profiles that you depend on using profile inheritance.
### Using inputs with Profile inheritance
When your profile relies on another profile using the `depends` key in the metadata file, you can set — that is, override — the value of the input in the dependent profile by including the `profile` option and naming the dependent profile.
```yaml
# child inspec.yml
name: child
inputs:
- name: favorite_food
value: pizza
```
```yaml
# wrapper inspec.yml
name: wrapper
depends:
- name: child
path: ../child
inputs:
- name: favorite_food
value: broccoli
profile: child # <----- REQUIRED to override the value in InSpec 4
```
In Chef InSpec 4+, every input is namespaced. For example, you could have an
input named `wrapper/favorite_food` and one named `child/favorite_food`. If no
explicit profile option is set within the `wrapper` profile metadata file, then
`wrapper` is assumed to be the profile.
## Setting Input values using `--input-file`
You may also provide inputs and values via YAML files on the command line. The
format can be seen below:
```yaml
an_input: a_value
another_input: another_value
```
CLI-input-file-set inputs have a priority of 40.
As of Chef InSpec 4.3.2, this mechanism has the following limitations:
1. No [input options](#input-options-reference) may be set - only the name and value.
1. Because the CLI is outside the scope of any individual profile and the inputs
don't take options, the inputs are clumsily copied into every profile,
effectively making the CLI mechanism global.
## Setting Input values using `--input`
You may also provide inputs and values directly on the command line:
```yaml
inspec exec my_profile --input input_name=input_value
```
To set multiple inputs, say:
```yaml
inspec exec my_profile --input input_name1=input_value1 name2=value2
```
If a CLI input value resembles a number, it will be converted to an Integer or
Float. Scientific notation is not currently recognized.
```yaml
inspec exec my_profile --input amplifier_volume=-11
inspec exec my_profile --input water_depth=11.5
```
You may set inputs with complex values, such as arrays and hashes using either
YAML or JSON syntax. Just be sure to protect the string from the shell using single
quotes.
```yaml
inspec exec my_profile --input alphabet='[a,b,c]'
inspec exec my_profile --input fruits='{a: apples, b: bananas, c: cantelopes}'
inspec exec my_profile --input json_fruit='{"a": "apples", "g": ["grape01", "grape02"] }'
```
Do not repeat the `--input` flag; that will override the previous setting.
CLI-set inputs have a priority of 50.
As of Chef InSpec 4.12, this mechanism has the following limitations:
1. No [input options](#input-options-reference) may be set - only the name and
value.
1. Because the CLI is outside the scope of any individual profile and the inputs
don't take options, the inputs are clumsily copied into every profile,
effectively making the CLI mechanism global.
## Input Options Reference
### Name
Required `String`. This option identifies the input.
Allowed in: All. When used in DSL and Metadata, the name is unique within the
current profile. When used in CLI input files, audit cookbook, and kitchen-inspec,
the input is copied across all profiles using the same name.
### Description
Optional `String`. Human-meaningful explanation of the input.
Allowed in: DSL, Metadata
### Value
Optional, any Ruby or YAML type. This is the value that will be available when
you read the input. See the [Reading Inputs](#reading-inputs-in-control-dsl) section
for more information.
Allowed in: All
### Type
Optional, `String`. This value must be one of `String`, `Numeric`, `Regexp`,
`Array`, `Hash`, `Boolean`, or `Any`. If provided, the value of the input will
be checked to see if it is of the corresponding type. Note that `Regexp` indicates
that the input value itself should be a regular expression, not that it should
match any particular regular expression.
Allowed in: DSL, Metadata
### Required
Optional, `true` or `false`. If `true`, a control using the input will be failed
if it [reads](#reading-inputs-in-control-dsl) the value when none has been set.
Allowed in: DSL, Metadata
### Priority
Optional, `Integer`, 0-100. Higher values make this assignment have higher
precedence. This is an advanced feature.
Allowed in: DSL, Metadata
### Profile
Optional, `String`. Allows you to set an input in another profile from your profile.
Allowed in: DSL, Metadata
## Advanced Topics
### Debugging Inputs with the Event Log
If it is difficult to determine why a particular value is being used, you can use
the Event Log to determine what is happening.
First, use the `input_object()` DSL method. This method is like `input()` in that
it looks up an input, but instead of evaluating the current value, it returns
the underlying `Inspec::Input` object.
```ruby
puts input_object('troublesome_input').diagnostic_string
# Or
require 'pp'
pp input_object('troublesome_input').events
```
`diagnostic_string` assembles the Event Log into a printable log message for
convenience.
The Event Log contains entries for every time that the value changed, as well as
one for when the input was first created. When possible, stack probing is used
to determine file and line numbers. Most importantly, you will see priority numbers;
remember that highest priority wins; order only matters to break a tie.

View file

@ -0,0 +1,137 @@
+++
title = "Chef InSpec and Friends"
draft = false
[menu]
[menu.inspec]
title = "Chef InSpec and Friends"
identifier = "inspec/inspec_and_friends.md Chef InSpec and friends"
parent = "inspec"
weight = 40
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/inspec_and_friends.md)
This page looks at projects that are similar to Chef InSpec to explain how they
relate to each other.
## RSpec
RSpec is an awesome framework that is widely used by software engineers to test
Ruby code. It enables test-driven development (TDD) and helps developers to write
better code every day.
Chef InSpec is built on top of RSpec and uses it as the underlying foundation
to execute tests. It uses the key strengths of RSpec, easily execute
tests and a DSL to write tests, but extends the functionality for use as
compliance audits. Chef InSpec ships with custom audit resources that make it
easy to write audit checks and with the ability to run those checks on
remote servers. These audit resources provided know the differences
between operating systems and help you abstract from the local operating
system, similar to other resources you might use in your Chef recipes.
A complete Chef InSpec rule looks like:
```ruby
control "sshd-11" do
impact 1.0
title "Server: Set protocol version to SSHv2"
desc "Set the SSH protocol version to 2. Don't use legacy
insecure SSHv1 connections anymore."
tag security: "level-1"
tag "openssh-server"
ref "Server Security Guide v.1.0", url: "http://..."
describe sshd_config do
its('Protocol') { should eq('2') }
end
end
```
That said, Chef InSpec is not RSpec. Some key differences:
- In InSpec, `describe` blocks should not be nested; instead use `control` blocks
to describe a higher-level grouping of tests.
- The RSpec `shared_example` construct is not supported. Instead, create a simple
custom resource that executes repetitious tasks.
- Chef InSpec is aimed at compliance practitioners and infrastructure testers, so
our focus is providing a few, well-supported, easy-to-use [universal matchers](/inspec/matchers/),
such as `cmp`. In contrast, RSpec is a tool designed for software engineers.
It thus supports a very large range of matchers, to enable testing of software
engineering constructs such as exceptions, Object Oriented Programming relationships,
and so on.
- While Chef InSpec uses parts of the RSpec project and codebase, it is a
separate project from InSpec. Rspec's release schedule and feature set are beyond
the control of the Chef InSpec team. While it is possible to use many of the
RSpec core features within Chef InSpec profiles, Chef InSpec can only guarantee
that the features described in the [InSpec documentation](/inspec/) will
function correctly. Some RSpec core functionality may be removed in future
versions of Chef InSpec as needed to ensure stability in the Chef InSpec project.
## Serverspec
Serverspec is the first extension of RSpec that enabled
users to run RSpec tests on servers to verify deployed artifacts. It was
created in March 2013 by Gosuke Miyashita and has been widely adopted.
It is also one of the core test frameworks within test-kitchen and has
been widely used within the Chef ecosystem. Chef InSpec takes lessons learned
implementing and using Serverspec and builds on them to make auditing
and compliance easier.
Lessons learned from Serverspec include:
- IT, compliance, and security professional require metadata beyond what Serverspec
offers, such as criticality, to fully describe controls.
- Setting up and running the same tests across multiple machines must be easy.
- It must be easy to locate, debug, and extend operating system-dependent code.
- It must be easy to extend the language and create custom resources.
- It must run multiple tests simultaneously.
- Support for Windows is a first-class requirement.
- A command line interface (CLI) is required for faster iteration of test code.
You can also watch this [podcast](http://foodfightshow.org/2016/02/inspec.html)
to find out more on the relationship of Chef InSpec and Serverspec.
### How is Chef InSpec different from Serverspec
One of the key differences is that Chef InSpec targets more user groups. It
is optimized for DevOps, Security, and Compliance professionals.
Additional metadata, such as impact, title, and description, make it
easier to fully describe the controls which makes it easier to share the
controls with other departments. This enables Security departments to
prioritize rules. DevOps teams use this information to focus on the most
critical issues to remediate.
```ruby
control "sshd-11" do
impact 1.0
title "Server: Set protocol version to SSHv2"
desc "Set the SSH protocol version to 2. Don't use legacy
insecure SSHv1 connections anymore."
tag security: "level-1"
tag "openssh-server"
ref "Server Security Guide v.1.0" url: "http://..."
describe sshd_config do
its('Protocol') { should cmp 2 }
end
end
```
**Why not fork Serverspec?**
Chef InSpec started as an extension of Serverspec. As the extension grew, it
became clear that a new library was required. Creating and maintaining a
fork was not practical so a new project was born.
**Will Chef InSpec only work on machines managed by Chef?**
No, Chef InSpec can be used on any machine. It doesnt matter if that machine
was configured by Chef or configured lovingly by the hands of your local
System Administrator.
**Is Chef InSpec a replacement of Serverspec?**
Chef InSpec is intended to be a drop-in replacement of Serverspec. Popular
Serverspec resources have been ported to InSpec. It changed some
behaviour as documented in our migration guide.

View file

@ -0,0 +1,153 @@
+++
title = "Install and Uninstall"
draft = false
[menu]
[menu.inspec]
title = "Install and Uninstall"
identifier = "inspec/install.md Install and Uninstall"
parent = "inspec"
weight = 20
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/install.md)
Users can choose between operating systems of MacOS, Windows, and Linux for Chef InSpec.
## Install Chef InSpec
You can download the latest Chef InSpec package relevant to your operating system
at [our Downloads Page](https://downloads.chef.io/inspec).
Alternatively, Chef InSpec can be installed via installer, script, or package
manager, according to your operating system and method as listed below.
### macOS
#### Homebrew
Chef InSpec is available as a standalone [Homebrew](https://brew.sh/) package.
Run the following command in your terminal to install Chef InSpec:
```
brew cask install chef/chef/inspec
```
While this command is running, you may be prompted to enter your macOS user account
password for installation to complete.
#### CLI
You can download Chef InSpec via curl script:
```
curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P inspec
```
### Windows
#### Installer
Once you downloaded the latest [Chef InSpec package](https://downloads.chef.io/inspec)
relevant to your Microsoft version, double-click the `.msi` file to launch the
installer and follow the prompts.
#### Powershell
Use the following command to install Chef InSpec via Powershell script:
```powershell
. { iwr -useb https://omnitruck.chef.io/install.ps1 } | iex; install -project inspec
```
Once Chef InSpec is installed, run `inspec version` to verify that the installation
was successful.
### Linux
#### CLI
The following curl script will install Chef InSpec for Ubuntu and Red Hat Enterprise Linux:
```
curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P inspec
```
If you prefer, you can use a package manager to install Chef InSpec.
Once you downloaded the latest [Chef InSpec package](https://downloads.chef.io/inspec)
relevant to your Linux-based platform, use the command for the respective package
manager listed below. Replace the example file path with the file path leading to
your downloaded package.
For Ubuntu, use the following command to install Chef InSpec:
```
sudo dpkg -i /path/to/inspec.deb
```
For Red Hat Enterprise Linux, use the following command to install Chef InSpec:
```
sudo rpm -U /path-to/inspec.rpm
```
For SUSE Linux Enterprise Server, use the following command to install Chef InSpec:
```
sudo zypper install /path-to/inspec.rpm
```
## Uninstall Chef InSpec
Chef InSpec can be uninstalled using the steps below that are appropriate for the
method of Chef InSpec installation.
### macOS
#### Homebrew
Use the following *destructive* command to remove the Chef InSpec standalone Homebrew package:
```
brew cask uninstall inspec
```
#### CLI
Use the following *destructive* command in your terminal to remove the Chef InSpec package:
```
sudo rm -rf /opt/inspec
```
### Windows
#### Installer
Use *Add / Remove Programs* to remove Chef InSpec.
### Linux
#### CLI
The supported Linux-based platforms and their respective *destructive* command
for their package manager are listed below.
For Ubuntu, use the following *destructive* command to uninstall:
```
sudo dpkg -P inspec
```
For Red Hat Enterprise Linux, use the following *destructive* command to uninstall:
```
sudo rpm -e inspec
```
For SUSE Linux Enterprise Server, use the following *destructive* command to uninstall Chef InSpec:
```
sudo zypper remove inspec
```

View file

@ -0,0 +1,173 @@
+++
title = "Chef InSpec Universal Matchers Reference"
draft = false
[menu]
[menu.inspec]
title = "Matchers"
identifier = "inspec/reference/matchers.md Matchers"
parent = "inspec/reference"
weight = 40
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/matchers.md)
Chef InSpec uses matchers to help compare resource values to expectations.
The following matchers are available:
You may also use any matcher provided by [RSpec::Expectations](https://relishapp.com/rspec/rspec-expectations/docs),
but those matchers are outside of InSpec's [scope of support](/inspec/inspec_and_friends/#rspec).
The following InSpec-supported universal matchers are available:
- [`be`](#be) - make numeric comparisons
- [`be_in`](#be_in) - look for the property value in a list
- [`cmp`](#cmp) - general-use equality (try this first)
- [`eq`](#eq) - type-specific equality
- [`include`](#include) - look for an expected value in a list-valued property
- [`match`](#match) - look for patterns in text using regular expressions
See [Explore Chef InSpec resources](https://learn.chef.io/modules/explore-inspec-resources#/)
on Learn Chef Rally to learn more about InSpec's built-in matchers.
## be
This matcher can be followed by many different comparison operators.
Always make sure to use numbers, not strings, for these comparisons.
```ruby
describe file('/proc/cpuinfo') do
its('size') { should be >= 10 }
its('size') { should be < 1000 }
end
```
## cmp
Unlike `eq`, `cmp` is a matcher for less-restrictive comparisons. It will
try to fit the actual value to the type you are comparing it to. This is
meant to relieve the user from having to write type-casts and
resolutions.
```ruby
describe sshd_config do
its('Protocol') { should cmp 2 }
end
describe passwd.uid(0) do
its('users') { should cmp 'root' }
end
```
`cmp` behaves in the following way:
* Compare strings to numbers
```ruby
describe sshd_config do
# Only `'2'` works
its('Protocol') { should eq '2' }
# Both of these work
its('Protocol') { should cmp '2' }
its('Protocol') { should cmp 2 }
end
```
* String comparisons are not case-sensitive
```ruby
describe auditd_conf do
its('log_format') { should cmp 'raw' }
its('log_format') { should cmp 'RAW' }
end
```
* Recognize versions embedded in strings
```ruby
describe package('curl') do
its('version') { should cmp > '7.35.0-1ubuntu2.10' }
end
```
* Compare arrays with only one entry to a value
```ruby
describe passwd.uids(0) do
its('users') { should cmp 'root' }
its('users') { should cmp ['root'] }
end
```
* Single-value arrays of strings may also be compared to a regex
```ruby
describe auditd_conf do
its('log_format') { should cmp /raw/i }
end
```
* Improved printing of octal comparisons
```ruby
describe file('/proc/cpuinfo') do
its('mode') { should cmp '0345' }
end
expected: 0345
got: 0444
```
## eq
Test for exact equality of two values.
```ruby
describe sshd_config do
its('RSAAuthentication') { should_not eq 'no' }
its('Protocol') { should eq '2' }
end
```
`eq` fails if types don't match. Please keep this in mind, when comparing
configuration entries that are numbers:
```ruby
its('Port') { should eq '22' } # ok
its('Port') { should eq 22 }
# fails: '2' != 2 (string vs int)
```
For less restrictive comparisons, please use `cmp`.
## include
Verifies if a value is included in a list.
```ruby
describe passwd do
its('users') { should include 'my_user' }
end
```
## be_in
Verifies that an item is included in a list.
```ruby
describe resource do
its('item') { should be_in LIST }
end
```
## match
Check if a string matches a regular expression.
```ruby
describe sshd_config do
its('Ciphers') { should_not match /cbc/ }
end
```

View file

@ -0,0 +1,301 @@
+++
title = "Chef InSpec Migration Guide"
draft = false
[menu]
[menu.inspec]
title = "Migration from Serverspec"
identifier = "inspec/reference/migration.md Migration from Serverspec"
parent = "inspec/reference"
weight = 130
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/migration.md)
## How is Chef InSpec different from Serverspec
We've written a complete blog post about that topic: [The Road to InSpec](https://blog.chef.io/2015/11/04/the-road-to-inspec/)
## Is Chef InSpec suitable for infrastructure testing?
Chef InSpec is a framework that allows you to run infrastructure testing as well as compliance testing. The compliance features are always optional and provide customers a way to use Chef InSpec for both use-cases. To ensure we build the best infrastructure testing, we migrate our cookbooks [chef-cookbooks](https://github.com/chef-cookbooks) to InSpec.
## Which Serverspec resources are available in InSpec?
The following resources are available in InSpec:
| Serverspec | Chef InSpec |
|:------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------:|
| [`bond`](http://serverspec.org/resource_types.html#bond) | [`bond`](/inspec/resources/bond/) |
| [`bridge`](http://serverspec.org/resource_types.html#bridge) | [`bridge`](/inspec/resources/bridge/) |
| [`command`](http://serverspec.org/resource_types.html#command) | [`command`](/inspec/resources/command/) |
| [`cron`](http://serverspec.org/resource_types.html#cron) | [`crontab`](/inspec/resources/crontab/) |
| [`docker_container`](http://serverspec.org/resource_types.html#docker_container) | [`docker_container`](/inspec/resources/docker_container/) |
| [`docker_image`](http://serverspec.org/resource_types.html#docker_image) | [`docker_image`](/inspec/resources/docker_image/) |
| [`file`](http://serverspec.org/resource_types.html#file) | [`file`](/inspec/resources/file/) |
| [`group`](http://serverspec.org/resource_types.html#group) | [`group`](/inspec/resources/group/) |
| [`host`](http://serverspec.org/resource_types.html#host) | [`host`](/inspec/resources/host/) |
| [`interface`](http://serverspec.org/resource_types.html#interface) | [`interface`](/inspec/resources/interface/) |
| [`iis_website`](http://serverspec.org/resource_types.html#iis_website) | [`iis_site`](/inspec/resources/iis_site/) |
| [`iis_app_pool`](http://serverspec.org/resource_types.html#iis_app_pool) | [`iis_app`](/inspec/resources/iis_app/) |
| [`iptables`](http://serverspec.org/resource_types.html#iptables) | [`iptables`](/inspec/resources/iptables/) |
| [`kernel_module`](http://serverspec.org/resource_types.html#kernel_module) | [`kernel_module`](/inspec/resources/kernel_module/) |
| [`linux_kernel_parameter`](http://serverspec.org/resource_types.html#linux_kernel_parameter) | [`kernel_parameter`](/inspec/resources/kernel_parameter/) |
| [`mysql_config`](http://serverspec.org/resource_types.html#mysql_config) | [`mysql_conf`](/inspec/resources/mysql_conf/) |
| [`package`](http://serverspec.org/resource_types.html#package) | [`package`](/inspec/resources/package/) |
| [`port`](http://serverspec.org/resource_types.html#port) | [`port`](/inspec/resources/port/) |
| [`ppa`](http://serverspec.org/resource_types.html#ppa) | [`apt`](/inspec/resources/apt/) |
| [`process`](http://serverspec.org/resource_types.html#process) | [`processes`](/inspec/resources/processes/) |
| [`service`](http://serverspec.org/resource_types.html#service) | [`service`](/inspec/resources/service/) |
| [`user`](http://serverspec.org/resource_types.html#user) | [`user`](/inspec/resources/user/) |
| [`windows_feature`](http://serverspec.org/resource_types.html#windows_feature) | [`windows_feature`](/inspec/resources/windows_feature/) |
| [`windows_registry_key`](http://serverspec.org/resource_types.html#windows_registry_key) | [`registry_key`](/inspec/resources/registry_key/) |
| [`x509_certificate`](http://serverspec.org/resource_types.html#x509_certificate) | [`x509_certificate`](/inspec/resources/x509_certificate/) |
| [`yumrepo`](http://serverspec.org/resource_types.html#yumrepo) | [`yum`](/inspec/resources/yum/) |
| [`zfs`](http://serverspec.org/resource_types.html#zfs) | [`zfs_pool`](/inspec/resources/zfs_pool/) |
Some Serverspec resources are not available yet. We will implement those resources based on user feedback. If you need a resource that is not available in InSpec, please open an [Github issue](https://github.com/chef/inspec/issues). The list of resources that are not available in InSpec:
* [`cgroup`](http://serverspec.org/resource_types.html#cgroup)
* [`default_gateway`](http://serverspec.org/resource_types.html#default_gateway)
* [`ip6tables`](http://serverspec.org/resource_types.html#ip6tables)
* [`ipfilter`](http://serverspec.org/resource_types.html#ipfilter)
* [`ipnat`](http://serverspec.org/resource_types.html#ipnat)
* [`linux_audit_system`](http://serverspec.org/resource_types.html#linux_audit_system)
* [`lxc`](http://serverspec.org/resource_types.html#lxc)
* [`mail_alias`](http://serverspec.org/resource_types.html#mail_alias)
* [`php_config`](http://serverspec.org/resource_types.html#php_config)
* [`routing_table`](http://serverspec.org/resource_types.html#routing_table)
* [`selinux`](http://serverspec.org/resource_types.html#selinux)
* [`selinux_module`](http://serverspec.org/resource_types.html#selinux_module)
* [`x509_private_key`](http://serverspec.org/resource_types.html#x509_private_key)
In addition Chef InSpec provides additional [resources](/inspec/resources/) that are not available in Serverspec:
* [`apache_conf`](/inspec/resources/apache_conf/)
* [`apt`](/inspec/resources/apt/)
* [`audit_policy`](/inspec/resources/audit_policy/)
* [`auditd_conf`](/inspec/resources/auditd_conf/)
* [`bash`](/inspec/resources/bash/)
* [`csv`](/inspec/resources/csv/)
* [`etc_shadow`](/inspec/resources/etc_shadow/)
* [`gem`](/inspec/resources/gem/)
* [`grub_conf`](/inspec/resources/grub_conf/)
* [`inetd_conf`](/inspec/resources/inetd_conf/)
* [`ini`](/inspec/resources/ini/)
* [`json`](/inspec/resources/json/)
* [`npm`](/inspec/resources/npm/)
* [`ntp_conf`](/inspec/resources/ntp_conf/)
* [`oneget`](/inspec/resources/oneget/)
* [`pip`](/inspec/resources/pip/)
* [`powershell`](/inspec/resources/powershell/)
* [`security_policy`](/inspec/resources/security_policy/)
* [`ssh_config`](/inspec/resources/ssh_config/)
* [`sshd_config`](/inspec/resources/sshd_config/)
* [`sys_info`](/inspec/resources/sys_info/)
## How do I migrate my Serverspec tests to InSpec
For most cases, the migration to Chef InSpec is pretty straight forward. First, replace the current verifier in `kitchen.yml` configuration with:
```
verifier:
name: inspec
```
Second, rename the directory `test/integration/default/serverspec` to
`test/integration/default/inspec`
Third, remove the Serverspec-specific code from the test files.
```
require 'serverspec'
# Required by serverspec
set :backend, :exec
```
Chef InSpec is now configured with Test-Kitchen:
```
kitchen verify package-install-centos-72
-----> Starting Kitchen (v1.14.2)
-----> Verifying <package-install-centos-72>...
Detected alternative framework tests for `inspec`
Loaded
Target: ssh://vagrant@127.0.0.1:2200
PHP has
✔ php
✔ the pear.php.net channel
✔ the pecl.php.net channel
Test Summary: 3 successful, 0 failures, 0 skipped
Finished verifying <package-install-centos-72> (0m0.40s).
-----> Kitchen is finished. (0m3.31s)
```
Some real-world migrations are available:
* [docker](https://github.com/chef-cookbooks/docker)
* [nginx](https://github.com/chef-cookbooks/chef_nginx/pull/5/files)
* [mysql](https://github.com/chef-cookbooks/mysql/pull/430/files)
* [php](https://github.com/chef-cookbooks/php/pull/189/files)
Some general recommendations:
* use test-kitchen 1.14+
* in case of errors, increase the log level `kitchen verify package-install-centos-72 -l debug`
## Do I still need the backend configuration?
Chef InSpec does not attach backend information to test files. All tests are defined independently of any backend. Therefore a Serverspec test file:
```
require 'serverspec'
# Required by serverspec
set :backend, :exec
describe 'PHP' do
it 'has php' do
expect(command('php -v').exit_status).to eq(0)
end
it 'has the pear.php.net channel' do
expect(command('pear list-channels').stdout).to include('pear.php.net')
end
it 'has the pecl.php.net channel' do
expect(command('pear list-channels').stdout).to include('pecl.php.net')
end
end
```
will become the following Chef InSpec test file:
```
describe 'PHP' do
it 'has php' do
expect(command('php -v').exit_status).to eq(0)
end
it 'has the pear.php.net channel' do
expect(command('pear list-channels').stdout).to include('pear.php.net')
end
it 'has the pecl.php.net channel' do
expect(command('pear list-channels').stdout).to include('pecl.php.net')
end
end
```
As you can see, the Chef InSpec test files just focuses on tests and tries to avoid all clutter.
## Nested describe blocks
Serverspec and RSpec allow you to define nested describe blocks. We did a survey and found out that most users use nested describe blocks only to improve their output report. We believe the code structure should not change to improve the output of a report. Nevertheless we understand that nested describe blocks help you to structure test code. A sample code block looks like:
```
describe 'chef-server-directories' do
describe file('/etc/opscode') do
it { should be_directory }
it { should be_owned_by 'root' }
end
describe file('/etc/opscode-analytics') do
it { should be_directory }
it { should be_owned_by 'opscode' }
it { should be_grouped_into 'opscode' }
end
describe file('/var/log/opscode') do
it { should be_directory }
it { should be_owned_by 'opscode' }
it { should be_grouped_into 'opscode' }
end
describe file('/var/opt/opscode') do
it { should be_directory }
it { should be_owned_by 'root' }
end
end
```
In Chef InSpec you would split up groups into files.
```
tests
├── server-directories.rb
├── other-tests.rb
└── further-tests.rb
```
Each file can have a top-level description of its content:
```
title "Chef Server Directories"
describe file('/etc/opscode') do
it { should be_directory }
it { should be_owned_by 'root' }
end
describe file('/etc/opscode-analytics') do
it { should be_directory }
it { should be_owned_by 'opscode' }
it { should be_grouped_into 'opscode' }
end
describe file('/var/log/opscode') do
it { should be_directory }
it { should be_owned_by 'opscode' }
it { should be_grouped_into 'opscode' }
end
describe file('/var/opt/opscode') do
it { should be_directory }
it { should be_owned_by 'root' }
end
```
## Are you supporting the `expect` syntax?
Of course. We still prefer the `should` syntax for UX reasons. We did surveys with various types of customers like devops engineers, auditors, managers. All participants who preferred the `expect` syntax have been Ruby experts. All non-Ruby developers found it easier to understand the `should` syntax.
### `should` syntax with InSpec
```
describe command('php -v') do
its('exit_status') { should eq 0 }
end
describe command('pear list-channels') do
its('stdout') { should include('pear.php.net')}
end
describe command('pear list-channels') do
its('stdout') { should include('pecl.php.net')}
end
```
### `expect` syntax with InSpec
```
describe 'PHP' do
it 'has php' do
expect(command('php -v').exit_status).to eq(0)
end
it 'has the pear.php.net channel' do
expect(command('pear list-channels').stdout).to include('pear.php.net')
end
it 'has the pecl.php.net channel' do
expect(command('pear list-channels').stdout).to include('pecl.php.net')
end
end
```

View file

@ -0,0 +1,220 @@
+++
title = "Using Chef InSpec on Cloud Platforms"
draft = false
[menu]
[menu.inspec]
title = "Chef InSpec for the Cloud"
identifier = "inspec/platforms.md Using Chef InSpec on Cloud Platforms"
parent = "inspec"
weight = 30
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/platforms.md)
As of Chef InSpec 2.0, we have expanded our platform support beyond individual
machines and now include support for select AWS and Azure resources.
Using InSpec, you can use several Chef InSpec resources to audit properties of
your cloud infrastructure - for example, an Amazon Web Services S3 bucket.
## AWS Platform Support in InSpec
### Setting up AWS credentials for InSpec
Chef InSpec uses the standard AWS authentication mechanisms. Typically, you will
create an IAM user specifically for auditing activities.
1. Create an IAM user in the AWS console, with your choice of username. Check the
box marked "Programmatic Access."
1. On the Permissions screen, choose Direct Attach. Select the AWS-managed IAM
Profile named "ReadOnlyAccess." If you wish to restrict the user further, you
may do so; see individual Chef InSpec resources to identify which permissions
are required.
1. After generating the key, record the Access Key ID and Secret Key.
#### Using Environment Variables to provide credentials
You may provide the credentials to Chef InSpec by setting the following environment
variables: `AWS_REGION`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_KEY_ID`. You may
also use `AWS_PROFILE`, or if you are using MFA, `AWS_SESSION_TOKEN`. See the
[AWS Command Line Interface Docs](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html)
for details.
Once you have your environment variables set, you can verify your credentials by running:
```bash
you$ inspec detect -t aws://
== Platform Details
Name: aws
Families: cloud, api
Release: aws-sdk-v2.10.125
```
#### Using the Chef InSpec target option to provide credentials on AWS
Look for a file in your home directory named `~/.aws/credentials`. If it does not
exist, create it. Choose a name for your profile; here, we're using the name
'auditing'. Add your credentials as a new profile, in INI format:
```bash
[auditing]
aws_access_key_id = AKIA....
aws_secret_access_key = 1234....abcd
```
You may now run Chef InSpec using the `--target` / `-t` option, using the format
`-t aws://region/profile`. For example, to connect to the Ohio region using a
profile named 'auditing', use `-t aws://us-east-2/auditing`.
To verify your credentials, run
```bash
you$ inspec detect -t aws://
== Platform Details
Name: aws
Families: cloud, api
Release: aws-sdk-v2.10.125
```
## Azure Platform Support in InSpec
### Setting up Azure credentials for InSpec
To use Chef InSpec Azure resources, you will need to create a Service Principal
Name (SPN) for auditing an Azure subscription.
This can be done on the command line or from the Azure Portal:
- [Azure CLI](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authenticate-service-principal-cli)
- [PowerShell](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authenticate-service-principal)
- [Azure Portal](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal)
The information from the SPN can be specified either in the file
`~/.azure/credentials`, as environment variables, or by using Chef InSpec target URIs.
#### Setting up the Azure Credentials File
By default, Chef InSpec is configured to look at `~/.azure/credentials`, and it
should contain:
```powershell
[<SUBSCRIPTION_ID>]
client_id = "<CLIENT_ID>"
client_secret = "<CLIENT_SECRET>"
tenant_id = "<TENANT_ID>"
```
{{< note >}}
In the Azure web portal, these values are labeled differently:
- The client_id is referred to as the 'Application ID'
- The client_secret is referred to as the 'Key (Password Type)'
- The tenant_id is referred to as the 'Directory ID'
{{< /note >}}
With the credentials are in place, you may now execute InSpec:
```bash
inspec exec my-inspec-profile -t azure://
```
#### Using Environment variables to provide credentials
You may also set the Azure credentials via environment variables:
- `AZURE_SUBSCRIPTION_ID`
- `AZURE_CLIENT_ID`
- `AZURE_CLIENT_SECRET`
- `AZURE_TENANT_ID`
For example:
```bash
AZURE_SUBSCRIPTION_ID="2fbdbb02-df2e-11e6-bf01-fe55135034f3" \
AZURE_CLIENT_ID="58dc4f6c-df2e-11e6-bf01-fe55135034f3" \
AZURE_CLIENT_SECRET="Jibr4iwwaaZwBb6W" \
AZURE_TENANT_ID="6ad89b58-df2e-11e6-bf01-fe55135034f3" inspec exec my-profile -t azure://
```
#### Using the Chef InSpec target option to provide credentials on Azure
If you have created a `~/.azure/credentials` file as above, you may also use the Chef InSpec command line `--target` / `-t` option to select a subscription ID. For example:
```bash
inspec exec my-profile -t azure://2fbdbb02-df2e-11e6-bf01-fe55135034f3
```
## GCP Platform Support in InSpec
### Setting up GCP credentials for InSpec
To use Chef InSpec GCP resources, you will need to install and configure the Google
Cloud SDK. Instructions for this pre-requisite can be found in the
[Google CLoud SDK documentation](https://cloud.google.com/sdk/docs/). Be sure
that your InSpec installation is the latest version. The minimal required InSpec
version is 3.0.25.
### Create an InSpec profile that makes use of `inspec-gcp`.
With a version of InSpec above 4.0.0, it is possible to create a profile with the
following command:
```
$ inspec init profile --platform gcp my-profile
Create new profile at /Users/me/my-profile
* Creating directory libraries
* Creating file README.md
* Creating directory controls
* Creating file controls/example.rb
* Creating file inspec.yml
* Creating file attributes.yml
* Creating file libraries/.gitkeep
```
Assuming the attributes yml file contains your GCP project ID, this sample
profile can then be executed using the following command:
```
inspec exec my-profile --attrs my-profile/attributes.yml -t gcp://
```
#### Setting up the GCP Credentials File
While InSpec can use user accounts for authentication,
[Google Cloud documentation](https://cloud.google.com/docs/authentication/)
recommends using service accounts. Following GCP best practices, first create a
service account with the scopes appropriate for your needs. See
[these instructions](https://cloud.google.com/docs/authentication/getting-started)
on creating a service account.
Then, download the credential JSON file, e.g. `project-credentials.json`, to your
workspace and run the following command to activate your service account:
```bash
gcloud auth activate-service-account --key-file project-credentials.json
```
#### Using Environment variables to provide credentials
You may also set the GCP credentials json file via the `GOOGLE_APPLICATION_CREDENTIALS` environment variable.
```bash
export GOOGLE_APPLICATION_CREDENTIALS='/Users/me/.config/gcloud/myproject-1-feb7993e8660.json'
```
Once you have your environment variables set, you can verify your credentials by running:
```bash
$ inspec detect -t gcp://
== Platform Details
Name: gcp
Families: cloud, api
Release: google-cloud-v
```

View file

@ -0,0 +1,70 @@
+++
title = "About kitchen-inspec"
draft = false
[menu]
[menu.inspec]
title = "kitchen-inspec"
identifier = "inspec/reference/plugin_kitchen_inspec.md kitchen-inspec"
parent = "inspec/reference"
weight = 110
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/plugin_kitchen_inspec.md)
Use Chef InSpec as a Kitchen verifier with `kitchen-inspec`.
Add the Chef InSpec verifier to the `.kitchen.yml` file:
```YML
verifier:
name: inspec
```
Use a compliance profile from the Chef Compliance server:
```YML
suites:
- name: compliance
run_list:
- recipe[ssh-hardening::default]
verifier:
inspec_tests:
- compliance://base/ssh
```
and then run the following command:
```bash
inspec compliance login https://compliance.test --user admin --insecure --token ''
```
where `--insecure` is required when using self-signed certificates.
Use a compliance profile from the Chef Supermarket:
```YML
suites:
- name: supermarket
run_list:
- recipe[ssh-hardening::default]
verifier:
inspec_tests:
- supermarket://dev-sec/ssh-baseline
```
Use Chef InSpec tests from the local file system:
```YML
suites:
- name: local
run_list:
- recipe[my_cookbook::default]
verifier:
inspec_tests:
- test/integration/default
```
Check out [Detect and correct with Test Kitchen](https://learn.chef.io/modules/detect-correct-kitchen#/)
on Learn Chef Rally for a hands-on look at how to use Test Kitchen to run Chef
InSpec profiles.

View file

@ -0,0 +1,86 @@
+++
title = "About Chef InSpec and Train Plugins"
draft = false
[menu]
[menu.inspec]
title = "Plugins"
identifier = "inspec/reference/plugins.md Plugins"
parent = "inspec/reference"
weight = 100
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/plugins.md)
## What are Chef InSpec Plugins?
Chef InSpec Plugins are optional software components that extend the capabilities
of InSpec. For example, [`inspec-iggy`](https://github.com/inspec/inspec-iggy)
is a Plugin project that aims to generate Chef InSpec controls from
infrastructure-as-code files. Plugins are distributed as RubyGems, and Chef InSpec
manages their installation. Chef InSpec Plugins always begin with the prefix
'inspec-'.
## What are Train Plugins?
Train Plugins allow Chef InSpec to speak to new kinds of targets (typically new
remote targets or APIs, but you could treat the local system in a new way if you
wished to). For example, if you wanted to audit a Kubernetes cluster, you might
want a transport that can talk to the supervisor API. You would develop a Train
Plugin for that, and install it using the Chef InSpec command line. Train Plugins
always begin with the prefix 'train-'.
## What can plugins do?
Currently, each plugin can offer one or more of these capabilities:
- define new output formats ("reporters")
- input sources
- define a new command-line-interface (CLI) command suite (`inspec` plugins)
- connectivity to new types of hosts or cloud providers (`train` plugins)
- DSL extensions at the file, control, describe block, or test level
- DSL extensions for custom resources
## How do I find out which plugins are available?
The Chef InSpec CLI can tell you which plugins are available:
```bash
inspec plugin search inspec-
```
## How do I install and manage plugins?
The Chef InSpec command line now offers a new subcommand just for managing plugins.
You can install a plugin by running:
```bash
inspec plugin install inspec-some-plugin
inspec plugin install train-some-plugin
```
For more details on what the `plugin` command can do, see the [online help](/inspec/cli/#plugin),
or run `inspec plugin help`.
## How do I use a different Gem server?
You can specify an alternate source by passing the base of your Gem repository to
the `--source` parameter:
```bash
inspec plugin search --source https://my.private.server inspec-private
inspec plugin install --source https://my.private.server inspec-private-plugin
```
## How do I write a plugin?
### Chef InSpec Plugins
For details on how to author a Chef InSpec Plugin, see the
[developer documentation](https://github.com/inspec/inspec/blob/master/docs/dev/plugins.md)
### Train Plugins
For details on how to author a Train Plugin, see the
[developer documentation](https://github.com/inspec/train/blob/master/docs/plugins.md)

View file

@ -0,0 +1,494 @@
+++
title = "About Chef InSpec Profiles"
draft = false
[menu]
[menu.inspec]
title = "Profiles"
identifier = "inspec/reference/profiles.md Profiles"
parent = "inspec/reference"
weight = 20
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/profiles.md)
Chef InSpec supports the creation of complex test and compliance profiles, which
organize controls to support dependency management and code reuse. Each profile
is a standalone structure with its own distribution and execution flow.
## Profile Structure
A profile should have the following structure::
```YAML
examples/profile
├── README.md
├── controls
│ ├── example.rb
│ └── control_etc.rb
├── libraries
│ └── extension.rb
|── files
│ └── extras.conf
└── inspec.yml
```
where:
- `inspec.yml` includes the profile description (required)
- `controls` is the directory in which all tests are located (required)
- `libraries` is the directory in which all Chef InSpec resource extensions are located (optional)
- `files` is the directory with additional files that a profile can access (optional)
- `README.md` should be used to explain the profile, its scope, and usage
See a complete example profile in the Chef InSpec open source repository:
[Example Chef InSpec Profile](https://github.com/chef/inspec/tree/master/examples/profile)
Also check out [Explore Chef InSpec resources](https://learn.chef.io/modules/explore-inspec-resources#/)
on Learn Chef Rally to learn more about how profiles are structured with hands-on-examples.
## inspec.yml
Each profile must have an `inspec.yml` file that defines the following information:
- Use `name` to specify a unique name for the profile. Required.
- Use `title` to specify a human-readable name for the profile.
- Use `maintainer` to specify the profile maintainer.
- Use `copyright` to specify the copyright holder.
- Use `copyright_email` to specify support contact information for the profile, typically an email address.
- Use `license` to specify the license for the profile.
- Use `summary` to specify a one line summary for the profile.
- Use `description` to specify a multiple line description of the profile.
- Use `version` to specify the profile version.
- Use `inspec_version` to place SemVer constraints on the version of Chef InSpec that the profile can run under.
- Use `supports` to specify a list of supported platform targets.
- Use `depends` to define a list of profiles on which this profile depends.
- Use `attributes` to define a list of attributes you can use in your controls.
`name` is required; all other profile settings are optional. For example:
```YAML
name: ssh
title: Basic SSH
maintainer: Chef Software, Inc.
copyright: Chef Software, Inc.
copyright_email: support@chef.io
license: Proprietary, All rights reserved
summary: Verify that SSH Server and SSH Client are configured securely
version: 1.0.0
supports:
- os-family: linux
depends:
- name: profile
path: ../path/to/profile
inspec_version: "~> 2.1"
```
The `inspec.yml` also supports embedded ERB in the file. For example:
```YAML
name: dummy
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
depends:
- name: inherit
url: "https://artifactory.com/artifactory/example-repo-local/inspec/0.4.1.tar.gz"
username: <%= ENV['USERNAME'] %>
password: <%= ENV['API_KEY'] %>
```
## Verify Profiles
Use the `inspec check` command to verify the implementation of a profile:
```bash
inspec check examples/profile
```
## Platform Support
Use the `supports` setting in the `inspec.yml` file to specify one (or more) platforms for which a profile is targeting. The list of supported platforms may contain the following:
- Use `platform-family` to restrict to a specific platform family.
- Use `platform-name` to restrict on a specific platform name.
- Use `release` to restrict to a specific platform version (used with platform-name).
- Use `platform` to restrict on either platform-name or platform-family.
For compatibility we support `os-name` and `os-family`. We recommend all users
to change `os-name` to `platform-name` and `os-family` to `platform-family`.
With Chef InSpec 2.0, we introduced new families to help distinguish the cloud
platforms. The new families can restrict the platform family to `os`, `aws`, `azure` or `gcp`.
For example, to target anything running Debian Linux:
```YAML
name: ssh
supports:
- platform-name: debian
```
and to target only Ubuntu version 14.04
```YAML
name: ssh
supports:
- platform-name: ubuntu
release: 14.04
```
and to target the entire RedHat platform (including CentOS and Oracle Linux):
```YAML
name: ssh
supports:
- platform-family: redhat
```
and to target anything running on Amazon AWS:
```YAML
name: ssh
supports:
- platform: aws
```
and to target all of these examples in a single `inspec.yml` file:
```YAML
name: ssh
supports:
- platform-name: debian
- platform-name: ubuntu
release: 14.04
- platform-family: redhat
- platform: aws
```
## Profile Dependencies
A Chef InSpec profile can bring in the controls and custom resources from another
Chef InSpec profile. Additionally, when inheriting the controls of another profile,
a profile can skip or even modify those included controls.
For hands-on examples, check out [Create a custom Chef InSpec profile](https://learn.chef.io/modules/create-a-custom-profile#/)
on Learn Chef Rally.
### Defining the Dependencies
Before a profile can use controls from another profile, the to-be-included profile
needs to be specified in the including profiles `inspec.yml` file in the `depends`
section. For each profile to be included, a location for the profile from where
to be fetched and a name for the profile should be included. For example:
```YAML
depends:
- name: linux-baseline
url: https://github.com/dev-sec/linux-baseline/archive/master.tar.gz
- name: ssh-baseline
url: https://github.com/dev-sec/ssh-baseline/archive/master.tar.gz
```
Chef InSpec supports a number of dependency sources.
#### path
The `path` setting defines a profile that is located on disk. This setting is
typically used during development of profiles and when debugging profiles.
```YAML
depends:
- name: my-profile
path: /absolute/path
- name: another
path: ../relative/path
```
#### url
The `url` setting specifies a profile that is located at an HTTP- or HTTPS-based
URL. The profile must be accessible via a HTTP GET operation and must be a valid
profile archive (zip, tar, or tar.gz format).
```YAML
depends:
- name: my-profile
url: https://my.domain/path/to/profile.tgz
- name: profile-via-git
url: https://github.com/myusername/myprofile-repo/archive/master.tar.gz
```
`url` also supports basic authentication.
```YAML
depends:
- name: my-profile
url: https://my.domain/path/to/profile.tgz
username: user
password: password
```
#### git
A `git` setting specifies a profile that is located in a git repository, with
optional settings for branch, tag, commit, version, and relative_path. The source
location is translated into a URL upon resolution. This type of dependency supports
version constraints via semantic versioning as git tags.
```YAML
depends:
- name: git-profile
git: http://url/to/repo
branch: desired_branch
tag: desired_version
commit: pinned_commit
version: semver_via_tags
relative_path: relative/optional/path/to/profile
```
#### supermarket
A `supermarket` setting specifies a profile that is located in a cookbook hosted
on Chef Supermarket. The source location is translated into a URL upon resolution.
For example:
```YAML
depends:
- name: supermarket-profile
supermarket: supermarket-username/supermarket-profile
```
Available Supermarket profiles can be listed with `inspec supermarket profiles`.
#### compliance
A `compliance` setting specifies a profile that is located on the Chef Automate
or Chef Compliance server.
For example:
```YAML
depends:
- name: linux
compliance: base/linux
```
## Vendoring Dependencies
When you execute a local profile, the `inspec.yml` file will be read in order to
source any profile dependencies. It will then cache the dependencies locally and
generate an `inspec.lock` file.
If you add or update dependencies in `inspec.yml`, dependencies may be re-vendored
and the lockfile updated with `inspec vendor --overwrite`
## Using Controls from an Included Profile
Once defined in the `inspec.yml`, controls from the included profiles can be used!
Lets look at some examples.
### Including All Controls from a Profile
With the `include_controls` command in a profile, all controls from the named
profile will be executed every time the including profile is executed.
![Include Controls](/images/inspec/include_controls.png)
In the example above, every time `my-app-profile` is executed, all the controls
from `my-baseline` are also executed. Therefore, the following controls would be
executed:
- myapp-1
- myapp-2
- myapp-3
- baseline-1
- baseline-2
This is a great reminder that having a good naming convention for your controls
is helpful to avoid confusion when
including controls from other profiles!
### Skipping a Control from a Profile
What if one of the controls from the included profile does not apply to your
environment? Luckily, it is not necessary to maintain a slightly-modified copy
of the included profile just to delete a control. The `skip_control` command
tells Chef InSpec to not run a particular control.
![Include Controls with Skip](/images/inspec/include_controls_with_skip.png)
In the above example, all controls from `my-app-profile` and `my-baseline` profile will be executed every time `my-app-profile` is executed **except** for control `baseline-2` from the `my-baseline` profile.
### Modifying a Control
Let's say a particular control from an included profile should still be run, but
the impact isn't appropriate? Perhaps the test should still run, but if it fails,
it should be treated as low severity instead of high severity?
When a control is included, it can also be modified!
![Include Controls with Modification](/images/inspec/include_controls_with_mod.png)
In the above example, all controls from `my-baseline` are executed along with
all the controls from the including profile, `my-app-profile`. However, should
control `baseline-1` fail, it will be raised with an impact of `0.5` instead of
the originally-intended impact of `1.0`.
### Selectively Including Controls from a Profile
If there are only a handful of controls that should be executed from an included
profile, it's not necessarily to skip all the unneeded controls, or worse,
copy/paste those controls bit-for-bit into your profile. Instead, use the
`require_controls` command.
![Require Controls](/images/inspec/require_controls.png)
Whenever `my-app-profile` is executed, in addition to its own controls, it will
run only the controls specified in the `require_controls` block. In the case, the
following controls would be executed:
- myapp-1
- myapp-2
- myapp-3
- baseline-2
- baseline-4
Controls `baseline-1`, `baseline-3`, and `baseline-5` would not be run, just as
if they were manually skipped. This method of including specific controls ensures
only the controls specified are executed; if new controls are added to a later
version of `my-baseline`, they would not be run.
And, just the way its possible to modify controls when using `include_controls`,
controls can be modified as well.
![Require Controls with Modification](/images/inspec/require_controls_with_mod.png)
As with the prior example, only `baseline-2` and `baseline-4` are executed, but
if `baseline-2` fails, it will report with an impact of `0.5` instead of the
originally-intended `1.0` impact.
## Using Resources from an Included Profile
By default, all of the custom resources from a listed dependency are available
for use in your profile. If two of your dependencies provide a resource with
the same name, you can use the `require_resource` DSL function to
disambiguate the two:
```YAML
require_resource(profile: 'my_dep', resource: 'my_res',
as: 'my_res2')
```
This will allow you to reference the resource `my_res` from the
profile `my_dep` using the name `my_res2`.
## Profile Inputs
Our documentation regarding [Inputs](/inspec/inputs/) is now on a dedicated page.
## Profile files
A Chef InSpec profile may contain additional files that can be accessed during
tests. A profile file enables you to separate the logic of your tests from the
data your tests check for, for example, the list of ports you require to be open.
To access these files, they must be stored in the `files` directory at the root
of a profile. They are accessed by their name relative to this folder with
`inspec.profile.file(...)`.
Here is an example for reading and testing a list of ports. The folder structure is:
```YAML
examples/profile
├── controls
│ ├── example.rb
│── files
│ └── services.yml
└── inspec.yml
```
With `services.yml` containing:
```YAML
- service_name: httpd-alpha
port: 80
- service_name: httpd-beta
port: 8080
```
The tests in `example.rb` can now access this file:
```Ruby
my_services = yaml(content: inspec.profile.file('services.yml')).params
my_services.each do |s|
describe service(s['service_name']) do
it { should be_running }
end
describe port(s['port']) do
it { should be_listening }
end
end
```
For a more complete example that uses a profile file, see
[Explore Chef InSpec resources](https://learn.chef.io/modules/explore-inspec-resources#/) on Learn Chef Rally.
## "should" vs. "expect" syntax
Users familiar with the RSpec testing framework may know that there are two ways
to write test statements: `should` and `expect`. The RSpec community decided that
`expect` is the preferred syntax. However, Chef InSpec recommends the `should`
syntax as it tends to read more easily to those users who are not as technical.
Chef InSpec will continue to support both methods of writing tests. Consider
this `file` test:
```Ruby
describe file('/tmp/test.txt') do
it { should be_file }
end
```
This can be re-written with `expect` syntax
```Ruby
describe file('/tmp/test.txt') do
it 'should be a file' do
expect(subject).to(be_file)
end
end
```
The output of both of the above examples looks like this:
```text
File /tmp/test.txt
✔ should be a file
```
In addition, you can make use of the `subject` keyword to further control your
output if you choose:
```Ruby
describe 'test file' do
subject { file('/tmp/test.txt') }
it 'should be a file' do
expect(subject).to(be_file)
end
end
```
... which will render the following output:
```text
test file
✔ should be a file
```

View file

@ -0,0 +1,186 @@
+++
title = "Chef InSpec Reporters"
draft = false
[menu]
[menu.inspec]
title = "Reporters"
identifier = "inspec/reference/reporters.md Reporters"
parent = "inspec/reference"
weight = 50
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/reporters.md)
Introduced in Chef InSpec 1.51.6
A `reporter` is a facility for formatting and delivering the results of a Chef InSpec auditing run.
Chef InSpec allows you to output your test results to one or more reporters. Configure the reporter(s) using either the `--reporter` option or as part of the general config file using the `--config` (or `--json-config`, prior to v3.6) option. While you can configure multiple reporters to write to different files, only one reporter can output to the screen(stdout).
## Syntax
You can specify one or more reporters using the `--reporter` cli flag. You can also specify a output by appending a path separated by a colon.
Output json to screen.
```bash
inspec exec example_profile --reporter json
# or explicitly specifying output to STDOUT:
inspec exec example_profile --reporter json:-
```
Output yaml to screen
```bash
inspec exec example_profile --reporter yaml
# or
inspec exec example_profile --reporter yaml:-
```
Output cli to screen and write json to a file.
```bash
inspec exec example_profile --reporter cli json:/tmp/output.json
```
Output nothing to screen and write junit and html to a file.
```bash
inspec exec example_profile --reporter junit:/tmp/junit.xml html:www/index.html
```
Output json to screen and write to a file. Write junit to a file.
```bash
inspec exec example_profile --reporter json junit:/tmp/junit.xml | tee out.json
```
If you wish to pass the profiles directly after specifying the reporters you will need to use the end of options flag `--`.
```bash
inspec exec --reporter json junit:/tmp/junit.xml -- profile1 profile2
```
If you are using the cli option `--config`, you can also set reporters.
Output cli to screen.
```json
{
"reporter": {
"cli" : {
"stdout" : true
}
}
}
```
Output cli to screen and write json to a file.
```json
{
"reporter": {
"cli" : {
"stdout" : true
},
"json" : {
"file" : "/tmp/output.json",
"stdout" : false
}
}
}
```
## Supported Reporters
The following are the current supported reporters:
### cli
This is the basic text base report. It includes details about which tests passed and failed and includes an overall summary at the end.
### json
This reporter includes all information about the profiles and test results in standard json format.
### json-min
This reporter is a redacted version of the json and only includes test results.
### yaml
This reporter includes all information about the profiles and test results in standard yaml format.
### documentation
This reporter is a very minimal text base report. It shows you which tests passed by name and has a small summary at the end.
### junit
This reporter outputs the standard junit spec in xml format.
### progress
This reporter is very condensed and gives you a `.`(pass), `f`(fail), or `*`(skip) character per test and a small summary at the end.
### json-rspec
This reporter includes all information from the rspec runner. Unlike the json reporter this includes rspec specific details.
### html
This renders html code to view your tests in a browser. It includes all the test and summary information.
## Automate Reporter
The `automate` reporter type is a special reporter used with [Chef Automate](https://automate.chef.io/). To use this reporter you must pass in the correct configuration via a json config `--config`.
Example config:
```json
{
"reporter": {
"automate" : {
"stdout" : false,
"url" : "https://YOUR_A2_URL/data-collector/v0/",
"token" : "YOUR_A2_ADMIN_TOKEN",
"insecure" : true,
"node_name" : "inspec_test_node",
"environment" : "prod"
}
}
}
```
### Mandatory fields
#### stdout
This will either suppress or show the automate report in the CLI screen on completion
#### url
This is your Automate 2 url. Append `data-collector/v0/` at the end.
#### token
This is your Automate 2 token. You can generate this token by navigating to the admin tab of A2 and then api keys.
### Optional fields
#### insecure
This will disable or enable the ssl check when accessing the Automate 2 instance.
#### node_name
This will be the node name which shows up in Automate.
#### node_uuid
This will be the node UUID which shows up in Automate. You will want to use a single static UUID per node for all your reports.
#### environment
This will set the environment metadata for Automate.

233
www/content/inspec/shell.md Normal file
View file

@ -0,0 +1,233 @@
+++
title = "Chef InSpec Shell"
draft = false
[menu]
[menu.inspec]
title = "InSpec Shell"
identifier = "inspec/reference/shell.md Chef InSpec Shell"
parent = "inspec/reference"
weight = 110
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/shell.md)
The Chef InSpec interactive shell is a pry based REPL that can be used to
quickly run Chef InSpec controls and tests without having to write it to a
file. Its functionality is similar to [chef-shell](/chef_shell/) as it provides a way
to exercise the Chef InSpec DSL, its resources, tests, and plugins without
having to create a profile or write a test file. See
[http://pryrepl.org/](http://pryrepl.org/) for an introduction to what pry is and what it can
do.
See [Explore Chef InSpec resources](https://learn.chef.io/modules/explore-inspec-resources#/)
on Learn Chef Rally for a hands-on example that uses Chef InSpec shell.
## Launching the shell
If you are using Chef InSpec from a platform-specific package (rpm, msi,
etc.) or from a Chef prepared shell in ChefDK, you can directly launch
Chef InSpec shell against your local machine using the following. See
<https://docs.chef.io/install_dk.html#set-system-ruby> for details.
```bash
inspec shell
inspec help shell # This will describe inspec shell usage
```
If you wish to connect to a remote machine (called a target within
InSpec), you can use the `-t` flag. We support connecting using SSH,
WinRM and docker. If no target is provided, we implicitly support the
"local" target - i.e. tests running on the current machine running
InSpec. For an SSH connection, use `-i` for specifying SSH key files,
and the `--sudo*` commands for requesting a privilege escalation after
logging in. For a WinRM connection, use `--path` to change the login
path, `--ssl` to use SSL for transport layer encryption.
```bash
inspec shell -t ssh://root@192.168.64.2:11022 # Login to remote machine using ssh as root.
inspec shell -t ssh://user@hostname:1234 -i /path/to/user_key # Login to hostname on port 1234 as user using given ssh key.
inspec shell -t winrm://UserName:Password@windowsmachine:1234 # Login to windowsmachine over WinRM as UserName.
inspec shell -t winrm://windowsmachine --user 'UserName@domain' --password 'Secret123!' # Login to windowsmachine as UserName@domain.org.
inspec shell -t docker://container_id # Login to a Docker container.
```
## Resource Packs
Use resource packs to share custom resources with other Chef InSpec users.
A resource pack is a Chef InSpec profile that contains only custom resources and
no other controls or tests.
For example, the profile in [`examples/profile`](https://github.com/chef/inspec/tree/master/examples/profile)
in the Chef InSpec GitHub repository defines an
[`example_config` resource](https://github.com/chef/inspec/blob/master/examples/profile/controls/example.rb).
To use these resources within the Chef InSpec shell, you will need to download
and specify them as a dependency.
Once you have local access to the profile, you can use the `example_config` custom
resource provided in the `examples/profile` GitHub repo in your local environment :
```bash
inspec shell --depends examples/profile
```
Once inside the shell your resource will be available:
```ruby
inspec> example_config
```
## Using Ruby in Chef InSpec shell
Since Chef InSpec shell is pry based, you may treat the shell as an
interactive Ruby session. You may write Ruby expressions and evaluate
them. Source high-lighting, automatic indentation and command history
(using the up and down arrow keys) are available to make your experience
more delightful. You can exit the shell using `exit`.
```bash
$ inspec shell
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
inspec> 1 + 2
=> 3
inspec> exit
```
## Using Chef InSpec DSL in Chef InSpec shell
Chef InSpec shell will automatically evaluate the result of every command as
if it were a test file. If you type in a Ruby command that is not an
Chef InSpec control or test, the shell will evaluate it as if it were a
regular ruby command.
Bare Chef InSpec resources are instantiated and their help text is presented.
You may also access the resource contents or other matchers that they
define. Run `help <resource>` to get more help on using a particular
resource or see the Chef InSpec resources documentation online.
```bash
$ inspec shell
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
inspec> file('/Users/myuser').directory?
=> true
inspec> os_env('HOME')
=> Environment variable HOME
inspec> os_env('HOME').content
=> /Users/myuser
inspec> exit
```
Chef InSpec tests are immediately executed.
```bash
inspec> describe file('/Users') # Empty test.
Summary: 0 successful, 0 failures, 0 skipped
inspec> describe file('/Users') do # Test with one check.
inspec> it { should exist }
inspec> end
✔ File /Users should exist
Summary: 1 successful, 0 failures, 0 skipped
```
All tests in a control are immediately executed as well. If a control is
redefined in the shell, the old control's tests are destroyed and
replaced with the redefinition and the control is re-run.
```bash
inspec> control 'my_control' do
inspec> describe os_env('HOME') do
inspec> its('content') { should eq '/Users/myuser' }
inspec> end
inspec> end
✔ my_control: Environment variable HOME content should eq "/Users/myuser"
Summary: 1 successful, 0 failures, 0 skipped
```
Syntax errors are illegal tests are also detected and reported.
```bash
inspec> control 'foo' do
inspec> thisisnonsense
inspec> end
NameError: undefined local variable or method `thisisnonsense' for #<#<Class:0x007fd63b571f98>:0x007fd639825cc8>
from /usr/local/lib/ruby/gems/2.3.0/gems/rspec-expectations-3.5.0/lib/rspec/matchers.rb:967:in `method_missing'
inspec> control 'foo' do
inspec> describe file('wut') do
inspec> its('thismakesnosense') { should cmp 'fail' }
inspec> end
inspec> end
✖ foo: File wut thismakesnosense (undefined method `thismakesnosense' for File wut:Inspec::Resource::Registry::File)
Summary: 0 successful, 1 failures, 0 skipped
```
## Running a single Chef InSpec command
If you wish to run a single Chef InSpec command and fetch its results, you
may use the `-c` flag. This is similar to using `bash -c`.
```bash
$ inspec shell -c 'describe file("/Users/myuser") do it { should exist } end'
Target: local://
✔ File /Users/myuser should exist
Summary: 1 successful, 0 failures, 0 skipped
```
```bash
$ inspec shell --format json -c 'describe file("/Users/test") do it { should exist } end'
{
"version": "1.49.2",
"controls": [{
"status": "passed",
"code_desc": "File /Users/test should exist",
"run_time": 0.002374,
"start_time": "2018-01-06 18:32:38 -0500"
}],
"other_checks": [],
"profiles": [{
"name": "inspec-shell",
"supports": [],
"controls": [{
"title": null,
"desc": null,
"impact": 0.5,
"refs": [],
"tags": {},
"code": "",
"source_location": {
"ref": "/usr/local/lib/ruby/gems/2.4.0/gems/inspec-1.49.2/lib/inspec/control_eval_context.rb",
"line": 89
},
"id": "(generated from (eval):1 7b6f82c2cc5e4205b3e2c97c8e855f2d)",
"results": [{
"status": "passed",
"code_desc": "File /Users/test should exist",
"run_time": 0.002374,
"start_time": "2018-01-06 18:32:38 -0500"
}]
}],
"groups": [{
"title": null,
"controls": ["(generated from (eval):1 7b6f82c2cc5e4205b3e2c97c8e855f2d)"],
"id": "unknown"
}],
"attributes": [],
"sha256": "29c070a90b7e3521babf618215573284a790d92907783d5b2c138f411bfd2e74"
}],
"platform": {
"name": "mac_os_x",
"release": "17.3.0"
},
"statistics": {
"duration": 0.003171
}
}
```

264
www/content/inspec/style.md Normal file
View file

@ -0,0 +1,264 @@
+++
title = "Chef InSpec Profile Style Guide"
draft = false
[menu]
[menu.inspec]
title = "Profile Style Guide"
identifier = "inspec/reference/style.md Profile Style Guide"
parent = "inspec/reference"
weight = 80
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/style.md)
This is a set of recommended Chef InSpec rules you should use when writing controls.
## Control Files
### Place control files in `controls/` and end them with `.rb`
Most syntax highlighters will render Chef InSpec files correctly across a wide list
of tools.
Avoid:
- `controls/ssh_config`
- `controls/ssh/config.rb`
Use:
- `controls/ssh_config.rb`
- `controls/ssh_config.rb`
### Avoid `controls`/`control` in your control filenames
Using `controls` in the filename creates unnecessary clutter when reading it.
Keep the names short and concise.
Avoid:
- `controls/ssh_controls.rb`
Use:
- `controls/ssh.rb`
## Code Style
### Avoid unnecessary parentheses in matchers
Adding additional parentheses is not required and provides more readability if
it is not used:
Avoid:
- `it { should eq(value) }`
Use:
- `it { should eq value }`
The exception are matchers that require additional arguments or named arguments.
## Controls
### Avoid wrapping controls in conditional statements
This will create dynamic profiles whose controls depend on the execution. The
problem here is that we cannot render the profile or provide its information
before scanning a system. We want to be able to inform users of the contents of
their profiles before they run them. It is valid to skip controls that are not
necessary for a system, as long as you do it via `only_if` conditions. Ruby's
internal conditionals will hide parts of the profile to static analysis and
should thus be avoided.
Avoid:
```ruby
if package('..').installed?
control "package-test1" do
..
end
end
```
Use:
```ruby
control "package-test1" do
only_if { package('..').installed? }
end
```
Avoid:
```ruby
case inspec.platform.name
when /centos/
include_controls 'centos-profile'
...
```
Instead use the `supports` attribute in the `inspec.yml` of the profile you
want to include:
```ruby
supports:
- platform-name: centos
```
Now whenever you run the base profile you can just
`include_controls 'centos-profile'`. It will only run the included profiles is
the platform matches the supported platform.
### Avoid dynamic elements in the control IDs
Control IDs are used to map test results to the tests and profiles. Dynamic
control IDs make it impossible to map results back, since the identifier which
connects tests and results may change in the process.
Avoid:
```ruby
control "test-file-#{name}" do
..
end
```
Use:
```ruby
control "test-all-files" do
..
end
```
Sometimes you may create controls from a static list of elements. If this list
stays the same no matter what system is scanned, it may be ok to do so and use
it as a generator for static controls.
### Avoid Ruby system calls
Ruby code is executed on the system that runs InSpec. This allows Chef InSpec to work
without Ruby and RubyGems being required on remote targets (servers or
containers). System calls are often used to interact with the local OS or remote
endpoints from a local installation.
Chef InSpec tests, however, are designed to be universally executable on all types
of runtimes, including local and remote execution. We want to give users the
ability to take an OS profile and execute it remotely or locally.
### Avoid shelling out
Avoid:
- `` `ls` ``
- `system("ls")`
- `IO.popen("ls")`
Use:
- `command("ls")` or `powershell("Get-ChildItem")`
Ruby's command executors will only run locally. Imagine a test like this:
```ruby
describe `whoami` do
it { should cmp "bob\n" }
end
```
If you run this test on your local system and happen to be using Bob's account
it will succeed. But if you were to run it against
`--target alice@remote-host.com` it will still report that the user is bob
instead of alice.
Instead, do this:
```ruby
describe command('whoami') do
its('stdout') { should cmp "bob\n" }
end
```
If the profile is pointed to a remote endpoint using the `command` resource
will run it on the remote OS.
### Avoid Ruby IO on files
Similar to the command interactions these files will only be read locally with
Ruby's internal calls. If you run this test against a remote target it won't
read the file from the remote endpoint, but from the local OS instead. Use the
`file` resource to read files on the target system.
Avoid:
- `File.new("filename").read`
- `File.read("filename")`
- `IO.read("filename")`
Use:
- `file("filename")`
In general, try to avoid Ruby's IO calls from within Chef InSpec controls and use
Chef InSpec resources instead.
### Avoid Ruby gem dependencies in controls
In addition to avoiding system-level gems and modules you should also limit the
use of external dependencies to resource packs or plugins. Gems need to be
resolved, installed, vendored, and protected from conflicts. We aim to avoid
exposing this complexity to users of InSpec, to make it a great tool even if you
are not a developer.
Plugins should declare gem dependencies in their gemspec, and then rely on the
plugin installation facility to install and manage dependencies.
### Avoid debugging calls (in production)
One of the best way to develop and explore tests is the interactive debugging
shell `pry` (see [Interactive Debugging with Pry] (/inspec/dsl_inspec/#interactive-debugging-with-pry)
at the end of this page). However, after you finish your profile make sure you
have no interactive statements included anymore. Sometimes interactive calls are
hidden behind conditionals (`if` statements) that are harder to reach. These
calls can easily cause trouble when an automated profiles runs into an
interactive `pry` call that stops the execution and waits for user input.
Avoid:
- `binding.pry` in production profiles
Use:
- Use debugging calls during development only
Also you may find it helpful to use the Chef InSpec logging interface:
```ruby
Inspec::Log.info('Hi')
```
#### 9. Favor `cmp` over `eq`
The `cmp` matcher handles type conversions, case insensitive comparisons,
converting strings to versions (e.g. '7.35.0-1ubuntu2.10'), and many other
troublesome things. Unless you want an exact match (if so use the `eq` matcher)
then the `cmp` matcher should be used.
For example, this:
```ruby
describe passwd.uids(0) do
its('users') { should cmp 'root' }
end
```
is preferred over:
```ruby
describe passwd.uids(0) do
its('users') { should eq ['root'] }
end
```
See the [`cmp` matcher documentation](/inspec/matchers/#cmp) for more examples.

View file

@ -0,0 +1,61 @@
+++
title = "Waivers"
draft = false
[menu]
[menu.inspec]
title = "Waivers"
identifier = "inspec/reference/waivers.md Waivers"
parent = "inspec/reference"
weight = 140
+++
[\[edit on GitHub\]](https://github.com/inspec/inspec/blob/master/www/content/inspec/waivers.md)
Waivers is a mechanism to mark controls as "waived" for various reasons, and to
control the running and/or reporting of those controls. It uses a YAML input file
that identifies:
1. which controls are waived
1. a description of why it is waived
1. (optionally) whether they should be skipped from running
1. (optionally) an expiration date for the waiver
## Usage
To use waivers, you must have a correctly formatted input file and
invoke `inspec exec` with `--waiver-file [path]`.
```bash
inspec exec path/to/profile --waiver-file waivers.yaml
```
## File Format
Waiver files are [input files](/inspec/inputs/) with a specific format:
```yaml
control_id:
expiration_date: YYYY-MM-DD
run: false
justification: "reason for waiving this control"
```
- `expiration_date` is optional. Absence means the waiver is permanent.
- `run` is optional. If present and true, the control will run and be
reported, but failures in it won't make the overall run fail. If absent or false, the control will not be run. You may use any of yes, no, true or false.
- `justification` can be any text you want and might include a reason
as well as who signed off on the waiver.
### Examples:
```yaml
waiver_control_1_2_3:
expiration_date: 2019-10-15
justification: Not needed until Q3. @secteam
xccdf_org.cisecurity.benchmarks_rule_1.1.1.4_Ensure_mounting_of_hfs_filesystems_is_disabled:
expiration_date: 2020-03-01
justification: "This might be a bug in the test. @qateam"
run: false
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB