From 4c6e08a8a932e87cb2a1e6d72ae2d0b36bf88127 Mon Sep 17 00:00:00 2001 From: david goodell <50417089+dgoodellrhy@users.noreply.github.com> Date: Mon, 3 May 2021 18:47:44 -0400 Subject: [PATCH] Changes to allow SSM access, disallow SSH Keypairs by default and allow external keypairs (#3) * Changes to allow SSM access, disallow SSH Keypairs by default and allow external keypairs * Apply automatic changes * addressing PR feedback and simplifying logic * Apply automatic changes * add iam role name to outputs Co-authored-by: Linter Bot --- README.md | 11 ++++++++--- main.tf | 44 ++++++++++++++++++++++++++++++-------------- outputs.tf | 5 +++++ terraform-docs | 0 variables.tf | 22 ++++++++++++++++++++-- versions.tf | 14 +++++++++++++- 6 files changed, 76 insertions(+), 20 deletions(-) create mode 100644 terraform-docs diff --git a/README.md b/README.md index 296031f..258844e 100644 --- a/README.md +++ b/README.md @@ -24,14 +24,16 @@ A bit about this module | Name | Version | |------|---------| -| terraform | >= 0.12.14 | +| terraform | >= 0.12.26 | +| aws | >= 2.45.0, < 4.0.0 | +| tls | >= 3.1.0, < 4.0.0 | ## Providers | Name | Version | |------|---------| -| aws | n/a | -| tls | n/a | +| aws | >= 2.45.0, < 4.0.0 | +| tls | >= 3.1.0, < 4.0.0 | ## Inputs @@ -47,8 +49,11 @@ A bit about this module | volume\_type | Type of storage for the instance attached volume. | `string` | n/a | yes | | vpc | VPC ID to create the instance in. | `string` | n/a | yes | | create | Whether or not this instance should be created. Unfortunately needed for TF < 0.13. | `bool` | `true` | no | +| external\_keypair | Name of an external SSH Keypair to associate with this instance. If use\_keypair is false and this is left null, no keypair will be associated with the instance. | `string` | `null` | no | | instance\_ip | Private IP to assign to the instance, if desired. | `string` | `null` | no | | tags | User-Defined tags. | `map(string)` | `{}` | no | +| use\_keypair | Whether or not to associate an SSH Keypair with this instance. If this is false and no external\_keypair is defined, no key will be associated with the instance. | `bool` | `false` | no | +| use\_ssm | Whether or not to associate an IAM managed policy to allow SSM access to the instance. | `bool` | `false` | no | | userdata\_script | Userdata script to execute when provisioning the instance. | `string` | `null` | no | ## Outputs diff --git a/main.tf b/main.tf index a01ae9d..c1f3023 100644 --- a/main.tf +++ b/main.tf @@ -1,6 +1,12 @@ -######################################## +locals { + allow_ssm = var.create && var.use_ssm + create_key = var.create && var.create_keypair + keypair = local.create_key ? aws_key_pair.instance_root[0].key_name : var.external_keypair +} + +########################################## # Security Group for instance -######################################## +########################################## resource "aws_security_group" "instance" { count = var.create ? 1 : 0 @@ -20,9 +26,9 @@ resource "aws_security_group" "instance" { } } -######################################## +########################################## # Instance IAM role and initial policy setup -######################################## +########################################## data "aws_iam_policy_document" "instance_sts_assume_role" { statement { @@ -35,6 +41,10 @@ data "aws_iam_policy_document" "instance_sts_assume_role" { } } +data "aws_iam_policy" "ssm_access" { + arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" +} + resource "aws_iam_role" "instance" { count = var.create ? 1 : 0 name_prefix = "${substr(var.name, 0, 26)}-role-" @@ -77,24 +87,30 @@ resource "aws_iam_instance_profile" "instance" { role = aws_iam_role.instance[0].name } -######################################## +resource "aws_iam_role_policy_attachment" "ssm_access" { + count = local.allow_ssm ? 1 : 0 + role = aws_iam_role.instance[0].name + policy_arn = data.aws_iam_policy.ssm_access.arn +} + +########################################## # Instance root key creation/storage -######################################## +########################################## resource "tls_private_key" "instance_root" { - count = var.create ? 1 : 0 + count = local.create_key ? 1 : 0 algorithm = "RSA" rsa_bits = 4096 } resource "aws_key_pair" "instance_root" { - count = var.create ? 1 : 0 + count = local.create_key ? 1 : 0 key_name_prefix = "${var.name}-root-" public_key = tls_private_key.instance_root[0].public_key_openssh } resource "aws_secretsmanager_secret" "instance_root_key" { - count = var.create ? 1 : 0 + count = local.create_key ? 1 : 0 name_prefix = "${var.name}-root-key-" description = "ssh key for ec2-user user on ${var.name} server" @@ -107,19 +123,19 @@ resource "aws_secretsmanager_secret" "instance_root_key" { } resource "aws_secretsmanager_secret_version" "instance_root_key_value" { - count = var.create ? 1 : 0 + count = local.create_key ? 1 : 0 secret_id = aws_secretsmanager_secret.instance_root_key[0].id secret_string = tls_private_key.instance_root[0].private_key_pem } -######################################## +########################################## # Instance Definition -######################################## +########################################## resource "aws_instance" "instance" { count = var.create ? 1 : 0 ami = var.ami_id iam_instance_profile = aws_iam_instance_profile.instance[0].id instance_type = var.instance_type - key_name = aws_key_pair.instance_root[0].key_name + key_name = local.keypair monitoring = true private_ip = var.instance_ip != null ? var.instance_ip : null subnet_id = var.subnet_id @@ -135,7 +151,7 @@ resource "aws_instance" "instance" { tags = merge( var.tags, { - "Name" = "${var.name}" + "Name" = var.name }, ) } diff --git a/outputs.tf b/outputs.tf index 8906f3f..872d6ee 100644 --- a/outputs.tf +++ b/outputs.tf @@ -17,3 +17,8 @@ output "iam_role_arn" { description = "ARN of the IAM Role generated for this instance" value = aws_iam_role.instance[0].arn } + +output "iam_role_name" { + description = "Name of the IAM Role generated for this instance" + value = aws_iam_role.instance[0].name +} diff --git a/terraform-docs b/terraform-docs new file mode 100644 index 0000000..e69de29 diff --git a/variables.tf b/variables.tf index b318483..be44120 100644 --- a/variables.tf +++ b/variables.tf @@ -1,6 +1,6 @@ -######################################## +########################################## # Variables -######################################## +########################################## variable "ami_id" { description = "ID of the AMI to use when creating this instance." type = string @@ -17,6 +17,12 @@ variable "env" { type = string } +variable "external_keypair" { + default = null + description = "Name of an external SSH Keypair to associate with this instance. If create_keypair is false and this is left null, no keypair will be associated with the instance." + type = string +} + variable "instance_ip" { description = "Private IP to assign to the instance, if desired." type = string @@ -49,6 +55,18 @@ variable "tags" { type = map(string) } +variable "create_keypair" { + default = false + description = "Whether or not to associate an SSH Keypair with this instance. If this is false and no external_keypair is defined, no key will be associated with the instance." + type = bool +} + +variable "use_ssm" { + default = true + description = "Whether or not to associate an IAM managed policy to allow SSM access to the instance." + type = bool +} + variable "userdata_script" { description = "Userdata script to execute when provisioning the instance." type = string diff --git a/versions.tf b/versions.tf index 7ac324f..5b6d761 100644 --- a/versions.tf +++ b/versions.tf @@ -1,3 +1,15 @@ terraform { - required_version = ">= 0.12.14" + required_version = ">= 0.12.26" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 2.45.0, < 4.0.0" + } + + tls = { + source = "hashicorp/tls" + version = ">= 3.1.0, < 4.0.0" + } + } }