こんにちは。
シンプラインの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です。
また、これらのパラメータの値は、設定変更の操作履歴として記録されたイベントからとってきます。
ということはつまり、変更履歴が残ってない値はチェック出来ないのでは?
心配になったので、またサポートに問い合わせしたところ、問題ないと回答をいただきました。
セキュリティグループの変更をトリガーとして発行されるイベントには、セキュリティグループの既存ルールも含めてデータが格納されています。
※一部抜粋&改変してます。
一旦以上です。
次回に続きます。
よろしくお願いいたします。