Explorar o código

Merge pull request #229 from mdr-engineering/feature/ftd_MSOCI-1799_LockDownTheCA

Initial Root CA Work
Frederick Damstra %!s(int64=4) %!d(string=hai) anos
pai
achega
1abad74d63

+ 81 - 0
base/CA_Infrastructure/root_CA/audit_bucket.tf

@@ -0,0 +1,81 @@
+resource "aws_s3_bucket" "audit_reports" {
+  provider = aws.c2 # The reports go in the c2 bucket
+  bucket = "xdr-ca-audit-reports"
+  acl    = "private"
+
+  versioning {
+    enabled = true
+  }
+
+  # TODO: Enable S3 logging... everywhere. We don't have a C2 bucket for this.
+  #logging {
+  #  target_bucket = module.xdr_config_logging_bucket.s3_bucket_name
+  #  target_prefix = "${var.aws_account_id}-${var.aws_region}-awsconfig/"
+  #}
+
+  lifecycle_rule {
+    id = "CleanUp"
+    enabled = true
+    abort_incomplete_multipart_upload_days = 7
+    # Clean up old versions after a year
+    noncurrent_version_expiration {
+      days = 365
+    }
+  }
+
+  server_side_encryption_configuration {
+    rule {
+      apply_server_side_encryption_by_default {
+        sse_algorithm = "AES256" # Default keys are fine. We don't really need encryption here.
+      }
+    }
+  }
+
+  tags = merge(var.standard_tags, var.tags)
+}
+
+data "aws_iam_policy_document" "audit_reports_bucket_access" {
+  statement {
+    actions = [
+      "s3:GetBucketAcl",
+      "s3:GetBucketLocation",
+      "s3:PutObject",
+      "s3:PutObjectAcl",
+    ]
+
+    resources = [
+      aws_s3_bucket.audit_reports.arn,
+      "${aws_s3_bucket.audit_reports.arn}/*",
+    ]
+
+    principals {
+      identifiers = ["acm-pca.amazonaws.com"]
+      type        = "Service"
+    }
+
+    # TODO: Consider restricting this to the accounts, but may need to add Get permissions?
+    # "Condition":{
+    #       "StringEquals":{
+    #          "aws:SourceAccount":"account",
+    #          "aws:SourceArn":"arn:partition:acm-pca:region:account:certificate-authority/CA-ID"
+    #       }
+    #    }
+  }
+}
+
+resource "aws_s3_bucket_policy" "audit_reports" {
+  provider = aws.c2 # The reports go in the c2 bucket
+  bucket = aws_s3_bucket.audit_reports.id
+  policy = data.aws_iam_policy_document.audit_reports_bucket_access.json
+  depends_on = [ aws_s3_bucket.audit_reports ]
+}
+
+resource "aws_s3_bucket_public_access_block" "audit_reports_bucket_block_public_access" {
+  provider = aws.c2 # The reports go in the c2 bucket
+  bucket                  = aws_s3_bucket.audit_reports.id
+  block_public_acls       = true
+  block_public_policy     = true
+  ignore_public_acls      = true
+  restrict_public_buckets = true
+  depends_on = [ aws_s3_bucket.audit_reports ]
+}

+ 47 - 0
base/CA_Infrastructure/root_CA/ca.tf

@@ -0,0 +1,47 @@
+resource "aws_acmpca_certificate_authority" "root_CA" {
+  type = "ROOT"
+  certificate_authority_configuration {
+    key_algorithm     = "RSA_4096"
+    signing_algorithm = "SHA512WITHRSA"
+
+    subject {
+      common_name = "XDR Root CA"
+      country = "US"
+      organization = "Accenture Federal Services"
+      organizational_unit = "XDR"
+      
+    }
+  }
+
+  revocation_configuration {
+    crl_configuration {
+      #custom_cname       = "crl.xdr.accenturefederalcyber.com" # Maybe we want to hide the S3 bucket? Adds cost and complexity so I'm going with YAGNI for now.
+      enabled            = true
+      expiration_in_days = 7
+      s3_bucket_name     = aws_s3_bucket.crl.id
+    }
+  }
+
+  tags = merge(var.standard_tags, var.tags)
+  depends_on = [aws_s3_bucket_policy.crl]
+}
+
+resource "aws_acmpca_certificate" "root_certificate" {
+  certificate_authority_arn   = aws_acmpca_certificate_authority.root_CA.arn
+  certificate_signing_request = aws_acmpca_certificate_authority.root_CA.certificate_signing_request
+  signing_algorithm           = "SHA512WITHRSA"
+
+  template_arn = "arn:${var.aws_partition}:acm-pca:::template/RootCACertificate/V1"
+
+  validity {
+    type  = "YEARS"
+    value = 20
+  }
+}
+
+resource "aws_acmpca_certificate_authority_certificate" "root_certificate" {
+  certificate_authority_arn = aws_acmpca_certificate_authority.root_CA.arn
+
+  certificate       = aws_acmpca_certificate.root_certificate.certificate
+  certificate_chain = aws_acmpca_certificate.root_certificate.certificate_chain
+}

+ 79 - 0
base/CA_Infrastructure/root_CA/crl.tf

@@ -0,0 +1,79 @@
+resource "aws_s3_bucket" "crl" {
+  bucket = "xdr-root-crl"
+
+  # CRLs are small, but regenerated every expiration/2 days, (every 3.5 days by default), so there will be a good number of versions
+  versioning {
+    enabled = true
+  }
+
+  # TODO: Enable S3 logging... everywhere. We don't have a C2 bucket for this.
+  #logging {
+  #  target_bucket = module.xdr_config_logging_bucket.s3_bucket_name
+  #  target_prefix = "${var.aws_account_id}-${var.aws_region}-awsconfig/"
+  #}
+
+  lifecycle_rule {
+    id = "CleanUp"
+    enabled = true
+    abort_incomplete_multipart_upload_days = 7
+    # Clean up old versions after a year
+    noncurrent_version_expiration {
+      days = 365
+    }
+  }
+
+  server_side_encryption_configuration {
+    rule {
+      apply_server_side_encryption_by_default {
+        sse_algorithm = "AES256" # Default keys are fine. We don't really need encryption here.
+      }
+    }
+  }
+
+  tags = merge(var.standard_tags, var.tags)
+}
+
+data "aws_iam_policy_document" "acmpca_bucket_access" {
+  statement {
+    actions = [
+      "s3:GetBucketAcl",
+      "s3:GetBucketLocation",
+      "s3:PutObject",
+      "s3:PutObjectAcl",
+    ]
+
+    resources = [
+      aws_s3_bucket.crl.arn,
+      "${aws_s3_bucket.crl.arn}/*",
+    ]
+
+    principals {
+      identifiers = ["acm-pca.amazonaws.com"]
+      type        = "Service"
+    }
+
+    # TODO: Consider restricting this to the account, but may need to add Get permissions?
+    # "Condition":{
+    #       "StringEquals":{
+    #          "aws:SourceAccount":"account",
+    #          "aws:SourceArn":"arn:partition:acm-pca:region:account:certificate-authority/CA-ID"
+    #       }
+    #    }
+
+  }
+}
+
+resource "aws_s3_bucket_policy" "crl" {
+  bucket = aws_s3_bucket.crl.id
+  policy = data.aws_iam_policy_document.acmpca_bucket_access.json
+}
+
+# We want the CRL publicly accessible for zero trust websites and such.
+#resource "aws_s3_bucket_public_access_block" "crl_bucket_block_public_access" {
+#  bucket                  = aws_s3_bucket.crl.id
+#  block_public_acls       = false # Not supported for CRLs, see https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-error-crl-acm-ca/
+#  block_public_policy     = true
+#  ignore_public_acls      = true
+#  restrict_public_buckets = true
+#  depends_on = [ aws_s3_bucket.crl ]
+#}

+ 44 - 0
base/CA_Infrastructure/root_CA/iam_splunk_sh.tf

@@ -0,0 +1,44 @@
+# Creates an IAM role so that splunk can trigger creation of audit reports
+resource "aws_iam_role" "run_audit_report_role" {
+  name = "run_audit_report_role"
+  path = "/service/"
+
+  assume_role_policy = jsonencode( 
+    {
+      "Version": "2012-10-17",
+      "Statement": [
+        {
+          "Effect": "Allow",
+          "Principal": {
+            "AWS": "arn:${var.aws_partition}:iam::${var.c2_accounts[var.aws_partition]}:role/instance/moose-splunk-sh-instance-role"
+          },
+          "Action": "sts:AssumeRole"
+        }
+      ]
+    })
+
+  tags = merge(var.standard_tags, var.tags)
+}
+
+data "aws_iam_policy_document" "run_audit_report_policy_doc" {
+    statement {
+    sid       = ""
+    effect    = "Allow"
+    resources = ["*"]
+
+    actions = [
+      "acm-pca:CreateCertificateAuthorityAuditReport"
+    ]
+  }
+}
+
+resource "aws_iam_policy" "run_audit_report_policy" {
+  name        = "run_audit_report_policy"
+  path        = "/"
+  policy      = data.aws_iam_policy_document.run_audit_report_policy_doc.json
+}
+
+resource "aws_iam_role_policy_attachment" "run_audit_report_policy_attach" {
+  role       = aws_iam_role.run_audit_report_role.name
+  policy_arn = aws_iam_policy.run_audit_report_policy.arn
+}

+ 4 - 0
base/CA_Infrastructure/root_CA/locals.tf

@@ -0,0 +1,4 @@
+locals {
+  # A list of people to receive the alert
+  recipients = toset([ "frederick.t.damstra@accenturefederal.com" ])
+}

+ 0 - 0
base/CA_Infrastructure/root_CA/main.tf


+ 7 - 0
base/CA_Infrastructure/root_CA/outputs.tf

@@ -0,0 +1,7 @@
+output root_authority_arn {
+  value = aws_acmpca_certificate_authority.root_CA.arn
+}
+
+output role_arn {
+  value = aws_iam_role.run_audit_report_role.arn
+}

+ 88 - 0
base/CA_Infrastructure/root_CA/sns_alerts.tf

@@ -0,0 +1,88 @@
+resource "aws_cloudwatch_log_group" "CAAccountCAAccountCloudTrailAnalysis" {
+  name = "CAAccountCloudTrailAnalysis"
+}
+
+resource "aws_iam_role" "ca_account_cloudtrail_role" {
+  name = "ca_account_cloudtrail_role"
+  assume_role_policy = <<EOF
+{
+    "Version": "2012-10-17",
+    "Statement": [
+      {
+        "Sid": "",
+        "Effect": "Allow",
+        "Principal": {
+          "Service": "cloudtrail.amazonaws.com"
+        },
+        "Action": "sts:AssumeRole"
+      }
+    ]
+}
+EOF
+}
+
+resource "aws_iam_role_policy" "allow_stream_policy" {
+  name = "allow_stream_change"
+  role = aws_iam_role.ca_account_cloudtrail_role.id
+
+  policy = <<EOF
+{
+      "Version": "2012-10-17",
+      "Statement": [
+          {
+              "Effect": "Allow",
+              "Action": [
+                  "logs:CreateLogStream",
+                  "logs:PutLogEvents"
+              ],
+              "Resource": [
+                "${aws_cloudwatch_log_group.CAAccountCAAccountCloudTrailAnalysis.arn}"
+              ]
+          }
+      ]
+}
+EOF
+}
+
+resource "aws_sns_topic" "ca_account_notification" {
+  name = "CAAccountNotification"
+}
+
+resource "aws_sns_topic_subscription" "ca_account_notification" {
+  for_each = local.recipients
+  topic_arn = aws_sns_topic.ca_account_notification.arn
+  protocol  = "email"
+  endpoint  = each.value
+}
+
+
+#resource "aws_cloudwatch_log_metric_filter" "rootEvent" {
+#  name           = "Root_Account_Login"
+#  pattern        = <<EOF
+#{ ($.eventSource = "signin.amazonaws.com" ) && ( $.userIdentity.type = "Root" ) }
+#EOF
+#  log_group_name = "${aws_cloudwatch_log_group.CAAccountCloudTrailAnalysis.name}"
+#
+#  metric_transformation {
+#    name      = "${var.thiseventname}"
+#    namespace = "${var.thisnamespace}"
+#    value     = "1"
+#  }
+#}
+
+data "aws_caller_identity" "current" {}
+data "aws_iam_account_alias" "current" {}
+
+#resource "aws_cloudwatch_metric_alarm" "rootAlarm" {
+#  alarm_name          = "Root_Account_Login"
+#  comparison_operator = "GreaterThanOrEqualToThreshold"
+#  evaluation_periods  = "1"
+#  metric_name         = "${var.thiseventname}"
+#  namespace           = "${var.thisnamespace}"
+#  period              = "300"
+#  statistic           = "Sum"
+#  threshold           = "1"
+
+#  alarm_description = "in the AWS account with id = ${data.aws_caller_identity.current.account_id} and alias = ${data.aws_iam_account_alias.current.account_alias} the root user logged in"
+#  alarm_actions     = ["${aws_sns_topic.ca_account_notification.arn}"]
+#}

+ 10 - 0
base/CA_Infrastructure/root_CA/vars.tf

@@ -0,0 +1,10 @@
+variable "c2_accounts" { type = map }
+variable "tags" { type = map }
+variable "standard_tags" { type = map }
+variable "environment" { type = string }
+variable "aws_region" { type = string }
+variable "aws_account_id" { type = string }
+variable "aws_partition" { type = string }
+variable "aws_partition_alias" { type = string }
+variable "common_services_account" { type = string }
+variable "instance_termination_protection" { type = bool }

+ 49 - 0
base/CA_Infrastructure/subordinate_CA/ca.tf

@@ -0,0 +1,49 @@
+resource "aws_acmpca_certificate_authority_certificate" "subordinate" {
+  provider = aws.common # COMMON SERVICES
+  certificate_authority_arn = aws_acmpca_certificate_authority.subordinate.arn
+
+  certificate       = aws_acmpca_certificate.subordinate.certificate
+  certificate_chain = aws_acmpca_certificate.subordinate.certificate_chain
+}
+
+resource "aws_acmpca_certificate" "subordinate" {
+  certificate_authority_arn   = var.root_authority_arn
+  certificate_signing_request = aws_acmpca_certificate_authority.subordinate.certificate_signing_request
+  signing_algorithm           = "SHA512WITHRSA"
+
+  template_arn = "arn:${var.aws_partition}:acm-pca:::template/SubordinateCACertificate_PathLen0/V1"
+
+  validity {
+    type  = "YEARS"
+    value = 10
+  }
+}
+
+resource "aws_acmpca_certificate_authority" "subordinate" {
+  provider = aws.common # COMMON SERVICES
+  type = "SUBORDINATE"
+
+  certificate_authority_configuration {
+    key_algorithm     = "RSA_2048"
+    signing_algorithm = "SHA512WITHRSA"
+
+    subject {
+      common_name = "XDR Subordinate CA #1"
+      country = "US"
+      organization = "Accenture Federal Services"
+      organizational_unit = "XDR"
+    }
+  }
+
+  revocation_configuration {
+    crl_configuration {
+      #custom_cname       = "crl.xdr.accenturefederalcyber.com" # Maybe we want to hide the S3 bucket? Adds cost and complexity so I'm going with YAGNI for now.
+      enabled            = true
+      expiration_in_days = 7
+      s3_bucket_name     = aws_s3_bucket.crl.id
+    }
+  }
+
+  tags = merge(var.standard_tags, var.tags)
+  depends_on = [aws_s3_bucket_policy.crl]
+}

+ 73 - 0
base/CA_Infrastructure/subordinate_CA/crl.tf

@@ -0,0 +1,73 @@
+resource "aws_s3_bucket" "crl" {
+  provider = aws.common # COMMON SERVICES
+  bucket = "xdr-subordinate-crl"
+
+  # CRLs are small, but regenerated every expiration/2 days, (every 3.5 days by default), so there will be a good number of versions
+  versioning {
+    enabled = true
+  }
+
+  # TODO: Enable S3 logging... everywhere. We don't have a C2 bucket for this.
+  #logging {
+  #  target_bucket = module.xdr_config_logging_bucket.s3_bucket_name
+  #  target_prefix = "${var.aws_account_id}-${var.aws_region}-awsconfig/"
+  #}
+
+  lifecycle_rule {
+    id = "CleanUp"
+    enabled = true
+    abort_incomplete_multipart_upload_days = 7
+    # Clean up old versions after a year
+    noncurrent_version_expiration {
+      days = 365
+    }
+  }
+
+  server_side_encryption_configuration {
+    rule {
+      apply_server_side_encryption_by_default {
+        sse_algorithm = "AES256" # Default keys are fine. We don't really need encryption here.
+      }
+    }
+  }
+
+  tags = merge(var.standard_tags, var.tags)
+}
+
+data "aws_iam_policy_document" "acmpca_bucket_access" {
+  statement {
+    actions = [
+      "s3:GetBucketAcl",
+      "s3:GetBucketLocation",
+      "s3:PutObject",
+      "s3:PutObjectAcl",
+    ]
+
+    resources = [
+      aws_s3_bucket.crl.arn,
+      "${aws_s3_bucket.crl.arn}/*",
+    ]
+
+    principals {
+      identifiers = ["acm-pca.amazonaws.com"]
+      type        = "Service"
+    }
+  }
+}
+
+resource "aws_s3_bucket_policy" "crl" {
+  provider = aws.common # COMMON SERVICES
+  bucket = aws_s3_bucket.crl.id
+  policy = data.aws_iam_policy_document.acmpca_bucket_access.json
+}
+
+# Publicly available CRL so clients can validate
+#resource "aws_s3_bucket_public_access_block" "crl_bucket_block_public_access" {
+#  provider = aws.common # COMMON SERVICES
+#  bucket                  = aws_s3_bucket.crl.id
+#  block_public_acls       = false # Not supported for CRLs, see https://aws.amazon.com/premiumsupport/knowledge-center/s3-bucket-error-crl-acm-ca/
+#  block_public_policy     = true
+#  ignore_public_acls      = true
+#  restrict_public_buckets = true
+#  depends_on = [ aws_s3_bucket.crl ]
+#}

+ 47 - 0
base/CA_Infrastructure/subordinate_CA/iam_splunk_sh.tf

@@ -0,0 +1,47 @@
+# Creates an IAM role so that splunk can trigger creation of audit reports
+resource "aws_iam_role" "run_audit_report_role" {
+  provider = aws.common # COMMON SERVICES
+  name = "run_audit_report_role"
+  path = "/service/"
+
+  assume_role_policy = jsonencode( 
+    {
+      "Version": "2012-10-17",
+      "Statement": [
+        {
+          "Effect": "Allow",
+          "Principal": {
+            "AWS": "arn:${var.aws_partition}:iam::${var.c2_accounts[var.aws_partition]}:role/instance/moose-splunk-sh-instance-role"
+          },
+          "Action": "sts:AssumeRole"
+        }
+      ]
+    })
+
+  tags = merge(var.standard_tags, var.tags)
+}
+
+data "aws_iam_policy_document" "run_audit_report_policy_doc" {
+    statement {
+    sid       = ""
+    effect    = "Allow"
+    resources = ["*"]
+
+    actions = [
+      "acm-pca:CreateCertificateAuthorityAuditReport"
+    ]
+  }
+}
+
+resource "aws_iam_policy" "run_audit_report_policy" {
+  provider = aws.common # COMMON SERVICES
+  name        = "run_audit_report_policy"
+  path        = "/"
+  policy      = data.aws_iam_policy_document.run_audit_report_policy_doc.json
+}
+
+resource "aws_iam_role_policy_attachment" "run_audit_report_policy_attach" {
+  provider = aws.common # COMMON SERVICES
+  role       = aws_iam_role.run_audit_report_role.name
+  policy_arn = aws_iam_policy.run_audit_report_policy.arn
+}

+ 4 - 0
base/CA_Infrastructure/subordinate_CA/locals.tf

@@ -0,0 +1,4 @@
+locals {
+  # A list of people to receive the alert
+  recipients = toset([ "frederick.t.damstra@accenturefederal.com" ])
+}

+ 0 - 0
base/CA_Infrastructure/subordinate_CA/main.tf


+ 7 - 0
base/CA_Infrastructure/subordinate_CA/outputs.tf

@@ -0,0 +1,7 @@
+output root_authority_arn {
+  value = aws_acmpca_certificate_authority.subordinate.arn
+}
+
+output role_arn {
+  value = aws_iam_role.run_audit_report_role.arn
+}

+ 93 - 0
base/CA_Infrastructure/subordinate_CA/sns_alerts.tf

@@ -0,0 +1,93 @@
+resource "aws_cloudwatch_log_group" "SubordinateCACloudTrailAnalysis" {
+  provider = aws.common # COMMON SERVICES
+  name = "SubordinateCACloudTrailAnalysis"
+}
+
+resource "aws_iam_role" "subordinate_ca_cloudtrail_role" {
+  provider = aws.common # COMMON SERVICES
+  name = "subordinate_ca_cloudtrail_role"
+  assume_role_policy = <<EOF
+{
+    "Version": "2012-10-17",
+    "Statement": [
+      {
+        "Sid": "",
+        "Effect": "Allow",
+        "Principal": {
+          "Service": "cloudtrail.amazonaws.com"
+        },
+        "Action": "sts:AssumeRole"
+      }
+    ]
+}
+EOF
+}
+
+resource "aws_iam_role_policy" "allow_stream_policy" {
+  provider = aws.common # COMMON SERVICES
+  name = "allow_stream_change"
+  role = aws_iam_role.subordinate_ca_cloudtrail_role.id
+
+  policy = <<EOF
+{
+      "Version": "2012-10-17",
+      "Statement": [
+          {
+              "Effect": "Allow",
+              "Action": [
+                  "logs:CreateLogStream",
+                  "logs:PutLogEvents"
+              ],
+              "Resource": [
+                "${aws_cloudwatch_log_group.SubordinateCACloudTrailAnalysis.arn}"
+              ]
+          }
+      ]
+}
+EOF
+}
+
+resource "aws_sns_topic" "subordinate_ca_notification" {
+  provider = aws.common # COMMON SERVICES
+  name = "SubordinateCANotification"
+}
+
+resource "aws_sns_topic_subscription" "subordinate_ca_notification" {
+  provider = aws.common # COMMON SERVICES
+  for_each = local.recipients
+  topic_arn = aws_sns_topic.subordinate_ca_notification.arn
+  protocol  = "email"
+  endpoint  = each.value
+}
+
+
+#resource "aws_cloudwatch_log_metric_filter" "rootEvent" {
+#  name           = "Root_Account_Login"
+#  pattern        = <<EOF
+#{ ($.eventSource = "signin.amazonaws.com" ) && ( $.userIdentity.type = "Root" ) }
+#EOF
+#  log_group_name = "${aws_cloudwatch_log_group.SubordinateCACloudTrailAnalysis.name}"
+#
+#  metric_transformation {
+#    name      = "${var.thiseventname}"
+#    namespace = "${var.thisnamespace}"
+#    value     = "1"
+#  }
+#}
+
+data "aws_caller_identity" "current" {}
+data "aws_iam_account_alias" "current" {}
+
+#resource "aws_cloudwatch_metric_alarm" "rootAlarm" {
+#  alarm_name          = "Root_Account_Login"
+#  comparison_operator = "GreaterThanOrEqualToThreshold"
+#  evaluation_periods  = "1"
+#  metric_name         = "${var.thiseventname}"
+#  namespace           = "${var.thisnamespace}"
+#  period              = "300"
+#  statistic           = "Sum"
+#  threshold           = "1"
+
+#  alarm_description = "in the AWS account with id = ${data.aws_caller_identity.current.account_id} and alias = ${data.aws_iam_account_alias.current.account_alias} the root user logged in"
+#  alarm_actions     = ["${aws_sns_topic.subordinate_ca_notification.arn}"]
+#}

+ 12 - 0
base/CA_Infrastructure/subordinate_CA/vars.tf

@@ -0,0 +1,12 @@
+variable "c2_accounts" { type = map }
+variable "root_authority_arn" { type = string }
+
+variable "tags" { type = map }
+variable "standard_tags" { type = map }
+variable "environment" { type = string }
+variable "aws_region" { type = string }
+variable "aws_account_id" { type = string }
+variable "aws_partition" { type = string }
+variable "aws_partition_alias" { type = string }
+variable "common_services_account" { type = string }
+variable "instance_termination_protection" { type = bool }

+ 108 - 0
base/splunk_servers/searchhead/iam.tf

@@ -0,0 +1,108 @@
+# The moose splunk SH has additional permissions beyond the default instance
+resource "aws_iam_instance_profile" "moose_splunk_sh_instance_profile" {
+  count    = local.is_moose ? 1 : 0
+  name     = "moose-splunk-sh-instance-profile"
+  path     = "/instance/"
+  role     = aws_iam_role.moose_splunk_sh_instance_role[count.index].name
+}
+
+resource "aws_iam_role" "moose_splunk_sh_instance_role" {
+  count    = local.is_moose ? 1 : 0
+  name     = "moose-splunk-sh-instance-role"
+  path     = "/instance/"
+  assume_role_policy = jsonencode(
+  {   
+    "Version": "2012-10-17",
+    "Statement": [
+      {   
+        "Sid": "", 
+        "Effect": "Allow",
+        "Principal": {
+          "Service": [
+            "ec2.amazonaws.com"
+            ]
+        },
+        "Action": "sts:AssumeRole"
+      }
+    ]
+  })
+}
+
+data "aws_iam_policy_document" "moose_splunk_sh_policy_doc" {
+  count    = local.is_moose ? 1 : 0
+
+  # Moose splunk SH can assumerole into the C2 and mdr-prod-root-ca accounts to run the ACM audit report
+  statement {
+    sid    = "AllowAssumeRole"
+    effect = "Allow"
+
+    actions = [
+      "sts:AssumeRole"
+    ]
+
+    resources = [
+      "arn:${var.aws_partition}:iam::*:role/service/run_audit_report_role"
+    ]
+  }
+
+  # Moose splunk SH can grab the ACM audit reports
+  statement {
+    sid       = ""
+    effect    = "Allow"
+    resources = ["arn:${var.aws_partition}:s3:::xdr-ca-audit-reports"]
+
+    actions = [
+      "s3:ListBucket",
+      "s3:ListBucketVersions",
+    ]
+  }
+
+  statement {
+    sid       = ""
+    effect    = "Allow"
+    resources = ["arn:${var.aws_partition}:s3:::xdr-ca-audit-reports/*"]
+
+    actions = [
+      "s3:GetObject",
+      "s3:GetObjectVersion",
+    ]
+  }
+}
+
+resource "aws_iam_policy" "moose_splunk_sh_policy" {
+  count    = local.is_moose ? 1 : 0
+  name        = "moose_splunk_sh"
+  path        = "/"
+  policy      = data.aws_iam_policy_document.moose_splunk_sh_policy_doc[count.index].json
+}
+
+resource "aws_iam_role_policy_attachment" "moose_splunk_sh_attach" {
+  count    = local.is_moose ? 1 : 0
+  role       = aws_iam_role.moose_splunk_sh_instance_role[count.index].name
+  policy_arn = aws_iam_policy.moose_splunk_sh_policy[count.index].arn
+}
+
+resource "aws_iam_role_policy_attachment" "moose_splunk_sh_AmazonEC2RoleforSSM" {
+  count    = local.is_moose ? 1 : 0
+  role       = aws_iam_role.moose_splunk_sh_instance_role[count.index].name
+  policy_arn = "arn:${var.aws_partition}:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
+}
+
+resource "aws_iam_role_policy_attachment" "moose_splunk_sh_policy_attach_tag_read" {
+  count    = local.is_moose ? 1 : 0
+  role       = aws_iam_role.moose_splunk_sh_instance_role[count.index].name
+  policy_arn = "arn:${var.aws_partition}:iam::${var.aws_account_id}:policy/launchroles/default_instance_tag_read"
+}
+
+resource "aws_iam_role_policy_attachment" "moose_splunk_sh_policy_attach_cloudwatch" {
+  count    = local.is_moose ? 1 : 0
+  role       = aws_iam_role.moose_splunk_sh_instance_role[count.index].name
+  policy_arn = "arn:${var.aws_partition}:iam::${var.aws_account_id}:policy/cloudwatch_events"
+}
+
+#This policy needs to be create prior to creating the Salt Master
+resource "aws_iam_role_policy_attachment" "moose_splunk_sh_policy_attach_binaries" {
+  count    = local.is_moose ? 1 : 0
+  role       = aws_iam_role.moose_splunk_sh_instance_role[count.index].name
+  policy_arn = "arn:${var.aws_partition}:iam::${var.aws_account_id}:policy/launchroles/default_instance_s3_binaries"
+}

+ 3 - 1
base/splunk_servers/searchhead/main.tf

@@ -36,7 +36,7 @@ resource "aws_instance" "instance" {
   instance_type = var.instance_type
   key_name = "msoc-build"
   monitoring = false
-  iam_instance_profile = "msoc-default-instance-profile"
+  iam_instance_profile = local.is_moose ? "moose-splunk-sh-instance-profile" : "msoc-default-instance-profile"
 
   ami = local.ami_map[local.ami_selection]
   # We need to ignore ebs_block_device changes, because if the AMI changes, so does the snapshot_id.
@@ -141,6 +141,8 @@ resource "aws_instance" "instance" {
   user_data = data.template_cloudinit_config.cloud-init.rendered
   tags = merge( var.standard_tags, var.tags, { Name = local.instance_name })
   volume_tags = merge( var.standard_tags, var.tags, { Name = local.instance_name })
+
+  depends_on = [ aws_iam_instance_profile.moose_splunk_sh_instance_profile ]
 }
 
 module "private_dns_record" {

+ 1 - 0
base/splunk_servers/searchhead/vars.tf

@@ -69,5 +69,6 @@ variable "environment" { type = string }
 variable "aws_region" { type = string }
 variable "aws_partition" { type = string }
 variable "aws_partition_alias" { type = string }
+variable "aws_account_id" { type = string }
 variable "common_services_account" { type = string }
 variable "instance_termination_protection" { type = bool }