Skip to content

Commit fee305b

Browse files
committed
Initial commit of code, scripts and guide
1 parent e464f9c commit fee305b

File tree

11 files changed

+261
-8
lines changed

11 files changed

+261
-8
lines changed

README.md

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,99 @@
1-
## My Project
1+
# aws-config-detect-environment-variables-secrets
22

3-
TODO: Fill this README out!
3+
Code to deploy a solution to detect secrets/tokens in Lambda functions using AWS Config.
44

5-
Be sure to:
5+
## Table of Contents
6+
7+
- [Description](#description)
8+
- [Prerequisites](#prerequisites)
9+
- [Dependencies](#dependencies)
10+
- [Variables](#variables)
11+
- [Usage](#usage)
12+
- [Preparing the Lambda layers (Bash Script)](#preparing-the-lambda-layers-bash-script)
13+
- [Deploying the code (Terraforms)](#deploying-the-code-terraforms)
14+
- [Security](#security)
15+
- [License](#license)
16+
17+
18+
## Description
19+
20+
This Terraform module create a custom rule on AWS Config that detects secrets/tokens in the Lambda functions in the account.
21+
22+
The following diagram applies to the current solution.
23+
24+
![Diagram](.images/lambda-secrets-detector.png)
25+
26+
Once a secret/token is identified in the environment variables of a Lambda function, they are flagged as NON_COMPLIANT with an annotation showing the type of the detected secret. (Example: _JSON Web Token_)
27+
The AWS Config rule is triggered at any modification of every environment variable in each Lambda functions in the account.
28+
29+
> Pay attention:
30+
this module is meant to be used as standalone module.
31+
32+
## Prerequisites
33+
34+
* **AWS Config**:
35+
This module expects that [AWS Config](https://aws.amazon.com/config/) is already up and running in the region where the rules will be deployed.
36+
The setup can be easily carried out by following the official [documentation](https://docs.aws.amazon.com/config/latest/developerguide/setting-up-aws-config-rules-with-console.html).
37+
38+
* **Docker**:
39+
In order to properly deploy the resources to your account, Docker needs to be installed on your machine. Please refer to this [link](https://docs.docker.com/get-docker/).
40+
41+
## Dependencies
42+
43+
* **rdklib**: 0.2.0 [Reference](https://github.com/awslabs/aws-config-rdklib);
44+
* **detect-secrets**: 1.1.0 [Reference](https://github.com/Yelp/detect-secrets)
45+
46+
## Variables
47+
48+
The available variables are described in [variables.tf](./variables.tf) file.
49+
50+
## Usage
51+
52+
In this example we are going to deploy the custom rule that will automatically check all lambda functions for vulnerable environment variables.
53+
54+
### Preparing the Lambda layers (Bash Script)
55+
56+
The lambda function that will be leveraged to carry out the detection process uses two libraries [rdklib](https://github.com/awslabs/aws-config-rdklib) and [detect-secrets](https://github.com/Yelp/detect-secrets)
57+
Therefore, you need to first ensure those libraries are available to the function in your account as lambda layers.
58+
59+
Use this command in your terminal to prepare them for Terraforms to deploy them in the following section:
60+
61+
```bash
62+
cd scripts
63+
./build.sh
64+
```
65+
66+
### Deploying the code (Terraforms)
67+
68+
**Option 1:**
69+
You can use the following sample to utilize the module within your code:
70+
71+
```yaml
72+
module "deploy_lambda_secrets_detector_rule" {
73+
config_rule_name = "lambda_has_no_secrets"
74+
source = "./modules/lambda_has_no_secrets"
75+
enabled = true
76+
}
77+
```
78+
Please have a look inside inside [variables.tf](./variables.tf) for all the possible options.
79+
80+
**Option 2:**
81+
Alternatively, if you have [Terraform](https://www.terraform.io/) installed on your workstation, you can deploy the example by executing:
82+
83+
```bash
84+
export AWS_PROFILE=$MY_AWS_PROFILE
85+
terraform init
86+
terraform apply
87+
```
88+
89+
> Pay attention:
90+
you should first modify the `region` in your AWS Profile in accordance to your requirements.
691

7-
* Change the title in this README
8-
* Edit your repository description on GitHub
992

1093
## Security
1194

12-
See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.
95+
See CONTRIBUTING for more information.
1396

1497
## License
1598

16-
This project is licensed under the Apache-2.0 License.
17-
99+
This project is licensed under the Apache-2.0 License.

lambda.tf

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
module "lambda_function" {
2+
create = var.enabled
3+
source = "terraform-aws-modules/lambda/aws"
4+
function_name = var.config_rule_name
5+
description = "Used by AWS Config to check for secret keys in lambda functions"
6+
handler = "lambda_has_no_secrets.lambda_handler"
7+
runtime = "python3.8"
8+
timeout = 10
9+
publish = true
10+
source_path = "${path.module}/src/lambda_has_no_secrets.py"
11+
allowed_triggers = {
12+
AllowExecutionFromConfig = {
13+
principal = "config.amazonaws.com"
14+
}
15+
}
16+
layers = [
17+
module.rdklib_layer.lambda_layer_arn,
18+
module.detectsecretslib_layer.lambda_layer_arn
19+
]
20+
attach_policy = true
21+
policy = "arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess"
22+
23+
attach_policy_statements = true
24+
policy_statements = {
25+
AWSConfig_AssumeRole = {
26+
effect = "Allow",
27+
actions = ["sts:AssumeRole"],
28+
resources = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${var.config_rule_name}"]
29+
},
30+
AWSConfig_PutEvaluations = {
31+
effect = "Allow",
32+
actions = ["config:PutEvaluations"],
33+
resources = ["*"]
34+
}
35+
}
36+
}
37+
38+
module "rdklib_layer" {
39+
create = var.enabled
40+
source = "terraform-aws-modules/lambda/aws"
41+
create_layer = true
42+
layer_name = "rdklib-layer"
43+
description = "RDK Library Layer"
44+
compatible_runtimes = ["python3.8"]
45+
create_package = false
46+
local_existing_package = "${path.module}/src/layers/rdklib-layer.zip"
47+
create_role = false
48+
}
49+
50+
module "detectsecretslib_layer" {
51+
create = var.enabled
52+
source = "terraform-aws-modules/lambda/aws"
53+
create_layer = true
54+
layer_name = "detectsecretslib-layer"
55+
description = "Detect Secrets Library Layer"
56+
compatible_runtimes = ["python3.8"]
57+
create_package = false
58+
local_existing_package = "${path.module}/src/layers/detect-secrets-layer.zip"
59+
create_role = false
60+
}

main.tf

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
data "aws_region" "current" {}
2+
data "aws_caller_identity" "current" {}
3+
4+
resource "aws_config_config_rule" "lambda_has_no_secrets" {
5+
count = var.enabled ? 1 : 0
6+
name = var.config_rule_name
7+
description = "Ensures that Lambda function don't have secret keys in their environment variables"
8+
input_parameters = "{\"ExecutionRoleName\": \"${var.config_rule_name}\"}"
9+
source {
10+
owner = "CUSTOM_LAMBDA"
11+
source_identifier = module.lambda_function.lambda_function_arn
12+
source_detail {
13+
event_source = "aws.config"
14+
message_type = "ConfigurationItemChangeNotification"
15+
}
16+
}
17+
18+
depends_on = [
19+
module.lambda_function
20+
]
21+
}

outputs.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
output "ConfigRuleName" {
2+
value = var.config_rule_name == "" ? aws_config_config_rule.lambda_has_no_secrets[0].name : var.config_rule_name
3+
}

scripts/.DS_Store

6 KB
Binary file not shown.

scripts/build.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/bash
2+
3+
layers=( "rdklib" "detect-secrets")
4+
5+
#Building layers
6+
for i in "${layers[@]}"
7+
do
8+
./build_layer.sh ${i}
9+
zip -r ../src/layers/${i}-layer.zip ./python/
10+
rm -rf python
11+
done

scripts/build_layer.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
export PKG_DIR="python/lib/python3.8/site-packages"
3+
rm -rf ${PKG_DIR} && mkdir -p ${PKG_DIR}
4+
5+
docker run --rm -v $(pwd):/package -w /package lambci/lambda:build-python3.8 \
6+
pip3 install $1 -t ${PKG_DIR}

src/.DS_Store

6 KB
Binary file not shown.

src/lambda_has_no_secrets.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from rdklib import Evaluator, Evaluation, ConfigRule, ComplianceType
2+
from detect_secrets import SecretsCollection
3+
from detect_secrets.settings import default_settings
4+
import json
5+
6+
APPLICABLE_RESOURCES = ['AWS::Lambda::Function']
7+
8+
9+
class lambda_has_no_secret_keys(ConfigRule):
10+
def evaluate_change(self, event, client_factory, configuration_item,
11+
valid_rule_parameters):
12+
13+
lamda_client = client_factory.build_client('lambda')
14+
resource_type = configuration_item.get('resourceType')
15+
16+
if resource_type == 'AWS::Lambda::Function':
17+
resource_id = configuration_item.get('resourceId')
18+
19+
envVariables = get_env_variables(lamda_client, resource_id)
20+
21+
filename = "/tmp/variables.txt"
22+
with open(filename, 'w+') as outfile:
23+
json.dump(envVariables, outfile)
24+
25+
secrets = scan_file_for_secrets(filename)
26+
if secrets:
27+
return [Evaluation(ComplianceType.NON_COMPLIANT, resource_id,
28+
APPLICABLE_RESOURCES[0],
29+
json.dumps(secrets.json()[filename][0]["type"], indent=2))]
30+
return [Evaluation(ComplianceType.COMPLIANT)]
31+
return [Evaluation(ComplianceType.NOT_APPLICABLE)]
32+
33+
def evaluate_parameters(self, rule_parameters):
34+
valid_rule_parameters = rule_parameters
35+
return valid_rule_parameters
36+
37+
38+
def get_env_variables(lambda_client, resource_id):
39+
lambda_config = lambda_client.get_function_configuration(
40+
FunctionName=resource_id)
41+
if lambda_config is not None:
42+
return lambda_config.get('Environment').get('Variables')
43+
return {}
44+
45+
46+
def scan_file_for_secrets(filename):
47+
secrets = SecretsCollection()
48+
with default_settings():
49+
secrets.scan_file(filename)
50+
return secrets
51+
52+
53+
################################
54+
# DO NOT MODIFY ANYTHING BELOW #
55+
################################
56+
def lambda_handler(event, context):
57+
my_rule = lambda_has_no_secret_keys()
58+
evaluator = Evaluator(my_rule, APPLICABLE_RESOURCES)
59+
return evaluator.handle(event, context)

src/layers/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)