Monday, July 19, 2021

AWS Security Hub Auto Remediation

 AWS Security Hub Auto Remediation

In this guide, we configure Security Hub account to be able to take action on any other accounts in the Organization. This is all triggered from CloudWatch Event Pattern. The result looks like this.




Cloudwatch Event Pattern

Here's an example of the CW Event Pattern. 

resource "aws_cloudwatch_event_rule" "example" {
  name        = "Example"
  description = "Example"

  event_pattern = <<EOF
{
    "source" : [
      "aws.securityhub"
    ],
    "detail-type" : [
      "Security Hub Findings - Imported"
    ],
    "detail" : {
      "findings" : {
         "GeneratorId":["arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0/rule/4.3"],
         "Compliance":{
            "Status":["FAILED"]
        }
      }
    }
  }
EOF
}

Cloudwatch Event Targets

SNS

Pass in a Topic arn and enable this target. 

resource "aws_cloudwatch_event_target" "cloudwatch_event_target_sns" {
  count = local.sns_arn == null ? 0:1
  ## [\.\-_A-Za-z0-9]+, 64 characters max
  rule = aws_cloudwatch_event_rule.cloudwatch_event_rule.name
  ## some unique assignment ID, random will be assigned since not provided
  ## target_id
  ## This is the ARN of the target regardless of the type
  arn = local.sns_arn
}

Be sure the SNS topic permission include this 

{
 "Sid": "allow_from_events",
 "Effect": "Allow",
 "Principal": {
   "Service": "events.amazonaws.com"
 },
 "Action": "SNS:Publish",
 "Resource": "arn:aws:sns:us-east-1:99999999999:security-hub-topic"
}

Lambda

Point to Lambda Function arn and enable this target.

resource "aws_cloudwatch_event_target" "cloudwatch_event_target_lambda" {
  count = local.lambda_arn == null ? 0:1
  ## [\.\-_A-Za-z0-9]+, 64 characters max
  rule = aws_cloudwatch_event_rule.cloudwatch_event_rule.name
  ## some unique assignment ID, random will be assigned since not provided
  ## target_id
  ## This is the ARN of the target regardless of the type
  arn = local.lambda_arn
}

Lambda Function

Create the lambda function here

resource "aws_lambda_function" "default" {
  ## ([a-zA-Z0-9-_]+)
  function_name    = local.rule_name
  filename         = local.lambda_zip_file
  role             = local.lambda_role_arn
  source_code_hash = local.lambda_hash

  description = "blah" 
  handler     = "lambda_function.lambda_handler" 
  runtime     = "python3.8"
  timeout     = 60
  memory_size = 128
}

Lambda Role

Permission Policy

data "aws_iam_policy_document" "lambda_role_basic" {
  ## Create log group
  statement {
    sid       = "SidLogGroup"
    actions   = ["logs:CreateLogGroup"]
    resources = ["arn:aws:logs:*:${local.self_account_id}:*"]
  }

  ## Create log stream
  statement {
    sid = "SidStream"
    actions = [
      "logs:PutLogEvents",
      "logs:CreateLogStream"
    ]
    resources = ["arn:aws:logs:*:${local.self_account_id}:log-group:/aws/lambda/${var.rule_name_prefix}*:*"]
  }

  ## Allow this role to assume target roles in other accounts
  statement {
    sid       = "SidAssumeAccountRoles"
    actions   = ["sts:AssumeRole"]
    resources = ["arn:aws:iam::*:role/${var.target_role_name}"]
  }
}

resource "aws_iam_policy" "lambda_role_basic" {
  name   = "${var.target_role_name}-policy"
  policy = data.aws_iam_policy_document.lambda_role_basic.json
}

Assume Role Policy

data "aws_iam_policy_document" "lambda_role_assume_policy" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }
  }
}

Role

resource "aws_iam_role" "lambda_role" {
  ## Create a new role and start with Assume Role Policy to let it be used by Lambda
  ## This is the role that is added to Lambda above
  name               = var.lambda_role_name
  assume_role_policy = data.aws_iam_policy_document.lambda_role_assume_policy.json
}

resource "aws_iam_role_policy_attachment" "lambda_role_basic" {
  ## Attach the permission policy defined above
  role       = aws_iam_role.lambda_role.name
  policy_arn = aws_iam_policy.lambda_role_basic.arn
}

Target Account's Role

Assume Role Policy

data "aws_iam_policy_document" "security_hub_assume_role_policy" {
  ## Allow the role from Main Account to assume this role
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${local.sechub_account_id}:role/${local.security_hub_lambda_role_name}"]
    }
  }
}

Role

resource "aws_iam_role" "security_hub_role" {
  ## Create a new role, start with Assume Role Policy
  name               = local.security_hub_role_name
  assume_role_policy = data.aws_iam_policy_document.security_hub_assume_role_policy.json
}

Permission Policies

  • Give SecHub account permission to take action inside this account when something triggers in SecHub
  • This role needs to be assumable from SecHub account
  • This role needs to do whatever we need to do to remediate any SecHub findings
  • Can only have up to 20 attached policies to a role (10 is default, 20 is when upped the limit to max), so be wise how you split this
  • Each policy can only be up to 5000 characters (1500 is default, 5000 is when upped the limit to max), so be wise how you word your policy
  • The roles names of assumed and assumer needs to match exactly

ReadOnly Policy

resource "aws_iam_role_policy_attachment" "security_hub_read_policy" {
  ## Use built-in policy for this
  role       = aws_iam_role.security_hub_role.id
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

Ability to Update Security Hub Finding Policy

data "aws_iam_policy_document" "security_hub_edit_sechub_policy_doc" {
  statement {
    actions = [
      "securityhub:CreateActionTarget",
      "securityhub:UpdateFindings",
      "securityhub:BatchDisableStandards",
    ]
    resources = ["arn:aws:securityhub:*:${local.account_id}:hub/default"]
  }
}

resource "aws_iam_policy" "security_hub_edit_sechub_policy" {
  name   = "Security-hub-edit-sechub-policy"
  path   = "/"
  policy = data.aws_iam_policy_document.security_hub_edit_sechub_policy_doc.json
}

resource "aws_iam_role_policy_attachment" "security_hub_edit_sechub_policy_attach" {
  role       = aws_iam_role.security_hub_role.id
  policy_arn = aws_iam_policy.security_hub_edit_sechub_policy.arn
}

Ability to Edit IAM Policy

data "aws_iam_policy_document" "security_hub_edit_IAM_policy_doc" {
  statement {
    actions = [
      "IAM:DeleteAccessKey",
      "IAM:Detach*",
      "IAM:DeleteUserPolicy"
    ]
    resources = ["*"]
  }
}

resource "aws_iam_policy" "security_hub_edit_IAM_policy" {
  name   = "Security-hub-edit-IAM-policy"
  path   = "/"
  policy = data.aws_iam_policy_document.security_hub_edit_IAM_policy_doc.json
}

resource "aws_iam_role_policy_attachment" "security_hub_edit_IAM_policy_attach" {
  role       = aws_iam_role.security_hub_role.id
  policy_arn = aws_iam_policy.security_hub_edit_IAM_policy.arn
}





















No comments:

Post a Comment

AWS WAF log4j query

How to query AWS WAF log for log4j attacks 1. Setup your Athena table using this instruction https://docs.aws.amazon.com/athena/latest/ug/wa...