こんにちは。
シンプラインのmiddleです。

前回に引き続き、壁の話をお送りします。
どうぞよろしくお願いいたします。

 

★今回のお題

セキュリティグループの開けてはいけないポートを開けてしまった時、検知したい

その1 背景〜使用するサービス選択
その2 AWS Configとは
その3 カスタムルール作成① ←本日はこちら
その4 カスタムルール作成②
その5 AWS Config設定〜まとめ

 

★書けました

こんな感じになりました。
※完成まで紆余曲折ありすぎたのですが、そこはAWSがどうこうというよりPythonの話なので、割愛します。

# Description: Check that security groups do not have an inbound rule
#              with port except permitted.
#
# Trigger Type: Change Triggered
# Scope of Changes: EC2:SecurityGroup
# Accepted Parameters: examplePort1, examplePort2, ...
# Example Values: 22,80,443, ...
#
# You can designate some ports permitted by fill in okPort.
# note: It doesn't accept by Ranges.


import boto3
import json

APPLICABLE_RESOURCES = ["AWS::EC2::SecurityGroup"]

def evaluate_compliance(configuration_item, rule_parameters):

    # Check if resource was deleted
    if configuration_item['configurationItemStatus'] == "ResourceDeleted":
        compliance_type = 'NOT_APPLICABLE'
        annotation = "This resource was deleted."

    # Check the resource for applicability
    elif configuration_item["resourceType"] not in APPLICABLE_RESOURCES:
        compliance_type = 'NOT_APPLICABLE'
        annotation = "The rule apply to only resources of type SecurityGroup."

    else:
        # Check IP violation
        for ipsg in configuration_item['configuration']['ipPermissions']:
            if 'fromPort' not in ipsg:
                compliance_type = 'NON_COMPLIANT'
                annotation = 'Exposed ports range is ALL.'
                break
            
            else:
                fp = ipsg['fromPort']
                rp = []
                rp = rule_parameters['okPort'].split(',')
                if str(fp) not in rp:
                    compliance_type = 'NON_COMPLIANT'
                    annotation = 'A forbidden port is exposed.'
                    break
                
                else:
                    compliance_type = 'COMPLIANT'
                    annotation = 'Security group is compliant.'

    return {
        "compliance_type": compliance_type,
        "annotation": annotation
    }


def lambda_handler(event, context):

    invoking_event = json.loads(event['invokingEvent'])
    rule_parameters = json.loads(event['ruleParameters'])
    configuration_item = invoking_event["configurationItem"]
    evaluation = evaluate_compliance(configuration_item, rule_parameters)
    config = boto3.client('config')

    print('Compliance evaluation for %s: %s' % (configuration_item['resourceId'], evaluation["compliance_type"]))
    print('Annotation: %s' % (evaluation["annotation"]))

    response = config.put_evaluations(
       Evaluations=[
           {
               'ComplianceResourceType': invoking_event['configurationItem']['resourceType'],
               'ComplianceResourceId':   invoking_event['configurationItem']['resourceId'],
               'ComplianceType':         evaluation["compliance_type"],
               "Annotation":             evaluation["annotation"],
               'OrderingTimestamp':      invoking_event['configurationItem']['configurationItemCaptureTime']
           },
       ],
       ResultToken=event['resultToken'])

fromPort」というパラメータが、開いているポート範囲の開始値です。
単一ポートのみを開けていた場合はその値が、レンジで開けた場合は最小値が該当します。

★「fromPort」の例

80番ポートを開けた場合
→「80

22番〜80番ポートを開けた場合
→「22

ちなみに後者の場合、「toPort」という値(開いているポート範囲の終了値)に80が該当します。
前者の場合は「toPort」も80です。

また、これらのパラメータの値は、設定変更の操作履歴として記録されたイベントからとってきます。
ということはつまり、変更履歴が残ってない値はチェック出来ないのでは?

心配になったので、またサポートに問い合わせしたところ、問題ないと回答をいただきました。

セキュリティグループの変更をトリガーとして発行されるイベントには、セキュリティグループの既存ルールも含めてデータが格納されています。

※一部抜粋&改変してます。

一旦以上です。
次回に続きます。
よろしくお願いいたします。

TOP