Prioritize, skip, and fail with policy severities in Checkov

Not all policies are created equal.

Some, like encryption and public access, are obviously more critical than others like backup retention and tagging.

To help categorize and distinguish the varying degrees of criticality, the Bridgecrew platform has always included severity metadata on policies. Checkov has never included this metadata—until now!

Now, when you run the latest version of Checkov with a Bridgecrew API token (that can be obtained by signing up for a free account) or Prisma API key, the scan results will now include a severity in the output for any check that exists in the Bridgecrew platform:

The possible values are LOW , MEDIUM, HIGH, and CRITICAL.

Having severities in Checkov not only helps you to better understand and prioritize misconfigurations but can also be used to make your configuration more concise.

As your Checkov usage matures, flags are crucial to specify which policies to skip and whether violations of specific policies should result in hard or soft fails in your CI/CD pipelines. But that list of flags can get long and unruly fast. Including severities as filters in your --check and --skip-check flags or your --hard-fail-on and --soft-fail-on flags gives you an option to start with more general filtered policy lists that you can then whittle down as described in the video and blog below.

Check and skip check

Previously, you had the option to specify a list of checks to run or skip using check IDs (e.g., CKV_AWS_123) or a wildcard ( CKV_AWS_*). Now, you can combine these options with a severity to control which checks are included without having to type out long lists of IDs.

The Checkov docs cover this in more detail, but here are some examples.

When you include a severity with the --check flag, Checkov will include all checks with a severity equal to or higher than the value you specify. So to include all HIGH and CRITICAL checks in your Checkov run:

checkov --check HIGH --bc-api-key API_KEY ...

When you include a severity with --skip-check, Checkov will skip all checks with a severity equal to or lower than the value you specify. So, to skip all LOW and MEDIUM severity checks:

checkov --skip-check MEDIUM --bc-api-key API_KEY ...

You can also combine severities and IDs. For example, to run all HIGH and CRITICAL checks, and also check CKV_AWS_123 which we can pretend is a LOW severity policy:

checkov --check HIGH,CKV_AWS_123 --bc-api-key API_KEY ...

You can also use the --check and --skip-check flags together to carve out other precise check lists. When you combine these flags, Checkov will first apply the --check flag, and then exclude any checks that match the --skip-check flag. For example, you can include all HIGH andCRITICAL checks, but not CKV_AWS_789 which we will pretend is a HIGH severity policy:

checkov --check HIGH --skip-check CKV_AWS_789 --bc-api-key API_KEY ...

Note that because of this add-then-subtract logic, which we chose in order to keep the behavior simple to explain, you should always specify the checks you want to run first, then exclude the ones that you want to skip. So, for example, if you want to skip all LOW and MEDIUM, but run CKV_AWS_123 (a LOW severity), it may be tempting to use this command:

checkov --skip-check MEDIUM --check CKV_AWS_123 --bc-api-key API_KEY ...

However, this will result in no checks being run, because first Checkov will take only CKV_AWS_123, then subtract all LOW / MEDIUM checks, resulting in an empty list. However, you can simply invert the logic to get what you want (this is the same example as above):

checkov --check HIGH,CKV_AWS_123 --bc-api-key API_KEY ...

Hard fail and soft fail

We previously added --hard-fail-on and --soft-fail-on flags to allow you to specify check IDs that should cause the job to fail or not fail. A hard fail is when the Checkov run exits with an error code, which you can use to do things like block CI/CD pipelines. A soft fail is when a Checkov scan does find errors, but the exit code is not an error code, allowing for report-only mode.

If you use the --soft-fail-on flag, then the run will not return an error code if all failed checks are within the --soft-fail-on list. Alternatively, with the --hard-fail-on flag, the job will return an exit code if any failed check is in the list.

We have now extended these arguments to accept severities. If you include a severity with the --soft-fail-on flag, then the run will soft fail if all failed checks are equal to or lower than the specified severity. If you include a severity with the --hard-fail-on flag, then the run will hard fail if any failed check result is equal to or higher than the specified severity.

Because of the inverse “all” logic for soft failures and “any” logic for hard failures, the behavior here can get a little complicated if you combine these flags together along with both IDs and severities.

The basic logic to determine the result of a run with multiple flags is as follows:

  1. If the failed check matches a check ID (or wildcard) in the hard-fail list, then the result for this check is a hard failure.
  2. If the failed check matches a check ID (or wildcard) in the soft-fail list, then the result for this check is a soft failure.
  3. If the failed check’s severity is equal to or higher than the severity in the hard-fail list, then the result for this check is a hard failure.
  4. If the failed check’s severity is equal to or lower than the severity in the soft-fail list, then the result for this check is a soft failure.
  5. If the failed check does not match a check ID, wildcard, or severity in either list, then the result for this check is the value of the --soft-fail flag.

If any check results in a hard failure, then the result of the run is a hard failure. If all checks result in a soft failure, then the result is a soft failure. You can find the docs for this logic here.

Here are some examples of how these options work on their own and together.

Assume we have a simple run that, with no customization, would have the following two failed checks:

The table below describes the exit code of the run for different combinations of --soft-fail, --hard-fail-on, and --soft-fail-on:

Here is a real-world example where I soft fail on HIGH severity and lower, and then also list out the CRITICAL severity policies that also fail (including some custom policies from the Bridgecrew platform), in order to achieve a soft-fail result at the end:

What’s next?

Now that Checkov can pull more policy metadata from the Bridgecrew platform and apply severity logic, we are very excited about what we can implement next. Here are some of the things you can expect to see soon:

  • Displaying additional metadata in Checkov, like benchmarks and categories that match the platform.
  • Applying your code repository configuration settings in Checkov in order to easily apply consistent configurations across your Checkov scans and scans against your pull requests.
  • Displaying Prisma Cloud policy metadata if you are running Checkov with Code Cloud Security.

Give it a shot and if you like this or other features, give us a star on GitHub.