Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Justin Kufro committed Jun 18, 2021
0 parents commit 90e1aee
Show file tree
Hide file tree
Showing 14 changed files with 742 additions and 0 deletions.
9 changes: 9 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Licensed under the Apache-2.0 license.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright/ digital rights legend, this list of conditions and the following Notice.

- Redistributions in binary form must reproduce the above copyright copyright/ digital rights legend, this list of conditions and the following Notice in the documentation and/or other materials provided with the distribution.

- Neither the name of The MITRE Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Serverless Heimdall Pusher (AWS)



### NOTICE

© 2019-2021 The MITRE Corporation.

Approved for Public Release; Distribution Unlimited. Case Number 18-3678.

### NOTICE

MITRE hereby grants express written permission to use, reproduce, distribute, modify, and otherwise leverage this software to the extent permitted by the licensed terms provided in the LICENSE.md file included with this project.

### NOTICE

This software was produced for the U. S. Government under Contract Number HHSM-500-2012-00008I, and is subject to Federal Acquisition Regulation Clause 52.227-14, Rights in Data-General.

No other use other than that granted to the U. S. Government, or to those acting on behalf of the U. S. Government under that Clause is authorized without the express written permission of The MITRE Corporation.
6 changes: 6 additions & 0 deletions build-image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
VERSION=$(cat './version')

docker build -t mitre/serverless-heimdall-pusher-lambda:$VERSION ./src/
docker tag mitre/serverless-heimdall-pusher-lambda:$VERSION mitre/serverless-heimdall-pusher-lambda:latest

# docker save mitre/serverless-heimdall-pusher-lambda:$VERSION > serverless-heimdall-pusher-lambda.tar
236 changes: 236 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@

##
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region
#
data "aws_region" "current" {}

##
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity
#
data "aws_caller_identity" "current" {}

##
# Computed local variables
#
locals {
# If image_version is not set, then default to the lastest available version
image_version = var.image_version != null ? var.image_version : file("${path.module}/version")
}

# Elastic Container Registry for SAF deployment
#
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository
#
resource "aws_ecr_repository" "mitre_heimdall_pusher" {
name = "mitre/serverless-heimdall-pusher-lambda"
image_tag_mutability = "MUTABLE"

image_scanning_configuration {
scan_on_push = true
}
}

##
# The KMS key used to encrypt/decrypt HeimdallPusher's Heimdall account password
#
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key
#
resource "aws_kms_key" "HeimdallPassKmsKey" {
description = "The KMS key used to encrypt/decrypt HeimdallPusher's Heimdall account password "
deletion_window_in_days = 10

tags = {
Name = "HeimdallPusherPassKmsKey"
}
}

##
# SSM SecureString parameter for the Heimdall password
#
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter
#
resource "aws_ssm_parameter" "heimdall_pass_ssm_param" {
name = "/serverless-heimdall-pusher-lambda/heimdall_pass_ssm_param"
description = "Stores the password for HeimdallPusher's Heimdall account."
type = "SecureString"
value = var.heimdall_password
key_id = aws_kms_key.HeimdallPassKmsKey.key_id
}

##
# HeimdallPusher Role to Invoke HeimdallPusher Lambda function
#
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role
#
resource "aws_iam_role" "serverless_heimdall_pusher_lambda_role" {
name = "serverless_heimdall_pusher_lambda_role"

# Allow execution of the lambda function
managed_policy_arns = [
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
]

# Allow assume role permission for lambda
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "lambda.amazonaws.com"
}
}
]
})

# Allow READ access to Heimdall password SSM parameter
inline_policy {
name = "HeimdallPassSsmReadAccess"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"ssm:GetParameter"
]
Effect = "Allow"
Resource = aws_ssm_parameter.heimdall_pass_ssm_param.arn
}
]
})
}

inline_policy {
name = "AllowHeimdallPassKmsKeyDecrypt"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"kms:Decrypt"
]
Effect = "Allow"
Resource = aws_kms_key.HeimdallPassKmsKey.arn
}
]
})
}

# Allow S3 read and write access to InSpec results bucket
inline_policy {
name = "S3ResultsAccess"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
]
Effect = "Allow"
Resource = "${data.aws_s3_bucket.results_bucket.arn}/*"
}
]
})
}
}

resource "null_resource" "push_image" {
depends_on = [
aws_ecr_repository.mitre_heimdall_pusher,
]

# Ensures this script always runs
triggers = {
always_run = timestamp()
}

# https://www.terraform.io/docs/language/resources/provisioners/local-exec.html
provisioner "local-exec" {
command = "${path.module}/push-image.sh"

environment = {
REPOSITORY_URL = aws_ecr_repository.mitre_heimdall_pusher.repository_url
AWS_REGION = data.aws_region.current.name
AWS_ACCOUNT_ID = data.aws_caller_identity.current.account_id
REPO_NAME = "mitre/serverless-heimdall-pusher-lambda"
IMAGE_TAG = local.image_version
}
}
}

##
# HeimdallPusher Lambda function
#
# https://registry.terraform.io/modules/terraform-aws-modules/lambda/aws/latest
#
module "serverless-heimdall-pusher-lambda" {
source = "terraform-aws-modules/lambda/aws"

function_name = var.lambda_name
description = "Lambda capable of pulling AWS Config data, mapping to HDF, and pushing results to Heimdall Server API."
handler = "lambda_function.lambda_handler"
runtime = "ruby2.7"
create_role = false
lambda_role = aws_iam_role.serverless_heimdall_pusher_lambda_role.arn
timeout = 900

vpc_subnet_ids = var.subnet_ids
vpc_security_group_ids = var.security_groups

create_package = false
image_uri = "${aws_ecr_repository.mitre_heimdall_pusher.repository_url}:${local.image_version}"
package_type = "Image"

environment_variables = {
HEIMDALL_URL = var.heimdall_url
HEIMDALL_API_USER = var.heimdall_user
HEIMDALL_PASS_SSM_PARAM = aws_ssm_parameter.heimdall_pass_ssm_param.name
}
}

##
# Get bucket data for use elsewhere
#
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_bucket
#
data "aws_s3_bucket" "results_bucket" {
bucket = var.results_bucket_id
}

##
# Allow the bucket events to trigger the pusher lambda
#
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission
#
resource "aws_lambda_permission" "allow_bucket" {
statement_id = "AllowHeimdallPusherExecutionFromS3Bucket"
action = "lambda:InvokeFunction"
function_name = module.HeimdallPusher.lambda_function_arn
principal = "s3.amazonaws.com"
source_arn = data.aws_s3_bucket.results_bucket.arn
}

##
# Trigger lambda when objects get placed in 'unprocessed/*'
#
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_notification
#
resource "aws_s3_bucket_notification" "bucket_notification" {
bucket = var.results_bucket_id

lambda_function {
lambda_function_arn = module.HeimdallPusher.lambda_function_arn
events = ["s3:ObjectCreated:*"]
filter_prefix = "unprocessed/"
}

depends_on = [aws_lambda_permission.allow_bucket]
}
8 changes: 8 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

output "function_name" {
value = module.serverless-heimdall-pusher-lambda.lambda_function_name
}

output "function_arn" {
value = module.serverless-heimdall-pusher-lambda.lambda_function_arn
}
68 changes: 68 additions & 0 deletions push-image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
set -xe

##
# ENV validation
#
if [ -z "$REPOSITORY_URL" ]; then
echo '$REPOSITORY_URL is a required ENV variable!'
exit 1
fi

if [ -z "$AWS_REGION" ]; then
echo '$AWS_REGION is a required ENV variable!'
exit 1
fi

if [ -z "$AWS_ACCOUNT_ID" ]; then
echo '$AWS_ACCOUNT_ID is a required ENV variable!'
exit 1
fi

if [ -z "$REPO_NAME" ]; then
echo '$REPO_NAME is a required ENV variable!'
exit 1
fi

if [ -z "$IMAGE_TAG" ]; then
echo '$IMAGE_TAG is a required ENV variable!'
exit 1
fi

echo "REPOSITORY_URL='$REPOSITORY_URL' AWS_REGION='$AWS_REGION' AWS_ACCOUNT_ID='$AWS_ACCOUNT_ID' REPO_NAME='$REPO_NAME' IMAGE_TAG='$IMAGE_TAG'"

##
# Variable creation
#
IMAGE_IDENTIFIER="$REPO_NAME:$IMAGE_TAG"
IMAGE="$REPOSITORY_URL:$IMAGE_TAG"
echo $IMAGE_IDENTIFIER
echo $IMAGE

##
# Log in to the AWS ECR registry
#
# https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html
#
aws ecr get-login-password \
--region $AWS_REGION \
| docker login \
--username AWS \
--password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com

##
# Re-tag the image to the identifier that will be pushed up to ECR
docker tag $IMAGE_IDENTIFIER $IMAGE

##
# Check the SHA of the local and remote images. Don't push if they are the same
#
LOCAL_SHA=$(docker images --no-trunc --quiet $IMAGE_IDENTIFIER | grep -oh 'sha256:[0-9,a-z]*')
REMOTE_SHA=$(aws ecr describe-images --repository-name $REPO_NAME --image-ids imageTag=$IMAGE_TAG --query 'imageDetails[0].imageDigest'| grep -oh 'sha256:[0-9,a-z]*' || echo 'image doesnt exist')
echo "LOCAL SHA: $LOCAL_SHA"
echo "REMOTE SHA: $REMOTE_SHA"
if [ "$LOCAL_SHA" != "$REMOTE_SHA" ]; then
docker push $IMAGE
sleep 60
else
echo 'LOCAL AND REMOTE SHA values are identical. Skipping docker push.'
fi
1 change: 1 addition & 0 deletions src/.ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.7.2
40 changes: 40 additions & 0 deletions src/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
##
# Interact with the base image:
# docker run --rm -it --entrypoint bash public.ecr.aws/lambda/ruby:2.7
#
##
# Interact with built container:
# docker run --rm -it --entrypoint bash mitre/serverless-heimdall-pusher-lambda:latest
#
#
##
# Make requests to local container: (https://docs.aws.amazon.com/lambda/latest/dg/images-test.html)
# docker run -p 9000:8080 mitre/serverless-heimdall-pusher-lambda:latest
# curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
#
##
#
# Build the image
# docker build -t mitre/serverless-heimdall-pusher-lambda:latest .
# OR
# cd terraform/modules/inspec-lambda/; ./build-image.sh

##
# Use Ruby from AWS lambda ECR
#
# https://gallery.ecr.aws/lambda/ruby
#
FROM public.ecr.aws/lambda/ruby:2.7

##
# Copy over the function code and bundle install
#
COPY lambda_function.rb Gemfile Gemfile.lock .ruby-version /var/task/
RUN bundle install --path vendor/bundle/

##
# Set the handler
#
# https://docs.aws.amazon.com/lambda/latest/dg/images-create.html
#
CMD [ "lambda_function.lambda_handler" ]
Loading

0 comments on commit 90e1aee

Please sign in to comment.