Skip to content

Commit

Permalink
DSOS-2124: allow placeholder ssm parameters (#184)
Browse files Browse the repository at this point in the history
* added most SSM parameter options

* typo

* fix

* fix

* remove file option

* fix

* fix

* fix

* allow PutParameter if placeholder params

* update policy

* fix

* fix checkov error

* checkov
  • Loading branch information
drobinson-moj authored Sep 7, 2023
1 parent 630ef66 commit 474387e
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 45 deletions.
23 changes: 22 additions & 1 deletion locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ locals {
}
tags = merge(local.default_tags, local.ssm_parameters_prefix_tag, var.tags)

ssm_random_passwords = {
for key, value in var.ssm_parameters != null ? var.ssm_parameters : {} :
key => value.random if value.random != null
}
ssm_parameters_value = {
for key, value in var.ssm_parameters != null ? var.ssm_parameters : {} :
key => value if value.value != null
}
ssm_parameters_random = {
for key, value in var.ssm_parameters != null ? var.ssm_parameters : {} :
key => merge(value, {
value = random_password.this[key].result
}) if value.value == null && value.random != null
}
ssm_parameters_default = {
for key, value in var.ssm_parameters != null ? var.ssm_parameters : {} :
key => merge(value, {
value = "placeholder, overwrite me outside of terraform"
}) if value.value == null && value.random == null
}

ami_block_device_mappings = {
for bdm in data.aws_ami.this.block_device_mappings : bdm.device_name => bdm
}
Expand Down Expand Up @@ -92,7 +113,7 @@ locals {

user_data_args_ssm_params = {
for key, value in var.ssm_parameters != null ? var.ssm_parameters : {} :
"ssm_parameter_${key}" => aws_ssm_parameter.this[key].name
"ssm_parameter_${key}" => try(aws_ssm_parameter.this[key].name, aws_ssm_parameter.placeholder[key].name)
}

user_data_args_common = {
Expand Down
90 changes: 51 additions & 39 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -178,62 +178,74 @@ resource "aws_route53_record" "external" {
}

#------------------------------------------------------------------------------
# ASM Passwords
# SSM Parameters
#------------------------------------------------------------------------------

resource "random_password" "this" {
for_each = var.ssm_parameters != null ? var.ssm_parameters : {}
for_each = local.ssm_random_passwords

length = each.value.random.length
special = lookup(each.value.random, "special", null)
length = each.value.length
special = each.value.special
}

# SSM parameters with values managed by terraform
resource "aws_ssm_parameter" "this" {
#checkov:skip=CKV_AWS_337: Ensure SSM parameters are using KMS CMK
# An AWS managed key is used at the moment.
# Fix ticket https://dsdmoj.atlassian.net/browse/DSOS-2011
#checkov:skip=CKV2_AWS_34: AWS SSM Parameter should be Encrypted. SecureString is the default but can be changed by user if needed

for_each = var.ssm_parameters != null ? var.ssm_parameters : {}
for_each = merge(
local.ssm_parameters_value,
local.ssm_parameters_random,
)

name = "/${var.ssm_parameters_prefix}${var.name}/${each.key}"
description = each.value.description
type = "SecureString"
value = random_password.this[each.key].result
type = each.value.type
key_id = each.value.kms_key_id
value = each.value.value

tags = merge(
local.tags,
{
Name = "${var.name}-${each.key}"
}
)
tags = merge(local.tags, {
Name = "${var.name}-${each.key}"
})
}

#------------------------------------------------------------------------------
# Instance IAM role extra permissions
# Temporarily allow get parameter when instance first created
# Attach policy inline on ec2-common-role
#------------------------------------------------------------------------------
# Placeholder SSM parameters with values set elsewhere
resource "aws_ssm_parameter" "placeholder" {
#checkov:skip=CKV2_AWS_34: AWS SSM Parameter should be Encrypted. SecureString is the default but can be changed by user if needed

for_each = local.ssm_parameters_default

resource "time_offset" "asm_parameter" {
# static time resource for controlling access to parameter
offset_minutes = 30
triggers = {
# if the instance is recycled we reset the timestamp to give access again
instance_id = aws_instance.this.arn
name = "/${var.ssm_parameters_prefix}${var.name}/${each.key}"
description = each.value.description
type = each.value.type
key_id = each.value.kms_key_id
value = each.value.value

tags = merge(local.tags, {
Name = "${var.name}-${each.key}"
})

lifecycle {
ignore_changes = [value]
}
}

data "aws_iam_policy_document" "asm_parameter" {
#------------------------------------------------------------------------------
# Instance IAM role extra permissions
# Allow GetParameter to the EC2 scoped SSM parameter path
# Allow PutParameter to the EC2 scoped SSM parameter path if there are
# placeholder SSM parameters (e.g. parameters generated elsewhere in the
# provisioning process such as ansible)
#------------------------------------------------------------------------------

data "aws_iam_policy_document" "ssm_parameter" {
statement {
effect = "Allow"
actions = ["ssm:GetParameter"]
#tfsec:ignore:aws-iam-no-policy-wildcards: acccess scoped to parameter path, plus time conditional restricts access to short duration after launch
effect = "Allow"
actions = flatten([
"ssm:GetParameter",
length(aws_ssm_parameter.placeholder) != 0 ? ["ssm:PutParameter"] : []
])
#tfsec:ignore:aws-iam-no-policy-wildcards: acccess scoped to parameter path of EC2
resources = ["arn:aws:ssm:${var.region}:${data.aws_caller_identity.current.id}:parameter/${var.ssm_parameters_prefix}${var.name}/*"]
condition {
test = "DateLessThan"
variable = "aws:CurrentTime"
values = [time_offset.asm_parameter.rfc3339]
}
}
}

Expand Down Expand Up @@ -267,11 +279,11 @@ resource "aws_iam_role" "this" {
)
}

resource "aws_iam_role_policy" "asm_parameter" {
resource "aws_iam_role_policy" "ssm_parameter" {
count = var.ssm_parameters != null ? 1 : 0
name = "asm-parameter-access-${var.name}"
name = "Ec2SSMParameterPolicy-${var.name}"
role = aws_iam_role.this.id
policy = data.aws_iam_policy_document.asm_parameter.json
policy = data.aws_iam_policy_document.ssm_parameter.json
}

resource "aws_iam_instance_profile" "this" {
Expand Down
13 changes: 8 additions & 5 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,16 @@ variable "ssm_parameters_prefix" {
}

variable "ssm_parameters" {
description = "A map of SSM parameters to create. If parameters are manually created, set to {} so IAM role still created"
description = "A map of SSM parameters to create. Set a specific value or a randomly generated value. If neither random or value are set, a placeholder value is created which can be updated outside of terraform"
type = map(object({
random = object({
description = optional(string)
type = optional(string, "SecureString")
kms_key_id = optional(string)
random = optional(object({
length = number
special = bool
})
description = string
special = optional(bool)
}))
value = optional(string)
}))
default = null
}
Expand Down

0 comments on commit 474387e

Please sign in to comment.