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