diff --git a/Jenkinsfile b/Jenkinsfile index 4837840..59b02d4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,7 +7,7 @@ pipeline { stage('Terraform fmt') { agent { docker { - image 'hashicorp/terraform:light' + image 'hashicorp/terraform:0.12.6' args '-w $WORKSPACE --entrypoint=""' } } @@ -25,7 +25,7 @@ pipeline { stage('Terraform validation') { agent { docker { - image 'hashicorp/terraform:0.12.1' + image 'hashicorp/terraform:0.12.6' args '-w $WORKSPACE --entrypoint=""' } } diff --git a/ami/base.json b/ami/base.json index 375a4a2..fd7e212 100644 --- a/ami/base.json +++ b/ami/base.json @@ -20,6 +20,14 @@ ], "most_recent": true }, + "launch_block_device_mappings": [ + { + "device_name": "/dev/xvda", + "volume_size": 20, + "volume_type": "gp2", + "delete_on_termination": true + } + ], "instance_type": "{{user `instance_type`}}", "ssh_username": "{{user `ssh_username`}}", "ami_name": "{{user `ami_name`}}-{{isotime \"2006-01-02T03-04-05\"}}", diff --git a/ami/files/teleport/teleport-secrets b/ami/files/teleport/teleport-secrets index 3864a3d..0921105 100755 --- a/ami/files/teleport/teleport-secrets +++ b/ami/files/teleport/teleport-secrets @@ -1,5 +1,7 @@ #!/bin/bash +cp /etc/teleport.yaml.tmpl /etc/teleport.yaml + # Setup teleport auth server config file INSTANCE_ID=$(curl -sSf http://169.254.169.254/latest/meta-data/instance-id) PRIVATE_IP=$(curl -sSf http://169.254.169.254/latest/meta-data/local-ipv4) @@ -7,7 +9,7 @@ REGION=$(curl -sSf http://169.254.169.254/latest/meta-data/placement/availabilit ENVIRONMENT=$(aws ec2 describe-tags --region "$REGION" --filters "Name=resource-id,Values=${INSTANCE_ID}" | jq '.Tags | .[] | select(.Key | contains("env")) | .Value ' | cut -f 2 -d '"') SECRET_ID="${ENVIRONMENT}/teleport/cluster_token" -NODENAME=$(aws ec2 describe-tags --region "$REGION" --filters "Name=resource-id,Values=${INSTANCE_ID}" | jq '.Tags | .[] | select(.Key | contains("Name")) | .Value ' | cut -f 2 -d '"') +NODENAME=$(aws ec2 describe-tags --region "$REGION" --filters "Name=resource-id,Values=${INSTANCE_ID}" | jq '.Tags | .[] | select(.Key == "Name") | .Value ' | cut -f 2 -d '"') CLUSTER_TOKEN=$(aws secretsmanager get-secret-value --region "$REGION" --secret-id ${SECRET_ID} | jq ".SecretString" | cut -f 2 -d '"') sed -i "s/{{ private_ip }}/${PRIVATE_IP}/g" /etc/teleport.yaml diff --git a/ami/files/teleport/teleport.yaml b/ami/files/teleport/teleport.yaml.tmpl similarity index 100% rename from ami/files/teleport/teleport.yaml rename to ami/files/teleport/teleport.yaml.tmpl diff --git a/ami/provision.sh b/ami/provision.sh index 2d03cb6..f593836 100644 --- a/ami/provision.sh +++ b/ami/provision.sh @@ -27,7 +27,7 @@ sudo useradd -d "/var/lib/teleport/" -g "adm" -k "/dev/null" -m -r -s "/sbin/nol sudo passwd -l teleport # Download info on the teleport release we are targeting -TELEPORT_VERSION="v4.0.1" +TELEPORT_VERSION="v4.0.2" TELEPORT_INFO=$(curl -sSf https://dashboard.gravitational.com/webapi/releases-oss?product=teleport | jq ".items | map(select(.version == \"${TELEPORT_VERSION}\")) | .[].downloads | map(select(.name == \"teleport-${TELEPORT_VERSION}-linux-amd64-bin.tar.gz\")) | .[]") # Install teleport binaries @@ -47,14 +47,17 @@ sudo chmod 0755 /usr/local/bin/teleport-secrets echo "--- Configure teleport" # Install teleport configuration -sudo cp /tmp/files/teleport/teleport.yaml /etc -sudo chmod 0644 /etc/teleport.yaml +sudo cp /tmp/files/teleport/teleport.yaml.tmpl /etc +sudo chmod 0644 /etc/teleport.yaml.tmpl # Install teleport systemd units sudo cp /tmp/files/teleport/*.service /etc/systemd/system sudo chmod 0644 /etc/systemd/system/teleport* echo "--- Turn on systemd services" -sudo systemctl enable --now docker -sudo systemctl enable --now yum-cron -sudo systemctl enable --now teleport +sudo systemctl enable docker +sudo systemctl enable yum-cron +sudo systemctl enable teleport + +echo "--- Turn off systemd services" +sudo systemctl disable --now amazon-ssm-agent \ No newline at end of file diff --git a/app_base/Readme.md b/app_base/Readme.md deleted file mode 100644 index ceede3a..0000000 --- a/app_base/Readme.md +++ /dev/null @@ -1,16 +0,0 @@ - -### Key feature comparison to previous Ad Hoc examples (default values used) - -| Feature | Foundation | Soapbox Platform | ACO API | QPP Foundational | USCIS RFDS RFI | -|--------------------|------------|------------------|---------|------------------|----------------| -| Plain instances | X | - | - | - | - | -| Auto-scaling group | X | X | - | X | X | -| ECS/Fargate Cluster| X | - | X | - | X | -| Domain Name | X | - | - | - | X | -| TLS | X | X | X | X | X | - -Key: - - X = Present - - - = Absent - - * = Optional - diff --git a/app_base/data.tf b/app_base/data.tf deleted file mode 100644 index f9eebba..0000000 --- a/app_base/data.tf +++ /dev/null @@ -1,45 +0,0 @@ -####### -### Lookup resources already created by foundation -####### - -data "aws_vpc" "vpc" { - tags = { - env = var.env - } -} - -data "aws_subnet" "application_subnet" { - count = 3 - vpc_id = data.aws_vpc.vpc.id - - tags = { - name = "app-sub-${count.index}" - env = var.env - } -} - -data "aws_subnet" "public_subnet" { - count = 3 - vpc_id = data.aws_vpc.vpc.id - - tags = { - name = "public-sub-${count.index}" - env = var.env - } -} - -data "aws_route53_zone" "external" { - name = var.domain_name - private_zone = false -} - -data "aws_route53_zone" "internal" { - name = "${var.env}.local" - private_zone = true -} - -data "aws_acm_certificate" "wildcard" { - domain = var.domain_name - most_recent = true -} - diff --git a/app_base/main.tf b/app_base/main.tf deleted file mode 100644 index 64375d2..0000000 --- a/app_base/main.tf +++ /dev/null @@ -1,154 +0,0 @@ -####### -### Domain names -####### - -resource "aws_route53_record" "external_cname" { - zone_id = data.aws_route53_zone.external.id - name = var.application_name - type = "CNAME" - ttl = 30 - - records = [aws_alb.application_alb.dns_name] -} - -resource "aws_route53_record" "internal_cname" { - zone_id = data.aws_route53_zone.internal.id - name = var.application_name - type = "CNAME" - ttl = 30 - - records = [aws_alb.application_alb.dns_name] -} - -####### -### Load balancer -####### - -resource "aws_alb" "application_alb" { - # max 6 characters for name prefix - name_prefix = "${format("%.5s", var.application_name)}-" - internal = false - security_groups = [aws_security_group.application_alb_sg.id] - subnets = data.aws_subnet.public_subnet.*.id - - ip_address_type = "ipv4" - - tags = { - env = var.env - terraform = "true" - app = var.application_name - name = "alb-${var.application_name}" - } -} - -# ALB target group and listeners -resource "aws_alb_target_group" "application_target_group" { - # max 6 characters for name prefix - name_prefix = "${format("%.5s", var.application_name)}-" - port = var.application_port - protocol = "HTTP" - vpc_id = data.aws_vpc.vpc.id - target_type = "ip" # Must use IP to support fargate - - health_check { - interval = 60 - path = var.health_check_path - port = var.application_port - healthy_threshold = 2 - unhealthy_threshold = 2 - } - - depends_on = [aws_alb.application_alb] - - tags = { - env = var.env - terraform = "true" - app = var.application_name - name = "alb-tg-${var.application_name}:${var.application_port}" - } -} - -resource "aws_alb_listener" "application_alb_https" { - load_balancer_arn = aws_alb.application_alb.arn - port = var.loadbalancer_port - protocol = "HTTPS" - ssl_policy = "ELBSecurityPolicy-2016-08" - certificate_arn = data.aws_acm_certificate.wildcard.arn - - default_action { - target_group_arn = aws_alb_target_group.application_target_group.arn - type = "forward" - } -} - -# Security Group: world -> alb -resource "aws_security_group" "application_alb_sg" { - name_prefix = "${var.application_name}-alb-" - vpc_id = data.aws_vpc.vpc.id - - tags = { - env = var.env - terraform = "true" - app = var.application_name - name = "world->alb-sg-${var.application_name}" - } -} - -// Allow inbound only to our listening port -resource "aws_security_group_rule" "lb_ingress" { - type = "ingress" - from_port = var.loadbalancer_port - to_port = var.loadbalancer_port - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] - - security_group_id = aws_security_group.application_alb_sg.id -} - -// Allow all outbound by default -resource "aws_security_group_rule" "lb_egress" { - type = "egress" - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - - security_group_id = aws_security_group.application_alb_sg.id -} - -####### -### Security group for application -####### - -resource "aws_security_group" "app_sg" { - name_prefix = "${var.application_name}-app-" - vpc_id = data.aws_vpc.vpc.id - - tags = { - app = var.application_name - env = var.env - } -} - -// Allow inbound only to our application port -resource "aws_security_group_rule" "app_ingress" { - type = "ingress" - from_port = var.application_port - to_port = var.application_port - protocol = "tcp" - source_security_group_id = aws_security_group.application_alb_sg.id - - security_group_id = aws_security_group.app_sg.id -} - -// Allow all outbound, e.g. third-pary API endpoints, by default -resource "aws_security_group_rule" "app_egress" { - type = "egress" - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - - security_group_id = aws_security_group.app_sg.id -} - diff --git a/app_base/outputs.tf b/app_base/outputs.tf deleted file mode 100644 index ede5779..0000000 --- a/app_base/outputs.tf +++ /dev/null @@ -1,8 +0,0 @@ -output "app_sg_id" { - value = aws_security_group.app_sg.id -} - -output "lb_tg_arn" { - value = aws_alb_target_group.application_target_group.arn -} - diff --git a/app_base/variables.tf b/app_base/variables.tf deleted file mode 100644 index fcc6985..0000000 --- a/app_base/variables.tf +++ /dev/null @@ -1,27 +0,0 @@ -variable "env" { - description = "the name of the environment, e.g. \"testing\". it must be unique in the account." -} - -variable "domain_name" { - description = "the external domain name for reaching the public resources. must have a certificate in ACM associated with it." -} - -variable "application_name" { - description = "name of the application to be hosted. must be unique in the environment." -} - -variable "health_check_path" { - description = "path used by load balancer to health check application. should return 200." - default = "/" -} - -variable "application_port" { - description = "port on which the application will be listening." - default = "80" -} - -variable "loadbalancer_port" { - description = "port on which the load balancer will be listening. it will terminate TLS on this port." - default = "443" -} - diff --git a/app_base/versions.tf b/app_base/versions.tf deleted file mode 100644 index ac97c6a..0000000 --- a/app_base/versions.tf +++ /dev/null @@ -1,4 +0,0 @@ - -terraform { - required_version = ">= 0.12" -} diff --git a/autoscaling/ingress.tf b/autoscaling/ingress.tf new file mode 100644 index 0000000..ac0ae3c --- /dev/null +++ b/autoscaling/ingress.tf @@ -0,0 +1,69 @@ +##### +# Target group in case it needs to be attached to an LB +##### +locals { + ingress_enabled = var.public ? 1 : 0 +} + +resource "aws_route53_record" "external" { + count = local.ingress_enabled + zone_id = var.base.external.id + name = var.application_name + type = "CNAME" + ttl = 30 + + records = ["ingress-${var.base.env}.${var.base.domain_name}"] +} + +resource "aws_alb_target_group" "application" { + count = local.ingress_enabled + # max 6 characters for name prefix + name_prefix = "app-lb" + port = var.application_ports[0] + protocol = "HTTP" + vpc_id = var.base.vpc.id + target_type = "instance" # Must use instance for ASGs + + health_check { + interval = 60 + path = var.health_check_path + port = var.application_ports[0] + healthy_threshold = 2 + unhealthy_threshold = 2 + matcher = "200-308" + } + + tags = { + env = var.base.env + terraform = "true" + app = var.application_name + name = "app-lb-${var.application_name}-${var.application_ports[0]}" + } +} + +resource "aws_alb_listener_rule" "applications" { + count = local.ingress_enabled + listener_arn = var.base.ingress.listener.arn + + action { + type = "forward" + target_group_arn = aws_alb_target_group.application[0].arn + } + + condition { + field = "host-header" + values = ["${var.application_name}.${var.base.domain_name}"] + } +} + +# Allow ingress to talk to our primary port +resource "aws_security_group_rule" "ingress" { + count = local.ingress_enabled + type = "ingress" + from_port = var.application_ports[0] + to_port = var.application_ports[0] + protocol = "tcp" + source_security_group_id = var.base.ingress.security_group.id + + security_group_id = aws_security_group.app.id +} diff --git a/autoscaling/main.tf b/autoscaling/main.tf new file mode 100644 index 0000000..659c39c --- /dev/null +++ b/autoscaling/main.tf @@ -0,0 +1,169 @@ +terraform { + required_version = ">= 0.12" +} + +locals { + ami_id = length(var.ami_id) == 0 ? var.base.ami.id : var.ami_id +} + +##### +# Autoscaling configuration +##### + +resource "aws_autoscaling_group" "application" { + name_prefix = "${aws_launch_template.application.id}-${aws_launch_template.application.latest_version}" + vpc_zone_identifier = var.base.vpc.application[*].id + + max_size = var.max_count + min_size = 1 + desired_capacity = var.desired_count + force_delete = false + + target_group_arns = coalescelist(var.target_group_arns, aws_alb_target_group.application[*].arn) + health_check_grace_period = 300 + health_check_type = "ELB" + wait_for_elb_capacity = var.desired_count + wait_for_capacity_timeout = "600s" + + lifecycle { + ignore_changes = [desired_capacity] + create_before_destroy = true + } + + launch_template { + id = aws_launch_template.application.id + version = "$Latest" + } + + tag { + key = "Name" + value = "${var.base.env}-${var.application_name}" + propagate_at_launch = true + } + tag { + key = "terraform" + value = "true" + propagate_at_launch = true + } + tag { + key = "env" + value = var.base.env + propagate_at_launch = true + } + tag { + key = "app" + value = var.application_name + propagate_at_launch = true + } +} + +resource "aws_autoscaling_policy" "cpu" { + name = "${var.base.env}-${var.application_name}-cpu-policy" + autoscaling_group_name = aws_autoscaling_group.application.name + policy_type = "TargetTrackingScaling" + + target_tracking_configuration { + predefined_metric_specification { + predefined_metric_type = "ASGAverageCPUUtilization" + } + + target_value = 60 + } +} + +resource "aws_launch_template" "application" { + name_prefix = "${var.base.env}-${var.application_name}-" + disable_api_termination = false + image_id = local.ami_id + instance_initiated_shutdown_behavior = "terminate" + instance_type = var.instance_size + ebs_optimized = true + + key_name = var.base.ssh_key + vpc_security_group_ids = [ + var.base.security_groups["teleport_nodes"].id, + var.base.security_groups["jumpbox_nodes"].id, + aws_security_group.app.id + ] + + iam_instance_profile { + name = aws_iam_instance_profile.iam.name + } + + user_data = var.user_data != "" ? base64encode(var.user_data) : null + + credit_specification { + cpu_credits = "unlimited" + } + + monitoring { + enabled = true + } + + tags = { + Name = "${var.base.env}-${var.application_name}-launch-template" + terraform = "true" + env = var.base.env + app = var.application_name + } +} + +####### +# Security group for application +####### + +resource "aws_security_group" "app" { + name_prefix = "${var.application_name}-app-" + vpc_id = var.base.vpc.id + + tags = { + app = var.application_name + terraform = "true" + env = var.base.env + } +} + +# Allow all outbound, e.g. third-pary API endpoints, by default +resource "aws_security_group_rule" "egress" { + type = "egress" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + + security_group_id = aws_security_group.app.id +} + + +##### +# Base IAM instance profile +##### +resource "aws_iam_instance_profile" "iam" { + name = "${var.base.env}-asg-${var.application_name}" + role = aws_iam_role.iam.name +} + +# Auth instance profile and roles +resource "aws_iam_role" "iam" { + name = "${var.base.env}-asg-${var.application_name}" + + assume_role_policy = < 0 ? 1 : 0 type = "ingress" - from_port = 22 - to_port = 22 + from_port = "5432" + to_port = "5432" protocol = "tcp" - source_security_group_id = data.aws_security_group.jumpbox.id - - security_group_id = aws_security_group.sg.id -} - -##### -# Base IAM instance profile -##### -resource "aws_iam_instance_profile" "iam" { - name = "${var.env}-command-console" - role = aws_iam_role.iam.name -} - -# Auth instance profile and roles -resource "aws_iam_role" "iam" { - name = "${var.env}-command-console" - - assume_role_policy = < /home/ec2-user/console +#!/usr/bin/env bash +set -euo pipefail + +command="${command}" +if [ $# -gt 0 ]; then + echo "Running alternate command: $@" + command="$@" +fi + +eval $(aws ecr get-login --region=us-east-1 --no-include-email) + +docker pull ${docker_image} + +docker run -it --rm \ + --entrypoint "" \ +%{ for name, value in environment_variables ~} + -e ${name}="${value}" +%{ endfor ~} + ${docker_image} \ + $command +DONE + +chown ec2-user:ec2-user /home/ec2-user/console +chmod +x /home/ec2-user/console diff --git a/command_console/variables.tf b/command_console/variables.tf index fd90b93..c8c989a 100644 --- a/command_console/variables.tf +++ b/command_console/variables.tf @@ -1,19 +1,24 @@ -variable "env" { - description = "the name of the environment, e.g. \"testing\". it must be unique in the account." +variable "base" { + description = "an object representing the outputs of the base module from the tf repo" } -variable "instance_size" { - description = "OPTIONAL: ec2 instance type to be used for hosting the app" - default = "t3.micro" +variable "fargate_cluster" { + description = "object representing the fargate cluster that we want to create a command console version of" } -variable "key_pair" { - description = "OPTIONAL: name of key pair to use with optional SSH jumpbox" - default = "infrastructure" +variable "database" { + description = "OPTIONAL: object representing the database that the console needs to connect to" + default = {} } -variable "user_data" { - description = "OPTIONAL: user data script to run on initialization" - default = "" +variable "environment_variables" { + type = map + description = "OPTIONAL: map of environment variables to set by default when running the docker image" + default = {} } +variable "default_command" { + type = string + description = "OPTIONAL: Default command to execute when running inside the docker container. Defaults to running a shell" + default = "/bin/sh" +} diff --git a/command_console/versions.tf b/command_console/versions.tf deleted file mode 100644 index ac97c6a..0000000 --- a/command_console/versions.tf +++ /dev/null @@ -1,4 +0,0 @@ - -terraform { - required_version = ">= 0.12" -} diff --git a/data.tf b/data.tf new file mode 100644 index 0000000..5a7a2a4 --- /dev/null +++ b/data.tf @@ -0,0 +1,21 @@ +data "aws_region" "current" {} +data "aws_caller_identity" "current" {} + +data "aws_route53_zone" "external" { + name = var.domain_name + private_zone = false +} + +data "aws_ami" "base" { + most_recent = true + owners = ["self"] + + filter { + name = "name" + values = ["adhoc_base*"] + } +} + +data "aws_secretsmanager_secret" "cluster_token" { + name = "${var.env}/teleport/cluster_token" +} diff --git a/database/Readme.md b/database/Readme.md index 7ebb291..f2a2e9a 100644 --- a/database/Readme.md +++ b/database/Readme.md @@ -1,5 +1,5 @@ -### Key feature comparision to prior Ad Hoc work +### Key feature comparison to prior Ad Hoc work | Feature | Foundation | Soapbox Platform | ACO API | QPP Foundational | USCIS RFDS RFI | @@ -9,4 +9,4 @@ | Password as Variable | X | - | - | X | X | | Ignore Lifecycle Events | X | - | X | - | X | | Store Credentials in AWS Service | - | - | X | - | - | -| Encrypted Storage | X | - | X | - | - | \ No newline at end of file +| Encrypted Storage | X | - | X | - | - | diff --git a/database/data.tf b/database/data.tf deleted file mode 100644 index 3aa9845..0000000 --- a/database/data.tf +++ /dev/null @@ -1,39 +0,0 @@ -#### -# Pull in external data for use here -#### - -data "aws_route53_zone" "internal" { - name = "${var.env}.local" - private_zone = true -} - -data "aws_vpc" "vpc" { - tags = { - env = var.env - } -} - -data "aws_subnet" "data_subnet" { - count = 3 - vpc_id = data.aws_vpc.vpc.id - - tags = { - name = "data-sub-${count.index}" - env = var.env - } -} - -data "aws_subnet" "application_subnet" { - count = 3 - vpc_id = data.aws_vpc.vpc.id - - tags = { - name = "app-sub-${count.index}" - env = var.env - } -} - -data "aws_kms_key" "main" { - key_id = "alias/${var.env}-main" -} - diff --git a/database/main.tf b/database/main.tf index c8c95e8..00ce136 100644 --- a/database/main.tf +++ b/database/main.tf @@ -1,37 +1,40 @@ +terraform { + required_version = ">= 0.12" +} + #### # Setup database specific networking #### resource "aws_db_subnet_group" "db_subnet_group" { - name = "${var.env}-${var.application_name}-rds-subnet-group" - subnet_ids = data.aws_subnet.data_subnet.*.id + name = "${var.base.env}-${var.application.name}-rds-subnet-group" + subnet_ids = var.base.vpc.data[*].id } -resource "aws_security_group" "db_sg" { - name = "${var.env}-${var.application_name}-db-sg" +resource "aws_security_group" "database" { + name = "${var.base.env}-${var.application.name}-db-sg" description = "SG for database servers" - vpc_id = data.aws_vpc.vpc.id + vpc_id = var.base.vpc.id } -resource "aws_security_group_rule" "app_ingress" { +resource "aws_security_group_rule" "ingress" { type = "ingress" from_port = 5432 to_port = 5432 protocol = "tcp" - source_security_group_id = var.app_sg + source_security_group_id = var.application.security_group.id - security_group_id = aws_security_group.db_sg.id + security_group_id = aws_security_group.database.id } -# TODO(bob) confirm this can be locked to egress 5432 only resource "aws_security_group_rule" "egress" { - type = "egress" - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] + type = "egress" + from_port = 5432 + to_port = 5432 + protocol = "tcp" + source_security_group_id = var.application.security_group.id - security_group_id = aws_security_group.db_sg.id + security_group_id = aws_security_group.database.id } #### @@ -39,26 +42,26 @@ resource "aws_security_group_rule" "egress" { #### resource "aws_db_instance" "primary" { - identifier_prefix = "${var.env}-${var.application_name}-" + identifier_prefix = "${var.base.env}-${var.application.name}-" username = var.user password = var.password db_subnet_group_name = aws_db_subnet_group.db_subnet_group.id - vpc_security_group_ids = [aws_security_group.db_sg.id] + vpc_security_group_ids = [aws_security_group.database.id] publicly_accessible = false multi_az = true - instance_class = "db.t2.small" + instance_class = var.instance_class engine = "postgres" engine_version = "10.5" port = 5432 storage_type = "gp2" skip_final_snapshot = true - allocated_storage = 30 + allocated_storage = 120 storage_encrypted = true - kms_key_id = data.aws_kms_key.main.arn + kms_key_id = var.base.key.arn parameter_group_name = aws_db_parameter_group.postgres.id enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"] @@ -76,16 +79,16 @@ resource "aws_db_instance" "primary" { } tags = { - env = var.env - app = var.application_name + env = var.base.env + app = var.application.name terraform = "true" - name = "${var.env}-db" + name = "${var.base.env}-db" } } # Enable query logging resource "aws_db_parameter_group" "postgres" { - name_prefix = "${var.env}-${var.application_name}-" + name_prefix = "${var.base.env}-${var.application.name}-" family = "postgres10" parameter { @@ -134,8 +137,8 @@ resource "aws_db_parameter_group" "postgres" { #### resource "aws_route53_record" "rds_cname" { - zone_id = data.aws_route53_zone.internal.id - name = "${var.application_name}-db-primary" + zone_id = var.base.vpc.internal_dns.zone_id + name = "${var.application.name}-db-primary" type = "CNAME" ttl = 30 @@ -146,7 +149,7 @@ resource "aws_route53_record" "rds_cname" { # Create an IAM role to allow enhanced monitoring ################################################## resource "aws_iam_role" "monitoring" { - name = "${var.env}-${var.application_name}-rds-monitoring-role" + name = "${var.base.env}-${var.application.name}-rds-monitoring-role" assume_role_policy = < alb -resource "aws_security_group" "application_alb_sg" { -name_prefix = "app-alb-" -vpc_id = data.aws_vpc.vpc.id - -tags = { -env = var.env -terraform = "true" -app = "helloworld" -name = "world->alb-sg-helloworld" -} -} - -// Allow inbound only to our listening port -resource "aws_security_group_rule" "lb_ingress" { -type = "ingress" -from_port = "80" -to_port = "80" -protocol = "tcp" -source_security_group_id = aws_security_group.nginx.id - -security_group_id = aws_security_group.application_alb_sg.id -} - -// Allow all outbound by default -resource "aws_security_group_rule" "lb_egress" { -type = "egress" -from_port = 0 -to_port = 0 -protocol = "-1" -cidr_blocks = ["0.0.0.0/0"] - -security_group_id = aws_security_group.application_alb_sg.id -} - -####### -# Web server -####### - -resource "aws_instance" "application" { -ami = data.aws_ami.base.id -instance_type = "t3.micro" - -user_data = <./` -- Callback URL: `https://teleport../v1/webapi/github/callback` +- Homepage URL: `https://teleport./` +- Callback URL: `https://teleport./v1/webapi/github/callback` and store the resulting Client ID and Secret in AWS Secrets Manager with names as follows: @@ -14,8 +14,8 @@ and store the resulting Client ID and Secret in AWS Secrets Manager with names a Example, if your `` is `adhocdemo.com` and `` is `main` then the values would be: -- Homepage URL: `https://teleport.main.adhocdemo.com/` -- Callback URL: `https://teleport.main.adhocdemo.com/v1/webapi/github/callback` +- Homepage URL: `https://teleport.adhocdemo.com/` +- Callback URL: `https://teleport.adhocdemo.com/v1/webapi/github/callback` - Client ID stored in `main/teleport/github_client_id` - Secret store in `main/teleport/github_secret` @@ -23,7 +23,7 @@ Example, if your `` is `adhocdemo.com` and `` is `main` then t ### Via the webui -Visit `https://teleport../` and use the login with Github button. Approve the oauth request for the app on github. Then select the node to ssh into from the webui. +Visit `https://teleport./` and use the login with Github button. Approve the oauth request for the app on github. Then select the node to ssh into from the webui. ### Via the command line @@ -32,7 +32,7 @@ You can download the client from [Gravitational](https://gravitational.com/telep Decompress and put the `tsh` someplace on your `$PATH`. There's an included `install` script that'll handle that but will also copy over the unneeded `teleport` and `tctl` binaries. **Always do** -Login using `tsh login --proxy=teleport..:443` which should open a browser window and complete the login via GitHub automatically +Login using `tsh login --proxy=teleport.:443` which should open a browser window and complete the login via GitHub automatically #### Then either: @@ -46,7 +46,7 @@ Setup SSH proxying in your `$HOME/.ssh/config` with the snippet after replacing ``` Host teleport - HostName teleport.. + HostName teleport. Port 3023 Host <10.1.>* diff --git a/utilities/teleport/auth.tf b/utilities/teleport/auth.tf index bd7f8cd..cc24bb9 100644 --- a/utilities/teleport/auth.tf +++ b/utilities/teleport/auth.tf @@ -8,16 +8,16 @@ ####### resource "aws_lb" "auth" { - name_prefix = "telep-" + name_prefix = "tp-aut" internal = true load_balancer_type = "network" - subnets = data.aws_subnet.application_subnet.*.id + subnets = var.base.vpc.application[*].id enable_cross_zone_load_balancing = true ip_address_type = "ipv4" tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" name = "lb-teleport-auth-internal" @@ -30,13 +30,13 @@ resource "aws_lb_target_group" "auth" { name_prefix = "telep-" port = 3025 protocol = "TCP" - vpc_id = data.aws_vpc.vpc.id + vpc_id = var.base.vpc.id target_type = "ip" depends_on = [aws_lb.auth] tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" Name = "lb-tg-telport-auth" @@ -58,50 +58,53 @@ resource "aws_lb_listener" "auth" { # Auth instances ####### -data "template_file" "auth_user_data" { - count = var.auth_count - template = file("${path.module}/auth-user-data.tmpl") +resource "aws_instance" "auths" { + count = var.auth_count + ami = var.base.ami.id + instance_type = "t3.nano" + key_name = var.base.ssh_key - vars = { + iam_instance_profile = aws_iam_instance_profile.auth.name + user_data = templatefile("${path.module}/auth-user-data.tmpl", { nodename = "teleport-auth-${count.index}" - cluster_token = random_string.cluster_token.result - region = data.aws_region.current.name + cluster_token = data.aws_secretsmanager_secret_version.cluster_token.secret_string + region = var.base.region.name dynamo_table_name = aws_dynamodb_table.teleport_state.name dynamo_events_table_name = aws_dynamodb_table.teleport_events.name s3_bucket = aws_s3_bucket.recordings.id - cluster_name = var.env + cluster_name = var.base.env client_id = data.aws_secretsmanager_secret_version.github_client_id.secret_string client_secret = data.aws_secretsmanager_secret_version.github_secret.secret_string proxy_domain = aws_route53_record.public.fqdn gh_team = var.gh_team - } -} - -resource "aws_instance" "auths" { - count = var.auth_count - ami = data.aws_ami.base.id - instance_type = "t3.nano" - key_name = var.key_pair - - iam_instance_profile = aws_iam_instance_profile.auth.name - user_data = element(data.template_file.auth_user_data.*.rendered, count.index) + }) associate_public_ip_address = false - subnet_id = element(data.aws_subnet.application_subnet.*.id, count.index) #distribute instances across AZs - vpc_security_group_ids = [aws_security_group.auths.id] + subnet_id = element(var.base.vpc.application[*].id, count.index) + vpc_security_group_ids = [ + var.base.security_groups["jumpbox_nodes"].id, + aws_security_group.auths.id + ] lifecycle { - ignore_changes = [ami] + ignore_changes = [ami] + create_before_destroy = true } credit_specification { cpu_credits = "unlimited" } + root_block_device { + volume_type = "gp2" + volume_size = 20 + delete_on_termination = true + } + tags = { Name = "teleport-auth-${count.index}" app = "teleport" - env = var.env + env = var.base.env terraform = "true" } } @@ -111,7 +114,7 @@ resource "aws_instance" "auths" { resource "aws_lb_target_group_attachment" "auth" { count = var.auth_count target_group_arn = aws_lb_target_group.auth.arn - target_id = element(aws_instance.auths.*.private_ip, count.index) + target_id = aws_instance.auths[count.index].private_ip } ####### @@ -120,10 +123,10 @@ resource "aws_lb_target_group_attachment" "auth" { resource "aws_security_group" "auths" { name_prefix = "teleport-auth-" - vpc_id = data.aws_vpc.vpc.id + vpc_id = var.base.vpc.id tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" Name = "teleport-auth" @@ -135,7 +138,7 @@ resource "aws_security_group_rule" "auth_webui" { from_port = 3025 to_port = 3025 protocol = "tcp" - cidr_blocks = [data.aws_vpc.vpc.cidr_block] + cidr_blocks = [var.base.vpc.cidr_block] security_group_id = aws_security_group.auths.id } @@ -151,32 +154,23 @@ resource "aws_security_group_rule" "auth_egress" { security_group_id = aws_security_group.auths.id } -# Support for emergency jumpbox -resource "aws_security_group_rule" "jumpbox_auth" { - type = "ingress" - from_port = 22 - to_port = 22 - protocol = "tcp" - source_security_group_id = data.aws_security_group.jumpbox.id - - security_group_id = aws_security_group.auths.id -} - ####### # DynamoDB table to store cluster state and audit events # TODO(bob) enable autoscaling of dynamodb capacity # cf. https://github.com/gravitational/teleport/blob/master/examples/aws/terraform/dynamo.tf ####### -// Dynamodb is used as a backend for auth servers, -// and only auth servers need access to the tables -// all other components are stateless. +# Dynamodb is used as a backend for auth servers, +# and only auth servers need access to the tables +# all other components are stateless. resource "aws_dynamodb_table" "teleport_state" { - name = "${var.env}-teleport-state" - read_capacity = 5 - write_capacity = 5 - hash_key = "HashKey" - range_key = "FullPath" + name = "${var.base.env}-teleport-state" + read_capacity = 5 + write_capacity = 5 + hash_key = "HashKey" + range_key = "FullPath" + stream_enabled = true + stream_view_type = "NEW_IMAGE" server_side_encryption { enabled = true @@ -205,7 +199,7 @@ resource "aws_dynamodb_table" "teleport_state" { } tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" Name = "teleport-auth-state" @@ -214,7 +208,7 @@ resource "aws_dynamodb_table" "teleport_state" { // Dynamodb events table stores events resource "aws_dynamodb_table" "teleport_events" { - name = "${var.env}-teleport-events" + name = "${var.base.env}-teleport-events" read_capacity = 5 write_capacity = 5 hash_key = "SessionID" @@ -266,7 +260,7 @@ resource "aws_dynamodb_table" "teleport_events" { } tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" Name = "teleport-auth-audit" @@ -282,21 +276,22 @@ resource "random_id" "unique_bucket" { } resource "aws_s3_bucket" "recordings" { - bucket = "${var.env}-teleport-${lower(random_id.unique_bucket.hex)}" + bucket = "${var.base.env}-teleport-${lower(random_id.unique_bucket.hex)}" acl = "private" force_destroy = true server_side_encryption_configuration { rule { apply_server_side_encryption_by_default { - kms_master_key_id = data.aws_kms_key.main.arn #TODO(bob) switch to unique, restricted key here? - sse_algorithm = "aws:kms" + kms_master_key_id = var.base.key.arn + #TODO(bob) switch to unique, restricted key here? + sse_algorithm = "aws:kms" } } } tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" } @@ -307,13 +302,13 @@ resource "aws_s3_bucket" "recordings" { ####### resource "aws_iam_instance_profile" "auth" { - name = "${var.env}-teleport-auth" + name = "${var.base.env}-teleport-auth" role = aws_iam_role.auth.name } // Auth instance profile and roles resource "aws_iam_role" "auth" { - name = "${var.env}-teleport-auth" + name = "${var.base.env}-teleport-auth" assume_role_policy = < proxy -resource "aws_security_group" "proxy_lb" { - name_prefix = "teleport-proxy-lb-" - vpc_id = data.aws_vpc.vpc.id + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.proxy.arn + } +} + +resource "aws_lb_target_group" "proxy" { + name_prefix = "in-tls" + port = 3023 + protocol = "TCP" + vpc_id = var.base.vpc.id + + # Use IP to support Fargate clusters + target_type = "ip" + + # Health check only on web port to prevent logs filling with connection resets + health_check { + protocol = "TCP" + port = 3080 + } + + depends_on = [aws_lb.nlb] tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" - Name = "world->teleport-proxy" + Name = "teleport-proxy-inbound-proxy" } } -resource "aws_security_group_rule" "lb_webui_ingress" { - type = "ingress" - from_port = 443 - to_port = 443 - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] +# SSH outbound reverse tunnel proxy +resource "aws_lb_listener" "tunnel" { + load_balancer_arn = aws_lb.nlb.arn + port = 3024 + protocol = "TCP" - security_group_id = aws_security_group.proxy_lb.id + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.tunnel.arn + } } -resource "aws_security_group_rule" "lb_client_ingress" { - type = "ingress" - from_port = 3080 - to_port = 3080 - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] +resource "aws_lb_target_group" "tunnel" { + name_prefix = "in-tls" + port = 3024 + protocol = "TCP" + vpc_id = var.base.vpc.id - security_group_id = aws_security_group.proxy_lb.id -} + # Use IP to support Fargate clusters + target_type = "ip" -resource "aws_security_group_rule" "lb_ssh_ingress" { - type = "ingress" - from_port = 3023 - to_port = 3023 - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] + # Health check only on web port to prevent logs filling with connection resets + health_check { + protocol = "TCP" + port = 3080 + } - security_group_id = aws_security_group.proxy_lb.id -} + depends_on = [aws_lb.nlb] -resource "aws_security_group_rule" "lb_cluster_ingress" { - type = "ingress" - from_port = 3024 - to_port = 3024 - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] + tags = { + env = var.base.env + terraform = "true" + app = "teleport" + Name = "teleport-proxy-reverse-tunnel" + } +} - security_group_id = aws_security_group.proxy_lb.id +resource "aws_lb_target_group_attachment" "https" { + count = length(aws_instance.proxies[*].private_ip) + target_group_arn = aws_lb_target_group.https.arn + target_id = aws_instance.proxies[count.index].private_ip } -resource "aws_security_group_rule" "lb_egress" { - type = "egress" - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] +resource "aws_lb_target_group_attachment" "proxy" { + count = length(aws_instance.proxies[*].private_ip) + target_group_arn = aws_lb_target_group.proxy.arn + target_id = aws_instance.proxies[count.index].private_ip +} - security_group_id = aws_security_group.proxy_lb.id +resource "aws_lb_target_group_attachment" "tunnel" { + count = length(aws_instance.proxies[*].private_ip) + target_group_arn = aws_lb_target_group.tunnel.arn + target_id = aws_instance.proxies[count.index].private_ip } ####### # Proxy instances ####### -data "template_file" "user_data" { - count = var.proxy_count - template = file("${path.module}/proxy-user-data.tmpl") - - vars = { - nodename = "teleport-proxy-${count.index}" - cluster_token = random_string.cluster_token.result - proxy_domain = aws_route53_record.public.fqdn - } -} resource "aws_instance" "proxies" { count = var.proxy_count - ami = data.aws_ami.base.id + ami = var.base.ami.id instance_type = "t3.micro" - key_name = var.key_pair + key_name = var.base.ssh_key - user_data = element(data.template_file.user_data.*.rendered, count.index) + user_data = templatefile("${path.module}/proxy-user-data.tmpl", { + nodename = "teleport-proxy-${count.index}" + cluster_token = data.aws_secretsmanager_secret_version.cluster_token.secret_string + proxy_domain = aws_route53_record.public.fqdn + }) associate_public_ip_address = false - subnet_id = element(data.aws_subnet.application_subnet.*.id, count.index) #distribute instances across AZs - vpc_security_group_ids = [aws_security_group.proxies.id] + + subnet_id = element(var.base.vpc.application[*].id, count.index) + vpc_security_group_ids = [ + var.base.security_groups["jumpbox_nodes"].id, + var.base.security_groups["teleport_proxies"].id, + ] lifecycle { - ignore_changes = [ami] + ignore_changes = [ami] + create_before_destroy = true } + root_block_device { + volume_type = "gp2" + volume_size = 20 + delete_on_termination = true + } + + depends_on = [aws_instance.auths] + credit_specification { cpu_credits = "unlimited" } @@ -167,84 +214,7 @@ resource "aws_instance" "proxies" { tags = { Name = "teleport-proxy-${count.index}" app = "teleport" - env = var.env - terraform = "true" - } -} - -# Add to target group to attach to LB - -resource "aws_elb_attachment" "proxy_ssh" { - count = var.proxy_count - elb = aws_elb.proxy.id - instance = element(aws_instance.proxies.*.id, count.index) -} - -####### -### Security group for proxy instances -####### - -resource "aws_security_group" "proxies" { - name_prefix = "teleport-proxies-" - vpc_id = data.aws_vpc.vpc.id - - tags = { - env = var.env + env = var.base.env terraform = "true" - app = "teleport" - Name = "teleport-proxies" } } - -resource "aws_security_group_rule" "proxy_webui" { - type = "ingress" - from_port = 3080 - to_port = 3080 - protocol = "tcp" - source_security_group_id = aws_security_group.proxy_lb.id - - security_group_id = aws_security_group.proxies.id -} - -resource "aws_security_group_rule" "proxy_ssh" { - type = "ingress" - from_port = 3023 - to_port = 3023 - protocol = "tcp" - source_security_group_id = aws_security_group.proxy_lb.id - - security_group_id = aws_security_group.proxies.id -} - -resource "aws_security_group_rule" "proxy_cluster" { - type = "ingress" - from_port = 3024 - to_port = 3024 - protocol = "tcp" - source_security_group_id = aws_security_group.proxy_lb.id - - security_group_id = aws_security_group.proxies.id -} - -# Must allow talking to the world to call out to AWS APIs -resource "aws_security_group_rule" "proxy_egress" { - type = "egress" - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - - security_group_id = aws_security_group.proxies.id -} - -# Support for emergency jumpbox -resource "aws_security_group_rule" "jumpbox_proxy" { - type = "ingress" - from_port = 22 - to_port = 22 - protocol = "tcp" - source_security_group_id = data.aws_security_group.jumpbox.id - - security_group_id = aws_security_group.proxies.id -} - diff --git a/utilities/teleport/variables.tf b/utilities/teleport/variables.tf index 921c910..f862f9a 100644 --- a/utilities/teleport/variables.tf +++ b/utilities/teleport/variables.tf @@ -1,27 +1,21 @@ -variable "env" { - description = "the name of the environment, e.g. \"testing\". it must be unique in the account." -} - -variable "domain_name" { - description = "the external domain name for reaching the public resources. must have a certificate in ACM associated with it." +variable "base" { + description = "an object representing the outputs of the base module from the tf repo" } variable "proxy_count" { - description = "number of proxy instances to create, for HA use 3 to spread across AZs" - default = "1" + type = number + description = "OPTIONAL: number of proxy instances to create, for HA use 3 to spread across AZs" + default = 1 } variable "auth_count" { - description = "number of proxy instances to create, for HA use 3 to spread across AZs" - default = "1" -} - -variable "key_pair" { - description = "the name of the key pair that provides access to the nodes if jumpbox is used" - default = "infrastructure" + type = number + description = "OPTIONAL: number of proxy instances to create, for HA use 3 to spread across AZs" + default = 1 } variable "gh_team" { + type = string description = "OPTIONAL: the Github team to provide access to via Teleport" default = "infrastructure-team" } diff --git a/utilities/teleport/versions.tf b/utilities/teleport/versions.tf deleted file mode 100644 index ac97c6a..0000000 --- a/utilities/teleport/versions.tf +++ /dev/null @@ -1,4 +0,0 @@ - -terraform { - required_version = ">= 0.12" -} diff --git a/utilities/teleport_subcluster/auth-user-data.tmpl b/utilities/teleport_subcluster/auth-user-data.tmpl index 16ec854..a5ebcb4 100644 --- a/utilities/teleport_subcluster/auth-user-data.tmpl +++ b/utilities/teleport_subcluster/auth-user-data.tmpl @@ -63,7 +63,7 @@ spec: EOF # Sleep to allow time for the authentication service to start up and then retry a few times -sleep 60 -for i in {1..5}; do sudo -u teleport /usr/local/bin/tctl create /var/lib/teleport/cluster.yaml && break || sleep 60; done +sleep 120 +for i in {1..15}; do sudo -u teleport /usr/local/bin/tctl create /var/lib/teleport/cluster.yaml && break || sleep 60; done echo "Teleport install complete" diff --git a/utilities/teleport_subcluster/auth.tf b/utilities/teleport_subcluster/auth.tf index 31a5ef1..906a02c 100644 --- a/utilities/teleport_subcluster/auth.tf +++ b/utilities/teleport_subcluster/auth.tf @@ -8,16 +8,16 @@ ####### resource "aws_lb" "auth" { - name_prefix = "telep-" + name_prefix = "tp-aut" internal = true load_balancer_type = "network" - subnets = data.aws_subnet.application_subnet.*.id + subnets = var.base.vpc.application[*].id enable_cross_zone_load_balancing = true ip_address_type = "ipv4" tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" name = "lb-teleport-auth-internal" @@ -30,13 +30,13 @@ resource "aws_lb_target_group" "auth" { name_prefix = "telep-" port = 3025 protocol = "TCP" - vpc_id = data.aws_vpc.vpc.id + vpc_id = var.base.vpc.id target_type = "ip" depends_on = [aws_lb.auth] tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" Name = "lb-tg-telport-auth" @@ -58,49 +58,52 @@ resource "aws_lb_listener" "auth" { # Auth instances ####### -data "template_file" "auth_user_data" { - count = var.auth_count - template = file("${path.module}/auth-user-data.tmpl") +resource "aws_instance" "auths" { + count = var.auth_count + ami = var.base.ami.id + instance_type = "t3.nano" + key_name = var.base.ssh_key - vars = { + iam_instance_profile = aws_iam_instance_profile.auth.name + user_data = templatefile("${path.module}/auth-user-data.tmpl", { nodename = "teleport-auth-${count.index}" - cluster_token = random_string.cluster_token.result - region = data.aws_region.current.name + cluster_token = data.aws_secretsmanager_secret_version.cluster_token.secret_string + region = var.base.region.name dynamo_table_name = aws_dynamodb_table.teleport_state.name dynamo_events_table_name = aws_dynamodb_table.teleport_events.name s3_bucket = aws_s3_bucket.recordings.id - cluster_name = var.env + cluster_name = var.base.env main_cluster = var.main_cluster main_cluster_token = data.aws_secretsmanager_secret_version.main_cluster_token.secret_string - main_cluster_url = "teleport.${var.domain_name}" - } -} - -resource "aws_instance" "auths" { - count = var.auth_count - ami = data.aws_ami.base.id - instance_type = "t3.nano" - key_name = var.key_pair - - iam_instance_profile = aws_iam_instance_profile.auth.name - user_data = element(data.template_file.auth_user_data.*.rendered, count.index) + main_cluster_url = "teleport.${var.base.domain_name}" + }) associate_public_ip_address = false - subnet_id = element(data.aws_subnet.application_subnet.*.id, count.index) #distribute instances across AZs - vpc_security_group_ids = [aws_security_group.auths.id] + subnet_id = element(var.base.vpc.application[*].id, count.index) + vpc_security_group_ids = [ + var.base.security_groups["jumpbox_nodes"].id, + aws_security_group.auths.id + ] lifecycle { - ignore_changes = [ami] + ignore_changes = [ami] + create_before_destroy = true } credit_specification { cpu_credits = "unlimited" } + root_block_device { + volume_type = "gp2" + volume_size = 20 + delete_on_termination = true + } + tags = { Name = "teleport-auth-${count.index}" app = "teleport" - env = var.env + env = var.base.env terraform = "true" } } @@ -110,7 +113,7 @@ resource "aws_instance" "auths" { resource "aws_lb_target_group_attachment" "auth" { count = var.auth_count target_group_arn = aws_lb_target_group.auth.arn - target_id = element(aws_instance.auths.*.private_ip, count.index) + target_id = aws_instance.auths[count.index].private_ip } ####### @@ -119,10 +122,10 @@ resource "aws_lb_target_group_attachment" "auth" { resource "aws_security_group" "auths" { name_prefix = "teleport-auth-" - vpc_id = data.aws_vpc.vpc.id + vpc_id = var.base.vpc.id tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" Name = "teleport-auth" @@ -134,7 +137,7 @@ resource "aws_security_group_rule" "auth_webui" { from_port = 3025 to_port = 3025 protocol = "tcp" - cidr_blocks = [data.aws_vpc.vpc.cidr_block] + cidr_blocks = [var.base.vpc.cidr_block] security_group_id = aws_security_group.auths.id } @@ -150,17 +153,6 @@ resource "aws_security_group_rule" "auth_egress" { security_group_id = aws_security_group.auths.id } -# Support for emergency jumpbox -resource "aws_security_group_rule" "jumpbox_auth" { - type = "ingress" - from_port = 22 - to_port = 22 - protocol = "tcp" - source_security_group_id = data.aws_security_group.jumpbox.id - - security_group_id = aws_security_group.auths.id -} - ####### # DynamoDB table to store cluster state and audit events # TODO(bob) enable autoscaling of dynamodb capacity @@ -171,11 +163,13 @@ resource "aws_security_group_rule" "jumpbox_auth" { // and only auth servers need access to the tables // all other components are stateless. resource "aws_dynamodb_table" "teleport_state" { - name = "${var.env}-teleport-state" - read_capacity = 5 - write_capacity = 5 - hash_key = "HashKey" - range_key = "FullPath" + name = "${var.base.env}-teleport-state" + read_capacity = 5 + write_capacity = 5 + hash_key = "HashKey" + range_key = "FullPath" + stream_enabled = true + stream_view_type = "NEW_IMAGE" server_side_encryption { enabled = true @@ -204,7 +198,7 @@ resource "aws_dynamodb_table" "teleport_state" { } tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" Name = "teleport-auth-state" @@ -213,7 +207,7 @@ resource "aws_dynamodb_table" "teleport_state" { // Dynamodb events table stores events resource "aws_dynamodb_table" "teleport_events" { - name = "${var.env}-teleport-events" + name = "${var.base.env}-teleport-events" read_capacity = 5 write_capacity = 5 hash_key = "SessionID" @@ -265,7 +259,7 @@ resource "aws_dynamodb_table" "teleport_events" { } tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" Name = "teleport-auth-audit" @@ -281,21 +275,21 @@ resource "random_id" "unique_bucket" { } resource "aws_s3_bucket" "recordings" { - bucket = "${var.env}-teleport-${lower(random_id.unique_bucket.hex)}" + bucket = "${var.base.env}-teleport-${lower(random_id.unique_bucket.hex)}" acl = "private" force_destroy = true server_side_encryption_configuration { rule { apply_server_side_encryption_by_default { - kms_master_key_id = data.aws_kms_key.main.arn #TODO(bob) switch to unique, restricted key here? + kms_master_key_id = var.base.key.arn #TODO(bob) switch to unique, restricted key here? sse_algorithm = "aws:kms" } } } tags = { - env = var.env + env = var.base.env terraform = "true" app = "teleport" } @@ -306,13 +300,13 @@ resource "aws_s3_bucket" "recordings" { ####### resource "aws_iam_instance_profile" "auth" { - name = "${var.env}-teleport-auth" + name = "${var.base.env}-teleport-auth" role = aws_iam_role.auth.name } // Auth instance profile and roles resource "aws_iam_role" "auth" { - name = "${var.env}-teleport-auth" + name = "${var.base.env}-teleport-auth" assume_role_policy = <