내용으로 건너뛰기

how to get an instance's security group from a Security Hub finding

0

looking to see if there is a way to get an instance's security group from a Security Hub finding.

I have the following lambda function used to pull HIGH and CRITICAL findings. There is a requirement to see the associated security group for each finding in the report. Given these are Security Hub finding details, I am not seeing this data. Would I have to get the instance ID from the finding and then somehow query the instance to get the group?

This is my current lambda function:

import boto3 import html

sns = boto3.client('sns') securityhub = boto3.client('securityhub')

def lambda_handler(event, context): findings = securityhub.get_findings( Filters={ "SeverityLabel": [{ "Value": "HIGH", "Comparison": "EQUALS"}, { "Value": "CRITICAL", "Comparison": "EQUALS"}], 'RecordState': [{'Value': 'ACTIVE', 'Comparison': 'EQUALS'}], "ResourceAwsEc2InstanceKeyName": [{"Value": "equine-wrkld-nprod", "Comparison": "PREFIX"}, {"Value": "equine-wrkld-demo", "Comparison": "PREFIX"}] }, MaxResults=20 )['Findings']

print(findings)

if not findings:
    message = "No active CRITICAL or HIGH severity findings."
else:
    note = "Security Hub controls reference  docs.aws.amazon.com/securityhub/latest/userguide/securityhub-controls-reference.html \n\n"
    message = "\n".join([f"{f['Resources'][0].get('Details', {}).get('AwsEc2Instance', {}).get('KeyName', 'N/A')}: {f['Severity']['Label']} \n{f['Title']}: {f['Description']} \n{f['Remediation']['Recommendation']['Text']}: " f"{f['Remediation']['Recommendation']['Url']}: Click here for remediation" "\n" for f in findings
    if f['Resources'] and 'Severity' in f and 'Title' in f and 'Description' in f
    ])
sns.publish(
    TopicArn='arn:aws:sns:ap-southeast-3:149536494602:EquineSecurityHubCriticalHighAlerts',
    Subject='Workload Top 20 Critical and High Security Hub Findings',
    Message=note + message
    #MessageStructure='html'
)
1개 답변
1

Security Hub findings don't actually include security group information directly. But don't worry, you can still get what you need with a few tweaks to your Lambda function. Here's how you'll approach it:

First, you'll grab the EC2 instance ID from each Security Hub finding. Then, you'll use that ID to query the EC2 service and fetch the security group details.

To make this work, you'll need to add the ec2:DescribeInstances permission to your Lambda's IAM role. This lets your function talk to EC2 and get the instance details you need.

Now, let's modify your existing Lambda function. You'll keep the core of what you have and add some new bits:

import boto3

sns = boto3.client('sns')
securityhub = boto3.client('securityhub')
ec2 = boto3.client('ec2')  # New EC2 client

def get_security_groups(instance_id):
    try:
        response = ec2.describe_instances(InstanceIds=[instance_id])
        if response['Reservations']:
            instance = response['Reservations'][0]['Instances'][0]
            security_groups = instance.get('SecurityGroups', [])
            return ', '.join([sg['GroupName'] for sg in security_groups])
    except Exception as e:
        print(f"Couldn't get security groups for {instance_id}: {str(e)}")
    return "N/A"

def lambda_handler(event, context):
    # Your existing code to get findings...

    if not findings:
        message = "No active CRITICAL or HIGH severity findings."
    else:
        note = "Security Hub controls reference: https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-controls-reference.html\n\n"
        message = ""
        for f in findings:
            if f['Resources'] and 'Severity' in f and 'Title' in f and 'Description' in f:
                instance_details = f['Resources'][0].get('Details', {}).get('AwsEc2Instance', {})
                instance_id = instance_details.get('InstanceId', 'N/A')
                key_name = instance_details.get('KeyName', 'N/A')
                security_groups = get_security_groups(instance_id) if instance_id != 'N/A' else 'N/A'
                
                message += f"{key_name}: {f['Severity']['Label']}\n"
                message += f"Instance ID: {instance_id}\n"
                message += f"Security Groups: {security_groups}\n"
                message += f"{f['Title']}: {f['Description']}\n"
                message += f"Remediation: {f['Remediation']['Recommendation']['Text']}\n"
                message += f"Remediation URL: {f['Remediation']['Recommendation']['Url']}\n\n"

    # Your existing code to publish to SNS...

A couple of things to keep in mind:

This might make your Lambda run a bit longer because of the extra EC2 API calls. Some instances in the findings might not exist anymore, so I've added some error handling. If you're processing a ton of findings, you might want to consider batching or pagination to avoid timeouts.

AWS
답변함 10달 전
전문가
검토됨 10달 전
  • thanks. I may need to do a little debugging, as none of the findings are returning an Instance ID nor a Security Group

    equine-wrkld-demo-kp-infor: HIGH Instance ID: N/A Security Groups: N/A EC2.8 EC2 instances should use Instance Metadata Service Version 2 (IMDSv2): This control checks whether your Amazon Elastic Compute Cloud (Amazon EC2) instance metadata version is configured with Instance Metadata Service Version 2 (IMDSv2). The control passes if HttpTokens is set to required for IMDSv2. The control fails if HttpTokens is set to optional. Remediation: For information on how to correct this issue, consult the AWS Security Hub controls documentation. Remediation URL: https://urldefense.proofpoint.com/v2/url?u=https-3A__docs.aws.amazon.com_console_securityhub_EC2.8_remediation&d=DwICaQ&c=BSDicqBQBDjDI9RkVyTcHQ&r=4nrs1sW7KAflogEbAAfK-A&m=pareEJ6BAfHKy5_r01Atb9J5b6Nj8eonXKFnfgqdR2X4Q7EDm-Wk2tIv_7DhzsRP&s=EeGNcbxSIeyS9ASCIybZGgRBYBY_Gex6Cq766PZ2Nws&e=

  • after looking at the output for "instance_details = f['Resources'][0].get('Details', {}).get('AwsEc2Instance', {})", I see the following:

    {'ImageId': 'ami-0018c5fd5443e1a7b', 'KeyName': 'equine-wrkld-demo-kp-infor', 'VpcId': 'vpc-0571c479312bbc1ad', 'SubnetId': 'subnet-03489189503767677', 'LaunchedAt': '2024-12-18T04:26:58.000Z', 'NetworkInterfaces': [{'NetworkInterfaceId': 'eni-00e9d90a6a9cea86e'}], 'VirtualizationType': 'hvm', 'MetadataOptions': {'HttpEndpoint': 'enabled', 'HttpProtocolIpv6': 'disabled', 'HttpPutResponseHopLimit': 1, 'HttpTokens': 'optional', 'InstanceMetadataTags': 'disabled'}, 'Monitoring': {'State': 'disabled'}}

    It doesn't look like there is an instance ID that can be retrieved from this.

  • I ended up using the arn Id that was returned from the Resource level and splitting that to get the instance Id. I also had to add a security policy that I created to perform an ec2:DescribeInstances. I can now pull the security group using the code provided with these adjustments

로그인하지 않았습니다. 로그인해야 답변을 게시할 수 있습니다.

좋은 답변은 질문에 명확하게 답하고 건설적인 피드백을 제공하며 질문자의 전문적인 성장을 장려합니다.

관련 콘텐츠