Excluding false positives with Prowler

Prowler is a security auditing tool for AWS that helps us catch security defects such as credentials stored in plain text or S3 buckets that are publically accessible by accident. While Prowler is generally a very useful technology it sometimes also reports false positives. Thankfully, Prowler also comes with a whitelisting functionality that allows us to ignore certain resources.

Planting a false positive

Let’s first plant a false positive. A simple example of a false positive that will be reported by Prowler is a Lambda environment variable that stores a Secret Manager ARN.

Prowler will find and report this as a potentially exposed secret as we can see below.

$ docker pull toniblyx/prowler
$ docker run -it \
    --rm \
    --name prowler \
    --env AWS_ACCESS_KEY_ID \
    --env AWS_SECRET_ACCESS_KEY \
    toniblyx/prowler:latest -r eu-central-1 -c extra759
                          _
  _ __  _ __ _____      _| | ___ _ __
 | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|
 | |_) | | | (_) \ V  V /| |  __/ |
 | .__/|_|  \___/ \_/\_/ |_|\___|_|v2.10.0-25May2022
 |_| the handy cloud security tool

 Date: Sun Jun 26 20:54:51 UTC 2022

 Color code for results:
 -  INFO (Information)
 -  PASS (Recommended value)
 -  WARNING (Ignored by allowlist)
 -  FAIL (Fix required)

 This report is being generated using the credentials below:

 AWS-CLI Profile: [] AWS API Region: [eu-central-1] AWS Filter Region: [all]
 AWS Account: [174394581677] UserId: [174394581677]
 Caller Identity ARN: [arn:aws:iam::174394581677:root]

7.59 [extra759] Find secrets in Lambda functions variables  - lambda [Critical]
       INFO! eu-north-1: No Lambda functions found
       INFO! ap-south-1: No Lambda functions found
       INFO! eu-west-3: No Lambda functions found
       INFO! eu-west-2: No Lambda functions found
       INFO! eu-west-1: No Lambda functions found
       INFO! ap-northeast-3: No Lambda functions found
       INFO! ap-northeast-2: No Lambda functions found
       INFO! ap-northeast-1: No Lambda functions found
       INFO! sa-east-1: No Lambda functions found
       INFO! ca-central-1: No Lambda functions found
       INFO! ap-southeast-1: No Lambda functions found
       INFO! ap-southeast-2: No Lambda functions found
       FAIL! eu-central-1: Potential secret found in Lambda function my-little-lambda variables
       INFO! us-east-1: No Lambda functions found
       INFO! us-east-2: No Lambda functions found
       INFO! us-west-1: No Lambda functions found
       INFO! us-west-2: No Lambda functions found

Note the line

FAIL! eu-central-1: Potential secret found in Lambda function my-little-lambda variables

More specifically, the false positive will be reported by the check extra759 which was selected for the Prowler run with -c extra759 to speed up execution.

:information_source: Note that prowler requires AWS credentials to run checks. I’m using my admin account’s credentials for this example. If you use Prowler in production, you will want to configure a dedicated user with the IAM auditing policies

  • arn:aws:iam::aws:policy/SecurityAudit and
  • arn:aws:iam::aws:policy/job-function/ViewOnlyAccess

(see Requirements and installation).

Prowler, y u do dis?

Prowler reports a finding because its check extra759 simply exports a temporary file with all environment variables of our Lambda and then runs IBM’s detect-secrets tool on it (see check_extra759 and secrets-detector for the mysterious inner workings).

The reason for detect-secrets to report a defect is that it apparently considers a JSON object entry with a Secrets Manager ARN on the right side a secret keyword. We can see this by running git-secrets on the environment variables export of the Lambda defined earlier. I.e. we run

$ aws lambda --region eu-central-1 get-function-configuration --function-name my-little-lambda --query 'Environment.Variables' --output json > /tmp/lambda-variables.json

to get a JSON export of our Lambda’s environment variables. The JSON file, in this case, looks like this:

$ cat /tmp/lambda-variables.json
{
    "FOO": "arn:aws:secretsmanager:eu-central-1:123456789012:secret:foo"
}

If we run detect-secrets scan on this file, we get the following output that tells us a secret keyword was found in line 2 (the finding is listed in results."/tmp/lambda-variables.json").

$ detect-secrets scan /tmp/lambda-variables.json
{
  "exclude": {
    "files": null,
    "lines": null
  },
  "generated_at": "2022-06-27T05:29:31Z",
  "plugins_used": [
    {
      "name": "AWSKeyDetector"
    },
    {
      "name": "ArtifactoryDetector"
    },
    {
      "name": "AzureStorageKeyDetector"
    },
    {
      "base64_limit": 4.5,
      "name": "Base64HighEntropyString"
    },
    {
      "name": "BasicAuthDetector"
    },
    {
      "name": "BoxDetector"
    },
    {
      "name": "CloudantDetector"
    },
    {
      "ghe_instance": "github.ibm.com",
      "name": "GheDetector"
    },
    {
      "name": "GitHubTokenDetector"
    },
    {
      "hex_limit": 3,
      "name": "HexHighEntropyString"
    },
    {
      "name": "IbmCloudIamDetector"
    },
    {
      "name": "IbmCosHmacDetector"
    },
    {
      "name": "JwtTokenDetector"
    },
    {
      "keyword_exclude": null,
      "name": "KeywordDetector"
    },
    {
      "name": "MailchimpDetector"
    },
    {
      "name": "NpmDetector"
    },
    {
      "name": "PrivateKeyDetector"
    },
    {
      "name": "SlackDetector"
    },
    {
      "name": "SoftlayerDetector"
    },
    {
      "name": "SquareOAuthDetector"
    },
    {
      "name": "StripeDetector"
    },
    {
      "name": "TwilioKeyDetector"
    }
  ],
  "results": {
    "/tmp/lambda-variables.json": [
      {
        "hashed_secret": "3c4c43b8cb2d7bbdba2ea6fd268e70483ef2235f",
        "is_verified": false,
        "line_number": 2,
        "type": "Secret Keyword",
        "verified_result": null
      }
    ]
  },
  "version": "0.13.1+ibm.50.dss",
  "word_list": {
    "file": null,
    "hash": null
  }
}

Excluding Prowler false positives with an allow list

This is obviously not great since we’d preferably only want to get reports for true defects. Luckily, Prowler gives us the option to whitelist some resources using something called an allowlist. Documentation is a bit sparse, but with some experimentation, it’s easy to verify that entries of the form

<check-id>:<resource-name>

will be converted from errors to warnings.

For example, let’s allowlist our Lambda’s environment by defining an allowlist file /tmp/allowlist.txt with the following content.

extra759:my-little-lambda

If we pass this file to Prowler and using the -w option and run check extra759 again, we get the following report:

$ cat <<EOF > /tmp/allowlist.txt
extra759:my-little-lambda
EOF
$ docker run -it \
    --rm \
    --name prowler \
    --env AWS_ACCESS_KEY_ID \
    --env AWS_SECRET_ACCESS_KEY \
    --mount type=bind,source="/tmp/allowlist.txt",target=/tmp/allowlist.txt \
    toniblyx/prowler:latest -r eu-central-1 -c extra759 -w /tmp/allowlist.txt
                          _
  _ __  _ __ _____      _| | ___ _ __
 | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|
 | |_) | | | (_) \ V  V /| |  __/ |
 | .__/|_|  \___/ \_/\_/ |_|\___|_|v2.10.0-25May2022
 |_| the handy cloud security tool

 Date: Mon Jun 27 06:06:36 UTC 2022

 Color code for results:
 -  INFO (Information)
 -  PASS (Recommended value)
 -  WARNING (Ignored by allowlist)
 -  FAIL (Fix required)

 This report is being generated using credentials below:

 AWS-CLI Profile: [] AWS API Region: [eu-central-1] AWS Filter Region: [all]
 AWS Account: [174394581677] UserId: [174394581677]
 Caller Identity ARN: [arn:aws:iam::174394581677:root]

 Getting allowlist from input file /tmp/allowlist.txt ...
 Success! Allowlist was downloaded, starting Prowler...
7.59 [extra759] Find secrets in Lambda functions variables  - lambda [Critical]
       INFO! eu-north-1: No Lambda functions found
       INFO! ap-south-1: No Lambda functions found
       INFO! eu-west-3: No Lambda functions found
       INFO! eu-west-2: No Lambda functions found
       INFO! eu-west-1: No Lambda functions found
       INFO! ap-northeast-3: No Lambda functions found
       INFO! ap-northeast-2: No Lambda functions found
       INFO! ap-northeast-1: No Lambda functions found
       INFO! sa-east-1: No Lambda functions found
       INFO! ca-central-1: No Lambda functions found
       INFO! ap-southeast-1: No Lambda functions found
       INFO! ap-southeast-2: No Lambda functions found
       WARNING! eu-central-1: Potential secret found in Lambda function my-little-lambda variables
       INFO! us-east-1: No Lambda functions found
       INFO! us-east-2: No Lambda functions found
       INFO! us-west-1: No Lambda functions found
       INFO! us-west-2: No Lambda functions found

Prowler now prints the line

WARNING! eu-central-1: Potential secret found in Lambda function my-little-lambda variables

instead of reporting a failed check. So, as expected, the security warning for our false positive has been converted to a warning. :rocket: