Skip to content

Commit 25e9a3d

Browse files
authored
[eks/karpenter] Add support for kubelet config, fix IAM support for v1alpha cleanup (#1076)
1 parent 2c7ac72 commit 25e9a3d

File tree

8 files changed

+94
-11
lines changed

8 files changed

+94
-11
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## Components [PR #1076](https://github.com/cloudposse/terraform-aws-components/pull/1076)
2+
3+
- Allow specifying elements of `spec.template.spec.kubelet`
4+
- Make taint values optional
5+
6+
The `var.node_pools` map now includes a `kubelet` field that allows specifying elements of `spec.template.spec.kubelet`.
7+
This is useful for configuring the kubelet to use custom settings, such as reserving resources for system daemons.
8+
9+
For more information, see:
10+
11+
- [Karpenter documentation](https://karpenter.sh/docs/concepts/nodepools/#spectemplatespeckubelet)
12+
- [Kubernetes documentation](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/)
13+
14+
The `value` fields of the `taints` and `startup_taints` lists in the `var.node_pools` map are now optional. This is in
15+
alignment with the Kubernetes API, where `key` and `effect` are required, but the `value` field is optional.

modules/eks/karpenter-node-pool/README.md

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

modules/eks/karpenter-node-pool/main.tf

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ locals {
88
public_subnet_ids = module.vpc.outputs.public_subnet_ids
99

1010
node_pools = { for k, v in var.node_pools : k => v if local.enabled }
11+
kubelets_specs_filtered = { for k, v in local.node_pools : k => {
12+
for kk, vv in v.kubelet : kk => vv if vv != null
13+
}
14+
}
15+
kubelet_specs = { for k, v in local.kubelets_specs_filtered : k => v if length(v) > 0 }
1116
}
1217

1318
# https://karpenter.sh/docs/concepts/nodepools/
@@ -40,8 +45,8 @@ resource "kubernetes_manifest" "node_pool" {
4045
)
4146
template = {
4247
metadata = {
43-
labels = each.value.labels
44-
annotations = each.value.annotations
48+
labels = coalesce(each.value.labels, {})
49+
annotations = coalesce(each.value.annotations, {})
4550
}
4651
spec = merge({
4752
nodeClassRef = {
@@ -64,6 +69,9 @@ resource "kubernetes_manifest" "node_pool" {
6469
},
6570
try(length(each.value.startup_taints), 0) == 0 ? {} : {
6671
startupTaints = each.value.startup_taints
72+
},
73+
try(local.kubelet_specs[each.key], null) == null ? {} : {
74+
kubelet = local.kubelet_specs[each.key]
6775
}
6876
)
6977
}

modules/eks/karpenter-node-pool/variables.tf

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ variable "node_pools" {
7777
taints = optional(list(object({
7878
key = string
7979
effect = string
80-
value = string
80+
value = optional(string)
8181
})))
8282
startup_taints = optional(list(object({
8383
key = string
8484
effect = string
85-
value = string
85+
value = optional(string)
8686
})))
8787
# Karpenter node metadata options. See https://karpenter.sh/docs/concepts/nodeclasses/#specmetadataoptions for more details
8888
metadata_options = optional(object({
@@ -120,6 +120,12 @@ variable "node_pools" {
120120
# Operators like "Exists" and "DoesNotExist" do not require a value
121121
values = optional(list(string))
122122
}))
123+
# Any values for spec.template.spec.kubelet allowed by Karpenter.
124+
# Not fully specified, because they are subject to change.
125+
# See:
126+
# https://karpenter.sh/docs/concepts/nodepools/#spectemplatespeckubelet
127+
# https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/
128+
kubelet = optional(any, {})
123129
}))
124130
description = "Configuration for node pools. See code for details."
125131
nullable = false

modules/eks/karpenter/CHANGELOG.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
1+
## Components [PR #1076](https://github.com/cloudposse/terraform-aws-components/pull/1076)
2+
3+
#### Bugfix
4+
5+
- Fixed issues with IAM Policy support for cleaning up `v1alpha` resources.
6+
7+
With the previous release of this component, we encouraged users to delete their `v1alpha` Karpenter resources before
8+
upgrading to `v1beta`. However, certain things, such as EC2 Instance Profiles, would not be deleted by Terraform because
9+
they were created or modified by the Karpenter controller.
10+
11+
To enable the `v1beta` Karpenter controller to clean up these resources, we added a second IAM Policy to the official
12+
Karpenter IAM Policy document. This second policy allows the Karpenter controller to delete the `v1alpha` resources.
13+
However, there were 2 problems with that.
14+
15+
First, the policy was subtly incorrect, and did not, in fact, allow the Karpenter controller to delete all the
16+
resources. This has been fixed.
17+
18+
Second, a long EKS cluster name could cause the Karpenter IRSA's policy to exceed the maximum character limit for an IAM
19+
Policy. This has also been fixed by making the `v1alpha` policy a separate managed policy attached to the Karpenter
20+
controller's role, rather than merging the statements into the `v1beta` policy. This change also avoids potential
21+
conflicts with policy SIDs.
22+
23+
:::note Innocuous Changes
24+
25+
Terraform will show IAM Policy changes, including deletion of statements from the existing policy and creation of a new
26+
policy. This is expected and innocuous. The IAM Policy has been split into 2 to avoid exceeding length limits, but the
27+
current (`v1beta`) policy remains the same and the now separate (`v1alpha`) policy has been corrected.
28+
29+
:::
30+
131
## Version 1.445.0
232

3-
Components PR #1039
33+
Components [PR #1039](https://github.com/cloudposse/terraform-aws-components/pull/1039)
434

535
:::warning Major Breaking Changes
636

modules/eks/karpenter/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ For more details on the CRDs, see:
362362
|------|------|
363363
| [aws_cloudwatch_event_rule.interruption_handler](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |
364364
| [aws_cloudwatch_event_target.interruption_handler](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
365+
| [aws_iam_policy.v1alpha](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
366+
| [aws_iam_role_policy_attachment.v1alpha](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
365367
| [aws_sqs_queue.interruption_handler](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue) | resource |
366368
| [aws_sqs_queue_policy.interruption_handler](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue_policy) | resource |
367369
| [aws_eks_cluster_auth.eks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/eks_cluster_auth) | data source |

modules/eks/karpenter/controller-policy-v1alpha.tf

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
# v1alpha API tag "karpenter.sh/provisioner-name" and to manage the EC2 Instance Profile
1414
# created by the EKS cluster component.
1515
#
16-
# WARNING: it is important that the SID values do not conflict with the SID values in the
17-
# controller-policy.tf file, otherwise they will be overwritten.
16+
# We create a separate policy and attach it separately to the Karpenter controller role
17+
# because the main policy is near the 6,144 character limit for an IAM policy, and
18+
# adding this to it can push it over. See:
19+
# https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-quotas-entities
1820
#
1921

2022
locals {
@@ -35,10 +37,10 @@ locals {
3537
],
3638
"Condition": {
3739
"StringEquals": {
38-
"aws:ResourceTag/kubernetes.io/cluster/${local.eks_cluster_id}": "owned"
40+
"ec2:ResourceTag/karpenter.k8s.aws/cluster": "${local.eks_cluster_id}"
3941
},
4042
"StringLike": {
41-
"aws:ResourceTag/karpenter.sh/provisioner-name": "*"
43+
"ec2:ResourceTag/karpenter.sh/provisioner-name": "*"
4244
}
4345
}
4446
},
@@ -65,3 +67,23 @@ locals {
6567
}
6668
EndOfPolicy
6769
}
70+
71+
# We create a separate policy and attach it separately to the Karpenter controller role
72+
# because the main policy is near the 6,144 character limit for an IAM policy, and
73+
# adding this to it can push it over. See:
74+
# https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-quotas-entities
75+
resource "aws_iam_policy" "v1alpha" {
76+
count = local.enabled ? 1 : 0
77+
78+
name = "${module.this.id}-v1alpha"
79+
description = "Legacy Karpenter controller policy for v1alpha workloads"
80+
policy = local.controller_policy_v1alpha_json
81+
tags = module.this.tags
82+
}
83+
84+
resource "aws_iam_role_policy_attachment" "v1alpha" {
85+
count = local.enabled ? 1 : 0
86+
87+
role = module.karpenter.service_account_role_name
88+
policy_arn = one(aws_iam_policy.v1alpha[*].arn)
89+
}

modules/eks/karpenter/main.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ module "karpenter" {
7777
service_account_role_arn_annotation_enabled = true
7878

7979
iam_role_enabled = true
80-
iam_source_policy_documents = [local.controller_policy_v1alpha_json, local.controller_policy_json]
80+
iam_source_policy_documents = [local.controller_policy_json]
8181

8282
values = compact([
8383
yamlencode({

0 commit comments

Comments
 (0)