Commit 71fef50d authored by Aleksander Cynarski's avatar Aleksander Cynarski
Browse files

init separate terraform module

parent fdcc7921
resource "aws_lb" "default" {
load_balancer_type = "application"
name = "${var.name}-${var.env}-alb"
subnets = var.jz_vpc.subnets.*.id
security_groups = [
aws_security_group.alb.id,
]
enable_deletion_protection = true
tags = {
Name = "${var.name}-${var.env}-alb"
Env = var.env
}
lifecycle {
ignore_changes = [
tags,
]
}
}
locals {
# Mapping of ALB listeners from config port_mapping.
listeners = {
for i, z in var.port_mapping:
z.alb_port => {
app_port = z.app_port
app_schema = upper(z.app_schema)
alb_port = z.alb_port
alb_schema = upper(z.alb_schema)
is_secure = upper(z.alb_schema) == "HTTPS" || upper(z.alb_schema) == "SSL"
host = lookup(z, "host", "")
}...
}
# Mapping of host-based-routed 443 (HTTPS) records.
https_with_hosts = {
for i,z in lookup(local.listeners, "443", []):
i => {
app_port = z.app_port
host = z.host
}
if lookup(z, "host", "") != ""
}
# Mapping of ALB target groups from config port_mapping.
target_groups = {
for i, z in var.port_mapping:
z.app_port => {
app_port = z.app_port
app_schema = upper(z.app_schema)
}...
}
# TGs * instances
instance_ids_flatten = flatten([
var.jz_swarm_project.instance_ids.leader,
var.jz_swarm_project.instance_ids.managers.*,
var.jz_swarm_project.instance_ids.workers.*]
)
target_group_arns = values(aws_lb_target_group.default).*.arn
tg_x_instance = setproduct(local.target_group_arns, local.instance_ids_flatten)
# SSL Cert arn
ssl_cert_arn = var.ssl_cert_arn != null ? var.ssl_cert_arn : data.aws_acm_certificate.default[0].arn
}
resource "aws_lb_listener" "default" {
for_each = local.listeners
load_balancer_arn = aws_lb.default.arn
port = each.value[0].alb_port
protocol = each.value[0].alb_schema
ssl_policy = each.value[0].is_secure ? "ELBSecurityPolicy-2016-08" : null
certificate_arn = each.value[0].is_secure ? local.ssl_cert_arn : null
dynamic "default_action" {
for_each = length(compact([for i,z in each.value: i if z.host != ""])) == 0 ? [1] : []
content {
type = "forward"
target_group_arn = aws_lb_target_group.default[each.value[0].app_port].arn
}
}
dynamic "default_action" {
for_each = length(compact([for i,z in each.value: i if z.host != ""])) > 0 ? [1] : []
content {
type = "fixed-response"
fixed_response {
content_type = "text/plain"
status_code = "404"
message_body = "Not Found"
}
}
}
}
resource "aws_lb_listener" "redirect80to443" {
count = var.redirect_80_to_443 == true ? 1 : 0
load_balancer_arn = aws_lb.default.arn
port = 80
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
resource "aws_lb_listener_rule" "https" {
for_each = local.https_with_hosts
listener_arn = aws_lb_listener.default["443"].arn
action {
type = "forward"
target_group_arn = aws_lb_target_group.default[each.value.app_port].arn
}
condition {
field = "host-header"
values = [
each.value.host
]
}
}
resource "aws_lb_target_group" "default" {
for_each = local.target_groups
name = "${var.name}-${var.env}-${each.key}-tg"
vpc_id = var.jz_vpc.self.id
port = each.value[0].app_port
protocol = each.value[0].app_schema
health_check {
enabled = true
healthy_threshold = 2
unhealthy_threshold = 5
interval = 30
timeout = 5
matcher = "200-499"
}
}
resource "aws_lb_target_group_attachment" "default" {
for_each = {
for key, value in local.tg_x_instance:
format("%s-%s", value[0], value[1]) => value
}
target_group_arn = each.value[0]
target_id = each.value[1]
}
data "aws_acm_certificate" "default" {
count = var.ssl_cert_domain != "" ? 1 : 0
domain = var.ssl_cert_domain
most_recent = true
}
output "self" {
value = aws_lb.default
description = "An aws_lb resource itself."
}
output "listeners" {
value = local.listeners
}
output "target_groups" {
value = local.target_groups
}
output "https_with_hosts" {
value = local.https_with_hosts
}
resource "aws_security_group" "alb" {
name = "alb-group"
description = "ALB security group is final world frontier security group."
vpc_id = var.jz_vpc.self.id
tags = {
Name = "${var.name}-${var.env}-alb-sg"
Env = var.env
}
dynamic "ingress" {
for_each = var.port_mapping
content {
from_port = ingress.value.alb_port
to_port = ingress.value.alb_port
protocol = "tcp"
cidr_blocks = [
"0.0.0.0/0",
]
}
}
dynamic "ingress" {
for_each = var.redirect_80_to_443 ? [true] : []
content {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = [
"0.0.0.0/0",
]
}
}
egress {
from_port = "0"
to_port = "0"
protocol = "-1"
cidr_blocks = [
"0.0.0.0/0",
]
}
}
variable "name" {
type = string
description = "The name of the Swarm project."
}
variable "env" {
type = string
description = "Deployment environment."
}
variable "jz_vpc" {
type = object({
self = object({
id = string
})
subnets = list(any)
})
description = "A reference to jz_vpc module."
}
variable "jz_swarm_project" {
type = object({
instance_ids = object({
leader = string
managers = set(string)
workers = set(string)
})
})
description = "A reference to jz_swarm_project module."
}
/*variable "port_mapping" {
type = list(object({
app_schema = string
app_port = number
alb_schema = string
alb_port = number
# host = string (optional)
}))
} CANNOT BE USED DUE TO NO "default" POSSIBILITIES FOR "host" */
variable "port_mapping" {
type = any
description = "ALB to app ports mapping."
}
variable "redirect_80_to_443" {
default = false
description = "If should add http redirect to https."
}
variable "ssl_cert_domain" {
type = string
default = ""
description = "Domain name (FQN) of existing ACM certificate for which https ELB listeners shall be launched."
}
variable "ssl_cert_arn" {
type = string
default = null
description = "Existing ACM certificate ARN for which https ELB listeners shall be launched. Overrides `ssl_cert_domain`."
}
\ No newline at end of file
# amzn2-docker-ami module
Get AMI ID for Jazzy Amazon Linux 2 Docker AMI.
## Variables
* *none*
## Outputs
* `ami_id`
data "aws_ami" "amzn2_docker" {
most_recent = true
filter {
name = "name"
values = [
"jazzy/ami/hvm-ssd/amzn2-docker-*",
]
}
# Jazzy
owners = [
"730893986781",
]
}
output "self" {
value = data.aws_ami.amzn2_docker
description = "An aws_ami resource itself."
}
output "ami_id" {
value = data.aws_ami.amzn2_docker.id
description = "The ID of Jazzy Amazon Linux 2 Docker AMI."
}
# ecr-repo module
Creates an ECR registry repository based on `project_slug` na repository `name`.
## Variables
* `namespace`
* `name`
* `max_image_count`
## Outputs
* `registry_id`
* `repository_url`
* `repository_name`
locals {
protected_images_rules = <<EOF
%{ for index, tag in var.protected_images }
{
"rulePriority": ${index+1},
"description": "Protect ${tag} - always keep latest version",
"selection": {
"tagStatus": "tagged",
"countType": "imageCountMoreThan",
"countNumber": 1,
"tagPrefixList": ["${tag}"]
},
"action": {
"type": "expire"
}
},
%{ endfor }
EOF
}
#
# Repository
#
resource "aws_ecr_repository" "default" {
name = "${var.namespace}/${var.name}"
}
#
# Lifecycle:
#
# - remove untagged
# - keep max `max_images_count` dev images
# - keep max `max_images_count` RC images
# - keep max `max_images_count` release images
# - keep latest version of protected images
#
# https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html#lp_evaluation_rules
#
resource "aws_ecr_lifecycle_policy" "default" {
repository = aws_ecr_repository.default.name
policy = <<EOF
{
"rules": [
${local.protected_images_rules}
{
"rulePriority": ${length(var.protected_images) + 1},
"description": "Always keep ${var.max_images_count} release images stored.",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["${var.release_images_prefix}"],
"countType": "imageCountMoreThan",
"countNumber": ${var.max_images_count}
},
"action": {
"type": "expire"
}
},
{
"rulePriority": ${length(var.protected_images) + 2},
"description": "Always keep ${var.max_images_count} RC images stored.",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["${var.rc_images_prefix}"],
"countType": "imageCountMoreThan",
"countNumber": ${var.max_images_count}
},
"action": {
"type": "expire"
}
},
{
"rulePriority": ${length(var.protected_images) + 3},
"description": "Remove untagged images.",
"selection": {
"tagStatus": "untagged",
"countType": "imageCountMoreThan",
"countNumber": 1
},
"action": {
"type": "expire"
}
},
{
"rulePriority": ${length(var.protected_images) + 4},
"description": "Remove dev images when reached ${var.max_images_count} images stored.",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": ${var.max_images_count}
},
"action": {
"type": "expire"
}
}
]
}
EOF
}
output "self" {
value = aws_ecr_repository.default
description = "An aws_ecr_repository resource itself."
}
output "registry_id" {
value = aws_ecr_repository.default.registry_id
description = "Registry ID"
}
output "repository_url" {
value = aws_ecr_repository.default.repository_url
description = "Repository URL"
}
output "repository_name" {
value = aws_ecr_repository.default.name
description = "Repository name"
}
variable "namespace" {
type = string
description = "Will be used as repository `$namespace` in `$namespace/$name`."
}
variable "name" {
type = string
description = "Will be used as repository `$name` in `$namespace/$name`."
}
variable "max_images_count" {
type = number
default = 50
description = "How many Docker Image versions AWS ECR will store."
}
variable "rc_images_prefix" {
type = string
default = "rc"
description = "Docker image prefix for RC."
}
variable "release_images_prefix" {
type = string
default = "v"
description = "Docker image prefix for release version."
}
variable "protected_images" {
type = list(string)
default = ["latest"]
description = "Protected tags (e.g. latest). Only newest will be kept."
}
\ No newline at end of file
resource "aws_elb" "default" {
name = "${var.name}-${var.env}-elb"
subnets = var.jz_vpc.subnets.*.id
security_groups = [
aws_security_group.elb.id,
]
dynamic "listener" {
for_each = var.port_mapping
content {
instance_protocol = listener.value.app_schema
instance_port = listener.value.app_port
lb_protocol = listener.value.elb_schema
lb_port = listener.value.elb_port
ssl_certificate_id = listener.value.elb_schema == "https" || listener.value.elb_schema == "ssl" ? data.aws_acm_certificate.default[0].arn : ""
}
}
health_check {
target = var.health_check_target
timeout = 5
interval = 30
unhealthy_threshold = 10
healthy_threshold = 2
}
instances = flatten([
var.jz_swarm_project.instance_ids.leader,
var.jz_swarm_project.instance_ids.managers.*,
var.jz_swarm_project.instance_ids.workers.*]
)
cross_zone_load_balancing = true
idle_timeout = 400
connection_draining = true
connection_draining_timeout = 400
tags = {
Name = "${var.name}-${var.env}-elb"
Env = var.env
}
lifecycle {
ignore_changes = [
tags,
]
}
}
data "aws_acm_certificate" "default" {
count = var.ssl_cert_domain != "" ? 1 : 0
domain = var.ssl_cert_domain
most_recent = true
}
output "self" {
value = aws_elb.default
description = "An aws_elb resource itself."
}
resource "aws_security_group" "elb" {
name = "elb-group"
description = "ELB security group is final world frontier security group."
vpc_id = var.jz_vpc.self.id
tags = {
Name = "${var.name}-${var.env}-elb-sg"
Env = var.env
}
dynamic "ingress" {
for_each = var.port_mapping
content {
from_port = ingress.value.elb_port
to_port = ingress.value.elb_port
protocol = "tcp"
cidr_blocks = [
"0.0.0.0/0",
]
}
}
egress {
from_port = "0"
to_port = "0"
protocol = "-1"
cidr_blocks = [
"0.0.0.0/0",
]
}
}
\ No newline at end of file
variable "name" {
type = string
description = "The name of the Swarm project."
}
variable "env" {
type = string
description = "Deployment environment."
}
variable "jz_vpc" {
type = object({
self = object({
id = string
})
subnets = list(any)
})
description = "A reference to jz_vpc module."
}
variable "jz_swarm_project" {
type = object({
instance_ids =<