diff --git a/.gitignore b/.gitignore index 0ecf69f..74b81f6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ terraform.tfstate terraform.tfstate* .terraform.lock.hcl -terraform.tfvars \ No newline at end of file +terraform.tfvars + +.idea/ \ No newline at end of file diff --git a/aws/asg/alb.tf b/aws/asg/alb.tf index 6a4d061..756a949 100644 --- a/aws/asg/alb.tf +++ b/aws/asg/alb.tf @@ -68,5 +68,5 @@ resource "aws_lb_listener_rule" "static" { resource "aws_autoscaling_attachment" "asg" { autoscaling_group_name = aws_autoscaling_group.asg.name - lb_target_group_arn = aws_lb_target_group.http.arn + lb_target_group_arn = aws_lb_target_group.http.arn } \ No newline at end of file diff --git a/aws/asg/asg.tf b/aws/asg/asg.tf index 5ca943c..d61e5eb 100644 --- a/aws/asg/asg.tf +++ b/aws/asg/asg.tf @@ -1,8 +1,8 @@ resource "aws_launch_template" "template" { - image_id = var.ami - instance_type = "t3.nano" - user_data = filebase64("userdata.tpl") - vpc_security_group_ids = [ aws_security_group.allow_http.id ] + image_id = var.ami + instance_type = "t3.nano" + user_data = filebase64("userdata.tpl") + vpc_security_group_ids = [aws_security_group.allow_http.id] } resource "aws_autoscaling_group" "asg" { @@ -31,4 +31,4 @@ resource "aws_autoscaling_group" "asg" { triggers = ["tag"] } } - + diff --git a/aws/asg/security_group.tf b/aws/asg/security_group.tf index 275a32a..46d3754 100644 --- a/aws/asg/security_group.tf +++ b/aws/asg/security_group.tf @@ -4,11 +4,11 @@ resource "aws_security_group" "allow_http" { vpc_id = var.vpc ingress { - description = "Open HTTP" - from_port = 80 - to_port = 80 - protocol = "tcp" - cidr_blocks = [ "0.0.0.0/0" ] + description = "Open HTTP" + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] } egress { diff --git a/aws/asg/variable.tf b/aws/asg/variable.tf index dcb841e..c20d074 100644 --- a/aws/asg/variable.tf +++ b/aws/asg/variable.tf @@ -21,8 +21,8 @@ variable "ami" { default = "ami-0efcece6bed30fd98" } variable "availability_zones" { - type = list(string) - default = [ "us-west-2c","us-west-2b" ] + type = list(string) + default = ["us-west-2c", "us-west-2b"] } variable "hostedzone" { type = string diff --git a/aws/ec2/alb.tf b/aws/ec2/alb.tf index 1c5de7d..5bb8a70 100644 --- a/aws/ec2/alb.tf +++ b/aws/ec2/alb.tf @@ -35,6 +35,15 @@ resource "aws_security_group" "http" { ipv6_cidr_blocks = ["::/0"] } + ingress { + description = "Allow HTTPS traffic" + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + ipv6_cidr_blocks = ["::/0"] + } + egress { from_port = 0 to_port = 0 @@ -74,3 +83,17 @@ resource "aws_lb_listener_rule" "static" { } } } + +resource "aws_lb_listener" "https" { + count = var.alb_certificate_arn != null ? 1 : 0 + load_balancer_arn = var.alb_arn == null ? aws_lb.alb[0].arn : var.alb_arn + port = "443" + protocol = "HTTPS" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = var.alb_certificate_arn + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.http.arn + } +} diff --git a/aws/ec2/ec2.tf b/aws/ec2/ec2.tf index 80c3778..14f3f08 100644 --- a/aws/ec2/ec2.tf +++ b/aws/ec2/ec2.tf @@ -1,6 +1,22 @@ # Create instance that serves traffic on port 80 (nginx) + +data "aws_ami" "ubuntu" { + most_recent = true + owners = ["099720109477"] # Canonical + + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] + } + + filter { + name = "virtualization-type" + values = ["hvm"] + } +} + resource "aws_instance" "ec2" { - ami = var.ami + ami = var.ami != null ? var.ami : data.aws_ami.ubuntu.image_id instance_type = "t3.micro" user_data = file("userdata.tpl") vpc_security_group_ids = [aws_security_group.allow_http.id] @@ -8,4 +24,4 @@ resource "aws_instance" "ec2" { tags = { Name = "${local.name}-instance" } -} \ No newline at end of file +} diff --git a/aws/ec2/main.tf b/aws/ec2/main.tf index 90d88f4..316af56 100644 --- a/aws/ec2/main.tf +++ b/aws/ec2/main.tf @@ -1,7 +1,7 @@ locals { name = var.name == null ? random_pet.name.id : lower(var.name) # use route53 domain if given, otherwise fallback to default ALB DNS name - lb_hostname = var.hostedzone == null ? aws_lb.alb[0].dns_name : "${local.name}.${data.aws_route53_zone.zone[0].name}" + lb_hostname = var.alb_route53_dns_name != null ? var.alb_route53_dns_name : var.hostedzone == null ? aws_lb.alb[0].dns_name : "${local.name}.${data.aws_route53_zone.zone[0].name}" tags = { lb_hostname = local.lb_hostname } diff --git a/aws/ec2/output.tf b/aws/ec2/output.tf index dcbfcf6..ccac1a8 100644 --- a/aws/ec2/output.tf +++ b/aws/ec2/output.tf @@ -1,19 +1,19 @@ output "name" { - value = local.name + value = local.name description = "Name of the ec2 instance" } output "ec2" { - value = aws_instance.ec2.arn + value = aws_instance.ec2.arn description = "ARN of the ec2 instance" } output "rule" { - value = "https://app.harness.io/ng/account/${data.harness_platform_current_account.current.id}/ce/autostopping-rules/rule/${harness_autostopping_rule_vm.rule.id}" + value = "https://app.harness.io/ng/account/${data.harness_platform_current_account.current.id}/ce/autostopping-rules/rule/${harness_autostopping_rule_vm.rule.id}" description = "Link to autostopping rule in Harness" } output "url" { - value = harness_autostopping_rule_vm.rule.custom_domains[0] + value = harness_autostopping_rule_vm.rule.custom_domains[0] description = "URL for the application" } \ No newline at end of file diff --git a/aws/ec2/readme.md b/aws/ec2/readme.md index 62b8c09..eca3fc6 100644 --- a/aws/ec2/readme.md +++ b/aws/ec2/readme.md @@ -20,6 +20,57 @@ Provision an EC2 instance, alb, and create an autostopping rule for the instance ![image](https://github.com/wings-software/AutoStoppingLab/assets/7338312/ab1a3163-3657-4244-833b-7e8ccb4b176b) +### Patterns + +#### http + +create an ec2, alb, and autostopping rule using http and the default alb dns name: +``` +region = "us-west-2" + +# common networking +vpc = "vpc-02767cb7b8b634d54" + +# ec2 instance +ec2_subnet = "subnet-022b0cf63cfa2b43e" + +# alb +alb_subnets = ["subnet-0afa8a1877a19c619", "subnet-08515090d18fe4e56"] + +#harness +harness_cloud_connector_id = "harness_impeng_play_ccm" +``` + +to use a custom domain, simple pass your route53 hosted zone id: +``` +hostedzone = "Z00081583ARZJ9LTKZHRI" +``` + +#### https + +create an ec2, alb, and autostopping rule using http and https using a custom domain: +``` +region = "us-west-2" + +# common networking +vpc = "vpc-02767cb7b8b634d54" + +# ec2 instance +ec2_subnet = "subnet-022b0cf63cfa2b43e" + +# alb +alb_subnets = ["subnet-0afa8a1877a19c619", "subnet-08515090d18fe4e56"] + +# https information +alb_certificate_arn = "arn:aws:acm:us-west-2:664418987337:certificate/bfb75fd2-a1d5-4de4-ab86-b2bc36983097" +alb_route53_dns_name = "asec2albtest.isehrns.rileysnyder.dev" + +#harness +harness_cloud_connector_id = "harness_impeng_play_ccm" +``` + +This requires that you have a certificate already created for the `alb_route53_dns_name` domain in your account + ## Requirements | Name | Version | diff --git a/aws/ec2/rule.tf b/aws/ec2/rule.tf index 2fe2623..9ef3905 100644 --- a/aws/ec2/rule.tf +++ b/aws/ec2/rule.tf @@ -1,8 +1,20 @@ +locals { + http = { + protocol = "http" + port = "80" + } + https = { + protocol = "https" + port = "443" + } + rule_routing = var.alb_certificate_arn != null ? [local.http, local.https] : [local.http] +} + # Import ALB and create autostopping rule resource "harness_autostopping_aws_alb" "harness_alb" { name = "${local.name}-lb" cloud_connector_id = var.harness_cloud_connector_id - host_name = local.lb_hostname + host_name = var.alb_route53_dns_name != null ? var.alb_route53_dns_name : local.lb_hostname alb_arn = var.alb_arn == null ? aws_lb.alb[0].arn : var.alb_arn region = var.region vpc = var.vpc @@ -10,6 +22,7 @@ resource "harness_autostopping_aws_alb" "harness_alb" { # setting hosted zone is not needed when route53 is already set up externally # route53_hosted_zone_id = "/hostedzone/${var.hostedzone}" delete_cloud_resources_on_destroy = false + certificate_id = var.alb_certificate_arn } resource "harness_autostopping_rule_vm" "rule" { @@ -22,12 +35,15 @@ resource "harness_autostopping_rule_vm" "rule" { } http { proxy_id = harness_autostopping_aws_alb.harness_alb.identifier - routing { - source_protocol = "http" - target_protocol = "http" - source_port = 80 - target_port = 80 - action = "forward" + dynamic "routing" { + for_each = local.rule_routing + content { + source_protocol = routing.value["protocol"] + target_protocol = routing.value["protocol"] + source_port = routing.value["port"] + target_port = routing.value["port"] + action = "forward" + } } health { protocol = "http" diff --git a/aws/ec2/security_group.tf b/aws/ec2/security_group.tf index 3b4e2db..7522231 100644 --- a/aws/ec2/security_group.tf +++ b/aws/ec2/security_group.tf @@ -19,6 +19,14 @@ resource "aws_security_group" "allow_http" { cidr_blocks = ["0.0.0.0/0"] } + ingress { + description = "Open HTTPS" + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + egress { from_port = 0 to_port = 0 diff --git a/aws/ec2/terraform.tfvars.example b/aws/ec2/terraform.tfvars.example index 274fd07..4a07eba 100644 --- a/aws/ec2/terraform.tfvars.example +++ b/aws/ec2/terraform.tfvars.example @@ -1,13 +1,18 @@ -# name = "stoptest" +# stack name +name = "hns-1035" +region = "us-east-1" -alb_subnets = ["subnet-0f91c1012f9ad74c5", "subnet-0c4c1bc4cacd3cd4d"] +# common networking +vpc = "vpc-0fxxxxxxxxxxxxx" -ec2_subnet = "subnet-08f14e7142d333595" +# ec2 instance +ec2_subnet = "subnet-yyyyyyyyy" +ami = "ami-0e35ddab05955cf57" -vpc = "vpc-078b51c6cbc5581f1" +# alb +alb_subnets = ["subnet-yyyyyyyyy", "subnet-xxxxxxxx"] +alb_certificate_arn = "arn:aws:acm:ap-south-1:xxxxxxxxxxx:certificate/08bcd2b0-3e84-40fd-bf49-37ce43644068" -ami = "ami-075686beab831bb7f" - -# hostedzone = "Z05277053H89HS3J9I2TS" - -harness_cloud_connector_id = "cs" \ No newline at end of file +#harness +harness_cloud_connector_id = "myconn07" +alb_route53_dns_name = "as60.mynewdomain.com" diff --git a/aws/ec2/userdata.tpl b/aws/ec2/userdata.tpl index dcea9c0..94481c7 100644 --- a/aws/ec2/userdata.tpl +++ b/aws/ec2/userdata.tpl @@ -1,3 +1,52 @@ #!/bin/bash -sudo apt-get update -y && -sudo apt-get install -y nginx \ No newline at end of file + +# Update & install nginx and openssl +sudo apt-get update -y +sudo apt-get install -y nginx openssl + +# Create self-signed SSL certificate +sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout /etc/ssl/private/nginx-selfsigned.key \ + -out /etc/ssl/certs/nginx-selfsigned.crt \ + -subj "/CN=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)" + +# Write nginx config with HTTP 200 message and HTTPS static file +sudo tee /etc/nginx/conf.d/default.conf > /dev/null <<'EOF' +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + + location / { + return 200 'Hello from Nginx over HTTP port 80'; + add_header Content-Type text/plain; + } +} + +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + server_name _; + + ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; + ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; + + location / { + return 200 'Hello from Nginx over HTTPS port 443'; + add_header Content-Type text/plain; + } +} +EOF + +# Create HTTPS content +echo "Hello from Nginx over HTTPS port 443" | sudo tee /var/www/html/index.html +sudo chown www-data:www-data /var/www/html/index.html + +# Remove default site +rm /etc/nginx/sites-enabled/default + +# Test and reload nginx +sudo nginx -t && sudo systemctl reload nginx + +# Done +echo "✅ Nginx is configured to serve HTTP and HTTPS with custom messages" diff --git a/aws/ec2/variable.tf b/aws/ec2/variable.tf index 98d7458..3038267 100644 --- a/aws/ec2/variable.tf +++ b/aws/ec2/variable.tf @@ -47,3 +47,15 @@ variable "harness_cloud_connector_id" { type = string default = "AWS CCM connector for target AWS account" } + +variable "alb_certificate_arn" { + type = string + description = "Alb certificate ARN" + default = null +} + +variable "alb_route53_dns_name" { + type = string + description = "alb dns name added in route 53" + default = null +} diff --git a/azure/provider.tf b/azure/provider.tf index bb2540e..93100eb 100644 --- a/azure/provider.tf +++ b/azure/provider.tf @@ -1,7 +1,7 @@ terraform { required_providers { harness = { - source = "harness/harness" + source = "harness/harness" version = "0.28.3" } } diff --git a/azure/rule.tf b/azure/rule.tf index 6e9d4f6..aff82d1 100644 --- a/azure/rule.tf +++ b/azure/rule.tf @@ -14,8 +14,8 @@ resource "harness_autostopping_rule_vm" "vm" { cloud_connector_id = var.cloud_connector_id idle_time_mins = 10 filter { - vm_ids = ["/subscriptions/${var.subscription_id}/resourceGroups/${var.resource_group}/providers/Microsoft.Compute/virtualMachines/${var.instance_id}" -] + vm_ids = ["/subscriptions/${var.subscription_id}/resourceGroups/${var.resource_group}/providers/Microsoft.Compute/virtualMachines/${var.instance_id}" + ] regions = [var.region] } http { @@ -36,5 +36,5 @@ resource "harness_autostopping_rule_vm" "vm" { status_code_to = 299 } } - custom_domains = [ "35.239.247.160.nip.io" ] + custom_domains = ["35.239.247.160.nip.io"] } \ No newline at end of file diff --git a/gcp/provider.tf b/gcp/provider.tf index a05fcbb..14ded5f 100644 --- a/gcp/provider.tf +++ b/gcp/provider.tf @@ -7,8 +7,8 @@ terraform { } } provider "google" { - project = "ccm-play" - region = "us-central1" + project = "ccm-play" + region = "us-central1" } provider "harness" { account_id = var.account_id diff --git a/gcp/rule.tf b/gcp/rule.tf index 4dc4b65..71ac6a7 100644 --- a/gcp/rule.tf +++ b/gcp/rule.tf @@ -37,5 +37,5 @@ resource "harness_autostopping_rule_vm" "vm" { status_code_to = 299 } } - custom_domains = [ "35.239.247.160.nip.io" ] + custom_domains = ["35.239.247.160.nip.io"] } \ No newline at end of file diff --git a/k8s/provider.tf b/k8s/provider.tf index c9422ca..95e879d 100644 --- a/k8s/provider.tf +++ b/k8s/provider.tf @@ -1,5 +1,5 @@ provider "kubernetes" { - config_path = "~/.kube/config" + config_path = "~/.kube/config" } provider "kubectl" { apply_retry_count = 15 diff --git a/k8s/rule.tf b/k8s/rule.tf index f1f4613..4cf9bed 100644 --- a/k8s/rule.tf +++ b/k8s/rule.tf @@ -1,4 +1,4 @@ resource "kubectl_manifest" "rule" { - yaml_body = file("rule.yaml") + yaml_body = file("rule.yaml") validate_schema = false } \ No newline at end of file diff --git a/k8s/variables.tf b/k8s/variables.tf index da29ef0..555aec7 100644 --- a/k8s/variables.tf +++ b/k8s/variables.tf @@ -1,12 +1,12 @@ variable "namespace" { - type = string + type = string default = "default" } variable "name" { - type = string + type = string default = "tf-test" } variable "k8s_connector_id" { - type = string - default = "nknautostoptest" + type = string + default = "nknautostoptest" } \ No newline at end of file