Explorar o código

Merge pull request #330 from mdr-engineering/feature/bp_MSOCI-1958_Portal_lambda_Updates

Migrates Portal Lambda to Queue Based
Brad Poulton %!s(int64=3) %!d(string=hai) anos
pai
achega
423afeeffb

+ 1 - 1
base/customer_portal/README.md

@@ -22,7 +22,7 @@ In Vault disable the auth method
 `vault auth disable aws`
 
 Then in terraform reapply the config. 
-`terragrunt-local apply -target=vault_auth_backend.aws -target=vault_aws_auth_backend_client.aws -target=vault_aws_auth_backend_role.portal`
+`VAULT_TOKEN=<fromvault> TF_VAR_okta_api_token=YOURTOKENHERE TF_VAR_okta_oidc_client_secret=YOURSECRETHERE terragrunt-local apply -target=vault_auth_backend.aws -target=vault_aws_auth_backend_client.aws -target=vault_aws_auth_backend_role.portal`
 
 Vault apparently caches the AWS response for the portal IAM role. 
 

+ 182 - 0
base/customer_portal_lambda/cloudwatch.tf

@@ -4,6 +4,18 @@ resource "aws_cloudwatch_log_group" "function" {
   tags = merge(var.standard_tags, var.tags)
 }
 
+resource "aws_cloudwatch_log_group" "function_scheduler" {
+  name              = "/aws/lambda/${aws_lambda_function.portal_scheduler.function_name}"
+  retention_in_days = 14
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_cloudwatch_log_group" "function_customer_sync" {
+  name              = "/aws/lambda/${aws_lambda_function.portal_customer_sync.function_name}"
+  retention_in_days = 14
+  tags = merge(var.standard_tags, var.tags)
+}
+
 ###
 ### Trigger Portal Sync Lambda with Rules and Targets
 ###
@@ -172,3 +184,173 @@ resource "aws_lambda_permission" "allow_cloudwatch_to_call_portal_lambda_monthly
   principal     = "events.amazonaws.com"
   source_arn    = aws_cloudwatch_event_rule.portal_event_monthly_rule.arn
 }
+
+
+###
+### Trigger Portal Scheduler Lambda with Rules and Targets
+###
+
+### Time-based rules for portal sync:
+resource "aws_cloudwatch_event_rule" "portal_scheduler_quarter_hourly_rule" {
+  name = "aws-portal-lambda-scheduler-quarter-hourly"
+  description = "Rule for portal scheduler lambda function - every 15 minutes"
+  schedule_expression = "rate(15 minutes)"
+  is_enabled = var.environment == "test" ? false : true
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_cloudwatch_event_rule" "portal_scheduler_half_hourly_rule" {
+  name = "aws-portal-lambda-scheduler-half-hourly"
+  description = "Rule for portal scheduler lambda function - every 30 minutes"
+  schedule_expression = "rate(30 minutes)"
+  is_enabled = var.environment == "test" ? false : true
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_cloudwatch_event_rule" "portal_scheduler_hourly_rule" {
+  name = "aws-portal-lambda-scheduler-hourly"
+  description = "Rule for portal scheduler lambda function - every hour"
+  schedule_expression = "rate(1 hour)"
+  is_enabled = var.environment == "test" ? false : true
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_cloudwatch_event_rule" "portal_scheduler_four_hourly_rule" {
+  name = "aws-portal-lambda-scheduler-four-hourly"
+  description = "Rule for portal scheduler lambda function - every 4 hours"
+  schedule_expression = "rate(4 hours)"
+  is_enabled = var.environment == "test" ? false : true
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_cloudwatch_event_rule" "portal_scheduler_daily_rule" {
+  name = "aws-portal-lambda-scheduler-daily"
+  description = "Rule for portal scheduler lambda function - every day"
+  schedule_expression = "cron(5 5 * * ? *)"
+  is_enabled = var.environment == "test" ? false : true
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_cloudwatch_event_rule" "portal_scheduler_weekly_rule" {
+  name = "aws-portal-lambda-scheduler-weekly"
+  description = "Rule for portal scheduler lambda function - every week"
+  schedule_expression = "rate(7 days)"
+  is_enabled = var.environment == "test" ? false : true
+  tags = merge(var.standard_tags, var.tags)
+}
+
+resource "aws_cloudwatch_event_rule" "portal_scheduler_monthly_rule" {
+  name = "aws-portal-lambda-scheduler-monthly"
+  description = "Rule for portal scheduler lambda function - every month"
+  schedule_expression = "rate(30 days)"
+  is_enabled = var.environment == "test" ? false : true
+  tags = merge(var.standard_tags, var.tags)
+}
+
+### Time-based targets for portal scheduler:
+resource "aws_cloudwatch_event_target" "portal_scheduler_cloudwatch_target_quarter_hourly" {
+  target_id = "PortalSchedulerQuarterHourly"
+  rule = aws_cloudwatch_event_rule.portal_scheduler_quarter_hourly_rule.name
+  input = "{\"frequency_identifier\":\"quarter-hourly\"}"
+  arn  = aws_lambda_function.portal_scheduler.arn
+}
+
+resource "aws_cloudwatch_event_target" "portal_scheduler_cloudwatch_target_half_hourly" {
+  target_id = "PortalSchedulerHalfHourly"
+  rule = aws_cloudwatch_event_rule.portal_scheduler_half_hourly_rule.name
+  input = "{\"frequency_identifier\":\"half-hourly\"}"
+  arn  = aws_lambda_function.portal_scheduler.arn
+}
+
+resource "aws_cloudwatch_event_target" "portal_scheduler_cloudwatch_target_hourly" {
+  target_id = "PortalSchedulerHourly"
+  rule = aws_cloudwatch_event_rule.portal_scheduler_hourly_rule.name
+  input = "{\"frequency_identifier\":\"hourly\"}"
+  arn  = aws_lambda_function.portal_scheduler.arn
+}
+
+resource "aws_cloudwatch_event_target" "portal_scheduler_cloudwatch_target_four_hourly" {
+  target_id = "PortalSchedulerFourHourly"
+  rule = aws_cloudwatch_event_rule.portal_scheduler_four_hourly_rule.name
+  input = "{\"frequency_identifier\":\"four-hourly\"}"
+  arn  = aws_lambda_function.portal_scheduler.arn
+}
+
+resource "aws_cloudwatch_event_target" "portal_scheduler_cloudwatch_target_daily" {
+  target_id = "PortalSchedulerDaily"
+  rule = aws_cloudwatch_event_rule.portal_scheduler_daily_rule.name
+  input = "{\"frequency_identifier\":\"daily\"}"
+  arn  = aws_lambda_function.portal_scheduler.arn
+}
+
+resource "aws_cloudwatch_event_target" "portal_scheduler_cloudwatch_target_weekly" {
+  target_id = "PortalSchedulerWeekly"
+  rule = aws_cloudwatch_event_rule.portal_scheduler_weekly_rule.name
+  input = "{\"frequency_identifier\":\"weekly\"}"
+  arn  = aws_lambda_function.portal_scheduler.arn
+}
+
+resource "aws_cloudwatch_event_target" "portal_scheduler_cloudwatch_target_monthly" {
+  target_id = "PortalSchedulerMonthly"
+  rule = aws_cloudwatch_event_rule.portal_scheduler_monthly_rule.name
+  input = "{\"frequency_identifier\":\"monthly\"}"
+  arn  = aws_lambda_function.portal_scheduler.arn
+}
+
+
+### Invoke permissions for Time-based rules for portal sync:
+resource "aws_lambda_permission" "allow_cloudwatch_to_call_portal_scheduler_quarter_hourly" {
+  statement_id  = "AllowExecutionFromCloudWatchQuarterHourly"
+  action        = "lambda:InvokeFunction"
+  function_name = aws_lambda_function.portal_scheduler.function_name
+  principal     = "events.amazonaws.com"
+  source_arn    = aws_cloudwatch_event_rule.portal_scheduler_quarter_hourly_rule.arn
+}
+
+resource "aws_lambda_permission" "allow_cloudwatch_to_call_portal_scheduler_half_hourly" {
+  statement_id  = "AllowExecutionFromCloudWatchHalfHourly"
+  action        = "lambda:InvokeFunction"
+  function_name = aws_lambda_function.portal_scheduler.function_name
+  principal     = "events.amazonaws.com"
+  source_arn    = aws_cloudwatch_event_rule.portal_scheduler_half_hourly_rule.arn
+}
+
+resource "aws_lambda_permission" "allow_cloudwatch_to_call_portal_scheduler_hourly" {
+  statement_id  = "AllowExecutionFromCloudWatchHourly"
+  action        = "lambda:InvokeFunction"
+  function_name = aws_lambda_function.portal_scheduler.function_name
+  principal     = "events.amazonaws.com"
+  source_arn    = aws_cloudwatch_event_rule.portal_scheduler_hourly_rule.arn
+}
+
+resource "aws_lambda_permission" "allow_cloudwatch_to_call_portal_scheduler_four_hourly" {
+  statement_id  = "AllowExecutionFromCloudWatchFourHourly"
+  action        = "lambda:InvokeFunction"
+  function_name = aws_lambda_function.portal_scheduler.function_name
+  principal     = "events.amazonaws.com"
+  source_arn    = aws_cloudwatch_event_rule.portal_scheduler_four_hourly_rule.arn
+}
+
+resource "aws_lambda_permission" "allow_cloudwatch_to_call_portal_scheduler_daily" {
+  statement_id  = "AllowExecutionFromCloudWatchDaily"
+  action        = "lambda:InvokeFunction"
+  function_name = aws_lambda_function.portal_scheduler.function_name
+  principal     = "events.amazonaws.com"
+  source_arn    = aws_cloudwatch_event_rule.portal_scheduler_daily_rule.arn
+}
+
+resource "aws_lambda_permission" "allow_cloudwatch_to_call_portal_scheduler_weekly" {
+  statement_id  = "AllowExecutionFromCloudWatchWeekly"
+  action        = "lambda:InvokeFunction"
+  function_name = aws_lambda_function.portal_scheduler.function_name
+  principal     = "events.amazonaws.com"
+  source_arn    = aws_cloudwatch_event_rule.portal_scheduler_weekly_rule.arn
+}
+
+resource "aws_lambda_permission" "allow_cloudwatch_to_call_portal_scheduler_monthly" {
+  statement_id  = "AllowExecutionFromCloudWatchMonthly"
+  action        = "lambda:InvokeFunction"
+  function_name = aws_lambda_function.portal_scheduler.function_name
+  principal     = "events.amazonaws.com"
+  source_arn    = aws_cloudwatch_event_rule.portal_scheduler_monthly_rule.arn
+}

+ 72 - 0
base/customer_portal_lambda/iam.tf

@@ -0,0 +1,72 @@
+data "aws_iam_policy_document" "policy_portal_data_sync_lambda" {
+  statement {
+    effect = "Allow"
+    actions = [
+      "ec2:CreateNetworkInterface",
+      "logs:CreateLogStream",
+      "ec2:DescribeNetworkInterfaces",
+      "logs:DescribeLogStreams",
+      "ec2:DeleteNetworkInterface",
+      "logs:PutRetentionPolicy",
+      "logs:CreateLogGroup",
+      "logs:PutLogEvents",
+      "sqs:ListQueues"
+    ]
+    resources = ["*"]
+  }
+
+  statement {
+    effect = "Allow"
+    actions = [
+        "sqs:*",
+    ]
+    resources = [ 
+        aws_sqs_queue.sqs_queue.arn,
+        aws_sqs_queue.sqs_queue_dlq.arn
+    ]
+  }
+
+  statement {
+    effect = "Allow"
+    actions = [
+      "kms:GenerateDataKey",
+      "kms:Decrypt"
+    ]
+    resources = [ 
+        aws_kms_key.sqs_key.arn
+    ]
+  }
+}
+
+resource "aws_iam_policy" "policy_portal_data_sync_lambda" {
+  name        = "policy_portal_data_sync_lambda"
+  path        = "/"
+  policy      = data.aws_iam_policy_document.policy_portal_data_sync_lambda.json
+  description = "IAM policy for portal_data_sync_lambda"
+}
+
+resource "aws_iam_role" "portal_lambda_role" {
+  name     = "portal-data-sync-lambda-role"
+  assume_role_policy = <<EOF
+{
+"Version": "2012-10-17",
+"Statement": [
+    { 
+    "Sid": "",
+    "Effect": "Allow",
+    "Principal": {
+        "Service": [
+        "lambda.amazonaws.com"
+        ]
+    },
+    "Action": "sts:AssumeRole"
+    }
+]
+}
+EOF
+}
+
+resource "aws_iam_role_policy_attachment" "lambda_role" {
+  role       = aws_iam_role.portal_lambda_role.name
+  policy_arn = aws_iam_policy.policy_portal_data_sync_lambda.arn
+}

+ 81 - 51
base/customer_portal_lambda/main.tf

@@ -7,60 +7,11 @@ locals {
       "VAULT_PATH"             = "portal/data/lambda_sync_env"
       "VERIFY_PORTAL_SSL"      = "0"
       "PYTHONWARNINGS"         = "ignore:Unverified HTTPS request"
+      "SQS_URL"                = "https://sqs.${var.aws_region}.amazonaws.com/${var.aws_account_id}/portal-scheduler.fifo"
 
   }
 }
 
-data "aws_iam_policy_document" "policy_portal_data_sync_lambda" {
-  statement {
-    effect = "Allow"
-    actions = [
-      "ec2:CreateNetworkInterface",
-      "logs:CreateLogStream",
-      "ec2:DescribeNetworkInterfaces",
-      "logs:DescribeLogStreams",
-      "ec2:DeleteNetworkInterface",
-      "logs:PutRetentionPolicy",
-      "logs:CreateLogGroup",
-      "logs:PutLogEvents"
-    ]
-    resources = ["*"]
-  }
-}
-
-resource "aws_iam_policy" "policy_portal_data_sync_lambda" {
-  name        = "policy_portal_data_sync_lambda"
-  path        = "/"
-  policy      = data.aws_iam_policy_document.policy_portal_data_sync_lambda.json
-  description = "IAM policy for portal_data_sync_lambda"
-}
-
-resource "aws_iam_role" "portal-lambda-role" {
-  name     = "portal-data-sync-lambda-role"
-  assume_role_policy = <<EOF
-{   
-    "Version": "2012-10-17",
-    "Statement": [
-      { 
-        "Sid": "",
-        "Effect": "Allow",
-        "Principal": {
-          "Service": [
-            "lambda.amazonaws.com"
-            ]
-        },
-        "Action": "sts:AssumeRole"
-      }
-    ]
-  }
-EOF
-}
-
-resource "aws_iam_role_policy_attachment" "lambda-role" {
-  role       = aws_iam_role.portal-lambda-role.name
-  policy_arn = aws_iam_policy.policy_portal_data_sync_lambda.arn
-}
-
 ####
 #
 #Security Group
@@ -103,7 +54,7 @@ resource "aws_lambda_function" "portal_data_sync" {
   filename         = "code.zip"
   source_code_hash = filebase64sha256("code.zip")
   function_name    = "portal_data_sync"
-  role             = aws_iam_role.portal-lambda-role.arn
+  role             = aws_iam_role.portal_lambda_role.arn
   handler          = "lambda_function.lambda_handler"
   runtime          = "python3.7"
   timeout          = "898"
@@ -127,3 +78,82 @@ resource "aws_lambda_function" "portal_data_sync" {
   }
 
 }
+
+resource "aws_lambda_function" "portal_scheduler" {
+  description      = "Used to schedule Portal sync jobs"
+  filename         = var.environment == "test" ? "test_portal_data_sync_20211209135332.zip" : "prod_portal_data_sync_20211209135448.zip"
+  source_code_hash = var.environment == "test" ? filebase64sha256("test_portal_data_sync_20211209135332.zip") : filebase64sha256("prod_portal_data_sync_20211209135448.zip") 
+  #s3_bucket        = aws_s3_bucket.bucket.bucket
+  #s3_key           = "code.zip" 
+  function_name    = "portal_scheduler"
+  role             = aws_iam_role.portal_lambda_role.arn
+  handler          = "lambda_function.scheduler"
+  runtime          = "python3.8"
+  timeout          = "180"
+  vpc_config {
+    subnet_ids          = var.subnets
+    security_group_ids  = [ data.aws_security_group.typical-host.id, aws_security_group.portal_lambda_splunk_sg.id ]
+  }
+  environment { 
+    variables = merge(var.customer_vars, local.environment_vars)
+  }
+  tags = merge(var.standard_tags, var.tags)
+
+  lifecycle {
+    # Ignoring changes to the code of the function so that we won't
+    # overlay changes to the function made outside of terraform.  Installing
+    # new versions of a lambda should not be a terraform-ish action we don't think
+    ignore_changes = [
+      last_modified,
+      source_code_hash
+    ]
+  }
+
+}
+
+resource "aws_lambda_function_event_invoke_config" "portal_scheduler" {
+  function_name                = aws_lambda_function.portal_scheduler.function_name
+  maximum_retry_attempts       = 0
+}
+
+resource "aws_lambda_function" "portal_customer_sync" {
+  description      = "Sync data between Splunk and Portal"
+  filename         = var.environment == "test" ? "test_portal_data_sync_20211209135332.zip" : "prod_portal_data_sync_20211209135448.zip"
+  source_code_hash = var.environment == "test" ? filebase64sha256("test_portal_data_sync_20211209135332.zip") : filebase64sha256("prod_portal_data_sync_20211209135448.zip") 
+  function_name    = "portal_customer_sync"
+  role             = aws_iam_role.portal_lambda_role.arn
+  handler          = "lambda_function.handler"
+  runtime          = "python3.8"
+  timeout          = "900"
+  vpc_config {
+    subnet_ids          = var.subnets
+    security_group_ids  = [ data.aws_security_group.typical-host.id, aws_security_group.portal_lambda_splunk_sg.id ]
+  }
+  environment { 
+    variables = merge(var.customer_vars, local.environment_vars)
+  }
+  tags = merge(var.standard_tags, var.tags)
+
+  lifecycle {
+    # Ignoring changes to the code of the function so that we won't
+    # overlay changes to the function made outside of terraform.  Installing
+    # new versions of a lambda should not be a terraform-ish action we don't think
+    ignore_changes = [
+      last_modified,
+      source_code_hash
+    ]
+  }
+
+}
+
+resource "aws_lambda_function_event_invoke_config" "portal_customer_sync" {
+  function_name                = aws_lambda_function.portal_customer_sync.function_name
+  maximum_retry_attempts       = 0
+}
+
+resource "aws_lambda_event_source_mapping" "portal_customer_sync" {
+  event_source_arn = aws_sqs_queue.sqs_queue.arn
+  function_name    = aws_lambda_function.portal_customer_sync.arn
+  batch_size       = 1
+
+}

BIN=BIN
base/customer_portal_lambda/prod_portal_data_sync_20211209135448.zip


+ 89 - 0
base/customer_portal_lambda/s3.tf

@@ -0,0 +1,89 @@
+# # TO BE IMPLEMENTED AT A LATER DATE!
+# resource "aws_s3_bucket" "bucket" {
+#   bucket        = "xdr-portal-lambda-${var.environment}"
+#   force_destroy = true
+#   acl           = "private"
+
+#   server_side_encryption_configuration {
+#     rule {
+#       apply_server_side_encryption_by_default {
+#         kms_master_key_id = aws_kms_key.key.arn
+#         sse_algorithm     = "aws:kms"
+#       }
+#     }
+#   }
+# }
+
+# resource "aws_s3_bucket_public_access_block" "public_access_block" {
+#   bucket                  = aws_s3_bucket.bucket.id
+#   block_public_acls       = true
+#   block_public_policy     = true
+#   ignore_public_acls      = true
+#   restrict_public_buckets = true
+
+#   # Not technically dependent, but prevents a "Conflicting conditional operation" conflict.
+#   # See https://github.com/hashicorp/terraform-provider-aws/issues/7628
+#   depends_on = [aws_s3_bucket_policy.policy]
+# }
+
+# resource "aws_s3_bucket_policy" "policy" {
+#   bucket = aws_s3_bucket.bucket.id
+#   policy = data.aws_iam_policy_document.policy_document.json
+# }
+
+# data "aws_iam_policy_document" "policy_document" {
+#   statement {
+#     sid = "AllowS3Access"
+#     actions = [ "s3:GetObject", "s3:GetObjectVersion" ]
+#     effect = "Allow"
+#     resources = [
+#         "${aws_s3_bucket.bucket.arn}",
+#         "${aws_s3_bucket.bucket.arn}/*"
+#       ]
+#     principals {
+#       type = "AWS"
+#       identifiers = [ "arn:${var.aws_partition}:iam::${var.aws_account_id}:root" ]
+#     }
+#   }
+# }
+
+# resource "aws_kms_key" "key" {
+#   description             = "Encryption of S3 code for portal-scheduler"
+#   policy                  = data.aws_iam_policy_document.kms_policy_document.json
+#   enable_key_rotation     = true
+#   tags                    = merge(var.standard_tags, var.tags)
+# }
+
+# data "aws_iam_policy_document" "kms_policy_document" {
+#   statement {
+#     sid = "AllowServices"
+#     effect = "Allow"
+#     principals {
+#       type = "AWS"
+#       identifiers = [ 
+#         "arn:${var.aws_partition}:iam::${var.aws_account_id}:role/user/mdr_terraformer",
+#         "arn:${var.aws_partition}:iam::${var.aws_account_id}:user/MDRAdmin"
+#         ]
+#     }
+#     actions   = [ "kms:*" ]
+#     resources = [ "*" ]
+#   }
+#   # allow account to modify/manage key
+#   statement {
+#     sid = "AllowThisAccount"
+#     effect = "Allow"
+#     principals {
+#       identifiers = ["arn:${var.aws_partition}:iam::${var.aws_account_id}:root"]
+#       type = "AWS"
+#     }
+#     actions = [
+#       "kms:*"
+#     ]
+#     resources = ["*"]
+#   }
+# }
+
+# resource "aws_kms_alias" "key_alias" {
+#   name          = "alias/portal-s3-key"
+#   target_key_id = aws_kms_key.key.key_id
+# }

+ 85 - 0
base/customer_portal_lambda/sqs.tf

@@ -0,0 +1,85 @@
+
+resource "aws_sqs_queue" "sqs_queue" {
+  name                        = "portal-scheduler.fifo"
+  visibility_timeout_seconds  = 900 # wait 15 minutes; this should always be equal or greater than the lambda timeout or we can get duplicate messages
+  message_retention_seconds   = 604800 # Keep a message in the queue for 7 days
+  receive_wait_time_seconds   = 0 # how long to wait for a message before returning
+  redrive_policy              = "{\"deadLetterTargetArn\":\"${aws_sqs_queue.sqs_queue_dlq.arn}\",\"maxReceiveCount\":1}"
+  fifo_queue                  = true
+  content_based_deduplication = true
+  deduplication_scope         = "queue"
+  fifo_throughput_limit       = "perQueue"
+  tags                        = merge(var.standard_tags, var.tags)
+  kms_master_key_id           = aws_kms_key.sqs_key.id
+  kms_data_key_reuse_period_seconds = 3600
+}
+
+# Dead Letter queue
+resource "aws_sqs_queue" "sqs_queue_dlq" {
+  name                      = "portal-scheduler-dlq.fifo"
+  fifo_queue                 = true
+  tags                      = merge(var.standard_tags, var.tags)
+  kms_master_key_id         = aws_kms_key.sqs_key.id
+  kms_data_key_reuse_period_seconds = 3600
+}
+
+data "aws_iam_policy_document" "sqs_policy" {
+  statement {
+    effect = "Allow"
+
+    principals {
+      identifiers = [ "arn:${var.aws_partition}:iam::${var.aws_account_id}:root" ]
+      type = "AWS"
+    }
+
+    actions = [ "SQS:*" ]
+
+    resources = [ aws_sqs_queue.sqs_queue.arn ]
+
+  }
+}
+
+resource "aws_sqs_queue_policy" "sqs_policy_attach" {
+  policy    = data.aws_iam_policy_document.sqs_policy.json
+  queue_url = aws_sqs_queue.sqs_queue.id
+}
+
+resource "aws_kms_key" "sqs_key" {
+  description             = "Encryption of SQS queue for portal-scheduler"
+  policy                  = data.aws_iam_policy_document.sqs_kms_policy.json
+  enable_key_rotation     = true
+}
+
+data "aws_iam_policy_document" "sqs_kms_policy" {
+  statement {
+    sid = "AllowServices"
+    effect = "Allow"
+    principals {
+      identifiers = ["cloudwatch.amazonaws.com", "sqs.amazonaws.com", "lambda.amazonaws.com"]
+      type = "Service"
+    }
+    actions = [
+      "kms:GenerateDataKey",
+      "kms:Decrypt"
+    ]
+    resources = [ "*" ]
+  }
+  # allow account to modify/manage key
+  statement {
+    sid = "AllowThisAccount"
+    effect = "Allow"
+    principals {
+      identifiers = ["arn:${var.aws_partition}:iam::${var.aws_account_id}:root"]
+      type = "AWS"
+    }
+    actions = [
+      "kms:*"
+    ]
+    resources = ["*"]
+  }
+}
+
+resource "aws_kms_alias" "sqs_key_alias" {
+  name          = "alias/portal-scheduler-key"
+  target_key_id = aws_kms_key.sqs_key.key_id
+}

BIN=BIN
base/customer_portal_lambda/test_portal_data_sync_20211209135332.zip