1000 feet overview of AWS Security Hub, AWS Config along with Lambda & CloudFormation the Hard Way.

Varun Kumar Manik
9 min readJun 14, 2020

--

OVERVIEW

If we talk about cloud computing, we all know AWS, isn’t it? AWS is one of the most leading Public Cloud Infrastructure and in today’s date, almost everyone is moving towards cloud weather you talk about data, whether you talk about application, infrastructure, whatever everyone wants it to be on the cloud.

In the case of AWS, which offers like 212 services ( June 2020) [3], and its growing day by day, we need to have some reliable methods to manage the security of our resources on AWS effectively.

So today, we will deep dive in the AWS Security hub and see how we can effectively utilize it when clubbed with few other AWS services.

AWS Security Hub

  1. It’s an AWS service, sits in the middle of AWS Guard Duty, Amazon Inspector, Amazon Macie, and over 30 more partner security solutions.
  2. It saves time with centralized and normalized findings, eliminating the need for time-consuming data parsing and normalization efforts.
  3. Automates security checks, generates its own findings by running continuous and automated account and resource-level configuration checks against the set of standard rules imposed by AWS itself, or it could be as per PCI DSS standard usually used in Banking and Finance Industries.
  4. It comes pre-packed with an interactive dashboard which helps us quickly take actions against any findings.

Use Case

In a real-world scenario, you may have some other security measures to be followed, which is not available in CIS or PCI or maybe for cost management, you need few more points to get covered as security findings in Security hub i.e only when we can say security hub as centralized security auditing or monitoring tool.

So this is where we will get our hands dirty. Below, we will be using a very simple example, where we import AWS config data to Security Hub using CloudWatch Event handler which triggers Lambda function and parses the Config data to Security hub. Similarly, you can implement your own rulesets as custom findings in the Security hub. We will use CloudFormation Stack to keep things sleek and simple.

First are going to use AWS Config (Enable it if not), where we will create a rule for EC2 Instance. (I am using EC2 Rules to demonstrate how we can import findings from AWS Config in Security hub. It could be any rule in your case.). We will make a rule to check if any instance being created in our account is t2.micro or not. Later on, we will provision EC2 instance which is not t2.micro, and see, If, it is getting reflected in Security hub Console or not?

Let’s get our hands dirty

Open Security hub console, and enable it.

Now open terminal or any code editor on your system.

Create lambda_function.py

vim lambda_function.py

Paste Below content in it (Ref 1)

import boto3config = boto3.client('config')
securityhub = boto3.client('securityhub')
def get_description_of_rule(config_rule_name):
# This function returns the description of a config rule
description = ""
try:
response = config.describe_config_rules(
ConfigRuleNames=[config_rule_name]
)
if 'Description' in response['ConfigRules'][0]:
description = response['ConfigRules'][0]['Description']
else:
description = response['ConfigRules'][0]['ConfigRuleName']
return description
except Exception as error:
print("Error: ", error)
raise

def get_compliance_and_severity(new_status):
# This function returns the compliance status and severity of the finding
status = ['FAILED', 3.0, 30]
if new_status == 'COMPLIANT':
status = ['PASSED', 0, 0]
return status
def map_config_findings_to_sh(args):
# This function import findings from aws-config to securityhub
new_findings = []
finding_id = args[0]
account_id = args[1]
config_rule_name = args[2]
resource_type = args[3]
resource_id = args[4]
region = args[5]
new_status = args[6]
new_recorded_time = args[7]
old_recorded_time = args[8]
config_rule_arn = args[9]
compliance_status = get_compliance_and_severity(new_status)
description = get_description_of_rule(config_rule_name)
remediation_url = "https://console.aws.amazon.com/config/home?region="+region+"#/rules/rule-details/"+config_rule_name
new_findings.append({
"SchemaVersion": "2018-10-08",
"Id": finding_id,
"ProductArn": "arn:aws:securityhub:{0}:{1}:product/{1}/default".format(region, account_id),
"GeneratorId": config_rule_arn,
"AwsAccountId": account_id,
"Types": [
"Software and Configuration Checks/AWS Config Analysis"
],
"CreatedAt": old_recorded_time,
"UpdatedAt": new_recorded_time,
"Severity": {
"Product": compliance_status[1],
"Normalized": compliance_status[2]
},
"Title": config_rule_name,
"Description": description,
'Remediation': {
'Recommendation': {
'Text': 'For directions on how to fix this issue, see the remediation action on the rule details page in AWS Config console',
'Url': remediation_url
}
},
'Resources': [
{
'Id': resource_id,
'Type': resource_type,
'Partition': "aws",
'Region': region
}
],
'Compliance': {'Status': compliance_status[0]}
})

if new_findings:
try:
response = securityhub.batch_import_findings(Findings=new_findings)
if response['FailedCount'] > 0:
print("Failed to import {} findings".format(response['FailedCount']))
except Exception as error:
print("Error: ", error)
raise

def parse_message(event):
# This function parse the cloudwatch event to get required data for the ingestion of finding in security hub
finding_id = event['id']
if event['detail']['messageType'] == 'ComplianceChangeNotification' and "securityhub.amazonaws.com" not in event['detail']['configRuleARN']:
account_id = event['detail']['awsAccountId']
config_rule_name = event['detail']['configRuleName']
config_rule_arn = event['detail']['configRuleARN']
resource_type = event['detail']['resourceType']
resource_id = event['detail']['resourceId']
region = event['detail']['awsRegion']
new_status = event['detail']['newEvaluationResult']['complianceType']
new_recorded_time = event['detail']['newEvaluationResult']['resultRecordedTime']
if 'oldEvaluationResult' not in event['detail']:
old_recorded_time = event['detail']['newEvaluationResult']['resultRecordedTime']
else:
old_recorded_time = event['detail']['oldEvaluationResult']['resultRecordedTime']
print("Compliance change notification for config rule: ", config_rule_name)
args = [finding_id, account_id, config_rule_name, resource_type, resource_id, region, new_status, new_recorded_time, old_recorded_time, config_rule_arn]
map_config_findings_to_sh(args)
else:
print("Other Notification")
def lambda_handler(event, context):
print("Event Before Parsing: ", event)
parse_message(event)

Create a zip file of the above lambda function and upload it to an S3 bucket.

zip -r lambda.zip lambda_function.py

Click on Create Bucket and follow the instruction.

Now you can see your bucket listed theirs.

Click on Upload

Navigate to the lambda.zip file we created in the last step and upload it.

Make sure you grant public assess to the object uploaded (I am skipping the s3 private bucket configuration to cover this as easy as possible)

Then upload it.

Note Down the s3 Bucket Key and Bucket name

Create a template.yaml file

vim template.yaml

Paste below content in it (Ref 1)

AWSTemplateFormatVersion: 2010-09-09
Description: This CloudFormation template will automate the importing of aws config findings into aws security hub
Resources:
LambdaServiceRole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: 'config-and-sec-hub-lambda-role'
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Policies:
- PolicyName: lambda-conf-sec-hub-policy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 'securityhub:BatchImportFindings'
Resource:
- '*'
- Effect: Allow
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: '*'
- Effect: Allow
Action:
- 'config:DescribeConfigRules'
Resource: '*'
ConfigSecHubFunction:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: '<Put YourBucket Name>'
S3Key: '<Put Your Object Key>'
FunctionName : 'Config-To-Sec-Hub-Lambda'
Handler: 'lambda_function.lambda_handler'
Role:
Fn::GetAtt:
- LambdaServiceRole
- Arn
Runtime: python3.7
Timeout: 300
ConfigSecHubCWRule:
Type: AWS::Events::Rule
Properties:
Description: This CW rule integrates AWS Config Compliance events with AWS Lambda as a target
Name: 'Config-Sechub-CW-Rule'
EventPattern:
source:
- aws.config
detail-type:
- Config Rules Compliance Change
detail:
messageType:
- ComplianceChangeNotification
State: 'ENABLED'
Targets:
-
Arn:
Fn::GetAtt:
- 'ConfigSecHubFunction'
- 'Arn'
Id: 'TargetFunctionV1'
PermissionForEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Ref: 'ConfigSecHubFunction'
Action: 'lambda:InvokeFunction'
Principal: 'events.amazonaws.com'
SourceArn:
Fn::GetAtt:
- 'ConfigSecHubCWRule'
- 'Arn'

Replace the Bucket name and Key in the above file with the one you created.

Now select CloudFormation from the service list and create a new stack, select Template is ready and Upload a template file, upload the file then click Next.

Provide the relevant name and leave the rest to default, let the stack launch by clicking Create Stack. Make sure you have checked the Capabilities in the last step. Once completed, you can see.

You will be able to see resources, once stack deployment gets completed.

This way we created 4 resources:

  1. Lambda function which takes input from Config to Security hub
  2. The role of the Lambda function to call other services.
  3. CloudWatch Events to trigger a lambda function
  4. Service permission to grant Amazon CloudWatch to invoke the Lambda function.

Go to AWS Config console.

From the menu at left, select Rules and then Add rule

Search ec2 and then select desired-instance-type.

Enter t2.micro and Save in this way we mean any other type of Instance creation will be non-compliant.

Now lets hope into the ec2 console and see if, we create any other type of ec2 machine do it reflect in the Security hub console or not?

Click on Launch instance

Click Select, on any image, you want.

Select any type of instance excluding t2.micro and then click Next, Follow the dashboard instruction and let other option to be the default.

Click Review and launch > Launch

Create and download key pair, if required, and hit launch instance.

Wait for few mins (Generally data get populated in Config within 5 min, but it should not take more than 10-20 min)

Now open the Security hub console, again.

Navigate to Findings at the left menu

In filters type Tile: desired-instance-type

Pros:

  1. One single centralized dashboard where you can access all the Resources and their Security related stuff.
  2. It does support multi-account setup [2]
  3. Can have custom rule-sets
  4. It can integrate with lots of other 3rd party tools like Mcafee, Imperva, Incapsula, etc.

Cons:

  1. It's a region-specific, it needs to be enabled in every region specifically [2]
  2. It's not available in all regions [2]
  3. In case, if configured with multiple accounts data gets to complicate to understand i.e its good for small scale organizations.

Conclusion:

In this post, We successfully showed step by step implementation of the security hub and its related resources. we showed, how to send findings to and from Security Hub, using AWS config, S3, CloudFormation stack. This can help your team collaborate, and respond faster to non-compliance operational security events.

For more info please connect & Follow me on:

LinkedIn: https://www.linkedin.com/in/vkmanik/

Email: varunmanik1@gmail.com

Facebook: https://www.facebook.com/cloudvirtualization/

References:

  1. https://aws.amazon.com/blogs/security/how-to-import-aws-config-rules-evaluations-findings-security-hub/
  2. https://aws.amazon.com/security-hub/faqs/
  3. https://en.wikipedia.org/wiki/Amazon_Web_Services

--

--

Varun Kumar Manik

AWS APN Ambassador | SME of DevOps DevSecOps | Cloud Architect & Trainer | Blogger | Youtuber |Chef