You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

373 lines
9.5 KiB

#####
# AWS Prodvider
#####
# Retrieve AWS credentials from env variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
provider "aws" {
region = var.aws_region
}
#####
# Generate kubeadm token
#####
module "kubeadm-token" {
source = "scholzj/kubeadm-token/random"
}
#####
# IAM roles
#####
# Master nodes
resource "aws_iam_policy" "master_policy" {
name = "${var.cluster_name}-master"
path = "/"
description = "Policy for role ${var.cluster_name}-master"
policy = file("${path.module}/template/master-policy.json.tpl")
}
resource "aws_iam_role" "master_role" {
name = "${var.cluster_name}-master"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy_attachment" "master-attach" {
name = "master-attachment"
roles = [aws_iam_role.master_role.name]
policy_arn = aws_iam_policy.master_policy.arn
}
resource "aws_iam_instance_profile" "master_profile" {
name = "${var.cluster_name}-master"
role = aws_iam_role.master_role.name
}
# Worker nodes
resource "aws_iam_policy" "node_policy" {
name = "${var.cluster_name}-node"
path = "/"
description = "Policy for role ${var.cluster_name}-node"
policy = file("${path.module}/template/node-policy.json.tpl")
}
resource "aws_iam_role" "node_role" {
name = "${var.cluster_name}-node"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy_attachment" "node-attach" {
name = "node-attachment"
roles = [aws_iam_role.node_role.name]
policy_arn = aws_iam_policy.node_policy.arn
}
resource "aws_iam_instance_profile" "node_profile" {
name = "${var.cluster_name}-node"
role = aws_iam_role.node_role.name
}
#####
# Security Group
#####
# Find VPC details based on Master subnet
data "aws_subnet" "cluster_subnet" {
id = var.master_subnet_id
}
resource "aws_security_group" "kubernetes" {
vpc_id = data.aws_subnet.cluster_subnet.vpc_id
name = var.cluster_name
tags = merge(
{
"Name" = var.cluster_name
format("kubernetes.io/cluster/%v", var.cluster_name) = "owned"
},
var.tags,
)
}
# Allow outgoing connectivity
resource "aws_security_group_rule" "allow_all_outbound_from_kubernetes" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.kubernetes.id
}
# Allow SSH connections only from specific CIDR (TODO)
resource "aws_security_group_rule" "allow_ssh_from_cidr" {
count = length(var.ssh_access_cidr)
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
# TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to
# force an interpolation expression to be interpreted as a list by wrapping it
# in an extra set of list brackets. That form was supported for compatibilty in
# v0.11, but is no longer supported in Terraform v0.12.
#
# If the expression in the following list itself returns a list, remove the
# brackets to avoid interpretation as a list of lists. If the expression
# returns a single list item then leave it as-is and remove this TODO comment.
cidr_blocks = [var.ssh_access_cidr[count.index]]
security_group_id = aws_security_group.kubernetes.id
}
# Allow the security group members to talk with each other without restrictions
resource "aws_security_group_rule" "allow_cluster_crosstalk" {
type = "ingress"
from_port = 0
to_port = 0
protocol = "-1"
source_security_group_id = aws_security_group.kubernetes.id
security_group_id = aws_security_group.kubernetes.id
}
# Allow API connections only from specific CIDR (TODO)
resource "aws_security_group_rule" "allow_api_from_cidr" {
count = length(var.api_access_cidr)
type = "ingress"
from_port = 6443
to_port = 6443
protocol = "tcp"
# TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to
# force an interpolation expression to be interpreted as a list by wrapping it
# in an extra set of list brackets. That form was supported for compatibilty in
# v0.11, but is no longer supported in Terraform v0.12.
#
# If the expression in the following list itself returns a list, remove the
# brackets to avoid interpretation as a list of lists. If the expression
# returns a single list item then leave it as-is and remove this TODO comment.
cidr_blocks = [var.api_access_cidr[count.index]]
security_group_id = aws_security_group.kubernetes.id
}
##########
# Bootstraping scripts
##########
data "cloudinit_config" "master_cloud_init" {
gzip = true
base64_encode = true
part {
filename = "init-aws-kubernete-master.sh"
content_type = "text/x-shellscript"
content = templatefile("${path.module}/scripts/init-aws-kubernetes-master.sh", { kubeadm_token = module.kubeadm-token.token, dns_name = "${var.cluster_name}.${var.hosted_zone}", ip_address = aws_eip.master.public_ip, cluster_name = var.cluster_name, addons = join(" ", var.addons), aws_region = var.aws_region, asg_name = "${var.cluster_name}-nodes", asg_min_nodes = var.min_worker_count, asg_max_nodes = var.max_worker_count, aws_subnets = join(" ", concat(var.worker_subnet_ids, [var.master_subnet_id])) } )
}
}
data "cloudinit_config" "node_cloud_init" {
gzip = true
base64_encode = true
part {
filename = "init-aws-kubernetes-node.sh"
content_type = "text/x-shellscript"
content = templatefile("${path.module}/scripts/init-aws-kubernetes-node.sh", { kubeadm_token = module.kubeadm-token.token, master_ip = aws_eip.master.public_ip, master_private_ip = aws_instance.master.private_ip, dns_name = "${var.cluster_name}.${var.hosted_zone}" } )
}
}
##########
# Keypair
##########
resource "aws_key_pair" "keypair" {
key_name = var.cluster_name
public_key = file(var.ssh_public_key)
}
#####
# AMI image
#####
data "aws_ami" "centos7" {
most_recent = true
owners = ["aws-marketplace"]
filter {
name = "product-code"
values = ["aw0evgkw8e5c1q413zgy5pjce", "cvugziknvmxgqna9noibqnnsy"]
}
filter {
name = "architecture"
values = ["x86_64"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
#####
# Master - EC2 instance
#####
resource "aws_eip" "master" {
vpc = true
}
resource "aws_instance" "master" {
instance_type = var.master_instance_type
ami = data.aws_ami.centos7.id
key_name = aws_key_pair.keypair.key_name
subnet_id = var.master_subnet_id
associate_public_ip_address = false
vpc_security_group_ids = [
aws_security_group.kubernetes.id,
]
iam_instance_profile = aws_iam_instance_profile.master_profile.name
user_data = data.cloudinit_config.master_cloud_init.rendered
tags = merge(
{
"Name" = join("-", [var.cluster_name, "master"])
format("kubernetes.io/cluster/%v", var.cluster_name) = "owned"
},
var.tags,
)
root_block_device {
volume_type = "gp2"
volume_size = "50"
delete_on_termination = true
}
lifecycle {
ignore_changes = [
ami,
user_data,
associate_public_ip_address,
]
}
}
resource "aws_eip_association" "master_assoc" {
instance_id = aws_instance.master.id
allocation_id = aws_eip.master.id
}
#####
# Nodes
#####
resource "aws_launch_configuration" "nodes" {
name_prefix = "${var.cluster_name}-nodes-"
image_id = data.aws_ami.centos7.id
instance_type = var.worker_instance_type
key_name = aws_key_pair.keypair.key_name
iam_instance_profile = aws_iam_instance_profile.node_profile.name
security_groups = [
aws_security_group.kubernetes.id,
]
associate_public_ip_address = var.public_worker
user_data = data.cloudinit_config.node_cloud_init.rendered
root_block_device {
volume_type = "gp2"
volume_size = "50"
delete_on_termination = true
}
lifecycle {
create_before_destroy = true
ignore_changes = [user_data]
}
}
resource "aws_autoscaling_group" "nodes" {
vpc_zone_identifier = var.worker_subnet_ids
name = "${var.cluster_name}-nodes"
max_size = var.max_worker_count
min_size = var.min_worker_count
desired_capacity = var.min_worker_count
launch_configuration = aws_launch_configuration.nodes.name
tags = concat(
[{
key = "kubernetes.io/cluster/${var.cluster_name}"
value = "owned"
propagate_at_launch = true
},
{
key = "Name"
value = "${var.cluster_name}-node"
propagate_at_launch = true
}],
var.tags2,
)
lifecycle {
ignore_changes = [desired_capacity]
}
}
#####
# DNS record
#####
data "aws_route53_zone" "dns_zone" {
name = "${var.hosted_zone}."
private_zone = var.hosted_zone_private
}
resource "aws_route53_record" "master" {
zone_id = data.aws_route53_zone.dns_zone.zone_id
name = "${var.cluster_name}.${var.hosted_zone}"
type = "A"
records = [aws_eip.master.public_ip]
ttl = 300
}