Remediating Noncompliant AWS Resources using AWS Native Tools

T. Devon Artis
4 min readJul 5, 2019

In this post I have added fictitious scenario where I will define the problem and develop the simple solution that outlines an automated workflow that utilizes the tools that I wrote about in my first post How To Validate Internal Security Compliance With AWS Native Tools.

Here is the scenario, a company called WantToBeAgile, Inc has started their migration to AWS Public Cloud. The Security Compliance team has mandated that all resources in AWS be tagged. If a resource is not tagged a Jira Issue should be created and assigned to the SOC team.

The Cloud Operations team has already enabled AWS Config in all accounts as their Cloud Asset and Resource management tool. The organization has requested that the Cloud Security Engineers implement a solution that will be used as the automated baseline.

AWS Config

In Jira, create an API token and make sure that you copy the key, as this key will be used in the next step.

AWS System Manager Parameter Store provides secure hierarchical storage for configuration data management and secrets management. You can store data such as passwords, database strings, and license codes as parameter values. I will be using it to store the API key.

Store your Jira Token in AWS SSM Parameter Store

# Store your Jira Token in Paramter Store resource "aws_ssm_parameter" "paramtoken" {
name = "jiraToken"
description = "Jira Token used in the AWS Config Create Jira Issue"
value = var.jiraToken
type = "SecureString"
}

Create IAM Role that will be used for the Lambda Function

# IAM Role For Lambda Functions
resource "aws_iam_role" "iam_for_lambda" {
name = "iam_for_lambda"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

Create the lambda function that will be used for SSM Document

# Archive the python code for that will be used for the lambda function
data "archive_file" "lambda_zip" {
type = "zip"
source_file = "../index.py"
output_path = "lambda_function.zip"
}
# Create your lambda function
resource "aws_lambda_function" "ssm_lambda" {
filename = "lambda_function.zip"
function_name = var.lambda_name
role = "${aws_iam_role.iam_for_lambda.arn}"
handler = "index.handler"
source_code_hash = "${data.archive_file.lambda_zip.output_base64sha256}"
runtime = "python2.7"
depends_on = [
"aws_iam_role_policy_attachment.lambda_ssm",
"aws_iam_role_policy_attachment.lambda_logs",
"aws_cloudwatch_log_group.createJiraIssuelogs"
]
}
resource "aws_cloudwatch_log_group" "createJiraIssuelogs" {
name = "/aws/lambda/${var.lambda_name}"
retention_in_days = 14
}
resource "aws_iam_policy" "policy_logging" {
name = "lambda_logging"
path = "/"
description = "IAM policy for logging from a lambda"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*",
"Effect": "Allow"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "lambda_logs" {
role = "${aws_iam_role.iam_for_lambda.name}"
policy_arn = "${aws_iam_policy.policy_logging.arn}"
}
resource "aws_iam_policy" "policy_ssm" {
name = "lambda_readssm"
path = "/"
description = "IAM policy for SSM Paramater Store for a lambda"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{

"Effect": "Allow",
"Action": "ssm:*",
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "lambda_ssm" {
role = "${aws_iam_role.iam_for_lambda.name}"
policy_arn = "${aws_iam_policy.policy_ssm.arn}"
}

Create the SSM Document that you will use with AWS Config

# Create SSM Document that will be used in AWS Config
resource "aws_ssm_document" "jiraDocument" {
content = <<EOF
{
"description": "Creates a Jira issue.",
"schemaVersion": "0.3",
"assumeRole": "{{ AutomationAssumeRole }}",
"parameters": {
"JiraUsername": {
"type": "String",
"description": "(Required) The name of the user the issue will be created with."
},
"SSMParameterName": {
"type": "String",
"description": "(Required) The name of an encrypted SSM Parameter containing the API key or password for the Jira user."
},
"JiraURL": {
"type": "String",
"description": "(Required) The url of the Jira instance."
},
"ProjectKey": {
"type": "String",
"description": "(Required) The key of the project the issue should be created in."
},
"IssueSummary": {
"type": "String",
"description": "(Required) A brief summary of the issue."
},
"IssueDescription": {
"type": "String",
"description": "(Required) A detailed description of the issue."
},
"IssueTypeName": {
"type": "String",
"description": "(Required) The name of the type of issue you want to create (ex. Task, Sub-task, Bug, etc)."
},
"PriorityName": {
"type": "String",
"description": "(Optional) The name of the priority of the issue.",
"default": ""
},
"AssigneeName": {
"type": "String",
"description": "(Optional) The username of the person the issue should be assigned to.",
"default": ""
},
"DueDate": {
"type": "String",
"description": "(Optional) The due date for the issue in yyyy-mm-dd format.",
"default": ""
},
"CreatedBy": {
"type": "String",
"description": "(Optional) The due date for the issue in yyyy-mm-dd format.",
"default": ""
},
"LambdaAssumeRole": {
"type": "String",
"description": "(Optional) The ARN of the role that allows Lambda created by Automation to perform the actions on your behalf. If not specified a transient role will be created to execute the Lambda function.",
"default": ""
},
"AutomationAssumeRole": {
"type": "String",
"description": "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf. ",
"default": ""
}
},
"mainSteps": [
{
"name": "createJiraIssue",
"action": "aws:invokeLambdaFunction",
"inputs": {
"FunctionName": "createComplainceJiraIssue",
"Payload": "{\"JiraUsername\": \"{{JiraUsername}}\", \"SSMParameterName\": \"{{SSMParameterName}}\", \"JiraURL\": \"{{JiraURL}}\", \"ProjectKey\": \"{{ProjectKey}}\", \"IssueSummary\": \"{{IssueSummary}}\", \"IssueDescription\": \"{{IssueDescription}}\", \"IssueTypeName\": \"{{IssueTypeName}}\", \"PriorityName\": \"{{PriorityName}}\", \"AssigneeName\": \"{{AssigneeName}}\", \"DueDate\": \"{{DueDate}}\"}"
}
}
],
"outputs": [
"createJiraIssue.Payload"
]
}
EOF
document_type = "Automation"
name = "Security-ComplainceWorkflowDemo"
document_format = "JSON"
}

Now that automation system has been built the last thing we have to do is choose the SSM document that we created in the code above.

Setting Up AWS Config

  1. Sign in to the AWS Management Console and open the AWS Config console at https://console.aws.amazon.com/config/.
  2. Choose Rules on the left, then on the Rules page in the search field, type in “required-tags”
  3. On the Edit name of the rule page, in the Choose remediation action section, select Security-ComplainceWorkflowDemo. Fill out the the required fields.
  4. Choose Save.

Now when a “required-tag” resource violation has occurred the “Security-ComplainceWorkflowDemo.” remediation action will be executed.

--

--

T. Devon Artis

Southwest Florida Realtor — Digital Marketing Consultant