diff --git a/main.tf b/main.tf index 2c8028b..2a056ef 100644 --- a/main.tf +++ b/main.tf @@ -38,12 +38,28 @@ resource "aws_ecr_repository" "mitre_heimdall_pusher" { resource "aws_kms_key" "HeimdallPassKmsKey" { description = "The KMS key used to encrypt/decrypt HeimdallPusher's Heimdall account password " deletion_window_in_days = 10 + enable_key_rotation = true tags = { Name = "HeimdallPusherPassKmsKey" } } +## +# KMS key for encrypting lambda log data +# +# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key +# +resource "aws_kms_key" "ServerlessHeimdallPusherLogsKmsKey" { + description = "The KMS key used to encrypt ConfigToHdf's logs" + deletion_window_in_days = 10 + enable_key_rotation = true + + tags = { + Name = "ServerlessHeimdallPusherLogsKmsKey" + } +} + ## # SSM SecureString parameter for the Heimdall password # @@ -58,7 +74,51 @@ resource "aws_ssm_parameter" "heimdall_pass_ssm_param" { } ## -# HeimdallPusher Role to Invoke HeimdallPusher Lambda function +# HeimdallPusher IAM Policy to Invoke HeimdallPusher Lambda function +# +# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy +# +resource "aws_iam_policy" "serverless_heimdall_pusher_lambda_policy" { + name = "ServerlessHeimdallPusherLambdaPolicy" + path = "/" + description = "Policy that provides proper lambda permissions for the serverless_heimdall_pusher_lambda_role" + + # Permissions + # - ssm:GetParameter => allows decryption of Heimdall Password + # - kms:Decrypt => allows decryption of Heimdall Password + # - s3:GetObject,PutObject,DeleteObject => Allow interaction with results S3 bucket + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "ssm:GetParameter" + ] + Effect = "Allow" + Resource = aws_ssm_parameter.heimdall_pass_ssm_param.arn + }, + { + Action = [ + "kms:Decrypt" + ] + Effect = "Allow" + Resource = aws_kms_key.HeimdallPassKmsKey.arn + }, + { + Action = [ + "s3:GetObject", + "s3:PutObject", + "s3:DeleteObject" + ] + Effect = "Allow" + Resource = "${data.aws_s3_bucket.results_bucket.arn}/*" + } + ] + }) +} + +## +# HeimdallPusher Role to Invoke HeimdallPusher Lambda function # # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role # @@ -68,7 +128,8 @@ resource "aws_iam_role" "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" + "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole", + aws_iam_policy.serverless_heimdall_pusher_lambda_policy.arn ] # Allow assume role permission for lambda @@ -85,61 +146,6 @@ resource "aws_iam_role" "serverless_heimdall_pusher_lambda_role" { } ] }) - - # 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" { @@ -189,10 +195,14 @@ module "serverless-heimdall-pusher-lambda" { image_uri = "${aws_ecr_repository.mitre_heimdall_pusher.repository_url}:${local.image_version}" package_type = "Image" + cloudwatch_logs_kms_key_id = aws_kms_key.ServerlessHeimdallPusherLogsKmsKey.key_id + cloudwatch_logs_retention_in_days = 30 + 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 + HEIMDALL_PUBLIC = var.heimdall_public } } @@ -211,11 +221,12 @@ data "aws_s3_bucket" "results_bucket" { # 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.serverless-heimdall-pusher-lambda.lambda_function_arn - principal = "s3.amazonaws.com" - source_arn = data.aws_s3_bucket.results_bucket.arn + statement_id = "AllowHeimdallPusherExecutionFromS3Bucket" + action = "lambda:InvokeFunction" + function_name = module.serverless-heimdall-pusher-lambda.lambda_function_arn + principal = "s3.amazonaws.com" + source_arn = data.aws_s3_bucket.results_bucket.arn + source_account = var.results_bucket_source_account_id != null ? var.results_bucket_source_account_id : data.aws_caller_identity.current.account_id } ## diff --git a/src/lambda_function.rb b/src/lambda_function.rb index baeccd6..219c77b 100644 --- a/src/lambda_function.rb +++ b/src/lambda_function.rb @@ -66,7 +66,7 @@ def process_record(_event, bucket_name, object_key) # Save to Heimdall heimdall_user_password = heimdall_password user_id, token = get_heimdall_api_token(heimdall_user_password) - push_to_heimdall(filename, hdf, user_id, token, record_contents['eval_tags']) + push_to_heimdall(filename, hdf, user_id, token, record_contents['eval_tags'], record_contents['groups']) # Save to S3 save_results_to_bucket(record_contents, bucket_name, filename) @@ -203,7 +203,7 @@ def get_heimdall_api_token(heimdall_user_password) # -H "Authorization: Bearer " \ # "http://my-heimdall/evaluations" # -def push_to_heimdall(filename, hdf, user_id, token, eval_tags) +def push_to_heimdall(filename, hdf, user_id, token, eval_tags, groups) $logger.info('Pushing HDF results to Heimdall Server...') url = URI("#{ENV['HEIMDALL_URL']}/evaluations") payload = { @@ -213,6 +213,8 @@ def push_to_heimdall(filename, hdf, user_id, token, eval_tags) public: ENV['HEIMDALL_PUBLIC'] || 'true', evaluationTags: eval_tags } + # Groups are broken out separately because groups may be nil/omitted + payload['groups'] = groups if groups request = Net::HTTP::Post::Multipart.new(url.path, payload) request['Authorization'] = "Bearer #{token}" response = Net::HTTP.start(url.host, url.port) do |http| diff --git a/variables.tf b/variables.tf index ef906fc..67b4e11 100644 --- a/variables.tf +++ b/variables.tf @@ -1,4 +1,10 @@ +variable "heimdall_public" { + description = "Set this to 'true' if results should be visible by anyone in Heimdall" + type = string + default = "false" +} + variable "heimdall_url" { description = "The url to the Heimdall server in http://... format" type = string @@ -20,6 +26,12 @@ variable "results_bucket_id" { type = string } +variable "results_bucket_source_account_id" { + description = "The AWS account ID (without a hyphen) of the results S3 bucket source owner." + type = string + default = null +} + variable "subnet_ids" { description = "The subnet ids to deploy the lambda to." type = list(string) @@ -41,5 +53,5 @@ variable "image_version" { variable "lambda_name" { description = "The name of the lambda function" type = string - default = "serverless-inspec-lambda" + default = "ServerlessHeimdallPusher" } diff --git a/version b/version index 6da28dd..341cf11 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.1.1 \ No newline at end of file +0.2.0 \ No newline at end of file