Skip to content

Commit 863d4ab

Browse files
authored
Fix for remote access and lifecycle issues (#30)
1 parent a93cdea commit 863d4ab

File tree

7 files changed

+85
-29
lines changed

7 files changed

+85
-29
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ Available targets:
208208
| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.<br>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
209209
| desired\_size | Initial desired number of worker nodes (external changes ignored) | `number` | n/a | yes |
210210
| disk\_size | Disk size in GiB for worker nodes. Defaults to 20. Ignored it `launch_template_id` is supplied.<br>Terraform will only perform drift detection if a configuration value is provided. | `number` | `20` | no |
211-
| ec2\_ssh\_key | SSH key name that should be used to access the worker nodes | `string` | `null` | no |
211+
| ec2\_ssh\_key | SSH key pair name to use to access the worker nodes | `string` | `null` | no |
212212
| enable\_cluster\_autoscaler | Set true to allow Kubernetes Cluster Auto Scaler to scale the node group | `bool` | `false` | no |
213213
| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
214214
| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
@@ -230,18 +230,19 @@ Available targets:
230230
| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no |
231231
| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.<br>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
232232
| resources\_to\_tag | List of auto-launched resource types to tag. Valid types are "instance", "volume", "elastic-gpu", "spot-instances-request". | `list(string)` | `[]` | no |
233-
| source\_security\_group\_ids | Set of EC2 Security Group IDs to allow SSH access (port 22) from on the worker nodes. If you specify `ec2_ssh_key`, but do not specify this configuration when you create an EKS Node Group, port 22 on the worker nodes is opened to the Internet (0.0.0.0/0) | `list(string)` | `[]` | no |
233+
| source\_security\_group\_ids | Set of EC2 Security Group IDs to allow SSH access (port 22) to the worker nodes. If you specify `ec2_ssh_key`, but do not specify this configuration when you create an EKS Node Group, port 22 on the worker nodes is opened to the Internet (0.0.0.0/0) | `list(string)` | `[]` | no |
234234
| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
235235
| subnet\_ids | A list of subnet IDs to launch resources in | `list(string)` | n/a | yes |
236236
| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no |
237-
| userdata\_override | Many features of this module rely on the `bootstrap.sh` provided with Amazon Linux, and this module<br>may generate "user data" that expects to find that script. If you want to use an AMI that is not<br>compatible with the Amazon Linux `bootstrap.sh` initialization, then use `userdata_override` to provide<br>your own (Base64 encoded) user data. Use "" to prevent any user data from being set.<br><br>Setting `userdata_override` disables `kubernetes_taints`, `kubelet_additional_options`,<br>`before_cluster_joining_userdata`, `after_cluster_joining_userdata`, and `bootstrap_additional_options`. | `string` | `null` | no |
237+
| userdata\_override\_base64 | Many features of this module rely on the `bootstrap.sh` provided with Amazon Linux, and this module<br>may generate "user data" that expects to find that script. If you want to use an AMI that is not<br>compatible with the Amazon Linux `bootstrap.sh` initialization, then use `userdata_override_base64` to provide<br>your own (Base64 encoded) user data. Use "" to prevent any user data from being set.<br><br>Setting `userdata_override_base64` disables `kubernetes_taints`, `kubelet_additional_options`,<br>`before_cluster_joining_userdata`, `after_cluster_joining_userdata`, and `bootstrap_additional_options`. | `string` | `null` | no |
238238

239239
## Outputs
240240

241241
| Name | Description |
242242
|------|-------------|
243243
| eks\_node\_group\_arn | Amazon Resource Name (ARN) of the EKS Node Group |
244244
| eks\_node\_group\_id | EKS Cluster name and EKS Node Group name separated by a colon |
245+
| eks\_node\_group\_remote\_access\_security\_group\_id | The ID of the security group generated to allow SSH access to the nodes, if this module generated one |
245246
| eks\_node\_group\_resources | List of objects containing information about underlying resources of the EKS Node Group |
246247
| eks\_node\_group\_role\_arn | ARN of the worker nodes IAM role |
247248
| eks\_node\_group\_role\_name | Name of the worker nodes IAM role |

docs/terraform.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
| delimiter | Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`.<br>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
3535
| desired\_size | Initial desired number of worker nodes (external changes ignored) | `number` | n/a | yes |
3636
| disk\_size | Disk size in GiB for worker nodes. Defaults to 20. Ignored it `launch_template_id` is supplied.<br>Terraform will only perform drift detection if a configuration value is provided. | `number` | `20` | no |
37-
| ec2\_ssh\_key | SSH key name that should be used to access the worker nodes | `string` | `null` | no |
37+
| ec2\_ssh\_key | SSH key pair name to use to access the worker nodes | `string` | `null` | no |
3838
| enable\_cluster\_autoscaler | Set true to allow Kubernetes Cluster Auto Scaler to scale the node group | `bool` | `false` | no |
3939
| enabled | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
4040
| environment | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
@@ -56,18 +56,19 @@
5656
| namespace | Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp' | `string` | `null` | no |
5757
| regex\_replace\_chars | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.<br>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
5858
| resources\_to\_tag | List of auto-launched resource types to tag. Valid types are "instance", "volume", "elastic-gpu", "spot-instances-request". | `list(string)` | `[]` | no |
59-
| source\_security\_group\_ids | Set of EC2 Security Group IDs to allow SSH access (port 22) from on the worker nodes. If you specify `ec2_ssh_key`, but do not specify this configuration when you create an EKS Node Group, port 22 on the worker nodes is opened to the Internet (0.0.0.0/0) | `list(string)` | `[]` | no |
59+
| source\_security\_group\_ids | Set of EC2 Security Group IDs to allow SSH access (port 22) to the worker nodes. If you specify `ec2_ssh_key`, but do not specify this configuration when you create an EKS Node Group, port 22 on the worker nodes is opened to the Internet (0.0.0.0/0) | `list(string)` | `[]` | no |
6060
| stage | Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
6161
| subnet\_ids | A list of subnet IDs to launch resources in | `list(string)` | n/a | yes |
6262
| tags | Additional tags (e.g. `map('BusinessUnit','XYZ')` | `map(string)` | `{}` | no |
63-
| userdata\_override | Many features of this module rely on the `bootstrap.sh` provided with Amazon Linux, and this module<br>may generate "user data" that expects to find that script. If you want to use an AMI that is not<br>compatible with the Amazon Linux `bootstrap.sh` initialization, then use `userdata_override` to provide<br>your own (Base64 encoded) user data. Use "" to prevent any user data from being set.<br><br>Setting `userdata_override` disables `kubernetes_taints`, `kubelet_additional_options`,<br>`before_cluster_joining_userdata`, `after_cluster_joining_userdata`, and `bootstrap_additional_options`. | `string` | `null` | no |
63+
| userdata\_override\_base64 | Many features of this module rely on the `bootstrap.sh` provided with Amazon Linux, and this module<br>may generate "user data" that expects to find that script. If you want to use an AMI that is not<br>compatible with the Amazon Linux `bootstrap.sh` initialization, then use `userdata_override_base64` to provide<br>your own (Base64 encoded) user data. Use "" to prevent any user data from being set.<br><br>Setting `userdata_override_base64` disables `kubernetes_taints`, `kubelet_additional_options`,<br>`before_cluster_joining_userdata`, `after_cluster_joining_userdata`, and `bootstrap_additional_options`. | `string` | `null` | no |
6464

6565
## Outputs
6666

6767
| Name | Description |
6868
|------|-------------|
6969
| eks\_node\_group\_arn | Amazon Resource Name (ARN) of the EKS Node Group |
7070
| eks\_node\_group\_id | EKS Cluster name and EKS Node Group name separated by a colon |
71+
| eks\_node\_group\_remote\_access\_security\_group\_id | The ID of the security group generated to allow SSH access to the nodes, if this module generated one |
7172
| eks\_node\_group\_resources | List of objects containing information about underlying resources of the EKS Node Group |
7273
| eks\_node\_group\_role\_arn | ARN of the worker nodes IAM role |
7374
| eks\_node\_group\_role\_name | Name of the worker nodes IAM role |

main.tf

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ locals {
2727
configured_launch_template_version = length(local.configured_launch_template_name) > 0 && length(compact([var.launch_template_version])) > 0 ? var.launch_template_version : ""
2828

2929
configured_ami_image_id = var.ami_image_id == null ? "" : var.ami_image_id
30+
have_ssh_key = var.ec2_ssh_key != null && var.ec2_ssh_key != ""
3031

3132
# See https://aws.amazon.com/blogs/containers/introducing-launch-template-and-custom-ami-support-in-amazon-eks-managed-node-groups/
3233
features_require_ami = local.enabled && local.need_bootstrap
@@ -46,6 +47,12 @@ locals {
4647

4748
launch_template_ami = length(local.configured_ami_image_id) == 0 ? (local.features_require_ami ? data.aws_ami.selected[0].image_id : "") : local.configured_ami_image_id
4849

50+
need_remote_access_sg = local.enabled && local.have_ssh_key && local.generate_launch_template
51+
launch_template_vpc_security_group_ids = (
52+
local.need_remote_access_sg ?
53+
concat(data.aws_eks_cluster.this[0].vpc_config[*].cluster_security_group_id, aws_security_group.remote_access.*.id) : null
54+
)
55+
4956
autoscaler_enabled_tags = {
5057
"k8s.io/cluster-autoscaler/${var.cluster_name}" = "owned"
5158
"k8s.io/cluster-autoscaler/enabled" = "true"
@@ -68,16 +75,14 @@ locals {
6875

6976
aws_policy_prefix = format("arn:%s:iam::aws:policy", join("", data.aws_partition.current.*.partition))
7077

71-
get_cluster_data = local.enabled ? (local.need_cluster_kubernetes_version || local.need_bootstrap) : false
78+
get_cluster_data = local.enabled ? (local.need_cluster_kubernetes_version || local.need_bootstrap || local.need_remote_access_sg) : false
7279
}
7380

7481
data "aws_eks_cluster" "this" {
7582
count = local.get_cluster_data ? 1 : 0
7683
name = var.cluster_name
7784
}
7885

79-
80-
8186
module "label" {
8287
source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.19.2"
8388

@@ -190,6 +195,7 @@ resource "aws_launch_template" "default" {
190195

191196
instance_type = var.instance_types[0]
192197
image_id = local.launch_template_ami == "" ? null : local.launch_template_ami
198+
key_name = local.have_ssh_key ? var.ec2_ssh_key : null
193199

194200
dynamic "tag_specifications" {
195201
for_each = var.resources_to_tag
@@ -211,8 +217,13 @@ resource "aws_launch_template" "default" {
211217
http_endpoint = "enabled"
212218
}
213219

214-
user_data = local.userdata
215-
tags = local.node_group_tags
220+
vpc_security_group_ids = local.launch_template_vpc_security_group_ids
221+
user_data = local.userdata
222+
tags = local.node_group_tags
223+
224+
lifecycle {
225+
create_before_destroy = true
226+
}
216227
}
217228

218229
data "aws_launch_template" "this" {
@@ -239,11 +250,14 @@ resource "random_pet" "cbd" {
239250
source_security_group_ids = join(",", var.source_security_group_ids)
240251
subnet_ids = join(",", var.subnet_ids)
241252

242-
launch_template_id = local.launch_template_id
243-
launch_template_ami = local.launch_template_ami
253+
launch_template_id = local.use_launch_template ? local.launch_template_id : null
254+
launch_template_ami = local.use_launch_template ? local.launch_template_ami : null
244255
}
245256

246257
depends_on = [var.module_depends_on]
258+
lifecycle {
259+
create_before_destroy = true
260+
}
247261
}
248262

249263

@@ -268,7 +282,9 @@ locals {
268282
min_size = var.min_size
269283
}
270284

271-
ec2_ssh_key = var.ec2_ssh_key == null ? "" : var.ec2_ssh_key
285+
# Configure remote access via Launch Template if we are using one
286+
need_remote_access = local.have_ssh_key && ! local.use_launch_template
287+
ec2_ssh_key = var.ec2_ssh_key
272288
source_security_group_ids = var.source_security_group_ids
273289
}
274290
}
@@ -317,7 +333,7 @@ resource "aws_eks_node_group" "default" {
317333
}
318334

319335
dynamic "remote_access" {
320-
for_each = length(local.ng.ec2_ssh_key) > 0 ? ["true"] : []
336+
for_each = local.ng.need_remote_access ? ["true"] : []
321337
content {
322338
ec2_ssh_key = local.ng.ec2_ssh_key
323339
source_security_group_ids = local.ng.source_security_group_ids
@@ -378,7 +394,7 @@ resource "aws_eks_node_group" "cbd" {
378394
}
379395

380396
dynamic "remote_access" {
381-
for_each = length(local.ng.ec2_ssh_key) > 0 ? ["true"] : []
397+
for_each = local.ng.need_remote_access ? ["true"] : []
382398
content {
383399
ec2_ssh_key = local.ng.ec2_ssh_key
384400
source_security_group_ids = local.ng.source_security_group_ids

outputs.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ output "eks_node_group_status" {
2727
description = "Status of the EKS Node Group"
2828
value = join("", aws_eks_node_group.default.*.status, aws_eks_node_group.cbd.*.status)
2929
}
30+
31+
output "eks_node_group_remote_access_security_group_id" {
32+
description = "The ID of the security group generated to allow SSH access to the nodes, if this module generated one"
33+
value = join("", aws_security_group.remote_access.*.id)
34+
}

sg.tf

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# https://docs.aws.amazon.com/eks/latest/APIReference/API_RemoteAccessConfig.html
2+
3+
resource "aws_security_group" "remote_access" {
4+
count = local.need_remote_access_sg ? 1 : 0
5+
name = format("%v%v%v", module.label.id, module.label.delimiter, "remoteAccess")
6+
description = "Allow SSH access to all nodes in the nodeGroup"
7+
vpc_id = data.aws_eks_cluster.this[0].vpc_config[0].vpc_id
8+
tags = module.label.tags
9+
}
10+
11+
resource "aws_security_group_rule" "remote_access_public_ssh" {
12+
count = local.need_remote_access_sg && length(var.source_security_group_ids) == 0 ? 1 : 0
13+
description = "Allow SSH access to nodes from anywhere"
14+
type = "ingress"
15+
protocol = "tcp"
16+
from_port = 22
17+
to_port = 22
18+
cidr_blocks = ["0.0.0.0/0"]
19+
20+
security_group_id = join("", aws_security_group.remote_access.*.id)
21+
}
22+
23+
resource "aws_security_group_rule" "remote_access_source_sgs_ssh" {
24+
for_each = local.need_remote_access_sg ? toset(var.source_security_group_ids) : []
25+
description = "Allow SSH access to nodes from security group"
26+
type = "ingress"
27+
protocol = "tcp"
28+
from_port = 22
29+
to_port = 22
30+
31+
security_group_id = aws_security_group.remote_access[0].id
32+
source_security_group_id = each.value
33+
}

userdata.tf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ locals {
4545
local.userdata_vars.after_cluster_joining_userdata]
4646
)) > 0 : false
4747

48-
# If var.userdata_override = "" then we explicitly set userdata to ""
49-
need_userdata = local.enabled && var.userdata_override == null ? (length(local.userdata_vars.before_cluster_joining_userdata) > 0) || local.need_bootstrap : false
48+
# If var.userdata_override_base64 = "" then we explicitly set userdata to ""
49+
need_userdata = local.enabled && var.userdata_override_base64 == null ? (length(local.userdata_vars.before_cluster_joining_userdata) > 0) || local.need_bootstrap : false
5050

51-
userdata = local.need_userdata ? base64encode(templatefile("${path.module}/userdata.tpl", merge(local.userdata_vars, local.cluster_data))) : var.userdata_override
51+
userdata = local.need_userdata ? base64encode(templatefile("${path.module}/userdata.tpl", merge(local.userdata_vars, local.cluster_data))) : var.userdata_override_base64
5252
}

variables.tf

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,16 @@ variable "create_before_destroy" {
2121

2222
variable "ec2_ssh_key" {
2323
type = string
24-
description = "SSH key name that should be used to access the worker nodes"
24+
description = "SSH key pair name to use to access the worker nodes"
2525
default = null
2626
}
2727

28+
variable "source_security_group_ids" {
29+
type = list(string)
30+
default = []
31+
description = "Set of EC2 Security Group IDs to allow SSH access (port 22) to the worker nodes. If you specify `ec2_ssh_key`, but do not specify this configuration when you create an EKS Node Group, port 22 on the worker nodes is opened to the Internet (0.0.0.0/0)"
32+
}
33+
2834
variable "desired_size" {
2935
type = number
3036
description = "Initial desired number of worker nodes (external changes ignored)"
@@ -158,12 +164,6 @@ variable "kubernetes_version" {
158164
}
159165
}
160166

161-
variable "source_security_group_ids" {
162-
type = list(string)
163-
default = []
164-
description = "Set of EC2 Security Group IDs to allow SSH access (port 22) from on the worker nodes. If you specify `ec2_ssh_key`, but do not specify this configuration when you create an EKS Node Group, port 22 on the worker nodes is opened to the Internet (0.0.0.0/0)"
165-
}
166-
167167
variable "module_depends_on" {
168168
type = any
169169
default = null
@@ -213,16 +213,16 @@ variable "bootstrap_additional_options" {
213213
description = "Additional options to bootstrap.sh. DO NOT include `--kubelet-additional-args`, use `kubelet_additional_args` var instead."
214214
}
215215

216-
variable "userdata_override" {
216+
variable "userdata_override_base64" {
217217
type = string
218218
default = null
219219
description = <<-EOT
220220
Many features of this module rely on the `bootstrap.sh` provided with Amazon Linux, and this module
221221
may generate "user data" that expects to find that script. If you want to use an AMI that is not
222-
compatible with the Amazon Linux `bootstrap.sh` initialization, then use `userdata_override` to provide
222+
compatible with the Amazon Linux `bootstrap.sh` initialization, then use `userdata_override_base64` to provide
223223
your own (Base64 encoded) user data. Use "" to prevent any user data from being set.
224224
225-
Setting `userdata_override` disables `kubernetes_taints`, `kubelet_additional_options`,
225+
Setting `userdata_override_base64` disables `kubernetes_taints`, `kubelet_additional_options`,
226226
`before_cluster_joining_userdata`, `after_cluster_joining_userdata`, and `bootstrap_additional_options`.
227227
EOT
228228
}

0 commit comments

Comments
 (0)