diff --git a/docs-chef-io/config.toml b/docs-chef-io/config.toml index 3bf0a712f..54d6eb3ba 100644 --- a/docs-chef-io/config.toml +++ b/docs-chef-io/config.toml @@ -15,6 +15,30 @@ identifier = "inspec" parent = "inspec" weight = 20 + [[menu.inspec]] + title = "Profiles" + identifier = "inspec/profiles" + parent = "inspec" + weight = 40 + + [[menu.inspec]] + title = "Cloud Platforms" + identifier = "inspec/cloud" + parent = "inspec" + weight = 50 + + [[menu.inspec]] + title = "Chef Tools" + identifier = "inspec/chef" + parent = "inspec" + weight = 480 + + [[menu.inspec]] + title = "Related Projects" + identifier = "inspec/friends" + parent = "inspec" + weight = 490 + [[menu.inspec]] title = "Chef InSpec Reference" identifier = "inspec/reference" diff --git a/docs-chef-io/content/inspec/_index.md b/docs-chef-io/content/inspec/_index.md index adf0d63e2..a087f9031 100644 --- a/docs-chef-io/content/inspec/_index.md +++ b/docs-chef-io/content/inspec/_index.md @@ -14,37 +14,71 @@ gh_repo = "inspec" weight = 10 +++ -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. +Chef InSpec is an open-source framework for testing and auditing your applications and infrastructure. +It compares the actual state of your system with the desired state that you express in easy-to-read and easy-to-write Chef InSpec code. +It detects violations and displays findings in the form of a report, but puts you in control of remediation. -## Getting started with Chef InSpec +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. -Below are some of the core concepts that make up Chef InSpec. +## How does Chef InSpec work? -### Create a profile +Chef InSpec uses profiles to audit infrastructure. An [InSpec profile](/inspec/profile/) organizes multiple controls into a reusable artifact. +You can describe your profiles with metadata, version them, pin them to specific versions of InSpec, define specific platforms that a profile can test, and define profile dependencies. -[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. +A control defines a regulatory recommendation or requirement for the state of a system. Each profile can have many controls and each control audits different aspects of a system. -### Add your tests +Chef InSpec resources allow you to test specific parts of your infrastructure. +Chef InSpec has {{% inspec/inspec_count_resources %}} [resources](/inspec/resources/) ready to use--from Apache2 to ZFS pool. +This includes resources for testing [AWS, Azure, AliCloud, and GCP cloud infrastructure](/inspec/cloud/), and you can create your own [custom resources](profiles/custom_resources) if we don't have a resource that meets your needs. -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 language. +[InSpec reporters](/inspec/reporters/) format and deliver the results of an InSpec audit run. +You can output results to the standard output; to text formats like JSON, HTML, or plain text; or send the results directly to [Chef Automate](/automate/). -### Target your system +## Use cases -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. +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. +InSpec to target applications and services running on Alibaba, AWS, Azure, and GCP. -### Resources +## Additional Resources -Chef InSpec has {{% inspec/inspec_count_resources %}} [resources](/inspec/resources/) ready to use--from Apache2 to ZFS pool. -If you need a solution that we haven’t provided, you can write your own [custom -resource](/inspec/dsl_resource/). +### Open-source profiles + +The InSpec community created several open-source profiles that are free to use. +Use the `inspec supermarket profiles` command to list the available profiles, or view them in [Chef Supermarket](https://supermarket.chef.io/tools?q=&type=compliance_profile). This includes the [DevSec Hardening Framework](https://dev-sec.io/), a set of server hardening profiles. + +### Premium profiles + +Chef offers [premium CIS- and STIG-based profiles](https://www.chef.io/products/chef-premium-content) for compliance scanning across a range of enterprise assets. + +### Learning + +- [Learn Chef: Test Expectations with Chef InSpec](https://learn.chef.io/courses/course-v1:chef+Inspec101+Perpetual/about) +- [Learn Chef: Extending InSpec: InSpec Wrappers and Custom Resources](https://learn.chef.io/courses/course-v1:chef+InSpec201+Perpetual/about) +- [Chef InSpec webinars](https://www.chef.io/webinars?products=chef-inspec&page=1) +- [Chef Resource Library](https://www.chef.io/resources?products=chef-inspec&page=1) + +### Community + +- [Chef InSpec on Discourse](https://discourse.chef.io/c/inspec/10) +- [Chef InSpec in the Chef Blog](https://www.chef.io/blog/category/chef-inspec) +- [Chef InSpec Community Resources](https://community.chef.io/tools/chef-inspec) + +### Support + +- [Chef Support](https://www.chef.io/support) +- [Chef Help Center](https://community.progress.com/s/products/chef) + +### GitHub repositories + +- [inspec GitHub organization](https://github.com/inspec) +- [inspec repository](https://github.com/inspec/inspec/) +- [inspec-alicloud repository](https://github.com/inspec/inspec-alicloud/) +- [inspec-aws repository](https://github.com/inspec/inspec-aws/) +- [inspec-azure](https://github.com/inspec/inspec-azure/) +- [inspec-gcp repository](https://github.com/inspec/inspec-gcp/) +- [inspec-k8s repository](https://github.com/inspec/inspec-k8s/) +- [inspec train repository](https://github.com/inspec/train) diff --git a/docs-chef-io/content/inspec/audit_log.md b/docs-chef-io/content/inspec/audit_log.md index 3ad881335..7bd2b62d8 100644 --- a/docs-chef-io/content/inspec/audit_log.md +++ b/docs-chef-io/content/inspec/audit_log.md @@ -6,8 +6,8 @@ gh_repo = "inspec" [menu] [menu.inspec] title = "Audit Log" - identifier = "inspec/reference/audit_logging.md InSpec audit log" - parent = "inspec/reference" + identifier = "inspec/Audit Log" + parent = "inspec" weight = 60 +++ @@ -48,4 +48,4 @@ The following options are available inside `inspec exec` and `inspec shell` to c ## More information -For details of the audit log format and implementation, refer to the (Train documentation)[https://github.com/inspec/train/blob/main/docs/audit_log.md]. +For details of the audit log format and implementation, refer to the [Train documentation](https://github.com/inspec/train/blob/main/docs/audit_log.md). diff --git a/docs-chef-io/content/inspec/cli.md b/docs-chef-io/content/inspec/cli.md index 58ead0b94..6c88a4399 100644 --- a/docs-chef-io/content/inspec/cli.md +++ b/docs-chef-io/content/inspec/cli.md @@ -275,99 +275,6 @@ Run all test files at the specified locations. The subcommand loads the given profiles, fetches their dependencies if needed, then connects to the target and executes any controls in the profiles. One or more reporters are used to generate the output. -```ruby -exit codes: - 0 normal exit, all tests passed - 1 usage or general error - 2 error in plugin system - 3 fatal deprecation encountered - 5 invalid profile signature - 6 mandatory profile signing mode enabled and no signature found - 100 normal exit, at least one test failed - 101 normal exit, at least one test skipped but none failed - 172 chef license not accepted -``` - -### Examples - -Below are some examples of using `exec` with different test locations. - -Chef Automate: - -```ruby -inspec automate login -inspec exec compliance://username/linux-baselinem -``` - -`inspec compliance` is a backwards compatible alias for `inspec automate` and works the same way: - -```ruby -inspec compliance login -``` - -Chef Supermarket: - -```ruby -inspec exec supermarket://username/linux-baseline -inspec exec supermarket://username/linux-baseline --supermarket_url="https://privatesupermarket.example.com" -``` - -Local profile (executes all tests in `controls/`): - -```ruby -inspec exec /path/to/profile -``` - -Local single test (doesn't allow inputs or custom resources): - -```ruby -inspec exec /path/to/a_test.rb -``` - -Git via SSH: - -```ruby -inspec exec git@github.com:dev-sec/linux-baseline.git -``` - -Git via HTTPS (.git suffix is required): - -```ruby -inspec exec https://github.com/dev-sec/linux-baseline.git -``` - -Private Git via HTTPS (.git suffix is required): - -```ruby -inspec exec https://api_token@github.com/dev-sec/linux-baseline.git -``` - -Private Git via HTTPS and cached credentials (.git suffix is required): - -```bash -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 file (also supports .zip): - -```bash -inspec exec https://webserver/linux-baseline.tar.gz -``` - -Web-hosted file with basic authentication (supports .zip): - -```bash -inspec exec https://username:password@webserver/linux-baseline.tar.gz -``` - -Web-hosted signed profile: - -```bash -inspec exec https://username:password@webserver/linux-baseline.iaf -``` - ### Syntax This subcommand has the following syntax: @@ -390,7 +297,7 @@ This subcommand has the following additional options: For more information, see [Signed InSpec Profiles](/inspec/signing/). `--attrs=one two three` -: Legacy name for --input-file - deprecated. +: Legacy name for `--input-file` - deprecated. `--audit-log-location=AUDIT_LOG_LOCATION` : The directory that the audit log saves diagnostic log files to. @@ -409,7 +316,7 @@ This subcommand has the following additional options: `--backend-cache` `--no-backend-cache` -: Allow caching for backend command output. (default: true). +: Allow caching for backend command output. (default: `true`). `--bastion-host=BASTION_HOST` : Specifies the bastion host if applicable. @@ -450,7 +357,7 @@ This subcommand has the following additional options: : 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. `--docker-url` -: Provides path to Docker API endpoint (Docker). Defaults to unix:///var/run/docker.sock on Unix systems and tcp://localhost:2375 on Windows. +: Provides path to Docker API endpoint (Docker). Defaults to `unix:///var/run/docker.sock` on Unix systems and `tcp://localhost:2375` on Windows. `--enable-password=ENABLE_PASSWORD` : Password for enable mode on Cisco IOS devices. @@ -460,13 +367,13 @@ This subcommand has the following additional options: : Filter empty profiles (profiles without controls) from the report. `--filter-waived-controls` -: Do not execute waived controls in InSpec at all. Must use with --waiver-file. Ignores the `run` setting of the waiver file. +: Do not execute waived controls in InSpec at all. Must use with `--waiver-file`. Ignores the `run` setting of the waiver file. `--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. +: 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. @@ -490,7 +397,7 @@ This subcommand has the following additional options: : Specify the login port for a remote scan. `--podman-url` -: Provides the path to the Podman API endpoint. Defaults to unix:///run/user/$UID/podman/podman.sock for rootless container, unix:///run/podman/podman.sock for rootful container (for this you need to execute inspec as root user). +: Provides the path to the Podman API endpoint. Defaults to `unix:///run/user/$UID/podman/podman.sock` for rootless container, `unix:///run/podman/podman.sock` for rootful container (for this you need to execute inspec as root user). `--profiles-path=PROFILES_PATH` : Folder which contains referenced profiles. @@ -503,7 +410,7 @@ This subcommand has the following additional options: `--reporter-backtrace-inclusion` `--no-reporter-backtrace-inclusion` -: Include a code backtrace in report data (default: true). +: Include a code backtrace in report data (default: `true`). `--reporter-include-source` : Include full source code of controls in the CLI report. @@ -588,6 +495,115 @@ This subcommand has the following additional options: `--enhanced-outcomes` : Includes enhanced outcome of controls in report data. +### Exit codes + +`0` +: normal exit, all tests passed + +`1` +: usage or general error + +`2` +: error in plugin system + +`3` +: fatal deprecation encountered + +`5` +: invalid profile signature + +`6` +: mandatory profile signing mode enabled and no signature found + +`100` +: normal exit, at least one test failed + +`101` +: normal exit, at least one test skipped but none failed + +`172` +: Chef license not accepted + +### Examples + +Below are some examples of using `exec` with different test locations. + +Chef Automate: + +```ruby +inspec automate login +inspec exec compliance://username/linux-baselinem +``` + +`inspec compliance` is a backwards compatible alias for `inspec automate` and works the same way: + +```ruby +inspec compliance login +``` + +Chef Supermarket: + +```ruby +inspec exec supermarket://username/linux-baseline +inspec exec supermarket://username/linux-baseline --supermarket_url="https://privatesupermarket.example.com" +``` + +Local profile (executes all tests in `controls/`): + +```ruby +inspec exec /path/to/profile +``` + +Local single test (doesn't allow inputs or custom resources): + +```ruby +inspec exec /path/to/a_test.rb +``` + +Git via SSH: + +```ruby +inspec exec git@github.com:dev-sec/linux-baseline.git +``` + +Git via HTTPS (.git suffix is required): + +```ruby +inspec exec https://github.com/dev-sec/linux-baseline.git +``` + +Private Git via HTTPS (.git suffix is required): + +```ruby +inspec exec https://api_token@github.com/dev-sec/linux-baseline.git +``` + +Private Git via HTTPS and cached credentials (.git suffix is required): + +```bash +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 file (also supports .zip): + +```bash +inspec exec https://webserver/linux-baseline.tar.gz +``` + +Web-hosted file with basic authentication (supports .zip): + +```bash +inspec exec https://username:password@webserver/linux-baseline.tar.gz +``` + +Web-hosted signed profile: + +```bash +inspec exec https://username:password@webserver/linux-baseline.iaf +``` + ## habitat Create a Chef Habitat package. diff --git a/docs-chef-io/content/inspec/cloud/_index.md b/docs-chef-io/content/inspec/cloud/_index.md new file mode 100644 index 000000000..e2f198b6e --- /dev/null +++ b/docs-chef-io/content/inspec/cloud/_index.md @@ -0,0 +1,19 @@ ++++ +title = "Using Chef InSpec on Cloud Platforms" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "Overview" + identifier = "inspec/cloud/" + parent = "inspec/cloud" + weight = 10 ++++ + +Chef InSpec provides resources for auditing the following cloud platforms: + +- [Alibaba Cloud](alicloud) +- [AWS](aws) +- [Azure](azure) +- [GCP](gcp) diff --git a/docs-chef-io/content/inspec/cloud/alicloud.md b/docs-chef-io/content/inspec/cloud/alicloud.md new file mode 100644 index 000000000..f59e3496e --- /dev/null +++ b/docs-chef-io/content/inspec/cloud/alicloud.md @@ -0,0 +1,30 @@ ++++ +title = "Chef InSpec and Alibaba Cloud" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "AliCloud" + identifier = "inspec/cloud/alibaba" + parent = "inspec/cloud" ++++ + +Chef InSpec has resources for auditing Alibaba. + +You will need to install AliCloud SDK version 0.8.0 and require AliCloud credentials to use the Chef InSpec AliCloud resources. + +## Set AliCloud credentials + +You can configure AliCloud credentials in an [.envrc file](https://github.com/inspec/inspec-alicloud/blob/main/.envrc_example) or export them in your shell. + +```bash +# Example configuration +export ALICLOUD_ACCESS_KEY="anaccesskey" +export ALICLOUD_SECRET_KEY="asecretkey" +export ALICLOUD_REGION="eu-west-1" +``` + +## Alibaba resources + +{{< inspec/inspec_resources platform="alicloud" >}} diff --git a/docs-chef-io/content/inspec/cloud/aws.md b/docs-chef-io/content/inspec/cloud/aws.md new file mode 100644 index 000000000..74f32ba08 --- /dev/null +++ b/docs-chef-io/content/inspec/cloud/aws.md @@ -0,0 +1,87 @@ ++++ +title = "Chef InSpec and AWS" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "AWS" + identifier = "inspec/cloud/aws" + parent = "inspec/cloud" ++++ + +Chef InSpec has resources for auditing AWS. + +## Initialize an InSpec profile for auditing AWS + +With Chef InSpec 4 or greater, you can create a profile for testing AWS resources with `inspec init profile`: + +```bash +$ inspec init profile --platform aws +Create new profile at /Users/me/ + * Creating directory libraries + * Creating file README.md + * Creating directory controls + * Creating file controls/example.rb + * Creating file inspec.yml + * Creating file inputs.yml + * Creating file libraries/.gitkeep +``` + +Assuming the `inputs.yml` file contains your AWS project ID, you can execute this sample profile using the following command: + +```bash +inspec exec --input-file=/inputs.yml -t gcp:// +``` + +## Set AWS credentials + +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. + +### Provide credentials with environment variables + +You may provide the credentials to Chef InSpec by setting the following environment variables: `AWS_REGION`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY`. 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 +$ inspec detect -t aws:// + +== Platform Details +Name: aws +Families: cloud, api +Release: aws-sdk-v2.10.125 +``` + +### Provide credentials using Chef InSpec target option + +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 +$ inspec detect -t aws:// + +== Platform Details +Name: aws +Families: cloud, api +Release: aws-sdk-v2.10.125 +``` + +## AWS resources + +{{< inspec/inspec_resources platform="aws" >}} diff --git a/docs-chef-io/content/inspec/cloud/azure.md b/docs-chef-io/content/inspec/cloud/azure.md new file mode 100644 index 000000000..7e2ce2672 --- /dev/null +++ b/docs-chef-io/content/inspec/cloud/azure.md @@ -0,0 +1,104 @@ ++++ +title = "Chef InSpec and Azure" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "Azure" + identifier = "inspec/cloud/azure" + parent = "inspec/cloud" ++++ + +Chef InSpec has resources for auditing Azure. + +## Initialize an InSpec profile for auditing Azure + +With Chef InSpec 4 or greater, you can create a profile for testing AWS resources with `inspec init profile`: + +```bash +$ inspec init profile --platform azure +Create new profile at /Users/me/ + * Creating directory libraries + * Creating file README.md + * Creating directory controls + * Creating file controls/example.rb + * Creating file inspec.yml + * Creating file inputs.yml + * Creating file libraries/.gitkeep +``` + +Assuming the `inputs.yml` file contains your Azure project ID, you can execute this sample profile using the following command: + +```bash +inspec exec --input-file=/inputs.yml -t gcp:// +``` + +## Set Azure credentials + +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. + +### Set the Azure credentials file + +By default, Chef InSpec is configured to look at `~/.azure/credentials`, and it should contain: + +```powershell +[] +client_id = "" +client_secret = "" +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 in place, you can now execute Chef InSpec. + +```bash +inspec exec -t azure:// +``` + +### Provide credentials using environment variables + +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:// +``` + +### Provide credentials using Chef InSpec target option + +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 +``` + +## Azure resources + +{{< inspec/inspec_resources platform="azure" >}} diff --git a/docs-chef-io/content/inspec/cloud/gcp.md b/docs-chef-io/content/inspec/cloud/gcp.md new file mode 100644 index 000000000..d414be1ff --- /dev/null +++ b/docs-chef-io/content/inspec/cloud/gcp.md @@ -0,0 +1,76 @@ ++++ +title = "Chef InSpec and GCP" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "GCP" + identifier = "inspec/cloud/gcp" + parent = "inspec/cloud" ++++ + +Chef InSpec has resources for auditing GCP. + +## Initialize an InSpec profile for auditing GCP + +With Chef InSpec 4 or greater, you can create a profile for testing GCP resources with `inspec init profile`: + +```bash +$ 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 inputs.yml + * Creating file libraries/.gitkeep +``` + +Assuming the `inputs.yml` file contains your GCP project ID, this sample profile can then be executed using the following command: + +```bash +inspec exec my-profile --input-file=my-profile/inputs.yml -t gcp:// +``` + +## Set GCP credentials + +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/). + +### Set 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. + +1. Create a [service account](https://cloud.google.com/docs/authentication/getting-started) with the scopes appropriate for your needs. + +1. Download the credential JSON file, for example `project-credentials.json`, to your workspace and activate your service account with `gcloud auth activate-service-account`. + + ```bash + gcloud auth activate-service-account --key-file project-credentials.json + ``` + +### Provide credentials using environment variables + +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 +``` + +## GCP resources + +{{< inspec/inspec_resources platform="gcp" >}} diff --git a/docs-chef-io/content/inspec/cloud_platforms.md b/docs-chef-io/content/inspec/cloud_platforms.md deleted file mode 100644 index 13712be7e..000000000 --- a/docs-chef-io/content/inspec/cloud_platforms.md +++ /dev/null @@ -1,207 +0,0 @@ -+++ -title = "Using Chef InSpec on Cloud Platforms" -draft = false -gh_repo = "inspec" - -[menu] - [menu.inspec] - title = "Chef InSpec for the Cloud" - identifier = "inspec/Chef InSpec on Cloud Platforms" - parent = "inspec" - weight = 30 -+++ - -As of Chef InSpec 2.0, we have expanded our platform support beyond individual machines and now include support for select AWS, Azure, GCP, and AliCloud 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_ACCESS_KEY`. 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 -$ 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 -$ 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 -[] -client_id = "" -client_secret = "" -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 -``` - -## AliCloud Platform Support in InSpec - -You will need to install AliCloud SDK version 0.8.0 and require AliCloud credentials to use the Chef InSpec AliCloud resources. - -### Setting up AliCloud credentials for InSpec - -You can configure AliCloud credentials in an [.envrc file](https://github.com/inspec/inspec-alicloud#:~:text=shell.%20(See%20example-,.envrc%20file,-)) or export them in your shell. - -```bash -# Example configuration -export ALICLOUD_ACCESS_KEY="anaccesskey" -export ALICLOUD_SECRET_KEY="asecretkey" -export ALICLOUD_REGION="eu-west-1" -``` - -## 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: - -```bash -$ 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 inputs.yml - * Creating file libraries/.gitkeep -``` - -Assuming the `inputs.yml` file contains your GCP project ID, this sample profile can then be executed using the following command: - -```bash -inspec exec my-profile --input-file=my-profile/inputs.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 for providing 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 -``` diff --git a/docs-chef-io/content/inspec/config.md b/docs-chef-io/content/inspec/config.md index 2ee72949e..7de68834a 100644 --- a/docs-chef-io/content/inspec/config.md +++ b/docs-chef-io/content/inspec/config.md @@ -5,38 +5,38 @@ gh_repo = "inspec" [menu] [menu.inspec] - title = "Configuration" - identifier = "inspec/reference/config.md Configuration" - parent = "inspec/reference" - weight = 60 + title = "Configure" + identifier = "inspec/config.md Configuration" + parent = "inspec" + weight = 30 +++ -This documents the Chef InSpec configuration file format introduced in version 3.5 of InSpec and extended in later versions. +This documents how to create a configuration file for Chef InSpec. A config file is **optional**. + +There are two config file versions, 1.1 and 1.2. ## 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. +By default, Chef InSpec looks for a config file in `~/.inspec/config.json`. 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 +## 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. +There are two possible versions for this config file, `1.1` or `1.2`. Only version `1.2` accepts the `plugins` setting. -## Version 1.1 +## Example -### Complete Example - -``` +```json { - "version": "1.1", + "version": "1.2", "cli_options":{ "color": "true" }, "credentials": { "ssh": { "my-target": { - "host":"somewhere.there.com", + "host":"somewhere.example.com", "user":"bob" } } @@ -44,81 +44,81 @@ Config files must contain a top-level key, `version`, which indicates the file f "reporter": { "automate" : { "stdout" : false, - "url" : "https://YOUR_A2_URL/data-collector/v0/", - "token" : "YOUR_A2_API_TOKEN", + "url" : "https://AUTOMATE_URL/data-collector/v0/", + "token" : "AUTOMATE_API_TOKEN", "insecure" : true, "node_name" : "inspec_test_node", "environment" : "prod" } - } + }, + "plugins": { + "inspec-training-wheels":{ + "diameter":"4 inches" + }, + "inspec-input-secrets":{ + "security-tokens":[ + "123456789", + "abcdef252875" + ] + } + } } ``` -version -: Should have the value '1.1'. +### Properties -cli_options +`version` +: **required** + + The file format version. + + Allowed values: `1.1` or `1.2` + +`cli_options` : Any long-form command line option, without the leading dashes. -credentials +`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: + For example, if the config file contains: -``` -{ - "credentials": { - "winrm": { - "myconn": { - "user": "Administrator", - "host": "prod01.east.example.com", - "disable_sspi": true, - "connection_retries": 10 + ```json + { + "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. + 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. + Each Train transport offers a variety of options. By using the credential set facility, you are able to set options that are not accessible via the Train URI. -You may have as many credential sets in the config file as you require. + 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`. + 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@example.com`. -You can use a credential set, and then override individual options using command line options. + 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. + 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 `example.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 +`reporter` +: Formats and delivers the results of a Chef InSpec audit run. For information on configuring reporters, see the [InSpec reporters documentation](/inspec/reporters/). -You may also set output (reporter) options in the config file. See the [Reporters Page](/inspec/reporters/) for details. +`plugins` -## Version 1.2 +: 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. -Version 1.2 adds a top-level field, "plugins". + Each plugin will have a key-value are that it may use as it sees fit - Chef InSpec does not specify the structure. -### plugins + Set the config file to **version 1.2** to use this setting. -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" - ] - } - } -} -``` + For more information on plugins, see the [Chef InSpec plugins documentation](/inspec/plugins/). diff --git a/docs-chef-io/content/inspec/dsl_inspec.md b/docs-chef-io/content/inspec/dsl_inspec.md index 541d00e4d..623c16a12 100644 --- a/docs-chef-io/content/inspec/dsl_inspec.md +++ b/docs-chef-io/content/inspec/dsl_inspec.md @@ -1,505 +1,4 @@ +++ -title = "Chef InSpec Language" -draft = false -gh_repo = "inspec" - -[menu] - [menu.inspec] - title = "Chef InSpec Language" - identifier = "inspec/reference/dsl_inspec.md Chef InSpec Language" - parent = "inspec/reference" - weight = 70 +layout = "redirect" +redirect_url = "/inspec/profiles/controls" +++ - -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](https://www.chef.io/products/chef-compliance) auditing is the same. -The open source [Chef InSpec resource](/inspec/resources/) framework is compatible with [Chef compliance](https://docs.chef.io/chef_compliance_phase/). - -The Chef InSpec Language 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 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 -``` - -This example checks for if certain pip packages are installed, but only if '/root/.aws' exists: - -```ruby -control 'pip-packages-installed' do - title 'Check if essential pips are installed' - only_if('aws-cli config not created.') do - directory('/root/.aws').exist? - end - %w(aws-mfa PyYAML awscli).each do |aws_pip_deps| - describe pip(aws_pip_deps) do - it { should be_installed } - end - 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. - -This example checks whether the Gnome Desktop is installed. If not installed, it resets the impact of the control to the new value which is passed as a hash with the impact key. - -Here, it resets it to 0: - -```ruby -control 'gnome-destkop-settings' do - impact 0.5 - desc 'some good settings' - desc 'check', 'check the settings file for good things' - desc 'fix', 'set the good things in the file /etc/gnome/settings' - tag nist: 'CM-6' - - only_if("The Gnome Desktop is not installed, this control is Not Applicable", impact: 0) { - package('gnome-desktop').installed? - } - - describe gnome_settings do - it should_be set_well - end -end -``` - -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 -* `only_if` also accepts hash with impact key to reset the impact value of the control. Control's impact is helpful in determining it is enhanced outcome. - -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 -``` - -### Use **only_applicable_if** to test controls for applicability - -The `only_applicable_if` block allows to test if a control is applicable or not. In this example, the control with `only_applicable_if` block checks the condition and marks the control as not applicable (N/A) if the results of the `only_applicable_if` block evaluates to `false`. - -If **gnome-desktop** is not installed, the following control to test gnome settings marks control as **not applicable**. - -```ruby -control 'gnome-destkop-settings' do - impact 0.5 - desc 'some good settings' - desc 'check', 'check the settings file for good things' - desc 'fix', 'set the good things in the file /etc/gnome/settings' - tag nist: 'CM-6' - - only_applicable_if("The Gnome Desktop is not installed, this control is Not Applicable") { - package('gnome-desktop').installed? - } - - describe gnome_settings do - it should_be set_well - end -end -``` - -Run output: - -```bash -inspec exec path/to/audit-gnome-settings-profile --enhanced-outcomes - -Profile: InSpec Profile (audit-gnome-settings-profile) -Version: 0.1.0 -Target: local:// -Target ID: fa3923b9-f806-4cc2-960d-1ddefb4c7654 - - N/A gnome-destkop-settings: No-op - × No-op - N/A control due to only_applicable_if condition: The Gnome Desktop is not installed, this control is Not Applicable - -Profile Summary: 0 successful controls, 0 control failure, 0 controls not reviewed, 1 controls not applicable, 0 controls have error -Test Summary: 0 successful, 1 failures, 0 skipped -``` - -Some notes about `only_applicable_if`: - -* `only_applicable_if` applies to the entire `control`. If the results of the `only_applicable_if` block evaluates 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. -* If the results of the `only_applicable_if` block evaluates to `false`, it will invoke a failing test which will state the reason for N/A. - -### 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 Language 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 -``` diff --git a/docs-chef-io/content/inspec/dsl_resource.md b/docs-chef-io/content/inspec/dsl_resource.md index b54eca8d4..42b349d7e 100644 --- a/docs-chef-io/content/inspec/dsl_resource.md +++ b/docs-chef-io/content/inspec/dsl_resource.md @@ -1,152 +1,4 @@ +++ -title = "Resource DSL" -draft = false -gh_repo = "inspec" - -[menu] - [menu.inspec] - title = "Custom Resources" - identifier = "inspec/reference/dsl_resource.md Custom Resources" - parent = "inspec/reference" - weight = 90 +layout = "redirect" +redirect_url = "/inspec/profiles/custom_resources/" +++ - -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 additional methods may be defined within the resource: - -- resource_id - An instance method. Place logic here to determine the unique identifier for a resource, and set it using the superclass method. Following is an example of its usage in an InSpec test: - -``` - # example_config resource can have unique conf file path as an identifier. - describe example_config do - its("resource_id") { should eq PATH_OF_CONF_FILE } - end -``` - -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 - - def resource_id - value = example_method_to_determine_resource_id # define logic to determine resource_id value - super(value) - 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/main/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.` 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.` 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/"`) _before_ your -profile is run to ensure it is eagerly loaded and in the global -resource registry. diff --git a/docs-chef-io/content/inspec/glossary.md b/docs-chef-io/content/inspec/glossary.md index 8f721014d..fd7d25935 100644 --- a/docs-chef-io/content/inspec/glossary.md +++ b/docs-chef-io/content/inspec/glossary.md @@ -6,8 +6,8 @@ gh_repo = "inspec" [menu] [menu.inspec] title = "Chef InSpec Glossary" - identifier = "inspec/glossary.md Chef InSpec Glossary" - parent = "inspec" + identifier = "inspec/reference/Chef InSpec Glossary" + parent = "inspec/reference" weight = 50 +++ @@ -172,7 +172,7 @@ end 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). +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. diff --git a/docs-chef-io/content/inspec/habitat.md b/docs-chef-io/content/inspec/habitat.md index 32917aaf5..609f4bcff 100644 --- a/docs-chef-io/content/inspec/habitat.md +++ b/docs-chef-io/content/inspec/habitat.md @@ -6,23 +6,22 @@ gh_repo = "inspec" [menu] [menu.inspec] title = "Chef Habitat Integration" - identifier = "inspec/reference/habitat.md Habitat Integration" - parent = "inspec/reference" - weight = 120 + identifier = "inspec/chef/Habitat Integration" + parent = "inspec/chef" + weight = 20 +++ 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 +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). +To learn more about Chef Habitat see the [Habitat documentation](/habitat/). ## Using the Chef Habitat Integration diff --git a/docs-chef-io/content/inspec/inputs.md b/docs-chef-io/content/inspec/inputs.md index 432bec5ab..e41aebada 100644 --- a/docs-chef-io/content/inspec/inputs.md +++ b/docs-chef-io/content/inspec/inputs.md @@ -1,450 +1,5 @@ +++ -title = "Chef InSpec Inputs" +layout="redirect" draft = false -gh_repo = "inspec" - -[menu] - [menu.inspec] - title = "Inputs" - identifier = "inspec/reference/inputs.md Inputs" - parent = "inspec/reference" - weight = 30 -+++ - -## 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: - -```bash - × 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`: - -```bash - ✔ 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 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 ) < 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 | -| 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 - sensitive: true -``` - -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. - -## Setting Input values using Plugins - -Inputs can also be set by custom input plugins, which retrieve values from external sources like secret stores or databases. Please check [RubyGems.org](https://rubygems.org/) for available InSpec input plugins. - -### Disabling Caching for Inputs - -Especially with plugins, it can be desirable to re-evaluate inputs every time and not cache them. By default, an existing input value is reused which can lead to problems if the retrieved values are expected to change. An example for this is using `kitchen-inspec` with input plugins to connect to a Vault server for password retrieval. - -To disable input caching, you can disable the cache from your Ruby code: - -```ruby -Inspec::InputRegistry.instance.cache_inputs = false -``` - -## 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, 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 - -### Sensitive - -Optional, `true` or `false`. If `true`, the value of the input will be used normally -during the `exec` run, but the value will be obscured as "***" in the "inputs" or -"attributes" section of any [Reporter](/inspec/reporters/) that explicitly lists -inputs (the `json` reporter is one such reporter). Note that this will not obscure -input values that are used as test results. - -Allowed in: Metadata - -### Pattern - -Optional, `Regexp`. This feature validates the input by matching it with the provided regular expression. - -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. +redirect_url="/inspec/profiles/inputs/" ++++ \ No newline at end of file diff --git a/docs-chef-io/content/inspec/inspec_and_friends.md b/docs-chef-io/content/inspec/inspec_and_friends.md index 204c8f0b3..00e503956 100644 --- a/docs-chef-io/content/inspec/inspec_and_friends.md +++ b/docs-chef-io/content/inspec/inspec_and_friends.md @@ -5,10 +5,10 @@ gh_repo = "inspec" [menu] [menu.inspec] - title = "Chef InSpec and Friends" - identifier = "inspec/inspec_and_friends.md Chef InSpec and friends" - parent = "inspec" - weight = 40 + title = "RSpec and Serverspec" + identifier = "inspec/friends/inspec_and_friends.md Chef InSpec and friends" + parent = "inspec/friends" + weight = 10 +++ This page looks at projects that are similar to Chef InSpec to explain how they diff --git a/docs-chef-io/content/inspec/license.md b/docs-chef-io/content/inspec/license.md index e0e930307..aa9418daf 100644 --- a/docs-chef-io/content/inspec/license.md +++ b/docs-chef-io/content/inspec/license.md @@ -74,7 +74,7 @@ Replace `` with one of the following options. ## License key -Set a license key for Chef InSpec using one of three methods. +You can add a license key to Chef InSpec using one of three methods: - [interactive license dialog](#interactive-license-dialog) - [command line option](#command-line-option-1) diff --git a/docs-chef-io/content/inspec/matchers.md b/docs-chef-io/content/inspec/matchers.md index 5fd2003dc..f19b1a767 100644 --- a/docs-chef-io/content/inspec/matchers.md +++ b/docs-chef-io/content/inspec/matchers.md @@ -22,8 +22,6 @@ Chef InSpec uses **matchers**, a testing framework based on [RSpec](https://rspe You can use any matcher provided by [RSpec::Expectations](https://relishapp.com/rspec/rspec-expectations/docs); however, these matchers are not [supported by InSpec](/inspec/inspec_and_friends/#rspec). -See [Test Expectations with Chef InSpec](https://learn.chef.io/courses/course-v1:chef+Inspec101+Perpetual/about) on Learn Chef to learn more about Chef InSpec's built-in matchers. - ## be Use the `be` matcher with comparison operators, and use numbers and not strings for these comparisons. For example: diff --git a/docs-chef-io/content/inspec/migration.md b/docs-chef-io/content/inspec/migration.md index cb1d0e43a..1f3a4953f 100644 --- a/docs-chef-io/content/inspec/migration.md +++ b/docs-chef-io/content/inspec/migration.md @@ -1,14 +1,14 @@ +++ -title = "Chef InSpec Migration Guide" +title = "Serverspec Migration Guide" draft = false gh_repo = "inspec" [menu] [menu.inspec] title = "Migration from Serverspec" - identifier = "inspec/reference/migration.md Migration from Serverspec" - parent = "inspec/reference" - weight = 130 + identifier = "inspec/friends/migration.md Migration from Serverspec" + parent = "inspec/friends" + weight = 20 +++ ## How is Chef InSpec different from Serverspec @@ -21,7 +21,7 @@ Chef InSpec is a framework that allows you to run infrastructure testing as well ## Which Serverspec resources are available in InSpec? -The following resources are available in InSpec: +The following resources are available in Chef InSpec: | Serverspec | Chef InSpec | |:------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------:| diff --git a/docs-chef-io/content/inspec/parallel.md b/docs-chef-io/content/inspec/parallel.md index 936b6bd58..22cf9720e 100644 --- a/docs-chef-io/content/inspec/parallel.md +++ b/docs-chef-io/content/inspec/parallel.md @@ -1,14 +1,14 @@ +++ -title = "InSpec Parallel" +title = "Chef InSpec Parallel" draft = false gh_repo = "inspec" [menu] [menu.inspec] - title = "InSpec Parallel" + title = "Parallel" identifier = "inspec/parallel.md InSpec Parallel" parent = "inspec" - weight = 25 + weight = 80 +++ Chef InSpec Parallel can automatically manage multiple profile executions in parallel on a system targeting several remote systems and environments. diff --git a/docs-chef-io/content/inspec/plugin_kitchen_inspec.md b/docs-chef-io/content/inspec/plugin_kitchen_inspec.md index 7ee439098..911ffacba 100644 --- a/docs-chef-io/content/inspec/plugin_kitchen_inspec.md +++ b/docs-chef-io/content/inspec/plugin_kitchen_inspec.md @@ -6,23 +6,25 @@ gh_repo = "inspec" [menu] [menu.inspec] title = "kitchen-inspec" - identifier = "inspec/reference/plugin_kitchen_inspec.md kitchen-inspec" - parent = "inspec/reference" - weight = 110 + identifier = "inspec/chef/kitchen-inspec" + parent = "inspec/chef" + weight = 10 +++ -Use Chef InSpec as a Kitchen verifier with `kitchen-inspec`. +Use Chef InSpec as a [Test Kitchen](https://kitchen.ci/) verifier with `kitchen-inspec`. + +For hands-on examples, learn how to use Test Kitchen to run Chef InSpec profiles on the Learn Chef course [Validate Infrastructure Code with Test Kitchen](https://learn.chef.io/courses/course-v1:chef+LocalDev101+Perpetual/about). Add the Chef InSpec verifier to the `.kitchen.yml` file: -```YML +```yaml verifier: name: inspec ``` Use a compliance profile from the Chef Compliance server: -```YML +```yaml suites: - name: compliance run_list: @@ -38,7 +40,9 @@ and then run the following command: inspec automate login https://compliance.test --user admin --insecure --token '' ``` -where `--insecure` is required when using self-signed certificates. +where: + +- `--insecure` is required when using self-signed certificates. `inspec compliance` is a backwards compatible alias for `inspec automate` and works the same way: @@ -48,7 +52,7 @@ inspec compliance login https://compliance.test --user admin --insecure --token Use a compliance profile from the Chef Supermarket: -```YML +```yaml suites: - name: supermarket run_list: @@ -60,7 +64,7 @@ suites: Use Chef InSpec tests from the local file system: -```YML +```yaml suites: - name: local run_list: @@ -69,7 +73,3 @@ suites: 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. diff --git a/docs-chef-io/content/inspec/plugins.md b/docs-chef-io/content/inspec/plugins.md index d81bbde18..293130035 100644 --- a/docs-chef-io/content/inspec/plugins.md +++ b/docs-chef-io/content/inspec/plugins.md @@ -6,27 +6,25 @@ gh_repo = "inspec" [menu] [menu.inspec] title = "Plugins" - identifier = "inspec/reference/plugins.md Plugins" - parent = "inspec/reference" - weight = 100 + identifier = "inspec/Plugins" + parent = "inspec" + weight = 90 +++ -## What are Chef InSpec Plugins? +## 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-'. +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? +## What are Train plugins? -Train Plugins allow Chef InSpec to speak to new kinds of targets (typically new +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 +plugin for that, and install it using the Chef InSpec command line. Train plugins always begin with the prefix 'train-'. ## What can plugins do? @@ -40,7 +38,7 @@ Currently, each plugin can offer one or more of these capabilities: - 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? +## Find available plugins The Chef InSpec CLI can tell you which plugins are available: @@ -48,7 +46,7 @@ The Chef InSpec CLI can tell you which plugins are available: inspec plugin search inspec- ``` -## How do I install and manage plugins? +## Install and manage plugins The Chef InSpec command line now offers a new subcommand just for managing plugins. @@ -61,24 +59,20 @@ inspec plugin install train-some-plugin For more details on what the `plugin` command can do, run `inspec plugin help`. -## How do I use a different Gem server? +## 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 +inspec plugin search --source https://private.example.com inspec-private +inspec plugin install --source https:/private.example.com inspec-private-plugin ``` -## How do I write a plugin? +## Write a plugin -### Chef InSpec Plugins +For details on creating a Chef InSpec plugin, see the +[InSpec developer documentation](https://github.com/inspec/inspec/blob/main/dev-docs/plugins.md) -For details on how to author a Chef InSpec Plugin, see the -[developer documentation](https://github.com/inspec/inspec/blob/main/dev-docs/plugins.md) - -### Train Plugins - -For details on how to author a Train Plugin, see the -[developer documentation](https://github.com/inspec/train/blob/main/docs/plugins.md) +For details on creating a Train plugin, see the +[Train developer documentation](https://github.com/inspec/train/blob/main/docs/plugins.md) diff --git a/docs-chef-io/content/inspec/profiles.md b/docs-chef-io/content/inspec/profiles.md deleted file mode 100644 index 8ff312954..000000000 --- a/docs-chef-io/content/inspec/profiles.md +++ /dev/null @@ -1,565 +0,0 @@ -+++ -title = "About Chef InSpec Profiles" -draft = false -gh_repo = "inspec" - -[menu] - [menu.inspec] - title = "Profiles" - identifier = "inspec/reference/profiles.md Profiles" - parent = "inspec/reference" - weight = 20 -+++ - -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/main/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 `inputs` to define a list of inputs you can use in your controls. -- Use `gem_dependencies` to specify a list of profile gem dependencies that is required to be installed for the profile to function correctly. - -`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: - - platform-family: linux -depends: - - name: profile - path: ../path/to/profile -gem_dependencies: - - name: "gem-name" - version: ">= 2.0.0" -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. `platform-name` supports asterisk (`*`) wildcard use. -- Use `release` to restrict to a specific platform version, and use together with `platform-name`. `release` supports asterisk (`*`) wildcard use. -- Use `platform` to restrict on either platform-name or platform-family. - -To get a list of all valid values for `platform-name` and `platform-family`, run `inspec schema platforms`, which returns the supported list in JSON format. - -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, use: - -```yaml -name: ssh -supports: - - platform-name: debian -``` - -To target only Ubuntu version 20.04, use: - -```yaml -name: ssh -supports: - - platform-name: ubuntu - release: 20.04 -``` - -To target the entire release of Ubuntu version 20.x, use: - -```yaml -name: ssh -supports: - - platform-name: ubuntu - release: 20.* -``` - -To target the Red Hat and derivative platforms such as CentOS and Oracle Linux, use: - -```yaml -name: ssh -supports: - - platform-family: redhat -``` - -To target the entire Windows 2019 platform family, including Datacenter and Core Servers, use: - -```yaml -name: ssh -supports: - - platform-name: windows_server_2019* -``` - -To target anything running on Amazon AWS, use: - -```yaml -name: ssh -supports: - - platform: aws -``` - -To target all of these examples in a single `inspec.yml` file, use: - -```yaml -name: ssh -supports: - - platform-name: debian - - platform-name: ubuntu - release: 20.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 [Test Expectations with Chef InSpec](https://learn.chef.io/courses/course-v1:chef+Inspec101+Perpetual/about) -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 profile’s `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/username/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 -``` -## Gem Dependencies - -Any profile with ruby gem dependencies that need to be installed can be specified using the `gem_dependencies` settings in the `inspec.yml` metadata file. - -For example, if you required any ruby library in a custom resource that needs a specific gem to be installed, then you can specify those gems in the metadata file. Chef InSpec will prompt to install the gems to `~/.inspec/gems` when you run your profile the first time. To skip the prompt and automatically install, pass the `--auto-install-gems` option to `inspec exec`. - -```yaml -gem_dependencies: - - name: "mongo" - version: ">= 2.3.12" -``` - -## 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! -Let’s 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. - -## Including or Selecting controls from a profile with same name and different version. - -When an inspec profile has dependency on another profile to it's specific version, then the controls can be included or selected by using profile name with version separated by `-`. - -Here, the Profile - A has following dependency: - -```yaml -name: profile-a -depends: - - name: ssh - git: https://github.com/dev-sec/ssh-baseline.git - tag: 2.6.0 -``` - -And Profile - B has following dependency: - -```yaml -name: profile-b -depends: - - name: ssh - git: https://github.com/dev-sec/ssh-baseline.git - tag: 2.7.0 -``` - -Controls of these profiles can be included or required in a profile in a following manner: - -```ruby -include_controls "ssh-2.6.0" -include_controls "ssh-2.7.0" -``` - -OR - -```ruby -require_controls "ssh-2.6.0" -require_controls "ssh-2.7.0" -``` - -## 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: - -```bash -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: - -```bash -test file - ✔ should be a file -``` diff --git a/docs-chef-io/content/inspec/profiles/_index.md b/docs-chef-io/content/inspec/profiles/_index.md new file mode 100644 index 000000000..05708e0dd --- /dev/null +++ b/docs-chef-io/content/inspec/profiles/_index.md @@ -0,0 +1,110 @@ ++++ +title = "About Chef InSpec Profiles" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "About Profiles" + identifier = "inspec/profiles/Overview" + parent = "inspec/profiles" + weight = 10 ++++ + +A Chef InSpec profile organizes multiple controls into a reusable artifact that can be described and versioned. +Each profile is a standalone structure with its own distribution and execution flow. + +Chef InSpec supports complex test and compliance profiles, which organize controls to support dependency management and code reuse. + +For hands-on examples, check out [Test Expectations with Chef InSpec](https://learn.chef.io/courses/course-v1:chef+Inspec101+Perpetual/about) on Learn Chef to learn more about how profiles are structured. + +## Initialize a new profile + +Use the InSpec CLI to generate a new profile. + +```sh +inspec init profile +``` + +### Platforms + +You can an initialize profiles that are configured for Google Cloud, Azure, or AWS using the `--platform` option. + +```sh +inspec init profile --platform +``` + +Replace: + +- `` with the name of your profile +- `` with one of the following: + - `aws` + - `azure` + - `gcp` + +## Profile structure + +A profile has following structure: + +```yaml +profile +├── README.md +├── controls +│ ├── example.rb +│ └── control_etc.rb +├── libraries +│ └── extension.rb +|── files +│ └── extras.conf +└── inspec.yml +``` + +`inspec.yml` +: The [`inspec.yml` file](inspec_yml) describes the profile. + + Required + +`controls` +: The [`controls` directory](controls) contains all tests. + + Required + +`libraries` +: The `libraries` directory contains all Chef InSpec [resource extensions](custom_resources). + + Optional + +`files` +: The [`files` directory](files) contains additional files that a profile can access. + + Optional + +`README.md` +: The `README.md` explains the profile, its scope, and usage. + + Optional + +## Verify profiles + +Use the `inspec check` command to verify the implementation of a profile: + +```bash +inspec check examples/profile +``` + +## Execute a profile + +Use the `exec` subcommand to execute a profile. + +```sh +inspec exec +``` + +`inspec exec` accepts profiles from several sources, including a local directory, Git repositories, and web-hosted tar files. +See the [`inspec exec` documentation](/inspec/cli#exec) for more information. + +You can format the results of an audit using [InSpec reporters](/inspec/reporters/). + +## Example profiles + +See the `inspec` repository for some [example profiles](https://github.com/inspec/inspec/tree/main/examples). diff --git a/docs-chef-io/content/inspec/profiles/controls.md b/docs-chef-io/content/inspec/profiles/controls.md new file mode 100644 index 000000000..951603237 --- /dev/null +++ b/docs-chef-io/content/inspec/profiles/controls.md @@ -0,0 +1,549 @@ ++++ +title = "InSpec Profile Controls" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "Controls" + identifier = "inspec/profiles/controls" + parent = "inspec/profiles" + weight = 30 ++++ + +Controls define the regulatory recommendations or requirements for the state of a system. + +Controls are written in Ruby using the InSpec DSL, which is a Ruby DSL for writing audit controls and includes audit resources that you can invoke. + +## Controls location + +Add the controls to the `controls` directory at the root of a profile. + +```text +examples/profile +├── controls +│ └── example.rb +└── inspec.yml +``` + +## 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' + 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 +``` + +### Control properties + +Name + +: The name of the control is a unique control ID that's initialized at the beginning of the control block. + + `sshd-8` is the control name in the example above. + +`impact` + +: The importance of the compliance results. + + Data type: String, Float + + Possible string values (based on CVSS 3.0): + + - `none` + - `low` + - `medium` + - `high` + - `critical` + + Numeric values 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 + +`title` + +: A human-readable title for the control block. + + Optional + +`desc` + +: A human-readable description of the what the control block does. + + `desc` may include two arguments. The first argument is used as a header when rendering in Chef Automate. For example: + + `desc 'rationale', 'This ensures that there are no unexpected settings'` + + Optional + +`tag` + +: Meta-information with key or key-value pairs. + + Optional + +`ref` +: A reference to an external document + +`describe` +: A describe block invokes an [InSpec resource](/inspec/resources/) or [custom resource](/inspec/profiles/custom_resources/) and encloses tests that apply to that resource. Group multiple related describe blocks under one control. + +## Advanced concepts + +### Check if at least one condition passes + +Use `describe.one` to define a set of `describe` blocks where only one block needs to pass. +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. + +```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` has the following conditions: + +- 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 + +Use the `:sensitive` flag in resource definition to suppress the output an audit. + +For example, you may write checks that involve resources with sensitive content, such as a file resource. + +```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 password complexity + +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 +``` + +This example checks for if certain pip packages are installed, but only if '/root/.aws' exists: + +```ruby +control 'pip-packages-installed' do + title 'Check if essential pips are installed' + only_if('aws-cli config not created.') do + directory('/root/.aws').exist? + end + %w(aws-mfa PyYAML awscli).each do |aws_pip_deps| + describe pip(aws_pip_deps) do + it { should be_installed } + end + 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. + +This example checks whether the Gnome Desktop is installed. If not installed, it resets the impact of the control to the new value which is passed as a hash with the impact key. + +Here, it resets it to 0: + +```ruby +control 'gnome-destkop-settings' do + impact 0.5 + desc 'some good settings' + desc 'check', 'check the settings file for good things' + desc 'fix', 'set the good things in the file /etc/gnome/settings' + tag nist: 'CM-6' + + only_if("The Gnome Desktop is not installed, this control is Not Applicable", impact: 0) { + package('gnome-desktop').installed? + } + + describe gnome_settings do + it should_be set_well + end +end +``` + +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 +- `only_if` also accepts hash with impact key to reset the impact value of the control. Control's impact is helpful in determining it is enhanced outcome. + +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 +``` + +### Test controls for applicability using `only_applicable_if` + +The `only_applicable_if` block allows to test if a control is applicable or not. In this example, the control with `only_applicable_if` block checks the condition and marks the control as not applicable (N/A) if the results of the `only_applicable_if` block evaluates to `false`. + +If **gnome-desktop** is not installed, the following control to test gnome settings marks control as **not applicable**. + +```ruby +control 'gnome-destkop-settings' do + impact 0.5 + desc 'some good settings' + desc 'check', 'check the settings file for good things' + desc 'fix', 'set the good things in the file /etc/gnome/settings' + tag nist: 'CM-6' + + only_applicable_if("The Gnome Desktop is not installed, this control is Not Applicable") { + package('gnome-desktop').installed? + } + + describe gnome_settings do + it should_be set_well + end +end +``` + +Run output: + +```bash +inspec exec path/to/audit-gnome-settings-profile --enhanced-outcomes + +Profile: InSpec Profile (audit-gnome-settings-profile) +Version: 0.1.0 +Target: local:// +Target ID: fa3923b9-f806-4cc2-960d-1ddefb4c7654 + + N/A gnome-destkop-settings: No-op + × No-op + N/A control due to only_applicable_if condition: The Gnome Desktop is not installed, this control is Not Applicable + +Profile Summary: 0 successful controls, 0 control failure, 0 controls not reviewed, 1 controls not applicable, 0 controls have error +Test Summary: 0 successful, 1 failures, 0 skipped +``` + +Some notes about `only_applicable_if`: + +- `only_applicable_if` applies to the entire `control`. If the results of the `only_applicable_if` block evaluates 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. +- If the results of the `only_applicable_if` block evaluates to `false`, it will invoke a failing test which will state the reason for N/A. + +### Additional metadata + +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 Language 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 +``` + diff --git a/docs-chef-io/content/inspec/profiles/custom_resources.md b/docs-chef-io/content/inspec/profiles/custom_resources.md new file mode 100644 index 000000000..7d3f37560 --- /dev/null +++ b/docs-chef-io/content/inspec/profiles/custom_resources.md @@ -0,0 +1,199 @@ ++++ +title = "InSpec Custom Resources" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "Custom Resources" + identifier = "inspec/profiles/libraries" + parent = "inspec/profiles" + weight = 40 ++++ + +You can extend the functionality of Chef InSpec profiles by creating custom resources. + +For hands-on examples, check out [Extending InSpec: InSpec Wrappers and Custom Resources](https://learn.chef.io/courses/course-v1:chef+InSpec201+Perpetual/about) on Learn Chef. + +## Resource location + +Create custom resources in a profile's libraries directory. + +```bash +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. + +### Resource attributes + +Use the following attributes to configure a resource. + +`name` +: Identifier of the resource. + + Required + +`desc` +: Description of the resource + + Optional + +`example` +: Example usage of the resource + + Optional + +`supports` +: Platform restrictions of the resource + + Optional + +### Resource methods + +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 additional methods may be defined within the resource: + +`resource_id` +: An instance method. Place logic here to determine the unique identifier for a resource, and set it using the superclass method. + + Following is an example of its usage in an InSpec test: + + ```ruby + # example_config resource can have unique conf file path as an identifier. + describe example_config do + its("resource_id") { should eq PATH_OF_CONF_FILE } + end + ``` + +### Example + +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 + + def resource_id + value = example_method_to_determine_resource_id # define logic to determine resource_id value + super(value) + 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/main/examples/profile/libraries/example_config.rb). + +## Alternate custom resource names + +If you have a profile that includes another profile with custom resources as a dependency, the custom resources from the dependent profile are included by default. +If two custom resource names conflict, you can use the `require_resource` InSpec DSL function to rename a custom resource in control code. + +```ruby +require_resource( + profile: '', + resource: '', + as: '' +) +``` + +where: + +- `` is the dependent profile +- `` is the resource name in the dependent profile +- `` is an alternate name for that resource + +## 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.` 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.` 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/"`) _before_ your +profile is run to ensure it is eagerly loaded and in the global +resource registry. diff --git a/docs-chef-io/content/inspec/profiles/depends.md b/docs-chef-io/content/inspec/profiles/depends.md new file mode 100644 index 000000000..9a7946c2c --- /dev/null +++ b/docs-chef-io/content/inspec/profiles/depends.md @@ -0,0 +1,362 @@ ++++ +title = "InSpec Profile Dependencies" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "Dependencies" + identifier = "inspec/profiles/depends" + parent = "inspec/profiles" + weight = 50 ++++ + +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 [Extending InSpec: InSpec Wrappers and Custom Resources](https://learn.chef.io/courses/course-v1:chef+InSpec201+Perpetual/about) on Learn Chef. + +## Define dependencies + +Before a profile can use controls from another profile, the to-be-included profile +needs to be specified in the including profile’s `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://example.com/path/to/profile.tgz +- name: profile-via-git + url: https://github.com/username/myprofile-repo/archive/master.tar.gz +``` + +`url` also supports basic authentication. + +```yaml +depends: +- name: my-profile + url: https://example.com/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://example.com/path/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 +``` + +## Gem dependencies + +Any profile with Ruby gem dependencies that need to be installed can be specified using the `gem_dependencies` settings in the `inspec.yml` metadata file. + +For example, if you required any Ruby library in a custom resource that needs a specific gem to be installed, then you can specify those gems in the metadata file. +Chef InSpec will prompt to install the gems to `~/.inspec/gems` when you run your profile the first time. +To skip the prompt and automatically install, pass the `--auto-install-gems` option to `inspec exec`. + +```yaml +gem_dependencies: + - name: "mongo" + version: ">= 2.3.12" +``` + +## Alternate resource names + +By default, all [custom resources](/inspec/profiles/custom_resources/) from a listed dependency are available for use in a profile. +If two of your dependencies provide a resource with the same name, you can use the `require_resource` InSpec DSL function to disambiguate the two: + +```ruby +require_resource( + profile: '', + resource: '', + as: '' +) +``` + +where: + +- `` is the dependent profile +- `` is the resource name in the dependent profile +- `` is an alternate name for that resource + +## Use controls from a dependent profile + +After you define a dependent profile in the `inspec.yml` file, you can use controls from those profiles. + +See the `inspec` repository for an [example profile](https://github.com/inspec/inspec/tree/main/examples/inheritance) that inherits controls from another profile. + +The following examples show you how to include controls from a dependent profile. + +### Include all controls + +With the `include_controls` command in a profile, all controls from the named +profile will be executed every time the including profile is executed. + +For example, if you have a profile called `baseline-profile` with the following controls: + +- baseline-1 +- baseline-2 + +And `app-profile` with the following controls: + +- app-1 +- app-2 +- app-3 + +Add `baseline-profile` as dependency of `app-profile`, then include the `baseline-profile` controls using `include_controls` in the control code of `app-profile`: + +```ruby +include_controls 'baseline-profile' +``` + +Every time you execute `app-profile`, InSpec also executes all the controls from `baseline-profile`: + +- app-1 +- app-2 +- app-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! + +### Skip a control + +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. + +For example, if you have a profile called `baseline-profile` with the following controls: + +- baseline-1 +- baseline-2 + +And `app-profile` with the following controls: + +- app-1 +- app-2 +- app-3 + +Add `baseline-profile` as dependency of `app-profile`, then include the `baseline-profile` controls using `include_controls` and `skip_control` to exclude the profile you don't want execute: + +```ruby +include_controls 'baseline-profile' do + skip_control 'baseline-2' +end +``` + +Every time you execute `app-profile`, InSpec also executes all the controls from `baseline-profile` except `baseline-2`: + +- app-1 +- app-2 +- app-3 +- baseline-1 + +### Modify 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! + +For example, if you have a profile called `baseline-profile` with the following controls: + +- baseline-1 +- baseline-2 + +And `baseline-1` has an `impact` of `1.0` defined in `baseline-profile`: + +```ruby +control 'baseline-1' do + impact 1.0 + ... +end +``` + +Add `baseline-profile` as dependency of `app-profile`, then include the `baseline-profile` controls to `app-profile` using `include_controls` and redefine the impact of `baseline-1`: + +```ruby +include_controls 'baseline-profile' do + control 'baseline-1' do + impact 0.5 + end +end +``` + +In the above example, all controls from `baseline-profile` are executed along with all the controls from the including profile, `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 include controls + +Use the `require_controls` command selectively include certain controls from an included +profile. You don't have to skip all the unneeded controls, or worse, +copy/paste those controls bit-for-bit into your profile. + +For example, if you have a profile called `baseline-profile` with the following controls: + +- baseline-1 +- baseline-2 +- baseline-3 +- baseline-4 +- baseline-5 + +And `app-profile` with the following controls: + +- app-1 +- app-2 +- app-3 + +Add `baseline-profile` as dependency of `app-profile`, then include specific `baseline-profile` controls using `require_controls` in the control code of `app-profile`: + +```ruby +require_controls 'baseline-profile' do + control 'baseline-2' + control 'baseline-4' +end +``` + +Every time you execute `app-profile`, InSpec executes the controls `app-profile` and the controls specified in the `require_controls` block: + +- app-1 +- app-2 +- app-3 +- baseline-2 +- baseline-4 + +Controls `baseline-1`, `baseline-3`, and `baseline-5` are not 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 `baseline-profile`, they would not be run. + +And, just the way its possible to modify controls when using `include_controls`, +controls can be modified with `require_controls` as well. + +```ruby +require_controls 'baseline-profile' do + control 'baseline-2' do + impact 0.5 + end + control 'baseline-4' +end +``` + +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. + +## Include controls from different profile versions + +When a Chef InSpec profile has dependency on another profile to its specific version, then the controls can be included or selected by using the profile name and version separated by `-`. + +Here, `profile-a` has following dependency: + +```yaml +name: profile-a +depends: + - name: ssh + git: https://github.com/dev-sec/ssh-baseline.git + tag: 2.6.0 +``` + +And `profile-b` has following dependency: + +```yaml +name: profile-b +depends: + - name: ssh + git: https://github.com/dev-sec/ssh-baseline.git + tag: 2.7.0 +``` + +You can include or require controls of these profiles in a following manner: + +```ruby +include_controls "ssh-2.6.0" +include_controls "ssh-2.7.0" +``` + +OR + +```ruby +require_controls "ssh-2.6.0" +require_controls "ssh-2.7.0" +``` + +## Vendor dependencies + +When you execute a local profile, Inspec reads the `inspec.yml` file in order to +source any profile dependencies. It then caches the dependencies locally and +generates 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` diff --git a/docs-chef-io/content/inspec/profiles/files.md b/docs-chef-io/content/inspec/profiles/files.md new file mode 100644 index 000000000..e3eeb185e --- /dev/null +++ b/docs-chef-io/content/inspec/profiles/files.md @@ -0,0 +1,60 @@ ++++ +title = "Profile Files" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "Files" + identifier = "inspec/profiles/files" + parent = "inspec/profiles" + weight = 50 ++++ + +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. + +## Files location + +Add files to the `files` directory at the root of a profile. + +```text +examples/profile +├── controls +│ ├── example.rb +│── files +│ └── services.yml +└── inspec.yml +``` + +## Access file + +Use `inspec.profile.file('FILENAME.yml')` to access data from the file. + +## Example + +With `files/services.yml` containing the following data: + +```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 +``` diff --git a/docs-chef-io/content/inspec/profiles/inputs.md b/docs-chef-io/content/inspec/profiles/inputs.md new file mode 100644 index 000000000..8d021b4b4 --- /dev/null +++ b/docs-chef-io/content/inspec/profiles/inputs.md @@ -0,0 +1,485 @@ ++++ +title = "Chef InSpec Inputs" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "Inputs" + identifier = "inspec/profiles/Inputs" + parent = "inspec/profiles" + weight = 60 ++++ + +Inputs allow you to customize the behavior of Chef InSpec profiles. + +In [_profiles that accept inputs_](#profile-support), you can configure them using the following methods: + +- Inline in [control code](#control-code) +- In the [`inspec.yml` file](#inspecyml-file) +- In the command line using the [`--input` option](#input-cli-option) +- In an input file that's invoked with the CLI [`--input-file` option](#input-file-cli-option) +- In [input plugins](#plugins) + +Profiles that include other profiles can set inputs in the included profile, enabling a multi-layered approach to configuring profiles. + +## Profile support + +Profiles accept inputs from any input method as long as one or both of the following conditions exists: + +- inputs are listed in the [`inspec.yml` file](#inspecyml-file) +- inputs are included in the [control source code](#control-code) + +## Simple example + +Suppose you have a profile named `rock_critic` and its profile `inspec.yml` metadata file includes the following inputs: + +```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, define the value of the input using the `input` function: + +```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: + +```bash + × 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 +``` + +The control fails because the value is set to `10`, but the control expects `11`. +That result clearly won't do. + +By default, inputs set using the CLI `--input` option override inputs defined in control code. +So, you can set the `amplifier_max_volume` to `11` and the control will pass. + +```sh +inspec exec rock_critic --input amplifier_max_volume=11 +``` + +which returns: + +```bash + ✔ Big Rock Show: 11 + ✔ 11 is expected to cmp == 11 + +Profile Summary: 1 successful control, 0 control failures, 0 controls skipped +``` + +## Set inputs + +You can set inputs using one or more of the following methods. Each method has a different priority allowing them to override each other. Some methods allow you to modify their priority. For more information, see the [input priority documentation](#input-priority). + +### `--input` CLI option + +Use the `--input` option to set inputs and values directly on the command line. + +Inputs set with the `--input` option have a priority of 50. + +```sh +inspec exec my_profile --input input_name=input_value +``` + +You can set multiple inputs. + +```sh +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 recognized. + +```sh +inspec exec my_profile --input amplifier_volume=-11 +inspec exec my_profile --input water_depth=11.5 +``` + +You can 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. + +```sh +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. + +As of Chef InSpec 4.12, this mechanism has the following limitations: + +- No [input options](#input-options) may be set---only the name and value. +- 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-file` CLI option + +You can set inputs and values with a YAML file in the command line. + +Inputs set the `--input-file` option have a priority of 40. + +Create a YAML file using the following format: + +```yaml +an_input: a_value +another_input: another_value +``` + +Invoke the input file using the `--input-file` option. + +```sh +inspec exec my_profile --input-file .yml +``` + +As of Chef InSpec 4.3.2, this mechanism has the following limitations: + +- No [input options](#input-options) may be set---only the name and value. +- 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. + +### inspec.yml file + +In the [`inspec.yml` file](/inspec/profiles/inspec_yml), 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 + sensitive: true +``` + +All [input options](#input-options) are supported in metadata files. + +Defining inputs in profile metadata has two major advantages: + +- 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. +- You can set inputs in other profiles that you depend on using profile inheritance. + +#### 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. + +### Control Code + +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 + +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). + +#### Reading Inputs + +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. + +### Plugins + +You can also set inputs using custom input plugins, which retrieve values from external sources like secret stores or databases. Please check [RubyGems.org](https://rubygems.org/) for available InSpec input plugins. + +#### Disabling Caching + +Especially with plugins, you may want to re-evaluate inputs every time and not cache them. +By default, an existing input value is reused which can lead to problems if the retrieved values are expected to change. +An example for this is using `kitchen-inspec` with input plugins to connect to a Vault server for password retrieval. + +To disable input caching, you can disable the cache from your Ruby code: + +```ruby +Inspec::InputRegistry.instance.cache_inputs = false +``` + + +## Input options + +`name` + +: The input name. + + Required + + Date type: `String`. + + Allowed in: all input methods. + + When used in control code and `inspec.yml` file, the name is unique within the + current profile. When used in CLI input files, and kitchen-inspec, + the input is copied across all profiles using the same name. + +`description` + +: Human-meaningful explanation of the input. + + Optional + + Data type: `String` + + Allowed in: control code, `inspec.yml` file + +`value` + +: The value that will be available when you read the input. + See the [Reading Inputs](#reading-inputs-in-control-dsl) section for more information. + + Optional + + Data type: any Ruby or YAML type + + Allowed in: all input methods. + +`type` + +: If provided, Inspec will check the value of the input to see if it's 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. + + Optional + + Data type: `String` + + Allowed values: + + - `String` + - `Numeric` + - `Regexp` + - `Array` + - `Hash` + - `Boolean` + - `Any` + + Allowed in: control code, `inspec.yml` file + +`required` + +: If `true`, a control using the input will be failed + if it [reads](#reading-inputs) the value when none has been set. + + Optional + + Data type: Boolean + + Allowed values: `true` or `false`. + + Allowed in: control code, `inspec.yml` file + +`priority` + +: Higher values have higher precedence. + For more information, see the [input priority documentation](#input-priority). + + Optional + + Data type: `Integer` + + Allowed values: 0-100 + + Allowed in: control code, `inspec.yml` file + +`profile` + +: Optional + + Data type: `String`. + + Sets an input in another profile from your profile. + + Allowed in: control code, `inspec.yml` file + +`sensitive` + +: Optional + + Date type: `true` or `false`. + + If `true`, the value of the input will be used normally + during the `exec` run, but the value will be obscured as "***" in the "inputs" or + "attributes" section of any [Reporter](/inspec/reporters/) that explicitly lists + inputs (the `json` reporter is one such reporter). Note that this will not obscure + input values that are used as test results. + + Allowed in: `inspec.yml` file + +`pattern` + +: Validates the input by matching it with the provided regular expression. + + Optional + + Date type: `Regexp`. + + Allowed in: control code, `inspec.yml` file + +## Input priority + +The following table lists the *default* priority for input methods in order from highest priority (50) to lowest priority (20). + +| Input Provider | Priority | May change priority | +| --------------------------------------- | -------- | ------------------- | +| CLI `--input` option | 50 | No | +| inspec-kitchen `inputs:` section | 40 | No | +| CLI `--input-file` option | 40 | No | +| `inspec.yml` file in a wrapper cookbook | 35 | Yes | +| `inspec.yml` file | 30 | Yes | +| Inline control code | 20 | Yes | + +### Priority override + +An input can have multiple assignments with varying priority values. +When Chef InSpec evaluates an input, it determines the input value by finding the setting event with the highest priority. + +You can set a priority using the [`priority` option](#input-options) in the following input methods: + +- `inspec.yml` metadata file +- Control code + +For example, to set a priority of 50 in an `inspec.yml` metadata file, use: + +```yaml +inputs: +- name: very_important_input + value: 12 + priority: 50 +``` + +To set a priority in control code, use: + +```ruby +input('also_important', value: 42, priority: 45) +``` + +### Priority debugging + +If it's difficult to determine why InSpec is using a particular priority value, 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 + +```ruby +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. + +## InSpec 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. diff --git a/docs-chef-io/content/inspec/profiles/inspec_yml.md b/docs-chef-io/content/inspec/profiles/inspec_yml.md new file mode 100644 index 000000000..b43f10ad8 --- /dev/null +++ b/docs-chef-io/content/inspec/profiles/inspec_yml.md @@ -0,0 +1,138 @@ ++++ +title = "inspec.yml File" +draft = false +gh_repo = "inspec" + +aliases = ["/inspec/profiles/inspec_yaml"] + +[menu] + [menu.inspec] + title = "inspec.yml" + identifier = "inspec/profiles/inspec.yml" + parent = "inspec/profiles" + weight = 20 ++++ + +The `inspec.yml` metadata file describes a profile. This file is required. + +## Parameters + +The `inspec.yml` file defines the following information: + +`name` +: A unique name for the profile. + + Required + +`title` +: A human-readable name for the profile. + + Optional + +`maintainer` +: The profile maintainer. + + Optional + +`copyright` +: The copyright holder. + + Optional + +`copyright_email` +: The support contact information for the profile, typically an email address. + + Optional + +`license` +: The license for the profile. + + Optional + +`summary` +: A one line summary for the profile. + + Optional + +`description` +: A multiple line description of the profile. + + Optional + +`version` +: The profile version. + + Optional + +`inspec_version` +: The SemVer version of Chef InSpec that the profile can run under. + + Optional + +`supports` +: A list of [supported platform](/inspec/profiles/platforms/) targets. + + Optional + +`depends` +: A list of [profile dependencies](/inspec/profiles/depends/). + + Optional + +`inputs` +: A list of [inputs](/inspec/profiles/inputs) you can use in your controls. + + Optional + +`gem_dependencies` +: A list of profile [gem dependencies](/inspec/profiles/depends/#gem-dependencies) that must be installed for the profile to function correctly. + + Optional + +### 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: + - platform-family: linux +inputs: +- name: input_name + required: true + description: 'Input description.' + value: 10 + priority: 50 +depends: + - name: profile + path: ../path/to/profile +gem_dependencies: + - name: "gem-name" + version: ">= 2.0.0" +inspec_version: "~> 2.1" +``` + +### Embedded ERB + +The `inspec.yml` also supports embedded ERB. + +```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'] %> +``` diff --git a/docs-chef-io/content/inspec/profiles/platforms.md b/docs-chef-io/content/inspec/profiles/platforms.md new file mode 100644 index 000000000..3649a1afc --- /dev/null +++ b/docs-chef-io/content/inspec/profiles/platforms.md @@ -0,0 +1,89 @@ ++++ +title = "InSpec Profile Platform Support" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "Platforms" + identifier = "inspec/profiles/platforms" + parent = "inspec/profiles" + weight = 90 ++++ + +Use the `supports` setting in the [`inspec.yml` file](/inspec/profiles/inspec_yml/) 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. `platform-name` supports asterisk (`*`) wildcard use. +- Use `release` to restrict to a specific platform version, and use together with `platform-name`. `release` supports asterisk (`*`) wildcard use. +- Use `platform` to restrict on either platform-name or platform-family. + +To get a list of all valid values for `platform-name` and `platform-family`, run `inspec schema platforms`, which returns the supported list in JSON format. + +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, use: + +```yaml +name: ssh +supports: + - platform-name: debian +``` + +To target only Ubuntu version 20.04, use: + +```yaml +name: ssh +supports: + - platform-name: ubuntu + release: 20.04 +``` + +To target the entire release of Ubuntu version 20.x, use: + +```yaml +name: ssh +supports: + - platform-name: ubuntu + release: 20.* +``` + +To target the Red Hat and derivative platforms such as CentOS and Oracle Linux, use: + +```yaml +name: ssh +supports: + - platform-family: redhat +``` + +To target the entire Windows 2019 platform family, including Datacenter and Core Servers, use: + +```yaml +name: ssh +supports: + - platform-name: windows_server_2019* +``` + +To target anything running on Amazon AWS, use: + +```yaml +name: ssh +supports: + - platform: aws +``` + +To target all of these examples in a single `inspec.yml` file, use: + +```yaml +name: ssh +supports: + - platform-name: debian + - platform-name: ubuntu + release: 20.04 + - platform-family: redhat + - platform: aws +``` diff --git a/docs-chef-io/content/inspec/profiles/signing.md b/docs-chef-io/content/inspec/profiles/signing.md new file mode 100644 index 000000000..6998d29b4 --- /dev/null +++ b/docs-chef-io/content/inspec/profiles/signing.md @@ -0,0 +1,193 @@ ++++ +title = "Signed InSpec Profiles" +draft = false +gh_repo = "inspec" + +aliases = ['/inspec/signing/'] + +[menu] + [menu.inspec] + title = "Signed Profiles" + identifier = "inspec/profiles/Signed profiles" + parent = "inspec/profiles" + weight = 100 ++++ + +This page documents how to make and use signed InSpec profiles. + +A signed profile, or `.iaf` file, is an InSpec profile with a digital signature that attests to its authenticity. +Progress Chef-authored profiles are available as signed profiles starting in 2022. + +IAF files are not human-readable, but you can view them using `inspec export`. Support for IAF v2.0 was added to InSpec 5. + +## How does profile signing work? + +Profile signing uses a matched pair of keys. The _signing key_ is secret and is used to sign the profile. The _validation key_ is widely distributed and verifies the signed profile signature. + +Keypairs are first searched for in the current directory and then in the user's `~/.inspec/keys` directory. +Progress Chef validation keys are also distributed in the `etc/keys` directory of the InSpec installation tree. +Finally, if a validation key is not found, the profile verification system attempts to download keys from the [InSpec Github](https://github.com/inspec/inspec/tree/main/etc/keys) repository. + +## Execute a signed profile + +You can execute a signed profile like any other profile. + +```bash +$ inspec exec simple.iaf + +Profile: InSpec Profile (simple) +Version: 0.1.0 +Target: local:// +Target ID: 46f308fc-7ad8-4230-8dd0-f2582227e164 + + ✔ tmp-1.0: Create /tmp directory + ✔ File /tmp is expected to be directory + + File /tmp + ✔ is expected to be directory + +Profile Summary: 1 successful control, 0 control failures, 0 controls skipped +Test Summary: 2 successful, 0 failures, 0 skipped +``` + +A signed profile is checked for validity before it's executed. If the profile cannot be verified, then InSpec exits with `code 5` (bad signature). + +## Identify key used to sign profile + +The `inspec sign verify` command displays which key is used to sign a profile. + +```bash +$ inspec sign verify simple-0.1.0-v2.iaf +Verifying simple-0.1.0-v2.iaf +Detected format version 'INSPEC-PROFILE-2' +Attempting to verify using key 'cwolfe-03' +Profile is valid. +``` + +## See contents of signed profile + +Use the `inspec export` command to examine a signed profile's contents. You must be able to verify the profile in order to export the contents. By default, the `export` command dumps a profile summary in a human-readable YAML format, including most of the metadata and the control IDs, control source code, inputs, and other profile information. + +- To view a **signed profile**, run: + + ```bash + $ inspec export simple-0.1.0.iaf + --- + :name: simple + :title: InSpec Profile + :maintainer: The Authors + :copyright: The Authors + :copyright_email: you@example.com + :license: Apache-2.0 + :summary: An InSpec Compliance Profile + :version: 0.1.0 + :supports: + - :platform: os + :controls: + - :title: + :desc: + :descriptions: {} + :impact: 0.5 + :refs: [] + :tags: {} + :code: '' + :source_location: + :ref: "/Users/cwolfe/sandbox/inspec/inspec-5/lib/inspec/control_eval_context.rb" + :line: 92 + :id: "(generated from example.rb:6 7007cd4757c4892cc89977e9847c1051)" + - :title: Create /tmp directory + :desc: An optional description... + :descriptions: + :default: An optional description... + :impact: 0.7 + :refs: [] + :tags: {} + :code: | + control "tmp-1.0" do # A unique ID for this control + impact 0.7 # The criticality, if this control fails. + title "Create /tmp directory" # A human-readable title + desc "An optional description..." + describe file("/tmp") do # The actual test + it { should be_directory } + end + end + :source_location: + :ref: controls/example.rb + :line: 11 + :id: tmp-1.0 + :groups: + - :title: sample section + :controls: + - "(generated from example.rb:6 7007cd4757c4892cc89977e9847c1051)" + - tmp-1.0 + :id: controls/example.rb + :inputs: [] + :sha256: c1a5298d56f028386edf4c52573264ca38d476ce6156a053a2c412991fb0b646 + :status_message: '' + :status: loaded + :generator: + :name: inspec + :version: 5.14.5 + ``` + +- To view a profile's **README**, run: + + ```bash + $ inspec export --what readme simple-0.1.0.iaf + # Example InSpec Profile + + This example shows the implementation of an InSpec profile. + + ``` + +- To view a **signed profile's metadata file (inspec.yml)**, run: + + ```bash + $ inspec export --what metadata simple-0.1.0.iaf + name: simple + title: InSpec Profile + maintainer: The Authors + copyright: The Authors + copyright_email: you@example.com + license: Apache-2.0 + summary: An InSpec Compliance Profile + version: 0.1.0 + supports: + platform: os + ``` + +## Mandatory profile signing + +**Chef InSpec 6** and above has an optional setting that requires that all profiles are signed. +If mandatory profile signing is enabled, InSpec will not execute functions with an un-signed profile and exits with exit code 6. + +To enable mandatory profile signing, set the environment variable `CHEF_PREVIEW_MANDATORY_PROFILE_SIGNING` to any non-empty value. + +If you need to bypass mandatory profile signing, use the `--allow-unsigned-profiles` CLI option or set the `CHEF_ALLOW_UNSIGNED_PROFILES` environment variable. + +## Advanced Usage + +### Create a signing and validation keys + +Most users of signed profiles need not create keys of their own unless they wish to sign and distribute profiles themselves. +To generate keys of your own, use the `inspec sign generate-keys` command: + +```bash +$ inspec sign generate-keys --keyname test-03 +Generating keys +Generating signing key in /Users/cwolfe/.inspec/keys/test-03.pem.key +Generating validation key in /Users/cwolfe/.inspec/keys/test-03.pem.pub +``` + +Keep your signing key secret. You must devise a way of distributing the validation key to your profile users; they will be unable to use your signed IAF files unless they have the validation key. + +### Sign profile + +You will need a signing key to sign profiles. Specify the path of profile and the name of the key. + +```bash +$ inspec sign profile simple --keyname test-03 +Signing simple with key cwolfe-03 +Dependencies for profile simple successfully vendored to /Users/cwolfe/sandbox/inspec/inspec-5/temp/simple/vendor +Successfully generated simple-0.1.0.iaf +``` diff --git a/docs-chef-io/content/inspec/style.md b/docs-chef-io/content/inspec/profiles/style.md similarity index 83% rename from docs-chef-io/content/inspec/style.md rename to docs-chef-io/content/inspec/profiles/style.md index 293c0b327..44a4ef3d1 100644 --- a/docs-chef-io/content/inspec/style.md +++ b/docs-chef-io/content/inspec/profiles/style.md @@ -3,16 +3,70 @@ title = "Chef InSpec Profile Style Guide" draft = false gh_repo = "inspec" +aliases = ['/inspec/style/'] + [menu] [menu.inspec] title = "Profile Style Guide" - identifier = "inspec/reference/style.md Profile Style Guide" - parent = "inspec/reference" - weight = 80 + identifier = "inspec/profiles/style" + parent = "inspec/profiles" + weight = 100 +++ This is a set of recommended Chef InSpec rules you should use when writing controls. +## "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: + +```bash +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: + +```bash +test file + ✔ should be a file +``` + ## Control Files ### Place control files in `controls/` and end them with `.rb` diff --git a/docs-chef-io/content/inspec/reporters.md b/docs-chef-io/content/inspec/reporters.md index e6f6f099a..723373e14 100644 --- a/docs-chef-io/content/inspec/reporters.md +++ b/docs-chef-io/content/inspec/reporters.md @@ -6,22 +6,25 @@ gh_repo = "inspec" [menu] [menu.inspec] title = "Reporters" - identifier = "inspec/reference/reporters.md Reporters" - parent = "inspec/reference" - weight = 50 + identifier = "inspec/Reporters" + parent = "inspec" + weight = 100 +++ -A `reporter` is a facility for formatting and delivering the results of a Chef InSpec auditing run. Reporters were introduced in Chef InSpec 1.51.6. +A Chef InSpec reporter formats and delivers the results of a Chef InSpec audit run. You can output the results of your audits to more than one reporter. -Chef InSpec allows you to output your test results to one or more reporters. +## Configure -Configure the reporter(s) using the `--reporter` option or as part of the general configuration file using the `--config` (or `--json-config`, prior to v3.6) option. Both the --reporter and --config options may be used, in which case the options are merged. While you can configure multiple reporters to write to different files, only one reporter can output to the screen(stdout). +Configure the reporter(s) using the `--reporter` option or as part of the general configuration file using the `--config` option. -## Syntax +You can use both the `--reporter` and `--config` options, in which case the options are merged. +While you can configure multiple reporters to write to different files, only one reporter can output to the screen(stdout). + +### reporter option You can specify one or more reporters using the `--reporter` CLI flag. You can also specify an output by appending a path separated by a colon. -**Output json to screen** +**Output JSON to screen** ```bash inspec exec example_profile --reporter json @@ -29,7 +32,7 @@ inspec exec example_profile --reporter json inspec exec example_profile --reporter json:- ``` -**Output yaml to screen.** +**Output YAML to screen.** ```bash inspec exec example_profile --reporter yaml @@ -37,19 +40,19 @@ inspec exec example_profile --reporter yaml inspec exec example_profile --reporter yaml:- ``` -**Output cli to screen and write json to a file.** +**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.** +**Output nothing to screen and write JUnit and HTML to a file.** ```bash inspec exec example_profile --reporter junit2:/tmp/junit.xml html:www/index.html ``` -**Output json to screen and write to a file. Write junit to a file.** +**Output JSON to screen and write to a file. Write JUnit to a file.** ```bash inspec exec example_profile --reporter json junit2:/tmp/junit.xml | tee out.json @@ -61,9 +64,18 @@ If you wish to pass the profiles directly after specifying the reporters, you mu inspec exec --reporter json junit2:/tmp/junit.xml -- profile1 profile2 ``` -Using the CLI option `--config`, you can also set reporters. +**Output real-time progress to screen with a progress bar.** -**Output cli to screen.** +```bash +inspec exec example_profile --reporter progress-bar +``` + +### config file + +You can also set reporters using a configuration file. +For guidance on creating and using a config file, see the [InSpec config documentation](/inspec/config/). + +**Output CLI to screen.** ```json { @@ -75,7 +87,7 @@ Using the CLI option `--config`, you can also set reporters. } ``` -**Output cli to screen and write json to a file.** +**Output CLI to screen and write JSON to a file.** ```json { @@ -91,31 +103,52 @@ Using the CLI option `--config`, you can also set reporters. } ``` -**Output real-time progress to screen with a progress bar.** +## Options -```bash -inspec exec example_profile --reporter progress-bar -``` - -## Reporter Options - -The following are CLI options that are used to modify reporter behavior. Many of these options allow you to limit the report size because some reporters (such as the json-automate reporter) limit on the total size of the report that can be processed. +The following are CLI options that are used to modify reporter behavior. +Many of these options allow you to limit the report size because some reporters (such as the json-automate reporter) limit on the total size of the report that can be processed. `--diff`, `--no-diff` -: Include a `diff` comparison of textual differences in the failed test output (default: `true`). +: Include a `diff` comparison of textual differences in the failed test output. + + Use `--no-diff` to limit the size of the report output when tests contain large amounts of text output. + + Default: `true` + +`--enhanced-outcomes` + +: Includes enhanced outcome of controls in report data. + + The control level status outcomes are: + - `Passed` + - `Failed` + - `Not Applicable (N/A)` + - `Not Reviewed (N/R)` + - `Error (ERR)`. + + Supported with the following reporters: + - automate + - cli + - html2 + - json + - json-automate + - progress-bar + - yaml -: Use `--no-diff` to limit the size of the report output when tests contain large amounts of text output. `--filter-empty-profiles` : Remove empty profiles (those containing zero controls, such as resource packs) from the reporter's output. -`--reporter-backtrace-inclusion`, `--no-reporter-backtrace-inclusion` +`--reporter-backtrace-inclusion` +`--no-reporter-backtrace-inclusion` -: Include a code backtrace in report data (default: `true`). +: Include a code backtrace in report data. -: The `--no-reporter-backtrace-inclusion` option may be used to limit report size when large code stack traces are present in the output. + The `--no-reporter-backtrace-inclusion` option may be used to limit report size when large code stack traces are present in the output. + + Default: `true` `--reporter-include-source` @@ -123,89 +156,75 @@ The following are CLI options that are used to modify reporter behavior. Many of `--reporter-message-truncation=N` -: Number of characters to truncate failure messages in report data (default: no truncation). +: Number of characters to truncate failure messages in report data. -: This may be used to limit the size of reports when failure messages are exceptionally large. + This may be used to limit the size of reports when failure messages are exceptionally large. -`--enhanced-outcomes` + Default: no truncation -: Includes enhanced outcome of controls in report data. +## Reporters -: The control level status outcomes are `Passed`, `Failed`, `Not Applicable (N/A)`, `Not Reviewed (N/R)`, or `Error (ERR)`. +The following are the supported reporters. -: Only supported for cli, progress-bar, html2, json, json-automate, automate, and yaml reporters. +### automate -## Supported Reporters +The `automate` reporter type is a special reporter which sends its results over the network to [Chef Automate]({{< relref "/automate/">}}). To use this reporter, you must pass in the correct configuration via a JSON configuration `--config`. -The following are the currently supported reporters: +Example Configuration: + +```json +{ + "reporter": { + "automate" : { + "stdout" : false, + "url" : "https://AUTOMATE_URL/data-collector/v0/", + "token" : "AUTOMATE_ADMIN_TOKEN", + "insecure" : true, + "node_name" : "inspec_test_node", + "environment" : "prod" + } + } +} +``` + +#### Mandatory fields + +`stdout` +: Either suppress or shows the automate report in the CLI screen on completion. + +`url` +: Chef Automate. Append `data-collector/v0/` at the end. + +`token` +: Chef Automate tokens. You can generate this token by navigating to the **admin** tab of Automate and then clicking **API keys**. + +#### Optional fields + +`insecure` +: Disables or enables the SSL check when accessing the Chef Automate instance. + +`node_name` +: Node name which shows up in Chef Automate. + +`node_uuid` +: Node UUID, which shows up in Chef Automate. Use a single static UUID per node for all your reports. You must specify a `node_uuid` in the Chef InSpec configuration file if running Chef InSpec outside of an audit cookbook or another environment where a `chef_guid` or `node_uuid` is already known to Chef InSpec. + +`environment` +: Sets the environment metadata for Chef Automate. ### cli This is the basic text based report. It includes details about tests that passed and failed and an overall summary at the end. -### json - -This reporter includes all information about the profiles and test results in standard JSON format. You may optionally pass through arbitrary structured JSON data by setting a JSON configuration with the `--config` parameter. - -For example: - -```json -{ - "reporter": { - "json": { - "stdout": true, - "passthrough": { - "a": 1, - "b": false - } - } - } -} -``` - -### 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. - -### junit2 - -This reporter outputs the standard JUnit spec in XML format and is recommended for all new users of JUnit. - -#### junit - -This legacy reporter outputs nonstandard JUnit XML and is provided only for backward compatibility. - -### progress - -This reporter is very condensed and provides you a `.`(pass), `f`(fail), or `*`(skip) character per test and a small summary at the end. - -### progress-bar - -This reporter outputs the real-time progress of a running InSpec profile using a progress bar and prints the running control's ID with an indicator of the control's status (`Passed`, `failed`, or `skipped`). - -For example: - -![Progress Bar Reporter Outcome](/images/inspec/reporter_outcome_progress_bar.png) - -And reporter outcome with `--enhanced-outcomes` option: - -![Progress Bar Reporter Outcome with enhanced outcomes](/images/inspec/reporter_outcome_progress_bar_enhanced_outcomes.png) - -### json-rspec - -This reporter includes all information from the Rspec runner. Unlike the json reporter, this includes Rspec-specific details. +This reporter is a very minimal text-based report. It shows you which tests passed by name and has a small summary at the end. ### html -This reporter is the legacy RSpec HTML reporter retained for backward compatibility. The report generated is unaware of profiles or controls and only contains unsorted test information. Most users should migrate to the `html2` reporter for more complete data. +This reporter is the legacy RSpec HTML reporter retained for backward compatibility. +The report generated is unaware of profiles or controls and only contains unsorted test information. +Most users should migrate to the `html2` reporter for more complete data. ### html2 @@ -237,53 +256,27 @@ Specifies the full path to the location of a CSS file that is read and inlined i Specifies the full path to the location of a JavaScript file that is read and inlined into the HTML report. The default JavaScript is included. The JavaScript file should implement at least a `pageLoaded()` function, which is called by the `onload` event of the HTML `body` element. -## Automate Reporter +### json -The `automate` reporter type is a special reporter which sends its results over the network to [Chef Automate]({{< relref "/automate/">}}). To use this reporter, you must pass in the correct configuration via a json configuration `--config`. +This reporter includes all information about the profiles and test results in standard JSON format. You may optionally pass through arbitrary structured JSON data by setting a JSON configuration with the `--config` parameter. -Example Configuration: +For example: ```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" + "json": { + "stdout": true, + "passthrough": { + "a": 1, + "b": false } + } } } ``` -### Mandatory fields - -`stdout` -: Either suppress or shows the automate report in the CLI screen on completion. - -`url` -: Automate 2 url. Append `data-collector/v0/` at the end. - -`token` -: Automate 2 tokens. You can generate this token by navigating to the **admin** tab of A2 and then clicking **API keys**. - -### Optional fields - -`insecure` -: Disables or enables the SSL check when accessing the Automate 2 instance. - -`node_name` -: Node name which shows up in Automate. - -`node_uuid` -: Node UUID, which shows up in Chef Automate. Use a single static UUID per node for all your reports. You must specify a `node_uuid` in the Chef InSpec configuration file if running Chef InSpec outside of an audit cookbook or another environment where a `chef_guid` or `node_uuid` is already known to Chef InSpec. - -`environment` -: Sets the environment metadata for Automate. - -## json-Automate Reporter +### json-automate The `json-automate` reporter is a special reporter that prepares the data format used by the Automate reporter. `json-automate` does not communicate on the network; instead, it simply produces the JSON report format that Automate would be consuming. Notably, the report is based on the `json` reporter, with the following modifications: @@ -291,3 +284,39 @@ The `json-automate` reporter is a special reporter that prepares the data format - Child profiles are deleted, flattening the report. The `json-automate` reporter is primarily used for internal needs, but some users may find it helpful if they want a JSON-based reporter that merges controls. + +### json-min + +This reporter is a redacted version of the JSON and only includes test results. + +### json-rspec + +This reporter includes all information from the Rspec runner. Unlike the JSON reporter, this includes Rspec-specific details. + +### junit + +This legacy reporter outputs nonstandard JUnit XML and is provided only for backward compatibility. New JUnit users should use the junit2 reporter. + +### junit2 + +This reporter outputs the standard JUnit spec in XML format. New JUnit users should use this reporter instead of the legacy junit reporter. + +### progress + +This reporter is very condensed and provides you a `.`(pass), `f`(fail), or `*`(skip) character per test and a small summary at the end. + +### progress-bar + +This reporter outputs the real-time progress of a running InSpec profile using a progress bar and prints the running control's ID with an indicator of the control's status (`Passed`, `failed`, or `skipped`). + +For example: + +![Progress Bar Reporter showing outcome of tests in CLI output.](/images/inspec/reporter_outcome_progress_bar.png) + +And reporter outcome with `--enhanced-outcomes` option: + +![Progress Bar Reporter showing outcome of tests in CLI output with enhance output.](/images/inspec/reporter_outcome_progress_bar_enhanced_outcomes.png) + +### yaml + +This reporter includes all information about the profiles and test results in standard yaml format. diff --git a/docs-chef-io/content/inspec/shell.md b/docs-chef-io/content/inspec/shell.md index b1e947b63..4428af25e 100644 --- a/docs-chef-io/content/inspec/shell.md +++ b/docs-chef-io/content/inspec/shell.md @@ -6,12 +6,12 @@ gh_repo = "inspec" [menu] [menu.inspec] title = "InSpec Shell" - identifier = "inspec/reference/shell.md Chef InSpec Shell" - parent = "inspec/reference" - weight = 110 + identifier = "inspec/Chef InSpec Shell" + parent = "inspec" + weight = 70 +++ -The Chef InSpec interactive shell is a pry based REPL that can be used to +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 Language, its resources, tests, and plugins without @@ -20,14 +20,13 @@ having to create a profile or write a test file. See 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. +on Learn Chef for a hands-on example that uses Chef InSpec shell. -## Launching the shell +## Launch the shell If you are using Chef InSpec from a platform-specific package (rpm, msi, etc.) or from a Chef prepared shell in Chef Workstation, you can directly launch -Chef InSpec shell against your local machine using the following. See - for details. +Chef InSpec shell against your local machine using the `inspec shell` command. ```bash inspec shell @@ -77,10 +76,10 @@ Once inside the shell your resource will be available: inspec> example_config ``` -## Using Ruby in Chef InSpec shell +## Use Ruby -Since Chef InSpec shell is pry based, you may treat the shell as an -interactive Ruby session. You may write Ruby expressions and evaluate +Since Chef InSpec shell is pry based, you can treat the shell as an +interactive Ruby session. You can 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`. @@ -95,12 +94,12 @@ inspec> 1 + 2 inspec> exit ``` -## Using Chef InSpec Language in Chef InSpec shell +## Use InSpec DSL -Chef InSpec shell will automatically evaluate the result of every command as +The Chef InSpec shell automatically evaluates 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. +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 @@ -167,10 +166,10 @@ inspec> end Summary: 0 successful, 1 failures, 0 skipped ``` -## Running a single Chef InSpec command +## Run InSpec commands -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`. +You can run a single Chef InSpec command and fetch its results using the `-c` flag. +This is similar to using `bash -c`. ```bash $ inspec shell -c 'describe file("/Users/username") do it { should exist } end' @@ -232,15 +231,15 @@ $ inspec shell --format json -c 'describe file("/Users/test") do it { should exi } ``` -## Running Chef InSpec Shell With Inputs +## Set inputs -With InSpec [profiles that support inputs]({{< relref "inputs/#which-profiles-support-inputs" >}}), -you can set inputs using the InSpec `shell` command. This allows you to work more consistently with -InSpec profiles when switching between the `shell` and `exec` commands. +With InSpec [profiles that support inputs]({{< relref "/inspec/profiles/inputs#profile-support" >}}), +you can set inputs using the InSpec `shell` command. +This allows you to work more consistently with InSpec profiles when switching between the `shell` and `exec` commands. -For more details on inputs, see the [inputs reference](/inspec/inputs/). +For more details on inputs, see the [inputs reference](/inspec/profiles/inputs/). -### Set Inputs with Command-line Options +### Set inputs with command-line options The `shell` command accepts one or more inputs in the command line as single-quoted YAML or JSON structures. @@ -264,7 +263,7 @@ Test Summary: 1 successful, 0 failures, 0 skipped inspec> exit ``` -### Set Inputs with YAML File +### Set inputs with YAML file You can also save inputs and values to one or more YAML files and pass them to `shell` in the command line. For example: diff --git a/docs-chef-io/content/inspec/signing.md b/docs-chef-io/content/inspec/signing.md deleted file mode 100644 index bc005734a..000000000 --- a/docs-chef-io/content/inspec/signing.md +++ /dev/null @@ -1,193 +0,0 @@ -+++ -title = "Signed InSpec Profiles" -draft = false -gh_repo = "inspec" - -[menu] - [menu.inspec] - title = "Signed InSpec Profiles" - identifier = "inspec/reference/signing.md Signed InSpec Profiles" - parent = "inspec/reference" - weight = 60 -+++ - -This page documents the `inspec sign` command introduced in InSpec 5, the mandatory profile signing feature introduced in InSpec 6, and details some methods to work with signed profiles. - -## Usage - -### What is a Signed Profile? - -A signed profile, or `.iaf` file, is an InSpec profile with a digital signature that attests to its authenticity. Progress Chef authored profiles are available as signed profiles starting from 2022. - -IAF files are not human-readable, but may be viewed using `inspec export`. Support for IAF v2.0 was added to InSpec 5. - -### Mandatory profile signing - -**Chef InSpec 6** and above has an optional setting that requires that all profiles are signed. -If mandatory profile signing is enabled, InSpec will not execute functions with an un-signed profile and exits with exit code 6. - -To enable mandatory profile signing, set the environment variable `CHEF_PREVIEW_MANDATORY_PROFILE_SIGNING` to any non-empty value. - -If you need to bypass mandatory profile signing, use the `--allow-unsigned-profiles` CLI option or set the `CHEF_ALLOW_UNSIGNED_PROFILES` environment variable. - -### How does Profile Signing Work? - -Profile signing uses a matched pair of keys. The _signing key_ is secret and is used to sign the profile. The _validation key_ is widely distributed and verifies the signed profile signature. - -Keypairs are first searched for in the current directory and then in the user's `~/.inspec/keys` directory. Progress Chef validation keys are also distributed in the `etc/keys` directory of the InSpec installation tree. Finally, if a validation key is not found, the profile verification system attempts to download keys from the [InSpec Github](https://github.com/inspec/inspec/tree/main/etc/keys) repository. - -### How do I execute a signed profile? - -You can execute a signed profile like any other profile. - -```bash -[cwolfe@lodi temp]$ inspec exec simple.iaf - -Profile: InSpec Profile (simple) -Version: 0.1.0 -Target: local:// -Target ID: 46f308fc-7ad8-4230-8dd0-f2582227e164 - - ✔ tmp-1.0: Create /tmp directory - ✔ File /tmp is expected to be directory - - File /tmp - ✔ is expected to be directory - -Profile Summary: 1 successful control, 0 control failures, 0 controls skipped -Test Summary: 2 successful, 0 failures, 0 skipped -``` - -A signed profile is checked for validity before being executed, and if it cannot be verified, then InSpec exits with `code 5` (bad signature). - -### How do I know which key is used to sign a profile? - -The `inspec sign verify` command displays which key is used to sign a profile. - -```bash -[cwolfe@lodi temp]$ inspec sign verify simple-0.1.0-v2.iaf -Verifying simple-0.1.0-v2.iaf -Detected format version 'INSPEC-PROFILE-2' -Attempting to verify using key 'cwolfe-03' -Profile is valid. -``` - -### How do I look inside a signed profile? - -Use the `inspec export` command to examine a signed profile's contents. You must be able to verify the profile in order to export the contents. By default, the `export` command dumps a profile summary in a human-readable YAML format, including most of the metadata and the control IDs, control source code, inputs, and other profile information. - -- To view a **signed profile**, run: - -```bash -[cwolfe@lodi temp]$ inspec export simple-0.1.0.iaf ---- -:name: simple -:title: InSpec Profile -:maintainer: The Authors -:copyright: The Authors -:copyright_email: you@example.com -:license: Apache-2.0 -:summary: An InSpec Compliance Profile -:version: 0.1.0 -:supports: -- :platform: os -:controls: -- :title: - :desc: - :descriptions: {} - :impact: 0.5 - :refs: [] - :tags: {} - :code: '' - :source_location: - :ref: "/Users/cwolfe/sandbox/inspec/inspec-5/lib/inspec/control_eval_context.rb" - :line: 92 - :id: "(generated from example.rb:6 7007cd4757c4892cc89977e9847c1051)" -- :title: Create /tmp directory - :desc: An optional description... - :descriptions: - :default: An optional description... - :impact: 0.7 - :refs: [] - :tags: {} - :code: | - control "tmp-1.0" do # A unique ID for this control - impact 0.7 # The criticality, if this control fails. - title "Create /tmp directory" # A human-readable title - desc "An optional description..." - describe file("/tmp") do # The actual test - it { should be_directory } - end - end - :source_location: - :ref: controls/example.rb - :line: 11 - :id: tmp-1.0 -:groups: -- :title: sample section - :controls: - - "(generated from example.rb:6 7007cd4757c4892cc89977e9847c1051)" - - tmp-1.0 - :id: controls/example.rb -:inputs: [] -:sha256: c1a5298d56f028386edf4c52573264ca38d476ce6156a053a2c412991fb0b646 -:status_message: '' -:status: loaded -:generator: - :name: inspec - :version: 5.14.5 -``` - -- To view a profile's **README**, run: - -```bash -[cwolfe@lodi temp]$ inspec export --what readme simple-0.1.0.iaf -# Example InSpec Profile - -This example shows the implementation of an InSpec profile. - -``` - -- To view a **signed profile's metadata file (inspec.yml)**, run: - -```bash -[cwolfe@lodi temp]$ inspec export --what metadata simple-0.1.0.iaf -name: simple -title: InSpec Profile -maintainer: The Authors -copyright: The Authors -copyright_email: you@example.com -license: Apache-2.0 -summary: An InSpec Compliance Profile -version: 0.1.0 -supports: - platform: os -``` - -## Advanced Usage - -### How do I create keys? - -Most users of signed profiles need not create keys of their own unless they wish to sign and distribute profiles themselves. To generate keys of your own, use the `inspec sign generate-keys` command: - -```bash -[cwolfe@lodi temp]$ inspec sign generate-keys --keyname test-03 -Generating keys -Generating signing key in /Users/cwolfe/.inspec/keys/test-03.pem.key -Generating validation key in /Users/cwolfe/.inspec/keys/test-03.pem.pub -[cwolfe@lodi temp]$ -``` - -Keep your signing key secret. You must devise a way of distributing the validation key to your profile users; they will be unable to use your signed IAF files unless they have the validation key. - -### How do I sign profiles? - -You will need a signing key to sign profiles. Specify the path of profile and the name of the key. - -```bash -[cwolfe@lodi temp]$ inspec sign profile simple --keyname test-03 -Signing simple with key cwolfe-03 -Dependencies for profile simple successfully vendored to /Users/cwolfe/sandbox/inspec/inspec-5/temp/simple/vendor -Successfully generated simple-0.1.0.iaf -[cwolfe@lodi temp]$ -``` diff --git a/docs-chef-io/content/inspec/troubleshooting.md b/docs-chef-io/content/inspec/troubleshooting.md index 6fe947ec9..c9b02067e 100644 --- a/docs-chef-io/content/inspec/troubleshooting.md +++ b/docs-chef-io/content/inspec/troubleshooting.md @@ -8,7 +8,7 @@ gh_repo = "inspec" title = "Troubleshooting" identifier = "inspec/Troubleshooting" parent = "inspec" - weight = 55 + weight = 120 +++ ## Exit code 5 diff --git a/docs-chef-io/content/inspec/waivers.md b/docs-chef-io/content/inspec/waivers.md index b56a6e08e..5e8b12e32 100644 --- a/docs-chef-io/content/inspec/waivers.md +++ b/docs-chef-io/content/inspec/waivers.md @@ -6,17 +6,17 @@ gh_repo = "inspec" [menu] [menu.inspec] title = "Waivers" - identifier = "inspec/reference/waivers.md Waivers" - parent = "inspec/reference" - weight = 140 + identifier = "inspec/Waivers" + parent = "inspec" + weight = 110 +++ Waivers allow you to waive controls and to dictate the running and/or reporting of those controls. A waiver file 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 +- which controls are waived +- a description of why it is waived +- (optionally) whether they should be skipped from running +- (optionally) an expiration date for the waiver ## Usage @@ -45,7 +45,7 @@ Specify the following parameters in the waiver file: `justification` **required** : A description of the waiver. This might include a reason for the waiver or the person who signed off on the waiver. -### Examples +## Examples Example in YAML: @@ -78,6 +78,14 @@ Example in JSON: Example in CSV: +```plain +control_id,justification,run,expiration_date +waiver_control_1_2_3,Not needed until Q3,TRUE,2019-10-15T00:00:00.000Z +xccdf_org.cisecurity.benchmarks_rule_1.1.1.4_Ensure_mounting_of_hfs_filesystems_is_disabled,This might be a bug in the test. @qateam,FALSE,2020-03-01T00:00:00.000Z +``` + +which looks like this: + | control_id | justification | run | expiration_date | |---------------------------------------------------------------------------------------------|------------------------------------------|-------|--------------------------| | waiver_control_1_2_3 | Not needed until Q3 | TRUE | 2019-10-15T00:00:00.000Z |