08 Aug 2022


AWS being one of the most leading Public Cloud Infrastructure and in today’s date, almost everyone is moving towards cloud, whether 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 has over 200 fully featured services  (Sep 2021) [3], and it’s growing day by day, we need to have some reliable methods to manage the security and compliance of our resources on AWS effectively.

So today, we will deep dive in the AWS Security hub and see how we can effectively centralize it using other AWS services.

AWS Security Hub:

  • It comes pre-packed with an interactive dashboard which helps us quickly take actions against any findings reported.
  • It’s an AWS service, sits behind AWS Guard Duty, Amazon Inspector, Amazon Macie, and over more then 30 more partner security solutions on AWS platform.
  • It saves time with centralized and normalized findings, eliminating the need for time-consuming data parsing and normalization efforts.
  • 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.


Todays Use Case:

The goal is to make the security hub’s Dashboard, a centralized Dashboard which should be able monitor custom parameters (rules). For example you have a Development AWS account and you don’t want any of the users associated with that account to be able to create EC2 instances of size more than t2.medium.


Lets understand this in this way, in a real-world scenario, you may have some other security or compliance measures to be followed and get logged on Security hub’s Dashboard, which is not available in CIS, PCI DSS or other compliances which are already covered by AWS Services behind Security hub. The reason may be for cost optimization or management needs. Being said that, then only when we can say AWS Security hub is a centralized security auditing and monitoring tool.


So this is where we will get our hands dirty. 


Below, we will be using a very simple example, where we will 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 AWS Config. We will use CloudFormation Stack to keep things sleek and simple.

First we 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 not greater than t2.medium. Later on, we will provision an EC2 instance which is bigger than t2.medium, and see, If, it is being logged by Security hub or not?


  1. Now open the terminal or any code editor on your system.
  2. Create
  1. Paste Below content in it (Ref 1)
import boto3
config = 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 = “”
      response = config.describe_config_rules(
      if ‘Description’ in response[‘ConfigRules’][0]:
          description = response[‘ConfigRules’][0][‘Description’]
          description = response[‘ConfigRules’][0][‘ConfigRuleName’]
      return description
  except Exception as error:
      print(“Error: “, error)
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 = “”+region+“#/rules/rule-details/”+config_rule_name
      “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:
          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)
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 “” 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’]
          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]
      print(“Other Notification”)
def lambda_handler(event, context):
  print(“Event Before Parsing: “, event)


  1. Create a zip file of the above lambda function and upload it to an S3 bucket.
zip -r
  1. Click on Create Bucket and follow the instructions.
  2. Now you can see your bucket listed theirs.
  3. Click on Upload
  4. Navigate to the file we created in the last step and upload it.
  5. Make sure you grant public access to the object uploaded (I am skipping the s3 private bucket configuration to cover this as easy as possible)
  6. Then upload it.
  7. Note Down the s3 Bucket Key and Bucket name
  8. Create a template.yaml file
vim template.yaml
  1. Paste below content in it (Ref 1)
AWSTemplateFormatVersion: 20100909
Description: This CloudFormation template will automate the importing of aws config findings into aws security hub
    Type: ‘AWS::IAM::Role’
      RoleName: ‘config-and-sec-hub-lambda-role’
        Version: 20121017
          – Effect: Allow
              – ‘sts:AssumeRole’
        – PolicyName: lambda-conf-sec-hub-policy
              – Effect: Allow
                  – ‘securityhub:BatchImportFindings’
                  – ‘*’
              – Effect: Allow
                  – ‘logs:CreateLogGroup’
                  – ‘logs:CreateLogStream’
                  – ‘logs:PutLogEvents’
                Resource: ‘*’
              – Effect: Allow
                  – ‘config:DescribeConfigRules’
                Resource: ‘*’
    Type: AWS::Lambda::Function
        S3Bucket: ‘<Put YourBucket Name>’
        S3Key: ‘<Put Your Object Key>’
      FunctionName : ‘Config-To-Sec-Hub-Lambda’
      Handler: ‘lambda_function.lambda_handler’
          – LambdaServiceRole
          – Arn
      Runtime: python3.7
      Timeout: 300 
    Type: AWS::Events::Rule
      Description: This CW rule integrates AWS Config Compliance events with AWS Lambda as a target
      Name: ‘Config-Sechub-CW-Rule’
          – aws.config
          – Config Rules Compliance Change
            – ComplianceChangeNotification
      State: ‘ENABLED’
              – ‘ConfigSecHubFunction’
              – ‘Arn’
          Id: ‘TargetFunctionV1’     
    Type: AWS::Lambda::Permission
        Ref: ‘ConfigSecHubFunction’
      Action: ‘lambda:InvokeFunction’
      Principal: ‘’
          – ‘ConfigSecHubCWRule’
          – ‘Arn’


  1. Replace the Bucket name and Key in the above file with the one you created.
  2. 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.
  3. 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.
  4. You will be able to see resources, once stack deployment gets completed.
  5. 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.
  6. Go to the AWS Config console.
  7. From the menu at left, select Rules and then Add rule
  8. Search ec2 and then select desired-instance-type.
  9. Enter t2.medium and Save, in this way we mean, any other type of Instance creation will be non-compliant.
  10. Now let’s hop into the ec2 console and see if we create any other type of ec2 machine. Does it get logged by Security hub or not?
  11. Click on Launch instance
  12. Click Select, on any image, you want.
  13. Select any type of instance excluding t2.micro and then click Next, Follow the dashboard instruction and let other options be the default.
  14. Click Review and launch > Launch
  15. Create and download key pair, if required, and hit launch instance.
  16. Wait for few mins (Generally data get populated in Config within 5 min, but it should not take more than 10-20 min)
  17. Now open the Security hub console, again.
  18. Navigate to Findings at the left menu
  19. In filters type Tile: desired-instance-type


In this post, We successfully showed step by step configuration to import Custom rules. We showed how to send findings to Security Hub from AWS config using S3, AWS lambda, CloudFormation stack. This can help your team collaborate, and respond faster to non-compliance operational security events.