Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

| Name | Type |
|------|------|
| [aws_iam_instance_profile.build_user_instance_profile](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource |
| [aws_iam_role.build_user_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_key_pair.deployer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/key_pair) | resource |
| [aws_secretsmanager_secret.secrets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
| [aws_secretsmanager_secret.ssh_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
Expand Down Expand Up @@ -79,6 +81,7 @@
| <a name="input_goss_source_type"></a> [goss\_source\_type](#input\_goss\_source\_type) | Type of source to be used for the Goss CodePipeline | `string` | `"CodeCommit"` | no |
| <a name="input_image"></a> [image](#input\_image) | n/a | <pre>object({<br> dest_tag = string<br> dest_docker_repo = string<br> source_image = string<br> source_tag = string<br> source_docker_repo = string<br> })</pre> | `null` | no |
| <a name="input_image_volume_mapping"></a> [image\_volume\_mapping](#input\_image\_volume\_mapping) | n/a | <pre>list(object({<br> device_name = string<br> volume_size = number<br> volume_type = string<br> delete_on_termination = bool<br> encrypted = optional(bool, false)<br> iops = optional(number, null)<br> snapshot_id = optional(string, null)<br> throughput = optional(number, null)<br> virtual_name = optional(string, null)<br> kms_key_id = optional(string, null)<br> mount_path = optional(string, null)<br> }))</pre> | `[]` | no |
| <a name="input_instance_profile"></a> [instance\_profile](#input\_instance\_profile) | n/a | `string` | `null` | no |
| <a name="input_kms_key_id"></a> [kms\_key\_id](#input\_kms\_key\_id) | n/a | `string` | `null` | no |
| <a name="input_nonmanaged_parameters"></a> [nonmanaged\_parameters](#input\_nonmanaged\_parameters) | n/a | `list(string)` | <pre>[<br> "dest_tag"<br>]</pre> | no |
| <a name="input_packer_bucket"></a> [packer\_bucket](#input\_packer\_bucket) | Source bucket details | <pre>object({<br> name = string,<br> key = string<br> })</pre> | `null` | no |
Expand Down
5 changes: 1 addition & 4 deletions locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ locals {
var.goss_bucket.name,
var.state.bucket
])
build_user_iam_policy = var.build_user_iam_policy == null ? data.aws_iam_policy_document.build_user_default.json : var.build_user_iam_policy
}

data "aws_iam_policy_document" "build_user_default" {
Expand Down Expand Up @@ -64,7 +65,3 @@ data "aws_iam_policy_document" "build_user_default" {
)
}
}

locals {
build_user_iam_policy = var.build_user_iam_policy == null ? data.aws_iam_policy_document.build_user_default.json : var.build_user_iam_policy
}
99 changes: 27 additions & 72 deletions parameters_and_secrets.tf
Original file line number Diff line number Diff line change
@@ -1,77 +1,46 @@

locals {
# Define a map of parameters for infrastructure provisioning.
# This includes configurations like region, subnets, security group IDs, VPC ID, source AMI, and more.
# Conditional logic is used to include optional parameters only if they are provided.
parameters = tomap(merge({
instance_profile = var.instance_profile == null ? "${var.project_name}-instance-profile" : var.instance_profile # IAM instance profile for the EC2 instance.
aws_account_id = data.aws_caller_identity.current.account_id, # AWS account ID where resources will be provisioned.
region = local.vpc_config.region, # AWS region where resources will be provisioned.
subnets = join(",", local.vpc_config.subnets), # Comma-separated list of subnet IDs.
security_group_ids = join(",", local.vpc_config.security_group_ids), # Comma-separated list of security group IDs.
vpc_id = local.vpc_config.vpc_id, # VPC ID where resources will be provisioned.
goss_profile = var.goss_profile, # GOSS profile for server testing.
goss_binary = var.goss_binary, # GOSS binary for server testing.
playbook = var.playbook, # Ansible playbook for configuration management.
troubleshoot = var.troubleshoot, # Enable troubleshooting mode.
# Mapping of volumes to attach to the instance.
volume_map = jsonencode(var.image_volume_mapping)

key_name = "${var.project_name}-deployer-key-${random_pet.keyname.id}" # KMS key ID for encryption.
}, var.playbook == null ? {} : {
playbook = var.playbook # Include playbook if provided.
}, var.userdata == null ? {
userdata = "" # Default userdata to an empty string if not provided.
} : {
userdata = var.userdata # Userdata script for instance initialization.
}, var.shared_accounts == null ? {
shared_accounts = "" # Default shared accounts to an empty string if not provided.
} : {
shared_accounts = join(",", var.shared_accounts), # Comma-separated list of shared AWS account IDs.
}, var.ssh_user == null ? {} : {
ssh_user = var.ssh_user, # SSH username for instance access.
keyname = "${var.project_name}-deployer-key" # Key pair name for SSH access.
}, var.image == null ? {} : merge(
var.image,
{
dest_image = var.project_name
}
),
var.ami == null ? {} : {
source_ami = var.ami.source_ami, # AMI ID used as the base image for instances.
ami_name = var.project_name, # Name assigned to the AMI created.
instance_type = var.ami.instance_type, # EC2 instance type.
}
))
instance_profile = var.instance_profile == null ? "${var.project_name}-instance-profile" : var.instance_profile,
aws_account_id = data.aws_caller_identity.current.account_id,
region = local.vpc_config.region,
subnets = join(",", local.vpc_config.subnets),
security_group_ids = join(",", local.vpc_config.security_group_ids),
vpc_id = local.vpc_config.vpc_id,
goss_profile = var.goss_profile,
goss_binary = var.goss_binary,
playbook = var.playbook,
troubleshoot = var.troubleshoot,
volume_map = jsonencode(var.image_volume_mapping),
key_name = "${var.project_name}-deployer-key-${random_pet.keyname.id}"
},
var.playbook == null ? {} : { playbook = var.playbook },
var.userdata == null ? { userdata = "" } : { userdata = var.userdata },
var.shared_accounts == null ? { shared_accounts = "" } : { shared_accounts = join(",", var.shared_accounts) },
var.ssh_user == null ? {} : { ssh_user = var.ssh_user, keyname = "${var.project_name}-deployer-key" },
var.image == null ? {} : merge(var.image, { dest_image = var.project_name }),
var.ami == null ? {} : { source_ami = var.ami.source_ami, ami_name = var.project_name, instance_type = var.ami.instance_type }))

# Merge base parameters with any extra parameters provided.
all_parameters = merge(
local.parameters,
var.extra_parameters # Extra parameters that can be passed for additional customization.
)
all_parameters = merge(local.parameters, var.extra_parameters)

# Extract keys from the parameters map, handling sensitive keys appropriately.
parameters_keys = concat(
issensitive(keys(local.all_parameters)) ? nonsensitive(keys(local.all_parameters)) : keys(local.all_parameters),
length(local.secret_keys) > 0 ? ["secrets"] : [] # Include secret keys if there's any secrets.
length(local.secret_keys) > 0 ? ["secrets"] : []
)

# Define a map of secrets, such as WinRM credentials and other sensitive information.
secrets = tomap(merge(
var.winrm_credentials == null ? {} : { winrm_credentials = var.winrm_credentials }, # Include WinRM credentials if provided.
var.secrets # Additional secrets provided as a map.
var.winrm_credentials == null ? {} : { winrm_credentials = var.winrm_credentials },
var.secrets
))

# Extract keys from the secrets map, handling sensitive keys appropriately.
secret_keys = issensitive(keys(local.secrets)) ? nonsensitive(keys(local.secrets)) : keys(local.secrets)

# Prepare parameters for AWS Systems Manager (SSM) Parameter Store.
# Replace empty or null values with "notset" and compile lists of parameter and secret keys.
ssm_parameters = merge(
{ for key, value in local.all_parameters : key => contains(["", null], value) ? "notset" : value }, # Replace empty/null values with "notset".
length(local.parameters_keys) > 0 ? { parameters = join(",", local.parameters_keys) } : {}, # Compile a comma-separated list of parameter keys.
length(local.secret_keys) > 0 ? { secrets = join(",", local.secret_keys) } : {} # Compile a comma-separated list of secret keys if any.
{ for key, value in local.all_parameters : key => contains(["", null], value) ? "notset" : value },
length(local.parameters_keys) > 0 ? { parameters = join(",", local.parameters_keys) } : {},
length(local.secret_keys) > 0 ? { secrets = join(",", local.secret_keys) } : {}
)

nonsensitive_parameters = tomap(
{ for k, v in local.ssm_parameters :
(issensitive(k) ? nonsensitive(k) : k) => (issensitive(v) ? nonsensitive(v) : v)
Expand All @@ -80,27 +49,13 @@ locals {
)
}

# Managed Parameters: Parameters not listed in var.nonmanaged_parameters are fully managed by Terraform.
resource "aws_ssm_parameter" "managed_parameters" {
for_each = local.nonsensitive_parameters
name = "/image-pipeline/${var.project_name}/${each.key}"
type = "StringList"
value = each.value
}

# # Non-Managed Parameters: Parameters listed in var.nonmanaged_parameters are partially managed by Terraform,
# # with changes to their values being ignored to allow for external updates without causing Terraform to
# # revert them.
# resource "aws_ssm_parameter" "nonmanaged_parameters" {
# for_each = [for param in local.nonsensitive_parameters : param if !contains(var.nonmanaged_parameters, param.key)]
# name = "/image-pipeline/${var.project_name}/${each.key}"
# type = "StringList"
# value = each.value
# lifecycle {
# ignore_changes = [value]
# }
# }

resource "aws_secretsmanager_secret" "secrets" {
for_each = toset(local.secret_keys)
name = "/image-pipeline/${var.project_name}/${each.key}"
Expand Down