DEV Community

César Sepúlveda Barra
César Sepúlveda Barra

Posted on • Edited on • Originally published at Medium

From Zero to EKS and Hybrid-Nodes — Part 2: The EKS and Hybrid Nodes configuration.

Introduction:

In the previous part, we set up the VPC and the VPN Site-to-Site connection to prepare for our EKS cluster and hybrid nodes. The network diagram at that stage looked like this:

initial infra

In this second part, we’ll configure the EKS cluster using OpenTofu, including SSM Activation, and manually set up two Hybrid nodes using nodeadm.

Setup the EKS cluster

Cluster creation is straightforward. We’ll use the state file from the VPC creation to retrieve outputs, and we’ll create the cluster using the terraform-aws-modules/eks/aws module.

Full code is available here: https://github.com/csepulveda/modular-aws-resources/tree/main/EKS-HYBRID

################################################################################ # EKS Module ################################################################################ module "eks" { source = "terraform-aws-modules/eks/aws" version = "20.35.0" cluster_name = local.name cluster_version = var.eks_version enable_cluster_creator_admin_permissions = true cluster_endpoint_public_access = true cluster_addons = { coredns = { configuration_values = jsonencode({ replicaCount = 1 }) } eks-pod-identity-agent = {} kube-proxy = {} vpc-cni = {} } vpc_id = data.terraform_remote_state.vpc.outputs.vpc_id subnet_ids = data.terraform_remote_state.vpc.outputs.private_subnets control_plane_subnet_ids = data.terraform_remote_state.vpc.outputs.control_plane_subnet_ids eks_managed_node_groups = { eks-base = { ami_type = "AL2023_x86_64_STANDARD" instance_types = ["t3.small", "t3a.small"] min_size = 1 max_size = 1 desired_size = 1 capacity_type = "SPOT" network_interfaces = [{ delete_on_termination = true }] } } node_security_group_additional_rules = { allow-all-80-traffic-from-loadbalancers = { cidr_blocks = [for s in data.aws_subnet.elb_subnets : s.cidr_block] description = "Allow all traffic from load balancers" from_port = 80 to_port = 80 protocol = "TCP" type = "ingress" } hybrid-all = { cidr_blocks = ["192.168.100.0/23"] description = "Allow all traffic from remote node/pod network" from_port = 0 to_port = 0 protocol = "all" type = "ingress" } } cluster_security_group_additional_rules = { hybrid-all = { cidr_blocks = ["192.168.100.0/23"] description = "Allow all traffic from remote node/pod network" from_port = 0 to_port = 0 protocol = "all" type = "ingress" } } cluster_remote_network_config = { remote_node_networks = { cidrs = ["192.168.100.0/24"] } remote_pod_networks = { cidrs = ["192.168.101.0/24"] } } access_entries = { hybrid-node-role = { principal_arn = module.eks_hybrid_node_role.arn type = "HYBRID_LINUX" } } node_security_group_tags = merge(local.tags, { "karpenter.sh/discovery" = local.name }) tags = local.tags } ################################################################################ # Hybrid nodes Support ################################################################################ module "eks_hybrid_node_role" { source = "terraform-aws-modules/eks/aws//modules/hybrid-node-role" version = "20.35.0" name = "hybrid" tags = local.tags } resource "aws_ssm_activation" "this" { name = "hybrid-node" iam_role = module.eks_hybrid_node_role.name registration_limit = 10 tags = local.tags } resource "local_file" "nodeConfig" { content = <<-EOT apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: cluster: name: ${module.eks.cluster_name} region: ${local.region} hybrid: ssm: activationId: ${aws_ssm_activation.this.id} activationCode: ${aws_ssm_activation.this.activation_code}  EOT  filename = "nodeConfig.yaml" } 
Enter fullscreen mode Exit fullscreen mode

Highlights of the configuration:

  • One EKS-managed node group for core services and ACK controllers (to be installed in Part 3).

  • VPC CNI enabled via cluster_addons.

  • Ingress rules to allow traffic from on-premise networks.

  • Defined remote node and pod networks.

  • Created a role for hybrid nodes and granted access via access_entries.

Hybrid Nodes and SSM Activation

We define:

  • An IAM role using the hybrid node module.

  • An SSM Activation to allow hybrid nodes to join the cluster.

  • A nodeConfig.yaml file containing the activation credentials, automatically generated during tofu apply.

tofu apply .... Apply complete! Resources: 50 added, 0 changed, 0 destroyed. 
Enter fullscreen mode Exit fullscreen mode

This generates a nodeConfig.yaml file, which is critical for authenticating on-prem nodes via AWS Systems Manager.

Update your kubeconfig after creation:

aws eks update-kubeconfig --region us-east-1 --name my-eks-cluster 
Enter fullscreen mode Exit fullscreen mode

Now your infrastructure should look like this:

eks on infra

Setting Up the Hybrid Nodes

SSH into the nodes (e.g., 192.168.100.101 and 192.168.100.102). These are configured with two networks:

  • 192.168.100.0/24 for nodes.

  • 192.168.101.0/24 for pods.

Transfer the node config:

scp nodeConfig.yaml cesar@192.168.100.101:/tmp/ scp nodeConfig.yaml cesar@192.168.100.102:/tmp/ 
Enter fullscreen mode Exit fullscreen mode

Install and configure nodeadm:

curl -OL 'https://hybrid-assets.eks.amazonaws.com/releases/latest/bin/linux/arm64/nodeadm' chmod a+x nodeadm mv nodeadm /usr/local/bin/. nodeadm install 1.32 --credential-provider ssm nodeadm init --config-source file:///tmp/nodeConfig.yaml 
Enter fullscreen mode Exit fullscreen mode

Repeat for both nodes.

node instalation

Once done, check node registration:

kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME ip-10-0-19-137.ec2.internal Ready <none> 16m v1.32.1-eks-5d632ec 10.0.19.137 <none> Amazon Linux 2023.7.20250331 6.1.131-143.221.amzn2023.x86_64 containerd://1.7.27 mi-03c1eb4c6173151d6 NotReady <none> 3m4s v1.32.1-eks-5d632ec 192.168.100.102 <none> Ubuntu 22.04.5 LTS 5.15.0-136-generic containerd://1.7.24 mi-091f1dddb980a80ff NotReady <none> 3m51s v1.32.1-eks-5d632ec 192.168.100.101 <none> Ubuntu 22.04.5 LTS 5.15.0-136-generic containerd://1.7.24 
Enter fullscreen mode Exit fullscreen mode

The hybrid nodes appear but are NotReady — this is expected until we install a network controller.

Disclaimer time: Although the documentation claims compatibility with Ubuntu 22.04 and 24.04, I couldn’t get 24.04 working due to missing nf_conntrack when kube-proxy attempts to apply iptables rules. If you manage to fix this, please share!

Setting Up the Network with Cilium

We’ll use Cilium as CNI.

cilium-values.yaml:

affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: eks.amazonaws.com/compute-type operator: In values: - hybrid ipam: mode: cluster-pool operator: clusterPoolIPv4MaskSize: 24 clusterPoolIPv4PodCIDRList: - 192.168.101.0/24 operator: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: eks.amazonaws.com/compute-type operator: In values: - hybrid unmanagedPodWatcher: restart: false envoy: enabled: false 
Enter fullscreen mode Exit fullscreen mode

This yaml file indicate the affinity on cilium pods and also the cilium operator to run only en hybrid nodes, also we set the clusterPoolIPv4PodCIDRList pool, using the subnet 192.168.101.0/24

Install Cilium:

helm repo add cilium https://helm.cilium.io/ helm upgrade -i cilium cilium/cilium \ --version 1.17.2 \ --namespace kube-system \ --values cilium-values.yaml ... Release "cilium" does not exist. Installing it now. NAME: cilium LAST DEPLOYED: Fri Apr 11 08:35:31 2025 NAMESPACE: kube-system STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: You have successfully installed Cilium with Hubble. Your release version is 1.17.2. For any further help, visit https://docs.cilium.io/en/v1.17/gettinghelp 
Enter fullscreen mode Exit fullscreen mode

After a few minutes the nodes will be ready

kubectl get nodes -o wide 
Enter fullscreen mode Exit fullscreen mode

You should see:

NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME ip-10-0-19-137.ec2.internal Ready <none> 56m v1.32.1-eks-5d632ec 10.0.19.137 <none> Amazon Linux 2023.7.20250331 6.1.131-143.221.amzn2023.x86_64 containerd://1.7.27 mi-03c1eb4c6173151d6 Ready <none> 42m v1.32.1-eks-5d632ec 192.168.100.102 <none> Ubuntu 22.04.5 LTS 5.15.0-136-generic containerd://1.7.24 mi-091f1dddb980a80ff Ready <none> 43m v1.32.1-eks-5d632ec 192.168.100.101 <none> Ubuntu 22.04.5 LTS 5.15.0-136-generic containerd://1.7.24 
Enter fullscreen mode Exit fullscreen mode

Your hybrid nodes are now fully integrated with EKS. 🎊

Eks nodes

Now your infrastructure should look like this:

Infra after nodes

What’s Next?

In the final part of this series, we’ll:

  • Deploy the Network Load Balancer (NLB) Controller.

  • Set up an Ingress.

  • Deploy a sample service running entirely on hybrid/on-prem nodes.

Top comments (0)