Skip to content

Commit ea747ca

Browse files
committed
Initial commit
1 parent dbef0e2 commit ea747ca

File tree

9 files changed

+466
-65
lines changed

9 files changed

+466
-65
lines changed

.github/settings.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
# Upstream changes from _extends are only recognized when modifications are made to this file in the default branch.
22
_extends: .github
33
repository:
4-
name: template
5-
description: Template for Terraform Components
4+
name: aws-eks-alb-controller-ingress-class
5+
description: This component deploys a Kubernetes `IngressClass` resource for the AWS Load Balancer Controller
66
homepage: https://cloudposse.com/accelerate
77
topics: terraform, terraform-component
8-
9-
10-
11-

README.yaml

Lines changed: 122 additions & 49 deletions
Large diffs are not rendered by default.

src/main.tf

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,38 @@
1-
locals {
2-
enabled = module.this.enabled
3-
}
4-
5-
1+
resource "kubernetes_ingress_class_v1" "default" {
2+
metadata {
3+
name = var.class_name
4+
annotations = {
5+
"ingressclass.kubernetes.io/is-default-class" = "true"
6+
}
7+
}
68

9+
spec {
10+
controller = "ingress.k8s.aws/alb"
11+
parameters {
12+
api_group = "elbv2.k8s.aws"
13+
kind = "IngressClassParams"
14+
name = var.class_name
15+
}
16+
}
717

18+
depends_on = [kubernetes_manifest.alb_controller_class_params]
19+
}
820

21+
resource "kubernetes_manifest" "alb_controller_class_params" {
22+
manifest = {
23+
apiVersion = "elbv2.k8s.aws/v1beta1"
24+
kind = "IngressClassParams"
25+
metadata = {
26+
name = var.class_name
27+
}
28+
spec = {
29+
group = {
30+
name = var.group
31+
}
32+
scheme = var.scheme
33+
ipAddressType = var.ip_address_type
34+
tags = [for k, v in merge(module.this.tags, var.additional_tags) : { key = k, value = v }]
35+
loadBalancerAttributes = var.load_balancer_attributes
36+
}
37+
}
38+
}

src/outputs.tf

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/provider-helm.tf

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
##################
2+
#
3+
# This file is a drop-in to provide a helm provider.
4+
#
5+
# It depends on 2 standard Cloud Posse data source modules to be already
6+
# defined in the same component:
7+
#
8+
# 1. module.iam_roles to provide the AWS profile or Role ARN to use to access the cluster
9+
# 2. module.eks to provide the EKS cluster information
10+
#
11+
# All the following variables are just about configuring the Kubernetes provider
12+
# to be able to modify EKS cluster. The reason there are so many options is
13+
# because at various times, each one of them has had problems, so we give you a choice.
14+
#
15+
# The reason there are so many "enabled" inputs rather than automatically
16+
# detecting whether or not they are enabled based on the value of the input
17+
# is that any logic based on input values requires the values to be known during
18+
# the "plan" phase of Terraform, and often they are not, which causes problems.
19+
#
20+
variable "kubeconfig_file_enabled" {
21+
type = bool
22+
default = false
23+
description = "If `true`, configure the Kubernetes provider with `kubeconfig_file` and use that kubeconfig file for authenticating to the EKS cluster"
24+
nullable = false
25+
}
26+
27+
variable "kubeconfig_file" {
28+
type = string
29+
default = ""
30+
description = "The Kubernetes provider `config_path` setting to use when `kubeconfig_file_enabled` is `true`"
31+
nullable = false
32+
}
33+
34+
variable "kubeconfig_context" {
35+
type = string
36+
default = ""
37+
description = <<-EOT
38+
Context to choose from the Kubernetes config file.
39+
If supplied, `kubeconfig_context_format` will be ignored.
40+
EOT
41+
nullable = false
42+
}
43+
44+
variable "kubeconfig_context_format" {
45+
type = string
46+
default = ""
47+
description = <<-EOT
48+
A format string to use for creating the `kubectl` context name when
49+
`kubeconfig_file_enabled` is `true` and `kubeconfig_context` is not supplied.
50+
Must include a single `%s` which will be replaced with the cluster name.
51+
EOT
52+
nullable = false
53+
}
54+
55+
variable "kube_data_auth_enabled" {
56+
type = bool
57+
default = false
58+
description = <<-EOT
59+
If `true`, use an `aws_eks_cluster_auth` data source to authenticate to the EKS cluster.
60+
Disabled by `kubeconfig_file_enabled` or `kube_exec_auth_enabled`.
61+
EOT
62+
nullable = false
63+
}
64+
65+
variable "kube_exec_auth_enabled" {
66+
type = bool
67+
default = true
68+
description = <<-EOT
69+
If `true`, use the Kubernetes provider `exec` feature to execute `aws eks get-token` to authenticate to the EKS cluster.
70+
Disabled by `kubeconfig_file_enabled`, overrides `kube_data_auth_enabled`.
71+
EOT
72+
nullable = false
73+
}
74+
75+
variable "kube_exec_auth_role_arn" {
76+
type = string
77+
default = ""
78+
description = "The role ARN for `aws eks get-token` to use"
79+
nullable = false
80+
}
81+
82+
variable "kube_exec_auth_role_arn_enabled" {
83+
type = bool
84+
default = true
85+
description = "If `true`, pass `kube_exec_auth_role_arn` as the role ARN to `aws eks get-token`"
86+
nullable = false
87+
}
88+
89+
variable "kube_exec_auth_aws_profile" {
90+
type = string
91+
default = ""
92+
description = "The AWS config profile for `aws eks get-token` to use"
93+
nullable = false
94+
}
95+
96+
variable "kube_exec_auth_aws_profile_enabled" {
97+
type = bool
98+
default = false
99+
description = "If `true`, pass `kube_exec_auth_aws_profile` as the `profile` to `aws eks get-token`"
100+
nullable = false
101+
}
102+
103+
variable "kubeconfig_exec_auth_api_version" {
104+
type = string
105+
default = "client.authentication.k8s.io/v1beta1"
106+
description = "The Kubernetes API version of the credentials returned by the `exec` auth plugin"
107+
nullable = false
108+
}
109+
110+
variable "helm_manifest_experiment_enabled" {
111+
type = bool
112+
default = false
113+
description = "Enable storing of the rendered manifest for helm_release so the full diff of what is changing can been seen in the plan"
114+
nullable = false
115+
}
116+
117+
locals {
118+
kubeconfig_file_enabled = var.kubeconfig_file_enabled
119+
kubeconfig_file = local.kubeconfig_file_enabled ? var.kubeconfig_file : ""
120+
kubeconfig_context = !local.kubeconfig_file_enabled ? "" : (
121+
length(var.kubeconfig_context) != 0 ? var.kubeconfig_context : (
122+
length(var.kubeconfig_context_format) != 0 ? format(var.kubeconfig_context_format, local.eks_cluster_id) : ""
123+
)
124+
)
125+
126+
kube_exec_auth_enabled = local.kubeconfig_file_enabled ? false : var.kube_exec_auth_enabled
127+
kube_data_auth_enabled = local.kube_exec_auth_enabled ? false : var.kube_data_auth_enabled
128+
129+
# Eventually we might try to get this from an environment variable
130+
kubeconfig_exec_auth_api_version = var.kubeconfig_exec_auth_api_version
131+
132+
exec_profile = local.kube_exec_auth_enabled && var.kube_exec_auth_aws_profile_enabled ? [
133+
"--profile", var.kube_exec_auth_aws_profile
134+
] : []
135+
136+
kube_exec_auth_role_arn = coalesce(var.kube_exec_auth_role_arn, module.iam_roles.terraform_role_arn)
137+
exec_role = local.kube_exec_auth_enabled && var.kube_exec_auth_role_arn_enabled ? [
138+
"--role-arn", local.kube_exec_auth_role_arn
139+
] : []
140+
141+
# Provide dummy configuration for the case where the EKS cluster is not available.
142+
certificate_authority_data = local.kubeconfig_file_enabled ? null : try(module.eks.outputs.eks_cluster_certificate_authority_data, null)
143+
cluster_ca_certificate = local.kubeconfig_file_enabled ? null : try(base64decode(local.certificate_authority_data), null)
144+
# Use coalesce+try to handle both the case where the output is missing and the case where it is empty.
145+
eks_cluster_id = coalesce(try(module.eks.outputs.eks_cluster_id, ""), "missing")
146+
eks_cluster_endpoint = local.kubeconfig_file_enabled ? null : try(module.eks.outputs.eks_cluster_endpoint, "")
147+
}
148+
149+
data "aws_eks_cluster_auth" "eks" {
150+
count = local.kube_data_auth_enabled ? 1 : 0
151+
name = local.eks_cluster_id
152+
}
153+
154+
provider "helm" {
155+
kubernetes {
156+
host = local.eks_cluster_endpoint
157+
cluster_ca_certificate = local.cluster_ca_certificate
158+
token = local.kube_data_auth_enabled ? one(data.aws_eks_cluster_auth.eks[*].token) : null
159+
# It is too confusing to allow the Kubernetes provider to use environment variables to set authentication
160+
# in this module because we have so many options, so we override environment variables like `KUBE_CONFIG_PATH`
161+
# in all cases. People can still use environment variables by setting TF_VAR_kubeconfig_file.
162+
config_path = local.kubeconfig_file
163+
config_context = local.kubeconfig_context
164+
165+
dynamic "exec" {
166+
for_each = local.kube_exec_auth_enabled && local.certificate_authority_data != null ? ["exec"] : []
167+
content {
168+
api_version = local.kubeconfig_exec_auth_api_version
169+
command = "aws"
170+
args = concat(local.exec_profile, [
171+
"eks", "get-token", "--cluster-name", local.eks_cluster_id
172+
], local.exec_role)
173+
}
174+
}
175+
}
176+
experiments {
177+
manifest = var.helm_manifest_experiment_enabled && module.this.enabled
178+
}
179+
}
180+
181+
provider "kubernetes" {
182+
host = local.eks_cluster_endpoint
183+
cluster_ca_certificate = local.cluster_ca_certificate
184+
token = local.kube_data_auth_enabled ? one(data.aws_eks_cluster_auth.eks[*].token) : null
185+
# It is too confusing to allow the Kubernetes provider to use environment variables to set authentication
186+
# in this module because we have so many options, so we override environment variables like `KUBE_CONFIG_PATH`
187+
# in all cases. People can still use environment variables by setting TF_VAR_kubeconfig_file.
188+
config_path = local.kubeconfig_file
189+
config_context = local.kubeconfig_context
190+
191+
dynamic "exec" {
192+
for_each = local.kube_exec_auth_enabled && local.certificate_authority_data != null ? ["exec"] : []
193+
content {
194+
api_version = local.kubeconfig_exec_auth_api_version
195+
command = "aws"
196+
args = concat(local.exec_profile, [
197+
"eks", "get-token", "--cluster-name", local.eks_cluster_id
198+
], local.exec_role)
199+
}
200+
}
201+
}

src/providers.tf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
provider "aws" {
2+
region = var.region
3+
4+
# Profile is deprecated in favor of terraform_role_arn. When profiles are not in use, terraform_profile_name is null.
5+
profile = module.iam_roles.terraform_profile_name
6+
7+
dynamic "assume_role" {
8+
# module.iam_roles.terraform_role_arn may be null, in which case do not assume a role.
9+
for_each = compact([module.iam_roles.terraform_role_arn])
10+
content {
11+
role_arn = assume_role.value
12+
}
13+
}
14+
}
15+
16+
module "iam_roles" {
17+
source = "../../account-map/modules/iam-roles"
18+
context = module.this.context
19+
}

src/remote-state.tf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module "eks" {
2+
source = "cloudposse/stack-config/yaml//modules/remote-state"
3+
version = "1.5.0"
4+
5+
component = var.eks_component_name
6+
7+
context = module.this.context
8+
}

src/variables.tf

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
variable "region" {
2+
description = "AWS Region."
3+
type = string
4+
}
5+
6+
variable "eks_component_name" {
7+
type = string
8+
description = "The name of the eks component"
9+
default = "eks/cluster"
10+
}
11+
12+
variable "is_default" {
13+
type = bool
14+
description = "Set `true` to make this the default IngressClass. There should only be one default per cluster."
15+
default = false
16+
}
17+
18+
variable "class_name" {
19+
type = string
20+
description = "Class name for default ingress"
21+
default = "default"
22+
}
23+
24+
variable "group" {
25+
type = string
26+
description = "Group name for default ingress"
27+
default = "common"
28+
}
29+
30+
variable "scheme" {
31+
type = string
32+
description = "Scheme for default ingress, one of `internet-facing` or `internal`."
33+
default = "internet-facing"
34+
35+
validation {
36+
condition = contains(["internet-facing", "internal"], var.scheme)
37+
error_message = "The default ingress scheme must be one of `internet-facing` or `internal`."
38+
}
39+
}
40+
41+
variable "ip_address_type" {
42+
type = string
43+
description = "IP address type for default ingress, one of `ipv4` or `dualstack`."
44+
default = "dualstack"
45+
46+
validation {
47+
condition = contains(["ipv4", "dualstack"], var.ip_address_type)
48+
error_message = "The default ingress IP address type must be one of `ipv4` or `dualstack`."
49+
}
50+
}
51+
52+
variable "load_balancer_attributes" {
53+
type = list(object({ key = string, value = string }))
54+
description = <<-EOT
55+
A list of load balancer attributes to apply to the default ingress load balancer.
56+
See [Load Balancer Attributes](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#load-balancer-attributes).
57+
EOT
58+
default = []
59+
}
60+
61+
variable "additional_tags" {
62+
type = map(string)
63+
description = "Additional tags to apply to the ingress load balancer."
64+
default = {}
65+
}

src/versions.tf

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
terraform {
22
required_version = ">= 1.0.0"
33

4-
required_providers {}
4+
required_providers {
5+
aws = {
6+
source = "hashicorp/aws"
7+
version = ">= 4.9.0"
8+
}
9+
helm = {
10+
source = "hashicorp/helm"
11+
version = ">= 2.0"
12+
}
13+
kubernetes = {
14+
source = "hashicorp/kubernetes"
15+
version = ">= 2.14.0, != 2.21.0"
16+
}
17+
}
518
}

0 commit comments

Comments
 (0)