From 38e0276aeefff4d7e3d9f2906b11206af12a5bb8 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 6 Oct 2023 12:42:49 +0200 Subject: [PATCH 01/20] vars --- variables.tf | 79 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/variables.tf b/variables.tf index a27d76b..a6d0a89 100644 --- a/variables.tf +++ b/variables.tf @@ -1,12 +1,67 @@ -# variable "variable_name" { -# description = "variable description" -# type = number -# default = 1 -# } - -# variable "variable_password" { -# description = "variable description" -# type = string -# sensitive = true -# default = "abc" -# } +variable "common_tags" { + description = "A map of tags to assign to every resource in this module." + type = map(string) + default = {} +} + +variable "name" { + description = "The name of the cluster." + type = string +} + +variable "k8s_version" { + description = "Desired Kubernetes master version." + type = string + default = null +} + + +variable "subnet_ids" { + description = "List of subnet IDs. Must be in at least two different availability zones." + type = set(string) +} + +variable "security_group_ids" { + description = "List of security group IDs to allow communication between your worker nodes and the Kubernetes control plane." + type = set(string) + default = [] +} + +variable "endpoint_private_access" { + description = "Whether the Amazon EKS private API server endpoint is enabled." + type = bool + default = false +} + +variable "endpoint_public_access" { + description = "Whether the Amazon EKS public API server endpoint is enabled." + type = bool + default = true +} + +variable "public_access_cidrs" { + description = "List of CIDR blocks that can access the Amazon EKS public API server endpoint when enabled." + type = list(string) + default = [ + "0.0.0.0/0", + ] +} + + +variable "enabled_cluster_log_types" { + description = "List of the desired control plane logging to enable." + type = list(string) + default = [ + "api", + # "audit", + "authenticator", + "controllerManager", + "scheduler", + ] +} + +variable "cluster_log_retention_in_days" { + description = "Specifies the number of days you want to retain log events." + type = number + default = 7 +} From a28ebe7dc65bea1d7c972e6011f6ecbcf5a18468 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 6 Oct 2023 12:43:24 +0200 Subject: [PATCH 02/20] cleanup --- examples/example_of_use/.tool-versions | 1 - examples/example_of_use/README.mkdn | 63 -------------------------- examples/example_of_use/main.tf | 4 -- examples/example_of_use/versions.tf | 13 ------ versions.tf | 13 ------ 5 files changed, 94 deletions(-) delete mode 100644 examples/example_of_use/.tool-versions delete mode 100644 examples/example_of_use/README.mkdn delete mode 100644 examples/example_of_use/main.tf delete mode 100644 examples/example_of_use/versions.tf delete mode 100644 versions.tf diff --git a/examples/example_of_use/.tool-versions b/examples/example_of_use/.tool-versions deleted file mode 100644 index 0743dde..0000000 --- a/examples/example_of_use/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -terraform 1.5.5 diff --git a/examples/example_of_use/README.mkdn b/examples/example_of_use/README.mkdn deleted file mode 100644 index fc28c30..0000000 --- a/examples/example_of_use/README.mkdn +++ /dev/null @@ -1,63 +0,0 @@ -# Example title - -Brief description of an example. - -## Required tools - -### AZ CLI - -Before you start, you need to install Azure CLI according to the official [documentation](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli). - -Use the `az login` command to login to your Azure subscription. - -### asdf and direnv - -Additinaly `asdf` and `direnv` must be installed and configured according to their official documentation. - -- [asdf](https://asdf-vm.com/) - manages multiple runtime versions; -- [direnv](https://direnv.net/) - augments existing shells with a new feature that can load and unload environment variables. - -### Terraform - -The suggested Terraform version is defined in the [.tool-versions](.tool-versions) file. -To install it, simply execute - -```bash -asdf install terraform -``` - -## Terraforming infrastructure - -To start working with the module, you need to initialize terraform. - -```shell -terraform init -``` - -Execute plan command. - -```shell -terraform plan -``` - -and verify what will be created. - -The last step is to create the repo - -```shell -terrafrorm apply -``` - -**IMPORTANT**: Please double-check the command output. The vital section can be seen in the example `Plan: 6 to add, 0 to change, 0 to destroy`. Ensure that you understand the changes you are making. - -Next, you will be asked - -```shell -Do you want to perform these actions? - Terraform will perform the actions described above. - Only 'yes' will be accepted to approve. - - Enter a value: -``` - -Type `yes` to approve and let the magic happen. diff --git a/examples/example_of_use/main.tf b/examples/example_of_use/main.tf deleted file mode 100644 index 9eda987..0000000 --- a/examples/example_of_use/main.tf +++ /dev/null @@ -1,4 +0,0 @@ -module "module_name" { - source = "../../" - -} diff --git a/examples/example_of_use/versions.tf b/examples/example_of_use/versions.tf deleted file mode 100644 index b7d3369..0000000 --- a/examples/example_of_use/versions.tf +++ /dev/null @@ -1,13 +0,0 @@ -terraform { - required_version = ">= 1.3.1" - required_providers { - # github = { - # source = "integrations/github" - # version = ">= 5.3.0" - # } - # azurerm = { - # source = "hashicorp/azurerm" - # version = ">= 3.22.0" - # } - } -} diff --git a/versions.tf b/versions.tf deleted file mode 100644 index b7d3369..0000000 --- a/versions.tf +++ /dev/null @@ -1,13 +0,0 @@ -terraform { - required_version = ">= 1.3.1" - required_providers { - # github = { - # source = "integrations/github" - # version = ">= 5.3.0" - # } - # azurerm = { - # source = "hashicorp/azurerm" - # version = ">= 3.22.0" - # } - } -} From 23574aab90eeb992cd80d04f89c3691d5203a9b8 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 6 Oct 2023 15:00:07 +0200 Subject: [PATCH 03/20] roles --- role-cluster.tf | 22 ++++++++++++++++++++++ role-fargate.tf | 22 ++++++++++++++++++++++ role-node.tf | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 role-cluster.tf create mode 100644 role-fargate.tf create mode 100644 role-node.tf diff --git a/role-cluster.tf b/role-cluster.tf new file mode 100644 index 0000000..7184def --- /dev/null +++ b/role-cluster.tf @@ -0,0 +1,22 @@ +# Reference: https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html + +data "aws_iam_policy_document" "assume_role_cluster" { + statement { + principals { + type = "Service" + identifiers = ["eks.amazonaws.com"] + } + effect = "Allow" + actions = ["sts:AssumeRole"] + } +} + +resource "aws_iam_role" "cluster" { + name = format("eks-%s-cluster-role", trimprefix(var.name, "eks-")) + assume_role_policy = data.aws_iam_policy_document.assume_role_cluster.json +} + +resource "aws_iam_role_policy_attachment" "AmazonEKSClusterPolicy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" + role = aws_iam_role.cluster.name +} diff --git a/role-fargate.tf b/role-fargate.tf new file mode 100644 index 0000000..cb05f26 --- /dev/null +++ b/role-fargate.tf @@ -0,0 +1,22 @@ +# Reference: https://docs.aws.amazon.com/eks/latest/userguide/pod-execution-role.html + +data "aws_iam_policy_document" "assume_role_fargate" { + statement { + principals { + type = "Service" + identifiers = ["eks-fargate-pods.amazonaws.com"] + } + effect = "Allow" + actions = ["sts:AssumeRole"] + } +} + +resource "aws_iam_role" "fargate" { + name = format("eks-%s-fargate-pods-role", trimprefix(var.name, "eks-")) + assume_role_policy = data.aws_iam_policy_document.assume_role_fargate.json +} + +resource "aws_iam_role_policy_attachment" "AmazonEKSFargatePodExecutionRolePolicy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy" + role = aws_iam_role.fargate.name +} diff --git a/role-node.tf b/role-node.tf new file mode 100644 index 0000000..1125a2e --- /dev/null +++ b/role-node.tf @@ -0,0 +1,34 @@ +# Reference: https://docs.aws.amazon.com/eks/latest/userguide/create-node-role.html + +data "aws_iam_policy_document" "assume_role_node" { + statement { + principals { + type = "Service" + identifiers = ["ec2.amazonaws.com"] + } + effect = "Allow" + actions = ["sts:AssumeRole"] + } +} + +resource "aws_iam_role" "node" { + name = format("eks-%s-node-role", trimprefix(var.name, "eks-")) + assume_role_policy = data.aws_iam_policy_document.assume_role_node.json +} + +resource "aws_iam_role_policy_attachment" "AmazonEKSWorkerNodePolicy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" + role = aws_iam_role.node.name +} + +resource "aws_iam_role_policy_attachment" "AmazonEC2ContainerRegistryReadOnly" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" + role = aws_iam_role.node.name +} + +# The AmazonEKS_CNI_Policy policy must be attached to either this role +# or to a different role that is mapped to the aws-node Kubernetes service account. +resource "aws_iam_role_policy_attachment" "AmazonEKS_CNI_Policy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" + role = aws_iam_role.node.name +} From 7cb9d91e10498c52971e0b7fa72e2415de6e4c80 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 6 Oct 2023 15:25:35 +0200 Subject: [PATCH 04/20] code --- main.tf | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++- outputs.tf | 63 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 123 insertions(+), 5 deletions(-) diff --git a/main.tf b/main.tf index 1c6a2e5..bc5bd4a 100644 --- a/main.tf +++ b/main.tf @@ -1 +1,64 @@ -# Terraform code goes here +terraform { + required_version = ">= 1.3.1" + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +resource "aws_eks_cluster" "main" { + name = var.name + version = var.k8s_version + role_arn = aws_iam_role.cluster.arn + tags = merge(var.common_tags, { + Name = var.name + }) + + enabled_cluster_log_types = var.enabled_cluster_log_types + + vpc_config { + subnet_ids = var.subnet_ids + endpoint_private_access = var.endpoint_private_access + endpoint_public_access = var.endpoint_public_access + public_access_cidrs = var.public_access_cidrs + security_group_ids = var.security_group_ids + } + + kubernetes_network_config { + ip_family = "ipv4" + service_ipv4_cidr = "172.20.0.0/16" + } + + # encryption_config { + # provider { + # key_arn = "aaa" + # } + # resources = ["secrets"] + # } + + depends_on = [ + aws_iam_role_policy_attachment.AmazonEKSClusterPolicy, + aws_iam_role_policy_attachment.AmazonEKSWorkerNodePolicy, + aws_iam_role_policy_attachment.AmazonEKSFargatePodExecutionRolePolicy, + aws_cloudwatch_log_group.cluster, + ] +} + +resource "aws_cloudwatch_log_group" "cluster" { + name = "/aws/eks/${var.name}/cluster" + retention_in_days = var.cluster_log_retention_in_days +} + +data "tls_certificate" "oidc_issuer" { + url = aws_eks_cluster.main.identity[0].oidc[0].issuer +} + +resource "aws_iam_openid_connect_provider" "eks_cluster" { + url = data.tls_certificate.oidc_issuer.url + thumbprint_list = [ + data.tls_certificate.oidc_issuer.certificates[0].sha1_fingerprint + ] + client_id_list = ["sts.amazonaws.com"] +} diff --git a/outputs.tf b/outputs.tf index 47cec5f..0a2940b 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,4 +1,59 @@ -# output "variable" { -# description = "output variable description" -# value = variable.main.name -# } +output "id" { + value = aws_eks_cluster.main.id +} + +output "arn" { + value = aws_eks_cluster.main.arn +} + +output "name" { + value = aws_eks_cluster.main.name +} + +output "endpoint" { + value = aws_eks_cluster.main.endpoint +} + +output "version" { + value = aws_eks_cluster.main.version +} + +output "cluster_ca" { + value = base64decode(aws_eks_cluster.main.certificate_authority[0].data) +} + +output "oidc_issuer" { + value = aws_eks_cluster.main.identity[0].oidc[0].issuer +} + +output "openid_arn" { + value = aws_iam_openid_connect_provider.eks_cluster.arn +} + +output "openid_sub" { + value = format("%s:sub", trimprefix(aws_iam_openid_connect_provider.eks_cluster.url, "https://")) +} + +output "cluster_role_arn" { + value = aws_iam_role.cluster.arn +} + +output "cluster_role_name" { + value = aws_iam_role.cluster.name +} + +output "node_role_arn" { + value = aws_iam_role.node.arn +} + +output "node_role_name" { + value = aws_iam_role.node.name +} + +output "fargate_role_arn" { + value = aws_iam_role.fargate.arn +} + +output "fargate_role_name" { + value = aws_iam_role.fargate.name +} From ee5acd2ddbb3b2c7cd3033482fed1c26187ebc94 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Sat, 14 Oct 2023 10:59:26 +0200 Subject: [PATCH 05/20] some data resources --- main.tf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/main.tf b/main.tf index bc5bd4a..68cccbf 100644 --- a/main.tf +++ b/main.tf @@ -8,6 +8,18 @@ terraform { } } +data "aws_caller_identity" "current" { + # no arguments +} + +data "aws_region" "current" { + # no arguments +} + +data "aws_eks_cluster_auth" "main" { + name = aws_eks_cluster.main.name +} + resource "aws_eks_cluster" "main" { name = var.name version = var.k8s_version From 501226a35b99854551a0e1bc8203ef6dd819354a Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Sat, 14 Oct 2023 11:00:09 +0200 Subject: [PATCH 06/20] add region output --- outputs.tf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/outputs.tf b/outputs.tf index 0a2940b..8c82106 100644 --- a/outputs.tf +++ b/outputs.tf @@ -18,6 +18,11 @@ output "version" { value = aws_eks_cluster.main.version } +output "region" { + description = "The region of the state storage resources." + value = data.aws_region.current.name +} + output "cluster_ca" { value = base64decode(aws_eks_cluster.main.certificate_authority[0].data) } From 92f66b68e5252106df6bca54eba0b73577609ac4 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Sat, 14 Oct 2023 11:00:35 +0200 Subject: [PATCH 07/20] add auth config vars --- variables.tf | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/variables.tf b/variables.tf index a6d0a89..31c30bf 100644 --- a/variables.tf +++ b/variables.tf @@ -65,3 +65,29 @@ variable "cluster_log_retention_in_days" { type = number default = 7 } + +variable "auth_map_accounts" { + description = "Maps IAM ARN from these accounts to username." + type = list(string) + default = ["current"] +} + +variable "auth_map_roles" { + description = "Maps an IAM role to a username and set of groups." + type = list(object({ + role_arn = string + username = optional(string) + groups = list(string) + })) + default = [] +} + +variable "auth_map_users" { + description = "Maps an IAM user to a static username and set of groups." + type = list(object({ + user_arn = string + username = optional(string) + groups = list(string) + })) + default = [] +} From 0c44b8259b1690ef56a0270a5cbf3b28d57835af Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 20 Oct 2023 14:44:21 +0200 Subject: [PATCH 08/20] outputs --- outputs.tf | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/outputs.tf b/outputs.tf index 8c82106..6eba015 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,21 +1,26 @@ output "id" { - value = aws_eks_cluster.main.id + description = "The ID of the cluster." + value = aws_eks_cluster.main.id } output "arn" { - value = aws_eks_cluster.main.arn + description = "The ARN of the cluster." + value = aws_eks_cluster.main.arn } output "name" { - value = aws_eks_cluster.main.name + description = "The name of the cluster." + value = aws_eks_cluster.main.name } output "endpoint" { - value = aws_eks_cluster.main.endpoint + description = "Endpoint for your Kubernetes API server." + value = aws_eks_cluster.main.endpoint } output "version" { - value = aws_eks_cluster.main.version + description = "The Kubernetes master version." + value = aws_eks_cluster.main.version } output "region" { @@ -24,41 +29,51 @@ output "region" { } output "cluster_ca" { - value = base64decode(aws_eks_cluster.main.certificate_authority[0].data) + description = "Decoded CA certificate of the cluster." + value = base64decode(aws_eks_cluster.main.certificate_authority[0].data) } output "oidc_issuer" { - value = aws_eks_cluster.main.identity[0].oidc[0].issuer + description = "Issuer URL for the OpenID Connect identity provider." + value = aws_eks_cluster.main.identity[0].oidc[0].issuer } output "openid_arn" { - value = aws_iam_openid_connect_provider.eks_cluster.arn + description = "The ARN assigned by AWS for IAM OpenID Connect of the cluster." + value = aws_iam_openid_connect_provider.eks_cluster.arn } output "openid_sub" { - value = format("%s:sub", trimprefix(aws_iam_openid_connect_provider.eks_cluster.url, "https://")) + description = "The URL of the identity provider. Corresponds to the iss claim." + value = format("%s:sub", trimprefix(aws_iam_openid_connect_provider.eks_cluster.url, "https://")) } output "cluster_role_arn" { - value = aws_iam_role.cluster.arn + description = "The ARN of the IAM role that provides permissions for the Kubernetes control plane." + value = aws_iam_role.cluster.arn } output "cluster_role_name" { - value = aws_iam_role.cluster.name + description = "The name of the IAM role that provides permissions for the Kubernetes control plane." + value = aws_iam_role.cluster.name } output "node_role_arn" { - value = aws_iam_role.node.arn + description = "The ARN of the IAM Role that provides permissions for the EKS Node Group." + value = aws_iam_role.node.arn } output "node_role_name" { - value = aws_iam_role.node.name + description = "The name of the IAM Role that provides permissions for the EKS Node Group." + value = aws_iam_role.node.name } output "fargate_role_arn" { - value = aws_iam_role.fargate.arn + description = "The ARN of the IAM Role that provides permissions for the EKS Fargate Profile." + value = aws_iam_role.fargate.arn } output "fargate_role_name" { - value = aws_iam_role.fargate.name + description = "The name of the IAM Role that provides permissions for the EKS Fargate Profile." + value = aws_iam_role.fargate.name } From fa12e1d3f0ba9e9ebf01171aac08c8d7fc89932c Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 20 Oct 2023 14:44:56 +0200 Subject: [PATCH 09/20] optionals --- variables.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variables.tf b/variables.tf index 31c30bf..7c2b83a 100644 --- a/variables.tf +++ b/variables.tf @@ -77,7 +77,7 @@ variable "auth_map_roles" { type = list(object({ role_arn = string username = optional(string) - groups = list(string) + groups = optional(list(string)) })) default = [] } @@ -87,7 +87,7 @@ variable "auth_map_users" { type = list(object({ user_arn = string username = optional(string) - groups = list(string) + groups = optional(list(string)) })) default = [] } From e9550a4e42cb3df9d4f078cf04c4082d672e7017 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 20 Oct 2023 14:45:37 +0200 Subject: [PATCH 10/20] fargate --- variables.tf | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/variables.tf b/variables.tf index 7c2b83a..b93e5d2 100644 --- a/variables.tf +++ b/variables.tf @@ -66,6 +66,20 @@ variable "cluster_log_retention_in_days" { default = 7 } +variable "fargate_subnet_ids" { + description = "Identifiers of private EC2 Subnets to associate with the EKS Fargate Profile." + type = set(string) + default = [] +} + +variable "fargate_profiles" { + type = map(object({ + namespace = string + labels = optional(map(string)) + })) + default = {} +} + variable "auth_map_accounts" { description = "Maps IAM ARN from these accounts to username." type = list(string) From b35c5d442aa2271c50bcc7ff1a085e35cbc31521 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 20 Oct 2023 19:05:48 +0200 Subject: [PATCH 11/20] vars --- variables.tf | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/variables.tf b/variables.tf index b93e5d2..90d0f50 100644 --- a/variables.tf +++ b/variables.tf @@ -66,16 +66,48 @@ variable "cluster_log_retention_in_days" { default = 7 } +variable "ec2_ssh_key" { + description = "The EC2 Key Pair name that provides access to the worker nodes." + type = string + default = null +} +variable "node_group_subnet_ids" { + description = "Identifiers of EC2 Subnets to associate with the EKS Node Groups." + type = set(string) + default = [] +} + +variable "node_groups" { + type = map(object({ + subnet_ids = optional(set(string)) + ami_type = optional(string, "AL2_x86_64") + capacity_type = optional(string, "ON_DEMAND") + instance_type = optional(string, "t3.medium") + disk_size = optional(number, 20) + min_size = optional(number, 0) + max_size = optional(number, 1) + desired_size = optional(number, 0) + labels = optional(map(string)) + taints = optional(list(object({ + key = string + value = string + effect = string # Valid values: NO_SCHEDULE, NO_EXECUTE, PREFER_NO_SCHEDULE. + })), []) + })) + default = {} +} + variable "fargate_subnet_ids" { - description = "Identifiers of private EC2 Subnets to associate with the EKS Fargate Profile." + description = "Identifiers of private EC2 Subnets to associate with the EKS Fargate Profiles." type = set(string) default = [] } variable "fargate_profiles" { type = map(object({ - namespace = string - labels = optional(map(string)) + subnet_ids = optional(set(string)) + namespace = string + labels = optional(map(string)) })) default = {} } @@ -89,7 +121,7 @@ variable "auth_map_accounts" { variable "auth_map_roles" { description = "Maps an IAM role to a username and set of groups." type = list(object({ - role_arn = string + arn = string username = optional(string) groups = optional(list(string)) })) @@ -99,7 +131,7 @@ variable "auth_map_roles" { variable "auth_map_users" { description = "Maps an IAM user to a static username and set of groups." type = list(object({ - user_arn = string + arn = string username = optional(string) groups = optional(list(string)) })) From 8b2f7aac350e1fcd40e19519d4e8db38ac7701fb Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 20 Oct 2023 19:06:25 +0200 Subject: [PATCH 12/20] aws-auth --- aws-auth.tf | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 aws-auth.tf diff --git a/aws-auth.tf b/aws-auth.tf new file mode 100644 index 0000000..c345f75 --- /dev/null +++ b/aws-auth.tf @@ -0,0 +1,73 @@ +locals { + account_map = { + current = data.aws_caller_identity.current.account_id + } + + # TODO: merge with extra roles from vars + nodes_role_arns = [aws_iam_role.node.arn] + nodes_map = [for arn in local.nodes_role_arns : { + rolearn = arn + username = "system:node:{{EC2PrivateDNSName}}" + groups = [ + "system:bootstrappers", + "system:nodes", + ] + }] + + # TODO: merge with extra roles from vars + fargate_role_arns = [aws_iam_role.fargate.arn] + fargate_map = [for arn in local.fargate_role_arns : { + rolearn = arn + username = "system:node:{{SessionName}}" + groups = [ + "system:bootstrappers", + "system:nodes", + "system:node-proxier", + ] + }] + + # TODO: merge with extra roles from vars + masters_role_arns = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/devops"] + masters_map = [for arn in local.masters_role_arns : { + rolearn = arn + username = "master:{{AccountID}}:{{SessionName}}" + groups = [ + "system:masters", + ] + }] +} + +resource "kubernetes_config_map" "aws_auth" { + metadata { + name = "aws-auth" + namespace = "kube-system" + } + data = { + mapAccounts = yamlencode([ + for account_id in var.auth_map_accounts : lookup(local.account_map, account_id, account_id) + ]) + mapRoles = yamlencode(flatten([ + local.nodes_map, + local.fargate_map, + local.masters_map, [ + for role in var.auth_map_roles : { + rolearn = role.arn + username = role.username + groups = role.groups + } + ] + ])) + mapUsers = yamlencode([ + for user in var.auth_map_users : { + userarn = user.arn + username = user.username + groups = user.groups + } + ]) + } + + depends_on = [ + aws_eks_cluster.main, + ] + +} From 477155eeee00069828a97fa2be279178fb70eea4 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 20 Oct 2023 19:06:42 +0200 Subject: [PATCH 13/20] tools --- .tool-versions | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.tool-versions b/.tool-versions index 580373a..955f343 100644 --- a/.tool-versions +++ b/.tool-versions @@ -2,3 +2,5 @@ terraform 1.5.5 terraform-docs 0.16.0 tflint 0.47.0 pre-commit 3.3.3 +kubectl 1.28.2 +yq 4.34.1 From fe36f48b0832a603dba00c2b849226612fc33a75 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 20 Oct 2023 19:14:38 +0200 Subject: [PATCH 14/20] source_security_group_ids --- variables.tf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/variables.tf b/variables.tf index 90d0f50..da59b2e 100644 --- a/variables.tf +++ b/variables.tf @@ -71,6 +71,14 @@ variable "ec2_ssh_key" { type = string default = null } + +variable "source_security_group_ids" { + description = "Set of EC2 Security Group IDs to allow SSH access (port 22) from on the worker nodes." + type = set(string) + default = null +} + + variable "node_group_subnet_ids" { description = "Identifiers of EC2 Subnets to associate with the EKS Node Groups." type = set(string) From 37400a05c91b592ddf16048f3e3c0acd78ead898 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 20 Oct 2023 19:32:40 +0200 Subject: [PATCH 15/20] workers --- compute.tf | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 compute.tf diff --git a/compute.tf b/compute.tf new file mode 100644 index 0000000..b9f3a6d --- /dev/null +++ b/compute.tf @@ -0,0 +1,92 @@ +resource "aws_eks_node_group" "main" { + for_each = var.node_groups + + node_group_name_prefix = each.key + cluster_name = aws_eks_cluster.main.name + node_role_arn = aws_iam_role.node.arn + subnet_ids = coalesce(each.value.subnet_ids, var.node_group_subnet_ids) + tags = merge(var.common_tags, { + Name = each.key + }) + + scaling_config { + min_size = each.value.min_size + max_size = each.value.max_size + desired_size = each.value.desired_size + } + + update_config { + max_unavailable = null + max_unavailable_percentage = 10 + } + + ami_type = each.value.ami_type + capacity_type = each.value.capacity_type + disk_size = each.value.disk_size + instance_types = [each.value.instance_type] + labels = each.value.labels + + # launch_template { + # id = each.value.launch_template_id + # name = each.value.launch_template_name + # version = each.value.launch_template_version + # } + + dynamic "remote_access" { + for_each = var.ec2_ssh_key != null ? [1] : [] + content { + ec2_ssh_key = var.ec2_ssh_key + source_security_group_ids = var.source_security_group_ids + } + } + + dynamic "taint" { + for_each = each.value.taints + content { + key = taint.value.key + value = taint.value.value + effect = taint.value.effect + } + } + + lifecycle { + create_before_destroy = true + ignore_changes = [ + # scaling_config[0].desired_size, # needed for autoscaling + ] + } + + depends_on = [ + aws_eks_cluster.main, + aws_iam_role.node, + aws_iam_role_policy_attachment.AmazonEKSWorkerNodePolicy, + kubernetes_config_map.aws_auth, + ] + +} + + +resource "aws_eks_fargate_profile" "main" { + for_each = var.fargate_profiles + + fargate_profile_name = each.key + cluster_name = aws_eks_cluster.main.name + pod_execution_role_arn = aws_iam_role.fargate.arn + subnet_ids = coalesce(each.value.subnet_ids, var.fargate_subnet_ids) + tags = merge(var.common_tags, { + Name = each.key + }) + + selector { + namespace = each.value.namespace + labels = each.value.labels + } + + depends_on = [ + aws_eks_cluster.main, + aws_iam_role.fargate, + aws_iam_role_policy_attachment.AmazonEKSFargatePodExecutionRolePolicy, + kubernetes_config_map.aws_auth, + ] + +} From 2a8d15421e494bc4b5465eadb82964f1f27c9a4b Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 27 Oct 2023 10:41:15 +0200 Subject: [PATCH 16/20] vars docs --- variables.tf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/variables.tf b/variables.tf index da59b2e..efada3a 100644 --- a/variables.tf +++ b/variables.tf @@ -15,6 +15,7 @@ variable "k8s_version" { default = null } +# EKS vpc_config variable "subnet_ids" { description = "List of subnet IDs. Must be in at least two different availability zones." @@ -47,6 +48,7 @@ variable "public_access_cidrs" { ] } +# EKS control plane logs variable "enabled_cluster_log_types" { description = "List of the desired control plane logging to enable." @@ -66,6 +68,8 @@ variable "cluster_log_retention_in_days" { default = 7 } +# Worker nodes + variable "ec2_ssh_key" { description = "The EC2 Key Pair name that provides access to the worker nodes." type = string @@ -105,6 +109,8 @@ variable "node_groups" { default = {} } +# Fargate pods + variable "fargate_subnet_ids" { description = "Identifiers of private EC2 Subnets to associate with the EKS Fargate Profiles." type = set(string) @@ -120,6 +126,8 @@ variable "fargate_profiles" { default = {} } +# kube-system/aws-auth configmap + variable "auth_map_accounts" { description = "Maps IAM ARN from these accounts to username." type = list(string) From 1dc8a6ea08ea720219386663bc994537ee49605e Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 27 Oct 2023 13:57:10 +0200 Subject: [PATCH 17/20] encryption_key_arn --- variables.tf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/variables.tf b/variables.tf index efada3a..e1cd40a 100644 --- a/variables.tf +++ b/variables.tf @@ -48,6 +48,12 @@ variable "public_access_cidrs" { ] } +variable "encryption_key_arn" { + description = "ARN of the KMS customer master key for secrets encryption." + type = string + default = null +} + # EKS control plane logs variable "enabled_cluster_log_types" { From abb3ceac935c2cb3918bc0f48494e64fb29b33f0 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 27 Oct 2023 13:59:31 +0200 Subject: [PATCH 18/20] encryption_key_arn --- main.tf | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/main.tf b/main.tf index 68cccbf..757d2af 100644 --- a/main.tf +++ b/main.tf @@ -43,12 +43,16 @@ resource "aws_eks_cluster" "main" { service_ipv4_cidr = "172.20.0.0/16" } - # encryption_config { - # provider { - # key_arn = "aaa" - # } - # resources = ["secrets"] - # } + dynamic "encryption_config" { + for_each = var.encryption_key_arn != null ? [1] : [] + content { + provider { + key_arn = var.encryption_key_arn + } + resources = ["secrets"] + + } + } depends_on = [ aws_iam_role_policy_attachment.AmazonEKSClusterPolicy, From 360b8dd77c7a5398f7c08d2873b73028ad128b16 Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Fri, 27 Oct 2023 14:02:02 +0200 Subject: [PATCH 19/20] node_group_name_prefix --- compute.tf | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compute.tf b/compute.tf index b9f3a6d..a1af1e1 100644 --- a/compute.tf +++ b/compute.tf @@ -1,7 +1,12 @@ +locals { + fixed_names = true +} + resource "aws_eks_node_group" "main" { for_each = var.node_groups - node_group_name_prefix = each.key + node_group_name = local.fixed_names ? each.key : null + node_group_name_prefix = local.fixed_names ? null : each.key cluster_name = aws_eks_cluster.main.name node_role_arn = aws_iam_role.node.arn subnet_ids = coalesce(each.value.subnet_ids, var.node_group_subnet_ids) @@ -50,6 +55,7 @@ resource "aws_eks_node_group" "main" { } lifecycle { + # only if node_group_name_prefix is in use, but (local.fixed_names == false) does not work.. create_before_destroy = true ignore_changes = [ # scaling_config[0].desired_size, # needed for autoscaling From 062e10910465a4384a6922b96c29365e2b03c71a Mon Sep 17 00:00:00 2001 From: Piotr Stawarski Date: Wed, 5 Jun 2024 12:37:52 +0200 Subject: [PATCH 20/20] cleanups --- README.md | 105 ++++++++++++++++++++++++---- aws-auth.tf | 10 +-- compute.tf | 6 +- examples/basic/main.tf | 75 ++++++++++++++++++++ examples/basic/outputs.tf | 9 +++ examples/basic/override.tf | 5 ++ examples/basic/terraform.tf | 32 +++++++++ examples/basic/update-kubeconfig.sh | 12 ++++ main.tf | 21 +++--- outputs.tf | 2 +- role-cluster.tf | 2 +- role-fargate.tf | 2 +- role-node.tf | 6 +- variables.tf | 22 ++++++ 14 files changed, 273 insertions(+), 36 deletions(-) create mode 100644 examples/basic/main.tf create mode 100644 examples/basic/outputs.tf create mode 100644 examples/basic/override.tf create mode 100644 examples/basic/terraform.tf create mode 100755 examples/basic/update-kubeconfig.sh diff --git a/README.md b/README.md index f6cb368..ceb21b0 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Meet **OPSd**. The unique and effortless way of managing cloud infrastructure. -# terraform-module-template +# terraform-module-aws-kubernetes ## Introduction @@ -11,12 +11,24 @@ What does the module provide? ## Usage ```hcl -module "module_name" { - source = "github.com/opsd-io/module_name?ref=v0.0.1" - - # Variables - variable_1 = "foo" - variable_2 = "bar" +module "kubernetes" { + source = "github.com/opsd-io/terraform-module-aws-kubernetes" + name = "basic-k8s-example" + + subnet_ids = [ + for subnet in module.network.public_subnet_groups["public1"] : subnet.id + ] + node_group_subnet_ids = [ + for subnet in module.network.private_subnet_groups["nodes1"] : subnet.id + ] + + node_groups = { + main = { + max_size = 9 + desired_size = 1 + disk_size = 8 + } + } } ``` @@ -27,11 +39,18 @@ module "module_name" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3.1 | +| [terraform](#requirement\_terraform) | >= 1.5.5 | +| [aws](#requirement\_aws) | ~> 5.0 | +| [kubernetes](#requirement\_kubernetes) | ~> 2.0 | +| [tls](#requirement\_tls) | ~> 4.0 | ## Providers -No providers. +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | ~> 5.0 | +| [kubernetes](#provider\_kubernetes) | ~> 2.0 | +| [tls](#provider\_tls) | ~> 4.0 | ## Modules @@ -39,15 +58,77 @@ No modules. ## Resources -No resources. +| Name | Type | +|------|------| +| [aws_cloudwatch_log_group.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_eks_cluster.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster) | resource | +| [aws_eks_fargate_profile.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_fargate_profile) | resource | +| [aws_eks_node_group.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_node_group) | resource | +| [aws_iam_openid_connect_provider.eks_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_openid_connect_provider) | resource | +| [aws_iam_role.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role.fargate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role.node](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.ec2_container_registry_readonly](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.eks_cluster_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.eks_cni_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.eks_fargate_pod_execution_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.eks_worker_node_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [kubernetes_config_map.aws_auth](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/config_map) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.assume_role_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.assume_role_fargate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.assume_role_node](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | +| [tls_certificate.oidc_issuer](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/data-sources/certificate) | data source | ## Inputs -No inputs. +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [auth\_map\_accounts](#input\_auth\_map\_accounts) | Maps IAM ARN from these accounts to username. | `list(string)` |
[
"current"
]
| no | +| [auth\_map\_roles](#input\_auth\_map\_roles) | Maps an IAM role to a username and set of groups. |
list(object({
arn = string
username = optional(string)
groups = optional(list(string))
}))
| `[]` | no | +| [auth\_map\_users](#input\_auth\_map\_users) | Maps an IAM user to a static username and set of groups. |
list(object({
arn = string
username = optional(string)
groups = optional(list(string))
}))
| `[]` | no | +| [cluster\_log\_retention\_in\_days](#input\_cluster\_log\_retention\_in\_days) | Specifies the number of days you want to retain log events. | `number` | `7` | no | +| [common\_tags](#input\_common\_tags) | A map of tags to assign to every resource in this module. | `map(string)` | `{}` | no | +| [ec2\_ssh\_key](#input\_ec2\_ssh\_key) | The EC2 Key Pair name that provides access to the worker nodes. | `string` | `null` | no | +| [enabled\_cluster\_log\_types](#input\_enabled\_cluster\_log\_types) | List of the desired control plane logging to enable. | `list(string)` |
[
"api",
"authenticator",
"controllerManager",
"scheduler"
]
| no | +| [encryption\_key\_arn](#input\_encryption\_key\_arn) | ARN of the KMS customer master key for secrets encryption. | `string` | `null` | no | +| [endpoint\_private\_access](#input\_endpoint\_private\_access) | Whether the Amazon EKS private API server endpoint is enabled. | `bool` | `false` | no | +| [endpoint\_public\_access](#input\_endpoint\_public\_access) | Whether the Amazon EKS public API server endpoint is enabled. | `bool` | `true` | no | +| [fargate\_profiles](#input\_fargate\_profiles) | Map of EKS Fargate Profile definitions. |
map(object({
subnet_ids = optional(set(string))
namespace = string
labels = optional(map(string))
}))
| `{}` | no | +| [fargate\_role\_arns](#input\_fargate\_role\_arns) | Additional IAM role ARNs of Fargate Profiles managed externally. | `list(string)` | `[]` | no | +| [fargate\_subnet\_ids](#input\_fargate\_subnet\_ids) | Identifiers of private EC2 Subnets to associate with the EKS Fargate Profiles. | `set(string)` | `[]` | no | +| [k8s\_version](#input\_k8s\_version) | Desired Kubernetes master version. | `string` | `null` | no | +| [masters\_role\_arns](#input\_masters\_role\_arns) | List of IAM role to set as system:masters. Shortcut for auth\_map\_roles. | `list(string)` | `[]` | no | +| [name](#input\_name) | The name of the cluster. | `string` | n/a | yes | +| [node\_group\_subnet\_ids](#input\_node\_group\_subnet\_ids) | Identifiers of EC2 Subnets to associate with the EKS Node Groups. | `set(string)` | `[]` | no | +| [node\_groups](#input\_node\_groups) | Map of EKS Node Group definitions. |
map(object({
subnet_ids = optional(set(string))
ami_type = optional(string, "AL2_x86_64")
capacity_type = optional(string, "ON_DEMAND")
instance_type = optional(string, "t3.medium")
disk_size = optional(number, 20)
min_size = optional(number, 0)
max_size = optional(number, 1)
desired_size = optional(number, 0)
labels = optional(map(string))
taints = optional(list(object({
key = string
value = string
effect = string # Valid values: NO_SCHEDULE, NO_EXECUTE, PREFER_NO_SCHEDULE.
})), [])
}))
| `{}` | no | +| [nodes\_role\_arns](#input\_nodes\_role\_arns) | Additional IAM role ARNs of Node Groups managed externally. | `list(string)` | `[]` | no | +| [public\_access\_cidrs](#input\_public\_access\_cidrs) | List of CIDR blocks that can access the Amazon EKS public API server endpoint when enabled. | `list(string)` |
[
"0.0.0.0/0"
]
| no | +| [security\_group\_ids](#input\_security\_group\_ids) | List of security group IDs to allow communication between your worker nodes and the Kubernetes control plane. | `set(string)` | `[]` | no | +| [source\_security\_group\_ids](#input\_source\_security\_group\_ids) | Set of EC2 Security Group IDs to allow SSH access (port 22) from on the worker nodes. | `set(string)` | `null` | no | +| [subnet\_ids](#input\_subnet\_ids) | List of subnet IDs. Must be in at least two different availability zones. | `set(string)` | n/a | yes | ## Outputs -No outputs. +| Name | Description | +|------|-------------| +| [arn](#output\_arn) | The ARN of the cluster. | +| [cluster\_ca](#output\_cluster\_ca) | Decoded CA certificate of the cluster. | +| [cluster\_role\_arn](#output\_cluster\_role\_arn) | The ARN of the IAM role that provides permissions for the Kubernetes control plane. | +| [cluster\_role\_name](#output\_cluster\_role\_name) | The name of the IAM role that provides permissions for the Kubernetes control plane. | +| [endpoint](#output\_endpoint) | Endpoint for your Kubernetes API server. | +| [fargate\_role\_arn](#output\_fargate\_role\_arn) | The ARN of the IAM Role that provides permissions for the EKS Fargate Profile. | +| [fargate\_role\_name](#output\_fargate\_role\_name) | The name of the IAM Role that provides permissions for the EKS Fargate Profile. | +| [id](#output\_id) | The ID of the cluster. | +| [name](#output\_name) | The name of the cluster. | +| [node\_role\_arn](#output\_node\_role\_arn) | The ARN of the IAM Role that provides permissions for the EKS Node Group. | +| [node\_role\_name](#output\_node\_role\_name) | The name of the IAM Role that provides permissions for the EKS Node Group. | +| [oidc\_issuer](#output\_oidc\_issuer) | Issuer URL for the OpenID Connect identity provider. | +| [openid\_arn](#output\_openid\_arn) | The ARN assigned by AWS for IAM OpenID Connect of the cluster. | +| [openid\_sub](#output\_openid\_sub) | The URL of the identity provider. Corresponds to the iss claim. | +| [region](#output\_region) | The region of of the cluster. | +| [version](#output\_version) | The Kubernetes master version. | ## Examples of usage diff --git a/aws-auth.tf b/aws-auth.tf index c345f75..dfdbecd 100644 --- a/aws-auth.tf +++ b/aws-auth.tf @@ -3,8 +3,7 @@ locals { current = data.aws_caller_identity.current.account_id } - # TODO: merge with extra roles from vars - nodes_role_arns = [aws_iam_role.node.arn] + nodes_role_arns = concat(var.nodes_role_arns, [aws_iam_role.node.arn]) nodes_map = [for arn in local.nodes_role_arns : { rolearn = arn username = "system:node:{{EC2PrivateDNSName}}" @@ -14,8 +13,7 @@ locals { ] }] - # TODO: merge with extra roles from vars - fargate_role_arns = [aws_iam_role.fargate.arn] + fargate_role_arns = concat(var.fargate_role_arns, [aws_iam_role.fargate.arn]) fargate_map = [for arn in local.fargate_role_arns : { rolearn = arn username = "system:node:{{SessionName}}" @@ -26,9 +24,7 @@ locals { ] }] - # TODO: merge with extra roles from vars - masters_role_arns = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/devops"] - masters_map = [for arn in local.masters_role_arns : { + masters_map = [for arn in var.masters_role_arns : { rolearn = arn username = "master:{{AccountID}}:{{SessionName}}" groups = [ diff --git a/compute.tf b/compute.tf index a1af1e1..2dc7516 100644 --- a/compute.tf +++ b/compute.tf @@ -58,14 +58,14 @@ resource "aws_eks_node_group" "main" { # only if node_group_name_prefix is in use, but (local.fixed_names == false) does not work.. create_before_destroy = true ignore_changes = [ - # scaling_config[0].desired_size, # needed for autoscaling + scaling_config[0].desired_size, # needed for autoscaling to work ] } depends_on = [ aws_eks_cluster.main, aws_iam_role.node, - aws_iam_role_policy_attachment.AmazonEKSWorkerNodePolicy, + aws_iam_role_policy_attachment.eks_worker_node_policy, kubernetes_config_map.aws_auth, ] @@ -91,7 +91,7 @@ resource "aws_eks_fargate_profile" "main" { depends_on = [ aws_eks_cluster.main, aws_iam_role.fargate, - aws_iam_role_policy_attachment.AmazonEKSFargatePodExecutionRolePolicy, + aws_iam_role_policy_attachment.eks_fargate_pod_execution_role_policy, kubernetes_config_map.aws_auth, ] diff --git a/examples/basic/main.tf b/examples/basic/main.tf new file mode 100644 index 0000000..4d161a8 --- /dev/null +++ b/examples/basic/main.tf @@ -0,0 +1,75 @@ +module "network" { + source = "github.com/opsd-io/terraform-module-aws-network" + + vpc_name = "k8s-test-vpc" + cidr_block = "10.100.0.0/16" + + public_subnet_groups = { + "public1" = { + availability_zones = { + "a" = { cidr_block = "10.100.1.0/24", nat_gateway = true } + "b" = { cidr_block = "10.100.2.0/24" } + "c" = { cidr_block = "10.100.3.0/24" } + } + } + } + private_subnet_groups = { + "nodes1" = { + nat_group_name = "public1" + availability_zones = { + "a" = { cidr_block = "10.100.101.0/24" } + "b" = { cidr_block = "10.100.102.0/24" } + "c" = { cidr_block = "10.100.103.0/24" } + } + } + "fargate1" = { + nat_group_name = "public1" + availability_zones = { + "a" = { cidr_block = "10.100.201.0/24" } + "b" = { cidr_block = "10.100.202.0/24" } + "c" = { cidr_block = "10.100.203.0/24" } + } + } + } +} + +module "kubernetes" { + source = "github.com/opsd-io/terraform-module-aws-kubernetes" + name = "basic-k8s-example" + + subnet_ids = [ + for subnet in module.network.public_subnet_groups["public1"] : subnet.id + ] + + node_group_subnet_ids = [ + for subnet in module.network.private_subnet_groups["nodes1"] : subnet.id + ] + node_groups = { + main = { + max_size = 9 + desired_size = 1 + disk_size = 8 + } + } + + fargate_subnet_ids = [ + for subnet in module.network.private_subnet_groups["fargate1"] : subnet.id + ] + fargate_profiles = { + "default-namespace" = { # default is bad, better put it "far" + namespace = "default" + } + "amazonaws-components" = { # this should put CoreDNS on fargate + namespace = "*" + labels = { "eks.amazonaws.com/component" = "*" } + } + } +} + +module "autoscaler" { + source = "github.com/opsd-io/terraform-module-eks-autoscaler" + cluster_region = module.kubernetes.region + cluster_name = module.kubernetes.name + openid_arn = module.kubernetes.openid_arn + openid_sub = module.kubernetes.openid_sub +} diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf new file mode 100644 index 0000000..9702544 --- /dev/null +++ b/examples/basic/outputs.tf @@ -0,0 +1,9 @@ +# output "network" { +# description = "The network module outputs." +# value = module.network +# } + +output "kubernetes" { + description = "The kubernetes module outputs." + value = module.kubernetes +} diff --git a/examples/basic/override.tf b/examples/basic/override.tf new file mode 100644 index 0000000..eb9cd7e --- /dev/null +++ b/examples/basic/override.tf @@ -0,0 +1,5 @@ +# Make sure we're using working version (from local directory, not git). + +module "kubernetes" { + source = "./../.." +} diff --git a/examples/basic/terraform.tf b/examples/basic/terraform.tf new file mode 100644 index 0000000..90b87e3 --- /dev/null +++ b/examples/basic/terraform.tf @@ -0,0 +1,32 @@ +terraform { + required_version = ">= 1.5.5" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +provider "aws" { + region = "eu-central-1" +} + +data "aws_eks_cluster_auth" "this" { + name = module.kubernetes.name +} + +provider "kubernetes" { + host = module.kubernetes.endpoint + cluster_ca_certificate = module.kubernetes.cluster_ca + token = data.aws_eks_cluster_auth.this.token +} + +provider "helm" { + kubernetes { + host = module.kubernetes.endpoint + cluster_ca_certificate = module.kubernetes.cluster_ca + token = data.aws_eks_cluster_auth.this.token + } +} diff --git a/examples/basic/update-kubeconfig.sh b/examples/basic/update-kubeconfig.sh new file mode 100755 index 0000000..aa40fca --- /dev/null +++ b/examples/basic/update-kubeconfig.sh @@ -0,0 +1,12 @@ +#!/bin/sh -eux + +aws sts get-caller-identity + +aws eks update-kubeconfig \ + --region "eu-central-1" \ + --name "basic-k8s-example" \ + --alias "k8s-example" + +kubectl version + +kubectl auth whoami diff --git a/main.tf b/main.tf index 757d2af..dc365b3 100644 --- a/main.tf +++ b/main.tf @@ -1,10 +1,19 @@ terraform { - required_version = ">= 1.3.1" + required_version = ">= 1.5.5" + required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.0" + } + tls = { + source = "hashicorp/tls" + version = "~> 4.0" + } } } @@ -16,10 +25,6 @@ data "aws_region" "current" { # no arguments } -data "aws_eks_cluster_auth" "main" { - name = aws_eks_cluster.main.name -} - resource "aws_eks_cluster" "main" { name = var.name version = var.k8s_version @@ -55,9 +60,9 @@ resource "aws_eks_cluster" "main" { } depends_on = [ - aws_iam_role_policy_attachment.AmazonEKSClusterPolicy, - aws_iam_role_policy_attachment.AmazonEKSWorkerNodePolicy, - aws_iam_role_policy_attachment.AmazonEKSFargatePodExecutionRolePolicy, + aws_iam_role_policy_attachment.eks_cluster_policy, + aws_iam_role_policy_attachment.eks_worker_node_policy, + aws_iam_role_policy_attachment.eks_fargate_pod_execution_role_policy, aws_cloudwatch_log_group.cluster, ] } diff --git a/outputs.tf b/outputs.tf index 6eba015..cd214e0 100644 --- a/outputs.tf +++ b/outputs.tf @@ -24,7 +24,7 @@ output "version" { } output "region" { - description = "The region of the state storage resources." + description = "The region of of the cluster." value = data.aws_region.current.name } diff --git a/role-cluster.tf b/role-cluster.tf index 7184def..bd24fd0 100644 --- a/role-cluster.tf +++ b/role-cluster.tf @@ -16,7 +16,7 @@ resource "aws_iam_role" "cluster" { assume_role_policy = data.aws_iam_policy_document.assume_role_cluster.json } -resource "aws_iam_role_policy_attachment" "AmazonEKSClusterPolicy" { +resource "aws_iam_role_policy_attachment" "eks_cluster_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" role = aws_iam_role.cluster.name } diff --git a/role-fargate.tf b/role-fargate.tf index cb05f26..64b25f0 100644 --- a/role-fargate.tf +++ b/role-fargate.tf @@ -16,7 +16,7 @@ resource "aws_iam_role" "fargate" { assume_role_policy = data.aws_iam_policy_document.assume_role_fargate.json } -resource "aws_iam_role_policy_attachment" "AmazonEKSFargatePodExecutionRolePolicy" { +resource "aws_iam_role_policy_attachment" "eks_fargate_pod_execution_role_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy" role = aws_iam_role.fargate.name } diff --git a/role-node.tf b/role-node.tf index 1125a2e..4591efc 100644 --- a/role-node.tf +++ b/role-node.tf @@ -16,19 +16,19 @@ resource "aws_iam_role" "node" { assume_role_policy = data.aws_iam_policy_document.assume_role_node.json } -resource "aws_iam_role_policy_attachment" "AmazonEKSWorkerNodePolicy" { +resource "aws_iam_role_policy_attachment" "eks_worker_node_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" role = aws_iam_role.node.name } -resource "aws_iam_role_policy_attachment" "AmazonEC2ContainerRegistryReadOnly" { +resource "aws_iam_role_policy_attachment" "ec2_container_registry_readonly" { policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" role = aws_iam_role.node.name } # The AmazonEKS_CNI_Policy policy must be attached to either this role # or to a different role that is mapped to the aws-node Kubernetes service account. -resource "aws_iam_role_policy_attachment" "AmazonEKS_CNI_Policy" { +resource "aws_iam_role_policy_attachment" "eks_cni_policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" role = aws_iam_role.node.name } diff --git a/variables.tf b/variables.tf index e1cd40a..9cd1523 100644 --- a/variables.tf +++ b/variables.tf @@ -96,6 +96,7 @@ variable "node_group_subnet_ids" { } variable "node_groups" { + description = "Map of EKS Node Group definitions." type = map(object({ subnet_ids = optional(set(string)) ami_type = optional(string, "AL2_x86_64") @@ -124,6 +125,7 @@ variable "fargate_subnet_ids" { } variable "fargate_profiles" { + description = "Map of EKS Fargate Profile definitions." type = map(object({ subnet_ids = optional(set(string)) namespace = string @@ -159,3 +161,23 @@ variable "auth_map_users" { })) default = [] } + +variable "nodes_role_arns" { + description = "Additional IAM role ARNs of Node Groups managed externally." + type = list(string) + default = [] +} + +variable "fargate_role_arns" { + description = "Additional IAM role ARNs of Fargate Profiles managed externally." + type = list(string) + default = [] +} + +variable "masters_role_arns" { + description = "List of IAM role to set as system:masters. Shortcut for auth_map_roles." + type = list(string) + default = [ + # "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/devops", + ] +}