<p>I'm having a hard time getting EKS to expose an IP address to the public internet. Do I need to set up the ALB myself or do you get that for free as part of the EKS cluster? If I have to do it myself, do I need to define it in the terraform template file or in the kubernetes object yaml?</p>
<p>Here's my EKS cluster defined in Terraform along with what I think are the required permissions.</p>
<pre class="lang-golang prettyprint-override"><code>// eks.tf

resource &quot;aws_iam_role&quot; &quot;eks_cluster_role&quot; {
  name = &quot;${local.env_name}-eks-cluster-role&quot;
  assume_role_policy = jsonencode({
    Version = &quot;2012-10-17&quot;,
    Statement = [
      {
        Effect = &quot;Allow&quot;,
        Principal = {
          Service = &quot;eks.amazonaws.com&quot;
        },
        Action = &quot;sts:AssumeRole&quot;
      }
    ]
  })
}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks-AmazonEKSClusterPolicy&quot; {
  policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEKSClusterPolicy&quot;
  role       = aws_iam_role.eks_cluster_role.name
}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks-AmazonEKSVPCResourceController&quot; {
  policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEKSVPCResourceController&quot;
  role       = aws_iam_role.eks_cluster_role.name
}

resource &quot;aws_kms_key&quot; &quot;eks_key&quot; {
  description             = &quot;EKS KMS Key&quot;
  deletion_window_in_days = 7
  enable_key_rotation     = true

  tags = {
    Environment = local.env_name
    Service     = &quot;EKS&quot;
  }
}

resource &quot;aws_kms_alias&quot; &quot;eks_key_alias&quot; {
  target_key_id = aws_kms_key.eks_key.id
  name          = &quot;alias/eks-kms-key-${local.env_name}&quot;
}

resource &quot;aws_eks_cluster&quot; &quot;eks_cluster&quot; {
  name                      = &quot;${local.env_name}-eks-cluster&quot;
  role_arn                  = aws_iam_role.eks_cluster_role.arn
  enabled_cluster_log_types = [&quot;api&quot;, &quot;audit&quot;, &quot;authenticator&quot;, &quot;controllerManager&quot;, &quot;scheduler&quot;]

  vpc_config {
    subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id]
  }

  encryption_config {
    resources = [&quot;secrets&quot;]

    provider {
      key_arn = aws_kms_key.eks_key.arn
    }
  }

  tags = {
    Environment = local.env_name
  }
}

resource &quot;aws_iam_role&quot; &quot;eks_node_group_role&quot; {
  name = &quot;${local.env_name}-eks-node-group&quot;
  assume_role_policy = jsonencode({
    Version = &quot;2012-10-17&quot;,
    Statement = [
      {
        Effect = &quot;Allow&quot;,
        Principal = {
          Service = &quot;ec2.amazonaws.com&quot;
        },
        Action = &quot;sts:AssumeRole&quot;
      }
    ]
  })
}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks-node-group-AmazonEKSWorkerNodePolicy&quot; {
  policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy&quot;
  role       = aws_iam_role.eks_node_group_role.name
}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks-node-group-AmazonEKS_CNI_Policy&quot; {
  policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy&quot;
  role       = aws_iam_role.eks_node_group_role.name
}

resource &quot;aws_iam_role_policy_attachment&quot; &quot;eks-node-group-AmazonEC2ContainerRegistryReadOnly&quot; {
  policy_arn = &quot;arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly&quot;
  role       = aws_iam_role.eks_node_group_role.name
}

resource &quot;aws_eks_node_group&quot; &quot;eks_node_group&quot; {
  instance_types  = var.node_group_instance_types
  node_group_name = &quot;${local.env_name}-eks-node-group&quot;
  node_role_arn   = aws_iam_role.eks_node_group_role.arn
  cluster_name    = aws_eks_cluster.eks_cluster.name
  subnet_ids      = [aws_subnet.private_a.id, aws_subnet.private_b.id]

  scaling_config {
    desired_size = 1
    max_size     = 1
    min_size     = 1
  }

  // Ensure that IAM Role permissions are created before and deleted after EKS Node Group handling.
  // Otherwise, EKS will not be able to properly delete EC2 Instances and Elastic Network Interfaces.
  depends_on = [
    aws_iam_role_policy_attachment.eks-node-group-AmazonEC2ContainerRegistryReadOnly,
    aws_iam_role_policy_attachment.eks-node-group-AmazonEKS_CNI_Policy,
    aws_iam_role_policy_attachment.eks-node-group-AmazonEKSWorkerNodePolicy,
  ]
</code></pre>
<p>And here's my kubernetes object yaml:</p>
<pre class="lang-yaml prettyprint-override"><code># hello-kubernetes.yaml

apiVersion: v1
kind: Service
metadata:
  name: hello-kubernetes
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: hello-kubernetes
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-kubernetes
  template:
    metadata:
      labels:
        app: hello-kubernetes
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.9
        ports:
        - containerPort: 8080
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: hello-ingress
spec:
  backend:
    serviceName: hello-kubernetes
    servicePort: 80
</code></pre>
<p>I've run <code>terraform apply</code> and the cluster is up and running. I've installed <code>eksctl</code> and <code>kubectl</code> and run <code>kubectl apply -f hello-kubernetes.yaml</code>. The pods, service, and ingress appear to be running fine.</p>
<pre class="lang-sh prettyprint-override"><code>$ kubectl get pods
NAME                                READY   STATUS             RESTARTS   AGE
hello-kubernetes-6cb7cd595b-25bd9   1/1     Running            0          6h13m
hello-kubernetes-6cb7cd595b-lccdj   1/1     Running            0          6h13m
hello-kubernetes-6cb7cd595b-snwvr   1/1     Running            0          6h13m

$ kubectl get services
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
hello-kubernetes   LoadBalancer   172.20.102.37   &lt;pending&gt;     80:32086/TCP   6h15m

$ kubectl get ingresses
NAME            CLASS    HOSTS   ADDRESS   PORTS   AGE
hello-ingress   &lt;none&gt;   *                 80      3h45m
</code></pre>
<p>What am I missing and which file does it belong in?</p>

<p>You need to install the <a href="https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/" rel="nofollow noreferrer">AWS Load Balancer Controller</a> by following the <a href="https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/deploy/installation/" rel="nofollow noreferrer">installation instructions</a>; first you need to create IAM Role and permissions, this can be done with Terraform; then you need to apply Kubernetes Yaml for installing the controller into your cluster, this can be done with Helm or Kubectl.</p>
<p>You also need to be aware of the <a href="https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html" rel="nofollow noreferrer">subnet tagging</a> that is needed for e.g. creating a public or private facing load balancer.</p>
