Kaynağa Gözat

Functional through the analysis step

Gogs 5 yıl önce
ebeveyn
işleme
f659fdcf25

+ 7 - 0
README.md

@@ -17,6 +17,13 @@ The _right_ way to protect your assets is to prevent them in the first place. Wh
 
 FCM is _reactive_, which is always a worse solution than proactive prevention. That said, FCM can find and fix security issues that may have slipped through the cracks.
 
+## Important Note about Loop Prevention
+To prevent loops, the analysis modules discard any event that comes in that was initiated by an assumedrole of `fcm-*` and has the string `exec-env/AWS_Lambda` in its userAgent.  For this reason, it is imperative that you do NOT change the role names from this convention, or you could end up with an endless loop and the accompanying endless AWS bill.
+
+TO BE VERY CLEAR: IF YOU CHANGE THE ROLE NAMES, YOU COULD BE RESPONSIBLE FOR A LOT OF AWS COSTS.
+
+(there's got to be a better way to do loop prevention? SQS subscription filters?)
+
 ## Dependencies
 Requires python3 and terraform.
 

+ 12 - 0
Roles.md

@@ -0,0 +1,12 @@
+# FCM Roles
+
+There are a number of roles required.
+
+# All Accounts
+`fcm-analysis-[functionname]` - Permissions for the function, can be assumed by the master account `fcm-lambda-analysis-[functionname]`.
+`fcm-remediation-[functionname]` - Permissions for the function, can be assumed by the master account `fcm-lambda-remediation-[functionname].
+
+# Master Account
+Master account has all of the "All Accounts" roles, plus:
+`fcm-lambda-analysis-[functionname]` - Allows basic FCM lambda access and the ability to assumerole into the above roles in all accounts.
+`fcm-lambda-remediation-[functionname]` - Allows basic FCM lambda access and the ability to assumerole into the above roles in all accounts.

+ 1 - 0
sample/caller.tf

@@ -0,0 +1 @@
+data "aws_caller_identity" "current" {}

+ 29 - 5
sample/fcm-analysis-EbsEncryptionByDefault/EbsEncryptionByDefault.py

@@ -7,8 +7,12 @@ import re
 
 logger = logging.getLogger('FCM')
 
-def determine_compliance(detail):
-    return
+def determine_compliance(ec2client, detail):
+    if ec2client.get_ebs_encryption_by_default().get('EbsEncryptionByDefault') is not True:
+        logger.info('Determined not to be compliant')
+        return False
+    logger.debug('Determined to be compliant')
+    return True
 
 def report(compliant, detail):
     return
@@ -19,6 +23,7 @@ def remediate(detail):
 def lambda_handler(event, context):
     init_logger()
 
+    # Extract the useful stuff out of the input data
     if isinstance(event, (str, )):
         event = json.loads(event)
     body = json.loads(event['Records'][0]['body'])
@@ -30,13 +35,32 @@ def lambda_handler(event, context):
         logger.info('Probable loop detected. Exiting.')
         return {}
 
-    # For now, we're just going to turn it back on.
-    compliant = determine_compliance(detail)
+    account = body['account']
+    region  = body['region']
+
+    # Get a session on the destination account
+    logger.info(f'Assuming role into account {account} in region {region}')
+    client = boto3.client('sts')
+    assumed_role_obj = client.assume_role(
+            RoleArn=f'arn:aws:iam::{account}:role/fcm/fcm-analysis-EbsEncryptionByDefault',
+            RoleSessionName='fcm-analysis-EbsEncryptionByDefault',
+            DurationSeconds=900
+        )
+    credentials = assumed_role_obj['Credentials']
+    logger.debug(f'Creating ec2client with credentials: {json.dumps(credentials, default=str)}')
+    ec2client = boto3.client(
+            'ec2',
+            aws_access_key_id = credentials['AccessKeyId'],
+            aws_secret_access_key = credentials['SecretAccessKey'],
+            aws_session_token = credentials['SessionToken'],
+            region_name = region
+            )
+
+    compliant = determine_compliance(ec2client, detail)
     report(compliant, detail)
     if not compliant:
         remediate(detail)
     return True
-    
 
 
 def init_logger():

+ 39 - 0
sample/iam.shared.tf

@@ -0,0 +1,39 @@
+resource "aws_iam_policy" "fcm-lambda-base" {
+  name        = "fcm-lambda-base"
+  path        = "/fcm/"
+  description = "FCM policy for EbsEncryptionByDefault Enforcement Analysis"
+
+  policy = <<LAMBDABASE
+{
+    "Version": "2012-10-17",
+    "Statement": [
+        {
+            "Effect": "Allow",
+            "Action": "logs:CreateLogGroup",
+            "Resource": "arn:aws:logs:us-east-2:082012130604:log-group:*"
+        },
+        {
+            "Effect": "Allow",
+            "Action": [
+                "logs:CreateLogStream",
+                "logs:PutLogEvents"
+            ],
+            "Resource": "arn:aws:logs:us-east-2:082012130604:log-group:/aws/lambda/*"
+        },
+        {
+            "Sid": "FCMRequiredAccess",
+            "Effect": "Allow",
+            "Action": [
+                "kms:Decrypt",
+                "kms:GenerateDataKey*",
+                "sqs:ReceiveMessage",
+                "sqs:DeleteMessage",
+                "sqs:GetQueueAttributes"
+            ],
+            "Resource": "*"
+         }
+     ]
+}
+LAMBDABASE
+}
+

+ 1 - 1
sample/kms.tf

@@ -43,7 +43,7 @@ resource "aws_kms_key" "FCM-Key" {
 					"Sid": "Grant access to lambda functions",
 					"Effect": "Allow",
 					"Principal": {
-            "AWS": "${aws_iam_role.fcm-analysis-EbsEncryptionByDefault.arn}"
+            "AWS": "${aws_iam_role.fcm-lambda-analysis-EbsEncryptionByDefault.arn}"
 					},
 					"Action": [
             "kms:GenerateDataKey*",

+ 78 - 33
sample/lambda.fcm-analysis-EbsEncryptionByDefault.tf

@@ -1,21 +1,32 @@
+#Allowed: arn:aws:iam::*:role/fcm/fcm-analysis-EbsEncryptionByDefault
+#Actual:  arn:aws:iam::082012130604:role/fcm/fcm-analysis-EbsEncryptionByDefault
+#
+#Role trust: arn:aws:iam::082012130604:role/fcm/fcm-lambda-analysis-EbsEncryptionByDefault
+#Actual:     arn:aws:iam::082012130604:role/fcm/fcm-lambda-analysis-EbsEncryptionByDefault
+
+# All Accounts Role
 resource "aws_iam_role" "fcm-analysis-EbsEncryptionByDefault" {
   name = "fcm-analysis-EbsEncryptionByDefault"
+  path        = "/fcm/"
+  description = "FCM role for EbsEncryptionByDefault Enforcement Analysis"
 
-  assume_role_policy = <<ASSUMEROLEDOC
+  assume_role_policy = <<DOC1
 {
   "Version": "2012-10-17",
   "Statement": [
     {
       "Action": "sts:AssumeRole",
       "Principal": {
-        "Service": "lambda.amazonaws.com"
+        "AWS": [
+          "${aws_iam_role.fcm-lambda-analysis-EbsEncryptionByDefault.arn}"
+        ]
       },
       "Effect": "Allow",
       "Sid": ""
     }
   ]
 }
-ASSUMEROLEDOC
+DOC1
 }
 
 resource "aws_iam_policy" "fcm-analysis-EbsEncryptionByDefault" {
@@ -23,37 +34,12 @@ resource "aws_iam_policy" "fcm-analysis-EbsEncryptionByDefault" {
   path        = "/fcm/"
   description = "FCM policy for EbsEncryptionByDefault Enforcement Analysis"
 
-  policy = <<POLICYDOC
+  policy = <<DOC2
 {
     "Version": "2012-10-17",
     "Statement": [
-        {
-            "Effect": "Allow",
-            "Action": "logs:CreateLogGroup",
-            "Resource": "arn:aws:logs:us-east-2:082012130604:log-group:*"
-        },
-        {
-            "Effect": "Allow",
-            "Action": [
-                "logs:CreateLogStream",
-                "logs:PutLogEvents"
-            ],
-            "Resource": "arn:aws:logs:us-east-2:082012130604:log-group:/aws/lambda/*"
-        },
-        {
-            "Sid": "FCMRequiredAccess",
-            "Effect": "Allow",
-            "Action": [
-                "kms:Decrypt",
-                "kms:GenerateDataKey*",
-                "sqs:ReceiveMessage",
-                "sqs:DeleteMessage",
-                "sqs:GetQueueAttributes"
-            ],
-            "Resource": "*"
-         },
          {
-            "Sid": "FunctionSpecificAccess",
+            "Sid": "FunctionSpecific",
             "Effect": "Allow",
             "Action": [
                 "ec2:GetEbsEncryptionByDefault"
@@ -62,18 +48,77 @@ resource "aws_iam_policy" "fcm-analysis-EbsEncryptionByDefault" {
          }
     ]
 }
-POLICYDOC
+DOC2
 }
 
 resource "aws_iam_role_policy_attachment" "fcm-analysis-EbsEncryptionByDefault" {
   role       = "${aws_iam_role.fcm-analysis-EbsEncryptionByDefault.name}"
   policy_arn = "${aws_iam_policy.fcm-analysis-EbsEncryptionByDefault.arn}"
 }
+### ABOVE needs to be in all accounts.
+
+# Master Account Only:
+resource "aws_iam_role" "fcm-lambda-analysis-EbsEncryptionByDefault" {
+  name = "fcm-lambda-analysis-EbsEncryptionByDefault"
+  path        = "/fcm/"
+  description = "FCM policy for EbsEncryptionByDefault Enforcement Analysis Lambda Function"
+
+  assume_role_policy = <<DOC3
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Action": "sts:AssumeRole",
+      "Principal": {
+        "Service": "lambda.amazonaws.com"
+      },
+      "Effect": "Allow",
+      "Sid": ""
+    }
+  ]
+}
+DOC3
+}
+
+resource "aws_iam_policy" "fcm-lambda-analysis-EbsEncryptionByDefault" {
+  name        = "fcm-lambda-analysis-EbsEncryptionByDefault"
+  path        = "/fcm/"
+  description = "FCM policy the lambda function EbsEncryptionByDefault"
+
+  policy = <<DOC4
+{
+    "Version": "2012-10-17",
+    "Statement": [
+         {
+            "Sid": "AssumeROle",
+            "Effect": "Allow",
+            "Action": [
+                "sts:AssumeRole"
+            ],
+            "Resource": "arn:aws:iam::*:role/fcm/fcm-analysis-EbsEncryptionByDefault"
+         }
+    ]
+}
+DOC4
+}
+
+resource "aws_iam_role_policy_attachment" "fcm-lambda-analysis-EbsEncryptionByDefault" {
+  role       = "${aws_iam_role.fcm-lambda-analysis-EbsEncryptionByDefault.name}"
+  policy_arn = "${aws_iam_policy.fcm-lambda-analysis-EbsEncryptionByDefault.arn}"
+}
+
+resource "aws_iam_role_policy_attachment" "fcm-lambda-analysis-EbsEncryptionByDefault-shared" {
+  role       = "${aws_iam_role.fcm-lambda-analysis-EbsEncryptionByDefault.name}"
+  policy_arn = "${aws_iam_policy.fcm-lambda-base.arn}"
+}
+
+# End of Roles
 
+# Function
 resource "aws_lambda_function" "fcm-analysis-EbsEncryptionByDefault" {
   filename      = "fcm-analysis-EbsEncryptionByDefault.zip"
   function_name = "fcm-analysis-EbsEncryptionByDefault"
-  role          = "${aws_iam_role.fcm-analysis-EbsEncryptionByDefault.arn}"
+  role          = "${aws_iam_role.fcm-lambda-analysis-EbsEncryptionByDefault.arn}"
   handler       = "EbsEncryptionByDefault.lambda_handler"
 
   # The filebase64sha256() function is available in Terraform 0.11.12 and later
@@ -92,7 +137,7 @@ resource "aws_lambda_function" "fcm-analysis-EbsEncryptionByDefault" {
   }
 }
 
-resource "aws_lambda_event_source_mapping" "example" {
+resource "aws_lambda_event_source_mapping" "fcm-analysis-EbsEncryptionByDefault" {
   event_source_arn = "${aws_sqs_queue.fcm-analysis-EbsEncryptionByDefault.arn}"
   function_name    = "${aws_lambda_function.fcm-analysis-EbsEncryptionByDefault.arn}"
   batch_size = 1 # How many messages to process at a time

+ 55 - 2
sample/sqs.tf

@@ -1,3 +1,4 @@
+#### SQS Queues for Analysis
 resource "aws_sqs_queue" "fcm-analysis-EbsEncryptionByDefault-deadletter" {
   name                      = "fcm-analysis-EbsEncryptionByDefault-deadletter"
   visibility_timeout_seconds = 5400 # How long before the item can be retried if something went wrong, should match processing time. Should be at least 6 times the lambda timeout
@@ -38,7 +39,7 @@ resource "aws_sqs_queue_policy" "fcm-analysis-EbsEncryptionByDefault" {
   "Id": "sqspolicy",
   "Statement": [
     {
-      "Sid": "First",
+      "Sid": "SNSPermissions",
       "Effect": "Allow",
       "Principal": "*",
       "Action": "sqs:SendMessage",
@@ -58,7 +59,6 @@ resource "aws_sqs_queue_policy" "fcm-analysis-EbsEncryptionByDefault" {
 POLICY
 }
 
-
 resource "aws_sns_topic_subscription" "fcm-analysis-EbsEncryptionByDefault1" {
   topic_arn = "${aws_sns_topic.fcm-input-DisableEbsEncryptionByDefault.arn}"
   protocol  = "sqs"
@@ -80,3 +80,56 @@ resource "aws_sns_topic_subscription" "fcm-analysis-EbsEncryptionByDefault3" {
   raw_message_delivery = true # don't add extra sns metadata
 }
 
+#### SQS Queues for Remediation
+resource "aws_sqs_queue" "fcm-remediation-EbsEncryptionByDefault-deadletter" {
+  name                      = "fcm-remediation-EbsEncryptionByDefault-deadletter"
+  visibility_timeout_seconds = 5400 # How long before the item can be retried if something went wrong, should match processing time. Should be at least 6 times the lambda timeout
+  delay_seconds             = 0 # Delay before message is delivered. This can be increased if resources take longer to be active.
+  max_message_size          = 262144 # How big messages can get. 256KB is the max for SNS and SQS
+  message_retention_seconds = 1209600 # Better handle it with 14 days!
+  kms_master_key_id         = "alias/fcm"
+  depends_on = [aws_kms_alias.FCM-Key]
+  kms_data_key_reuse_period_seconds = 300 # keep using the same data key for up to 5 minutes
+
+  tags = {
+    Project = "FredsCloudMonitor"
+  }
+}
+
+resource "aws_sqs_queue" "fcm-remediation-EbsEncryptionByDefault" {
+  name                      = "fcm-remediation-EbsEncryptionByDefault"
+  visibility_timeout_seconds = 900 # How long before the item can be retried if something went wrong, should match processing time
+  delay_seconds             = 0 # Delay before message is delivered. This can be increased if resources take longer to be active.
+  max_message_size          = 262144 # How big messages can get. 256KB is the max for SNS and SQS
+  message_retention_seconds = 86400 # How long to keep the message
+  redrive_policy            = "{\"deadLetterTargetArn\":\"${aws_sqs_queue.fcm-remediation-EbsEncryptionByDefault-deadletter.arn}\",\"maxReceiveCount\":4}" # maxReceiveCount is how many times to attempt processing
+  kms_master_key_id         = "alias/fcm"
+  depends_on = [aws_kms_alias.FCM-Key]
+  kms_data_key_reuse_period_seconds = 300 # keep using the same data key for up to 5 minutes
+
+  tags = {
+    Project = "FredsCloudMonitor"
+  }
+}
+
+resource "aws_sqs_queue_policy" "fcm-remediation-EbsEncryptionByDefault" {
+  queue_url = "${aws_sqs_queue.fcm-remediation-EbsEncryptionByDefault.id}"
+
+  policy = <<POLICY
+{
+  "Version": "2012-10-17",
+  "Id": "sqspolicy",
+  "Statement": [
+    {
+      "Sid": "AllowAnalysisToSend",
+      "Effect": "Allow",
+      "Principal": {
+        "AWS": "${aws_iam_role.fcm-lambda-analysis-EbsEncryptionByDefault.arn}"
+      },
+      "Action": "sqs:SendMessage",
+      "Resource": "${aws_sqs_queue.fcm-remediation-EbsEncryptionByDefault.arn}"
+    }
+  ]
+}
+POLICY
+}