Home

Awesome

Modernisation Platform Terraform EC2 Instance

Standards Icon Format Code Icon Scorecards Icon SCA Icon Terraform SCA Icon

Usage


module "ec2_test_instance" {
  source = "github.com/ministryofjustice/modernisation-platform-terraform-ec2-instance"

  providers = {
    aws.core-vpc = aws.core-vpc # core-vpc-(environment) holds the networking for all accounts
  }

  for_each = try(local.ec2_test.ec2_test_instances, {})

  name = each.key

  ami_name                      = each.value.ami_name
  ami_owner                     = try(each.value.ami_owner, "core-shared-services-production")
  instance                      = merge(local.ec2_test.instance, lookup(each.value, "instance", {}))
  ebs_volumes_copy_all_from_ami = try(each.value.ebs_volumes_copy_all_from_ami, true)
  ebs_kms_key_id                = module.environment.kms_keys["ebs"].arn
  ebs_volume_config             = lookup(each.value, "ebs_volume_config", {})
  ebs_volumes                   = lookup(each.value, "ebs_volumes", {})
  ebs_volume_tags               = lookup(each.value, "ebs_volume_tags", {})
  ssm_parameters_prefix         = lookup(each.value, "ssm_parameters_prefix", "test/")
  ssm_parameters                = lookup(each.value, "ssm_parameters", null)
  route53_records               = merge(local.ec2_test.route53_records, lookup(each.value, "route53_records", {}))

  iam_resource_names_prefix = "ec2-test-instance"
  instance_profile_policies = local.ec2_common_managed_policies

  business_unit            = local.business_unit
  application_name         = local.application_name
  environment              = local.environment
  region                   = local.region
  availability_zone        = local.availability_zone_1
  subnet_id                = module.environment.subnet["private"][local.availability_zone_1].id
  tags                     = merge(local.tags, local.ec2_test.tags, try(each.value.tags, {}))
  account_ids_lookup       = local.environment_management.account_ids
  cloudwatch_metric_alarms = {}
}

For a deployed example, please check example. A second fully self-contained example has been added for ease of use.

Setting backup tags

Read the Modernisation Platform backup functionality to understand how the backup plan works. The following is a summary of the backup behaviour based on the tags that are set and passed in this module.

Production environment

By default, all production resources (EC2 and EBS) will be backed up. This is determined by the is-production tag being set to true. Production backups can be skipped by setting backup tag to false (passed in tags input).

Non-production environments

Additionally, you are able to control backups in non-production environments by setting backup tag to true (passed in tags input).

Backup duplication problem

NOTE, setting backup tag to true that is passed in tags input will set backup tag to true on all EC2 and EBS resources. This will result in duplicated backups as EBS resources that are part of an EC2 will get backed up during the EC2 backup and EBS backup selection by the backup plan.

In order to select either EC2 backups or EBS backups it is possible to set backup tag to true on only EC2 instance, by passing the tag as part of the instance.tags input or setting the backup tag to true on only EBS by setting the backup tag to true and passing it in the ebs_volume_tags input. NOTE, if the backup tag is passed in tags and instance.tags/ebs_volume_tags, the tag set on the specific resources will take priority. For example, backup tag is set to:

Looking for issues?

If you're looking to raise an issue with this module, please create a new issue in the Modernisation Platform repository.

<!-- BEGIN_TF_DOCS -->

Requirements

NameVersion
<a name="requirement_terraform"></a> terraform>= 1.1.7
<a name="requirement_aws"></a> aws~> 5.0
<a name="requirement_cloudinit"></a> cloudinit~> 2.3.5
<a name="requirement_random"></a> random~> 3.0
<a name="requirement_time"></a> time> 0.9.0

Providers

NameVersion
<a name="provider_aws"></a> aws~> 5.0
<a name="provider_aws.core-vpc"></a> aws.core-vpc~> 5.0
<a name="provider_cloudinit"></a> cloudinit~> 2.3.5
<a name="provider_random"></a> random~> 3.0

Modules

No modules.

Resources

NameType
aws_cloudwatch_metric_alarm.thisresource
aws_ebs_volume.thisresource
aws_eip.thisresource
aws_eip_association.thisresource
aws_iam_instance_profile.thisresource
aws_iam_role.thisresource
aws_iam_role_policy.ssm_params_and_secretsresource
aws_instance.thisresource
aws_route53_record.externalresource
aws_route53_record.internalresource
aws_secretsmanager_secret.fixedresource
aws_secretsmanager_secret.placeholderresource
aws_secretsmanager_secret_version.fixedresource
aws_ssm_parameter.placeholderresource
aws_ssm_parameter.thisresource
aws_volume_attachment.thisresource
random_password.secretsresource
random_password.thisresource
aws_ami.thisdata source
aws_caller_identity.currentdata source
aws_ec2_instance_type.thisdata source
aws_iam_policy_document.ssm_params_and_secretsdata source
aws_route53_zone.externaldata source
aws_route53_zone.internaldata source
cloudinit_config.thisdata source

Inputs

NameDescriptionTypeDefaultRequired
<a name="input_account_ids_lookup"></a> account_ids_lookupA map of account names to account ids that can be used for AMI ownermap(any){}no
<a name="input_ami_name"></a> ami_nameName of AMI to be used to launch the database ec2 instancestringn/ayes
<a name="input_ami_owner"></a> ami_ownerOwner of AMI to be used to launch the database ec2 instancestring"self"no
<a name="input_application_name"></a> application_nameThe name of the application. This will be name of the environment in Modernisation Platformstring"nomis"no
<a name="input_availability_zone"></a> availability_zoneThe availability zone in which to deploy the infrastructurestring"eu-west-2a"no
<a name="input_business_unit"></a> business_unitThis corresponds to the VPC in which the application residesstring"hmpps"no
<a name="input_cloudwatch_metric_alarms"></a> cloudwatch_metric_alarmsMap of cloudwatch metric alarms. The alarm name is set to the ec2 instance name plus the map key.<pre>map(object({<br/> comparison_operator = string<br/> evaluation_periods = number<br/> metric_name = string<br/> namespace = string<br/> period = number<br/> statistic = string<br/> threshold = number<br/> alarm_actions = list(string)<br/> ok_actions = optional(list(string), [])<br/> actions_enabled = optional(bool, false)<br/> alarm_description = optional(string)<br/> datapoints_to_alarm = optional(number)<br/> treat_missing_data = optional(string, "missing")<br/> dimensions = optional(map(string), {})<br/> }))</pre>{}no
<a name="input_ebs_kms_key_id"></a> ebs_kms_key_idKMS Key to use for EBS volumes if not explicitly set in ebs_volumes variablestringnullno
<a name="input_ebs_volume_config"></a> ebs_volume_configEC2 volume configurations, where key is a label, e.g. flash, which is assigned to the disk in ebs_volumes. All disks with same label have the same configuration. If not specified, use values from the AMI. If total_size specified, the volume size is this divided by the number of drives with the given label<pre>map(object({<br/> iops = optional(number)<br/> throughput = optional(number)<br/> total_size = optional(number)<br/> type = optional(string)<br/> kms_key_id = optional(string)<br/> }))</pre>n/ayes
<a name="input_ebs_volume_tags"></a> ebs_volume_tagsAdditional tags to apply to ebs volumesmap(string){}no
<a name="input_ebs_volumes"></a> ebs_volumesEC2 volumes, see aws_ebs_volume for documentation. key=volume name, value=ebs_volume_config key. label is used as part of the Name tag<pre>map(object({<br/> label = optional(string)<br/> snapshot_id = optional(string)<br/> iops = optional(number)<br/> throughput = optional(number)<br/> size = optional(number)<br/> type = optional(string)<br/> kms_key_id = optional(string)<br/> }))</pre>n/ayes
<a name="input_ebs_volumes_copy_all_from_ami"></a> ebs_volumes_copy_all_from_amiIf true, ensure all volumes in AMI are also present in EC2. If false, only create volumes specified in ebs_volumes varbooltrueno
<a name="input_environment"></a> environmentApplication environment - i.e. the terraform workspacestringn/ayes
<a name="input_iam_resource_names_prefix"></a> iam_resource_names_prefixPrefix IAM resources with this prefix, e.g. ec2-databasestring"ec2"no
<a name="input_instance"></a> instanceEC2 instance settings, see aws_instance documentation<pre>object({<br/> associate_public_ip_address = optional(bool, false)<br/> disable_api_termination = bool<br/> disable_api_stop = bool<br/> instance_type = string<br/> key_name = string<br/> metadata_endpoint_enabled = optional(string, "enabled")<br/> metadata_options_http_tokens = optional(string, "required")<br/> monitoring = optional(bool, true)<br/> ebs_block_device_inline = optional(bool, false)<br/> vpc_security_group_ids = list(string)<br/> private_dns_name_options = optional(object({<br/> enable_resource_name_dns_aaaa_record = optional(bool)<br/> enable_resource_name_dns_a_record = optional(bool)<br/> hostname_type = string<br/> }))<br/> tags = optional(map(string), {})<br/> })</pre>n/ayes
<a name="input_instance_profile_policies"></a> instance_profile_policiesA list of managed IAM policy document ARNs to be attached to the database instance profilelist(string)n/ayes
<a name="input_name"></a> nameProvide a unique name for the instancestringn/ayes
<a name="input_region"></a> regionDestination AWS Region for the infrastructurestring"eu-west-2"no
<a name="input_route53_records"></a> route53_recordsOptionally create internal and external DNS records<pre>object({<br/> create_internal_record = bool<br/> create_external_record = bool<br/> })</pre>n/ayes
<a name="input_secretsmanager_secrets"></a> secretsmanager_secretsA map of secretsmanager secrets 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<pre>map(object({<br/> description = optional(string)<br/> kms_key_id = optional(string)<br/> recovery_window_in_days = optional(number)<br/> random = optional(object({<br/> length = number<br/> special = optional(bool)<br/> }))<br/> value = optional(string)<br/> }))</pre>nullno
<a name="input_secretsmanager_secrets_prefix"></a> secretsmanager_secrets_prefixOptionally prefix secretsmanager secrets with this prefix. Add a trailing /string""no
<a name="input_ssm_parameters"></a> ssm_parametersA 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<pre>map(object({<br/> description = optional(string)<br/> type = optional(string, "SecureString")<br/> kms_key_id = optional(string)<br/> random = optional(object({<br/> length = number<br/> special = optional(bool)<br/> }))<br/> value = optional(string)<br/> }))</pre>nullno
<a name="input_ssm_parameters_prefix"></a> ssm_parameters_prefixOptionally prefix ssm parameters with this prefix. Add a trailing /string""no
<a name="input_subnet_id"></a> subnet_idThe subnet id in which to deploy the infrastructurestringn/ayes
<a name="input_tags"></a> tagsDefault tags to be applied to resources. Additional tags can be added to EBS volumes or EC2s, see instance.tags and ebs_volume_tags variables.map(any)n/ayes
<a name="input_user_data_cloud_init"></a> user_data_cloud_initUse this instead of user_data_raw to run multiple scripts using cloud_init<pre>object({<br/> args = optional(map(string))<br/> scripts = optional(list(string))<br/> write_files = optional(map(object({<br/> path = string<br/> owner = string<br/> permissions = string<br/> })), {})<br/> })</pre>nullno
<a name="input_user_data_raw"></a> user_data_rawBase64 encoded user data, script or cloud formation templatestringnullno

Outputs

NameDescription
<a name="output_aws_ebs_volume"></a> aws_ebs_volumeaws_ebs_volume resource
<a name="output_aws_instance"></a> aws_instanceaws_instance resource
<!-- END_TF_DOCS -->