EbsEncryptionByDefault.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #! /usr/bin/env python3
  2. import boto3
  3. import json
  4. import logging
  5. import os
  6. import re
  7. logger = logging.getLogger('FCM')
  8. def determine_compliance(ec2client, detail):
  9. if ec2client.get_ebs_encryption_by_default().get('EbsEncryptionByDefault') is not True:
  10. logger.info('Determined not to be compliant')
  11. return False
  12. logger.debug('Determined to be compliant')
  13. return True
  14. def report(sqsclient, compliant, function_name, detail):
  15. output = {
  16. 'plugin': function_name,
  17. 'compliant': compliant,
  18. 'trigger': detail
  19. }
  20. logger.debug(f'Sending report: {json.dumps(output, default=str)}')
  21. # TODO - Actually report
  22. def remediate(sqsclient, account, region):
  23. output = {
  24. 'account': account,
  25. 'region': region
  26. }
  27. logger.debug(f'Sending remediation request to queue: {json.dumps(output, default=str)}')
  28. response = sqsclient.send_message(
  29. QueueUrl = 'https://sqs.us-east-2.amazonaws.com/082012130604/fcm-remediation-EbsEncryptionByDefault',
  30. MessageBody = json.dumps(output)
  31. )
  32. def lambda_handler(event, context):
  33. init_logger()
  34. # Extract the useful stuff out of the input data
  35. if isinstance(event, (str, )):
  36. event = json.loads(event)
  37. body = json.loads(event['Records'][0]['body'])
  38. detail = body.get('detail', {})
  39. logger.debug(f'Inbound event: {json.dumps(event, default=str)}')
  40. logger.debug(f'Inbound body: {json.dumps(body, default=str)}')
  41. logger.debug(f'Inbound detail: {json.dumps(detail, default=str)}')
  42. if prevent_loop(detail):
  43. logger.info('Probable loop detected. Exiting.')
  44. return {}
  45. account = body['account']
  46. region = body['region']
  47. function_name = str(context.function_name)
  48. logger.debug(f'Determined function name is: "{function_name}"')
  49. # Get a session on the destination account
  50. logger.info(f'Assuming role into account {account} in region {region}')
  51. client = boto3.client('sts')
  52. assumed_role_obj = client.assume_role(
  53. RoleArn=f'arn:aws:iam::{account}:role/fcm/{function_name}',
  54. RoleSessionName=function_name,
  55. DurationSeconds=900
  56. )
  57. credentials = assumed_role_obj['Credentials']
  58. logger.debug(f'Creating ec2client with credentials: {json.dumps(credentials, default=str)}')
  59. ec2client = boto3.client(
  60. 'ec2',
  61. aws_access_key_id = credentials['AccessKeyId'],
  62. aws_secret_access_key = credentials['SecretAccessKey'],
  63. aws_session_token = credentials['SessionToken'],
  64. region_name = region
  65. )
  66. logger.debug(f'Creating local account sqsclient')
  67. sqsclient = boto3.client('sqs')
  68. compliant = determine_compliance(ec2client, detail)
  69. report(sqsclient, compliant, function_name, detail)
  70. if not compliant:
  71. remediate(sqsclient, account, region)
  72. return True
  73. def init_logger():
  74. global logger
  75. try:
  76. logger.setLevel(os.environ['LOGLEVEL'])
  77. except:
  78. logger.setLevel('DEBUG')
  79. logger.warning('Logging level not set or set to invalid value.')
  80. def prevent_loop(detail):
  81. arn = r'^arn:aws:sts::\d{12}:assumed-role/fcm-'
  82. useragent = r'exec-env/AWS_Lambda'
  83. if re.search(arn, detail.get('userIdentity', {}).get('arn', '')):
  84. # We're in an fcm assumed role
  85. if re.search(useragent, detail.get('userAgent', '')):
  86. return True
  87. return False
  88. if __name__ == "__main__":
  89. # For testing only:
  90. handler = logging.StreamHandler()
  91. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  92. handler.setFormatter(formatter)
  93. logger.addHandler(handler)
  94. event = {
  95. "Records": [
  96. {
  97. "messageId": "39647048-eb52-4393-a39a-fda3a8d3fdfc",
  98. "receiptHandle": "AQEBXWJnH5nZjA5CYGceVCf/S8Rxy0MK0leslGeCZy5BNzejyqUNfmItzpc2D8AiapnByQk5AmR1UDMtfm6eptnEuKerBebtw0zJDXa/ed5joiWYKo8v2evl8Kun8dj77MRr70vsVqXenvSY5neNUSmtwKcnfNpsxL1qBYA7fatI/xLSOy08i4C8jsntJLA93Xag1IN0/+xiuzkYoBHm5oFf24Ed1EZ5izKJsWjKQc9bAzd4EKSuUXbNpFjW8WWDcr1c9Sdi6NS0F2P/qFRNinwCYRENicQZ5KSNISxqZgLe+nBfQRipn1kGMMNsgBfGgonOakkFB7KI1GGXFspxEYIPrIcUUJt7XwYKgvqUOF/gKezOdAPpVOSoAYkVdV4BjWxCTbw8L03wuDsqe0ihanB6oE/6GTachRsPg0WiSQcq2tw=",
  99. "body": "{\"version\":\"0\",\"id\":\"8e098047-456d-45b1-9ac4-2c2571bafcbd\",\"detail-type\":\"AWS API Call via CloudTrail\",\"source\":\"aws.ec2\",\"account\":\"082012130604\",\"time\":\"2019-09-26T19:37:50Z\",\"region\":\"us-east-2\",\"resources\":[],\"detail\":{\"eventVersion\":\"1.05\",\"userIdentity\":{\"type\":\"Root\",\"principalId\":\"082012130604\",\"arn\":\"arn:aws:iam::082012130604:root\",\"accountId\":\"082012130604\",\"accessKeyId\":\"ASIARGGCNZUWBA2LEEP3\",\"sessionContext\":{\"sessionIssuer\":{},\"webIdFederationData\":{},\"attributes\":{\"mfaAuthenticated\":\"true\",\"creationDate\":\"2019-09-26T13:53:54Z\"}}},\"eventTime\":\"2019-09-26T19:37:50Z\",\"eventSource\":\"ec2.amazonaws.com\",\"eventName\":\"DisableEbsEncryptionByDefault\",\"awsRegion\":\"us-east-2\",\"sourceIPAddress\":\"99.56.213.129\",\"userAgent\":\"console.ec2.amazonaws.com\",\"requestParameters\":{\"DisableEbsEncryptionByDefaultRequest\":{}},\"responseElements\":{\"DisableEbsEncryptionByDefaultResponse\":{\"xmlns\":\"http://ec2.amazonaws.com/doc/2016-11-15/\",\"ebsEncryptionByDefault\":false,\"requestId\":\"5e6d6a10-a7b9-4e55-9dd3-c04ec7db7198\"}},\"requestID\":\"5e6d6a10-a7b9-4e55-9dd3-c04ec7db7198\",\"eventID\":\"014d99f8-ac9b-41c6-8d8a-a7bb1dffd20a\",\"eventType\":\"AwsApiCall\"}}",
  100. "attributes": {
  101. "ApproximateReceiveCount": "1",
  102. "SentTimestamp": "1569526676382",
  103. "SenderId": "AIDAJQR6QDGQ7PATMSYEY",
  104. "ApproximateFirstReceiveTimestamp": "1569526676385"
  105. },
  106. "messageAttributes": {},
  107. "md5OfBody": "41bfacdf79a8139308b1790eac435955",
  108. "eventSource": "aws:sqs",
  109. "eventSourceARN": "arn:aws:sqs:us-east-2:082012130604:fcm-analysis-EbsEncryptionByDefault",
  110. "awsRegion": "us-east-2"
  111. }
  112. ]
  113. }
  114. lambda_handler(event = event, context={})