Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added automatic lambda code scan to Inspector #179

Merged
merged 4 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Table of Contents<!-- omit in toc -->

- [Introduction](#introduction)
- [2023-10-10](#2023-10-10)
- [2023-09-22](#2023-09-22)
- [2023-08-07](#2023-08-07)
- [2023-07-07](#2023-07-07)
Expand Down Expand Up @@ -44,6 +45,9 @@
All notable changes to this project will be documented in this file.

---
## 2023-10-10

- Updated [Inspector](https://github.com/aws-samples/aws-security-reference-architecture-examples/tree/main/aws_sra_examples/solutions/inspector/inspector_org) solution to enable automatic lambda code scan.

## 2023-09-22

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ resources:

# Inspector Solution
- parameter_key: pScanComponents
parameter_value: 'EC2, ECR, LAMBDA'
parameter_value: 'EC2, ECR, LAMBDA, LAMBDA_CODE'
- parameter_key: pEcrRescanDuration
parameter_value: 'LIFETIME'

Expand Down
6 changes: 3 additions & 3 deletions aws_sra_examples/easy_setup/templates/sra-easy-setup.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ Metadata:
default: SRA Staging S3 Bucket Stack Name

pScanComponents:
default: Comma separated list of scan components (EC2, ECR, LAMBDA)
default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE)
pEcrRescanDuration:
default: ECR Rescan Duration
pDeployInspectorSolution:
Expand Down Expand Up @@ -522,8 +522,8 @@ Parameters:
Type: String

pScanComponents:
AllowedValues: [EC2, ECR, LAMBDA]
Default: EC2, ECR, LAMBDA
AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE]
Default: EC2, ECR, LAMBDA, LAMBDA_CODE
Description: Lambda Function Logging Level
Type: CommaDelimitedList
pEcrRescanDuration:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ resources:
- parameter_key: pDeployInspectorSolution
parameter_value: 'Yes'
- parameter_key: pScanComponents
parameter_value: 'EC2, ECR, LAMBDA'
parameter_value: 'EC2, ECR, LAMBDA, LAMBDA_CODE'
- parameter_key: pEcrRescanDuration
parameter_value: 'LIFETIME'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ Metadata:
pSRAStagingS3BucketName:
default: SRA Staging S3 Bucket Name
pScanComponents:
default: Comma separated list of scan components (EC2, ECR, LAMBDA)
default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE)
pSecurityContactAction:
default: Security Alternate Contact Action
pSecurityEmail:
Expand Down Expand Up @@ -929,8 +929,8 @@ Parameters:
name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
Type: AWS::SSM::Parameter::Value<String>
pScanComponents:
AllowedValues: [EC2, ECR, LAMBDA]
Default: EC2, ECR, LAMBDA
AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE]
Default: EC2, ECR, LAMBDA, LAMBDA_CODE
Description: Lambda Function Logging Level
Type: CommaDelimitedList
pSecurityContactAction:
Expand Down
13 changes: 7 additions & 6 deletions aws_sra_examples/solutions/inspector/inspector_org/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ The Inspector Organization solution will automate enabling Amazon Inspector by d
#### 1.10 Inspector<!-- omit in toc -->

- The Inspector delegated administrator is registered within organizations in the `management account` using the Inspector APIs within each provided region.
- EC2, ECR, and Lambda function scanning is set to be auto-enabled for all associated member accounts (newly associated and newly created accounts)
- EC2, ECR, Lambda standard and Lambda code scanning is set to be auto-enabled for all associated member accounts (newly associated and newly created accounts)

#### 1.11 Lambda Layer<!-- omit in toc -->

Expand All @@ -112,7 +112,7 @@ populated from the `SecurityAccountId` parameter within the `AWSControlTowerBP-B
#### 2.3 Inspector (Delegated admin)<!-- omit in toc -->

- Inspector is enabled in the delegated admin account within each provided region.
- EC2, ECR, and Lambda function scanning is enabled.
- EC2, ECR, Lambda standard and Lambda code scanning is enabled.

---

Expand All @@ -129,7 +129,7 @@ populated from the `SecurityAccountId` parameter within the `AWSControlTowerBP-B
#### 3.3 Inspector (Members)<!-- omit in toc -->

- Inspector is enabled from the delegated administrator account.
- EC2, ECR, and Lambda function scanning is enabled.
- EC2, ECR, Lambda standard and Lambda code scanning is enabled.

---

Expand Down Expand Up @@ -171,9 +171,9 @@ In the `management account (home region)`, launch an AWS CloudFormation **Stack*
1. Verify that the delegated admin account is set for each region
2. Log into the Audit account and navigate to the Inspector page
1. Verify the Inspector service is enabled in each region
2. Verify the auto-enable ec2, ecr, and lambda scanning for new accounts is ON in each region
3. Verify all existing member accounts have inspector ec2, ecr, and lambda scanning enabled in each region
3. Log into a member account and verify the inspector is enabled and configured to scan ec2, ecr, and lambda functions
2. Verify the auto-enable ec2, ecr and lambda standard scanning for new accounts is ON in each region, and lambda code scanning in supported regions
3. Verify all existing member accounts have inspector ec2, ecr, and lambda standard scanning enabled in each region, and lambda code scanning in supported regions
3. Log into a member account and verify the inspector is enabled and configured to scan ec2, ecr, lambda functions and lambda code

#### Solution Update Instructions<!-- omit in toc -->

Expand Down Expand Up @@ -205,3 +205,4 @@ In the `management account (home region)`, launch an AWS CloudFormation **Stack*
- [Managing AWS SDKs in Lambda Functions](https://docs.aws.amazon.com/lambda/latest/operatorguide/sdks-functions.html)
- [Lambda runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html)
- [Python Boto3 SDK changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [AWS Regions where Lambda code scanning is currently available](https://docs.aws.amazon.com/inspector/latest/user/inspector_regions.html)
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ resources:
- parameter_key: pSRASolutionVersion
parameter_value: 'v1.0'
- parameter_key: pScanComponents
parameter_value: EC2, ECR, LAMBDA
parameter_value: EC2, ECR, LAMBDA, LAMBDA_CODE
- parameter_key: pEcrRescanDuration
parameter_value: 'LIFETIME'
deploy_method: stack_set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
},
{
"ParameterKey": "pScanComponents",
"ParameterValue": "EC2, ECR, LAMBDA"
"ParameterValue": "EC2, ECR, LAMBDA, LAMBDA_CODE"
},
{
"ParameterKey": "pEcrRescanDuration",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
},
{
"ParameterKey": "pScanComponents",
"ParameterValue": "EC2, ECR, LAMBDA"
"ParameterValue": "EC2, ECR, LAMBDA, LAMBDA_CODE"
},
{
"ParameterKey": "pEcrRescanDuration",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
UNEXPECTED = "Unexpected!"
SERVICE_NAME = "inspector2.amazonaws.com"
SNS_PUBLISH_BATCH_MAX = 10
ALL_INSPECTOR_SCAN_COMPONENTS = ["EC2", "ECR", "LAMBDA"]
ALL_INSPECTOR_SCAN_COMPONENTS = ["EC2", "ECR", "LAMBDA", "LAMBDA_CODE"]

helper = CfnResource(json_logging=True, log_level=log_level, boto_level="CRITICAL", sleep_on_delete=120)

Expand Down Expand Up @@ -172,7 +172,9 @@ def get_validated_parameters(event: Dict[str, Any]) -> dict:
params.update(parameter_pattern_validator("SNS_TOPIC_ARN", os.environ.get("SNS_TOPIC_ARN"), pattern=sns_topic_pattern))
params.update(
parameter_pattern_validator(
"SCAN_COMPONENTS", os.environ.get("SCAN_COMPONENTS"), pattern=r"(?i)^((ec2|ecr|lambda),?){0,2}(ec2|ecr|lambda){1}$"
"SCAN_COMPONENTS",
os.environ.get("SCAN_COMPONENTS"),
pattern=r"(?i)^((ec2|ecr|lambda|lambda_code),?){0,3}(ec2|ecr|lambda|lambda_code){1}$",
)
)
params.update(parameter_pattern_validator("ECR_SCAN_DURATION", os.environ.get("ECR_SCAN_DURATION"), pattern=r"^(LIFETIME|DAYS_30|DAYS_180){1}$"))
Expand Down Expand Up @@ -374,22 +376,17 @@ def setup_inspector_in_region(
scan_components: list of components to scan
ecr_scan_duration: ecr scan duration
"""
scan_component_dict: AutoEnableTypeDef = {"ec2": False, "ecr": False, "lambda": False}
scan_component_dict: AutoEnableTypeDef = {"ec2": False, "ecr": False, "lambda": False, "lambdaCode": False}
for scan_component in scan_components:
if scan_component.lower() == "ec2":
scan_component_dict["ec2"] = True
elif scan_component.lower() == "ecr":
scan_component_dict["ecr"] = True
elif scan_component.lower() == "lambda":
scan_component_dict["lambda"] = True
scan_component_dict[common.snake_to_camel(scan_component)] = True # type: ignore

if scan_component_dict["lambdaCode"] and not scan_component_dict["lambda"]:
scan_component_dict["lambda"] = True

disabled_components: list = []
if scan_component_dict["ec2"] is False:
disabled_components.append("ec2")
if scan_component_dict["ecr"] is False:
disabled_components.append("ecr")
if scan_component_dict["lambda"] is False:
disabled_components.append("lambda")
for scan_component in scan_component_dict:
if scan_component_dict[scan_component] is False: # type: ignore
disabled_components.append(scan_component)

LOGGER.info(f"setup_inspector_in_region: scan_components - ({scan_components}) in {region}")
LOGGER.info(f"setup_inspector_in_region: created scan_component_dict as ({scan_component_dict})")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,30 @@ def create_service_linked_role(
LOGGER.info(api_call_details)
except iam_client.exceptions.NoSuchEntityException:
iam_client.create_service_linked_role(AWSServiceName=service_name, Description=description)


def snake_to_camel(snake_str: str) -> str:
"""Convert snake case to camel case.

Args:
snake_str: String to convert

Returns:
Camel case string
"""
camel_str = snake_str.title().replace("_", "")
return camel_str[0].lower() + camel_str[1:]


def camel_to_snake_upper(camel_str: str) -> str:
"""Concert camel case to snake upper case.

Args:
camel_str: String to convert

Returns:
Snake upper case string
"""
snake_chars = ["_" + x.lower() if x.isupper() else x for x in camel_str]
snake_str = "".join(snake_chars).lstrip("_")
return snake_str.upper()
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ def check_inspector_org_auto_enabled(inspector2_delegated_admin_client: Inspecto
org_config_ec2_auto_enabled = 0
org_config_ecr_auto_enabled = 0
org_config_lambda_auto_enabled = 0
org_config_lambda_code_auto_enabled = 0
if "ec2" in describe_org_conf_response["autoEnable"] and describe_org_conf_response["autoEnable"]["ec2"] is True:
org_config_ec2_auto_enabled = 1
LOGGER.info("Organization inspector scanning for ec2 is already configured to be auto-enabled")
Expand All @@ -255,11 +256,14 @@ def check_inspector_org_auto_enabled(inspector2_delegated_admin_client: Inspecto
if "lambda" in describe_org_conf_response["autoEnable"] and describe_org_conf_response["autoEnable"]["lambda"] is True:
org_config_lambda_auto_enabled = 1
LOGGER.info("Organization inspector scanning for lambda is already configured to be auto-enabled")
return org_config_ec2_auto_enabled + org_config_ecr_auto_enabled + org_config_lambda_auto_enabled
if "lambdaCode" in describe_org_conf_response["autoEnable"] and describe_org_conf_response["autoEnable"]["lambdaCode"] is True:
org_config_lambda_code_auto_enabled = 1
LOGGER.info("Organization inspector scanning for lambda code is already configured to be auto-enabled")
return org_config_ec2_auto_enabled + org_config_ecr_auto_enabled + org_config_lambda_auto_enabled + org_config_lambda_code_auto_enabled


def disable_auto_scanning_in_org(delegated_admin_account_id: str, configuration_role_name: str, regions: list) -> None:
"""Disable auto-enable setting in org for ec2, ec2, and lambda.
"""Disable auto-enable setting in org for ec2, ec2, lambda and lambdaCode.

Args:
regions: AWS Region List
Expand All @@ -273,7 +277,7 @@ def disable_auto_scanning_in_org(delegated_admin_account_id: str, configuration_
if check_inspector_org_auto_enabled(inspector_delegated_admin_region_client) > 0:
LOGGER.info(f"disabling inspector scanning auto-enable in region {region}")
update_organization_configuration_response = inspector_delegated_admin_region_client.update_organization_configuration(
autoEnable={"ec2": False, "ecr": False, "lambda": False}
autoEnable={"ec2": False, "ecr": False, "lambda": False, "lambdaCode": False}
)
api_call_details = {"API_Call": "inspector:UpdateOrganizationConfiguration", "API_Response": update_organization_configuration_response}
LOGGER.info(api_call_details)
Expand Down Expand Up @@ -301,8 +305,8 @@ def get_inspector_status(inspector2_client: Inspector2Client, account_id: str, s
if status["state"]["status"] == "ENABLED":
LOGGER.info(f"Status: {status['state']['status']}")
for scan_component in scan_components:
LOGGER.info(f"{scan_component} status: {status['resourceState'][scan_component.lower()]['status']}") # type: ignore
if status["resourceState"][scan_component.lower()]["status"] != "ENABLED": # type: ignore
LOGGER.info(f"{scan_component} status: {status['resourceState'][common.snake_to_camel(scan_component)]['status']}") # type: ignore
if status["resourceState"][common.snake_to_camel(scan_component)]["status"] != "ENABLED": # type: ignore
LOGGER.info(f"{scan_component} scan component is disabled...")
else:
LOGGER.info(f"{scan_component} scan component is enabled...")
Expand Down Expand Up @@ -358,15 +362,17 @@ def check_for_updates_to_scan_components(inspector2_client: Inspector2Client, ac
if status["state"]["status"] == "ENABLED":
LOGGER.info(f"Status: {status['state']['status']}")
for scan_component in disabled_components:
LOGGER.info(f"{scan_component} status: {status['resourceState'][scan_component.lower()]['status']}") # type: ignore
if status["resourceState"][scan_component.lower()]["status"] != "ENABLED": # type: ignore
LOGGER.info(f"{scan_component} status: {status['resourceState'][scan_component]['status']}") # type: ignore
if status["resourceState"][scan_component]["status"] != "ENABLED": # type: ignore
LOGGER.info(f"{scan_component} scan component is disabled...")
else:
LOGGER.info(f"{scan_component} scan component is enabled (disablement required)...")
disablement = True
if disablement is True:
LOGGER.info("Disabling some scan components...")
disable_inspector2(inspector2_client, account_id, [disabled_component.upper() for disabled_component in disabled_components])
disable_inspector2(
inspector2_client, account_id, [common.camel_to_snake_upper(disabled_component) for disabled_component in disabled_components]
)


def enable_inspector2_in_mgmt_and_delegated_admin(
Expand Down Expand Up @@ -490,20 +496,17 @@ def set_auto_enable_inspector_in_org(
scan_component_dict: dictionary of scan components with true/false enable value
"""
enabled_component_count: int = 0
if scan_component_dict["ec2"] is True:
enabled_component_count = enabled_component_count + 1
if scan_component_dict["ecr"] is True:
enabled_component_count = enabled_component_count + 1
if scan_component_dict["lambda"] is True:
enabled_component_count = enabled_component_count + 1
for scan_component in scan_component_dict:
if scan_component_dict[scan_component] is True: # type: ignore
enabled_component_count = enabled_component_count + 1

LOGGER.info(f"set_auto_enable_inspector_in_org: scan_component_dict - ({scan_component_dict})")
delegated_admin_session = common.assume_role(configuration_role_name, "sra-enable-inspector", delegated_admin_account_id)
LOGGER.info(f"open session {configuration_role_name} and account id {delegated_admin_account_id} to set auto-enablement of inspector in org")
inspector_delegated_admin_region_client: Inspector2Client = delegated_admin_session.client("inspector2", region)

if check_inspector_org_auto_enabled(inspector_delegated_admin_region_client) != enabled_component_count:
LOGGER.info(f"configuring aut-enable inspector via update_organization_configuration in region {region}")
LOGGER.info(f"configuring auto-enable inspector via update_organization_configuration in region {region}")
update_organization_configuration_response = inspector_delegated_admin_region_client.update_organization_configuration(
autoEnable=scan_component_dict
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Metadata:
pInspectorConfigurationRoleName:
default: Inspector Configuration Role Name
pScanComponents:
default: Comma separated list of scan components (EC2, ECR, LAMBDA)
default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE)
pEcrRescanDuration:
default: ECR Rescan Duration

Expand Down Expand Up @@ -195,8 +195,8 @@ Parameters:
numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
Type: String
pScanComponents:
AllowedValues: [EC2, ECR, LAMBDA]
Default: EC2, ECR, LAMBDA
AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE]
Default: EC2, ECR, LAMBDA, LAMBDA_CODE
Description: Lambda Function Logging Level
Type: CommaDelimitedList
pEcrRescanDuration:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Metadata:
pSRAStagingS3BucketName:
default: SRA Staging S3 Bucket Name
pScanComponents:
default: Comma separated list of scan components (EC2, ECR, LAMBDA)
default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE)
pEcrRescanDuration:
default: ECR Rescan Duration

Expand Down Expand Up @@ -202,8 +202,8 @@ Parameters:
Description: The SRA solution version. Used to trigger updates on the nested StackSets.
Type: String
pScanComponents:
AllowedValues: [EC2, ECR, LAMBDA]
Default: EC2, ECR, LAMBDA
AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE]
Default: EC2, ECR, LAMBDA, LAMBDA_CODE
Description: Lambda Function Logging Level
Type: CommaDelimitedList
pEcrRescanDuration:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Metadata:
pSRASolutionVersion:
default: SRA Solution Version
pScanComponents:
default: Comma separated list of scan components (EC2, ECR, LAMBDA)
default: Comma separated list of scan components (EC2, ECR, LAMBDA, LAMBDA_CODE)
pEcrRescanDuration:
default: ECR Rescan Duration

Expand Down Expand Up @@ -200,8 +200,8 @@ Parameters:
Description: The SRA solution version. Used to trigger updates on the nested StackSets.
Type: String
pScanComponents:
AllowedValues: [EC2, ECR, LAMBDA]
Default: EC2, ECR, LAMBDA
AllowedValues: [EC2, ECR, LAMBDA, LAMBDA_CODE]
Default: EC2, ECR, LAMBDA, LAMBDA_CODE
Description: Lambda Function Logging Level
Type: CommaDelimitedList
pEcrRescanDuration:
Expand Down