EKS Cluster Endpoint
EKS에는 2가지의 VPC 영역이 존재합니다.
1. Control Plane을 AWS에서 관리하는 AWS VPC
2. Data Plane을 사용자가 직접 관리하는 Customer VPC
이에 따라 AWS의 EKS에서는 사용자(고객)가 Control Plane을 관리하지 않고, 실질적으로 애플리케이션만 운영, 관리할 수 있게 Data Plane만 관리하게 하여 Customer VPC에만 집중할 수 있습니다.
이때, EKS 클러스터에 접근하기 위한 Cluster Endpoint에는 이래의 3종류가 존재합니다.
- Public: 인터넷을 통해 접근 가능
- Private: 내부 네트워크를 통해서만 접근 가능
- Public + Private: 퍼블릭과 프라이빗 환경 모두에서 접근 가능
Only Public endpoint
public endpoint는 기본 설정으로 요청자의 VPC에 상관없이 Cluster Endpoint에 접근할 수 있습니다. 또한 Endpoint로 접근하는 도메인 주소는 NLB의 public IP주소가 됩니다.
사용자가 명령어(kubectl)를 통해 cluster에 접근 시 흐름 정리
[접근 시] 사용자의 kubectl 명령어 → 퍼블릭 도메인 → Control Plane(kube-apiserver) → EKS owned ENI → 워커노드의 Kubelet
[응답 시] 워커노드의 Kubelet → 퍼블릭 도메인 → Control Plane(kube-apiserver)
: kubelet은 작업을 수행하고 워커노드의 상태를 다시 control Plane의 kube-apiserver로 보고합니다. 이때, Endpoint가 현재 NLB의 public IP 주소로 되어 있어 해당 요청은 외부로 빠져나가 다시 Control Plane의 kube-apiserver로 전송됩니다.
PublicAccess 설정
eksctl
...
vpc:
autoAllocateIPv6: false
clusterEndpoints:
privateAccess: false
publicAccess: true
...
만약, eksctl 을 통해 위와 같이 privateAccess를 false로 설정하고, publicAccess를 true로 설정하여 배포한다면 해당 eks cluster는 public하게 접근할 수 있게 됩니다.
terraform
resource "aws_eks_cluster" "main" {
...
vpc_config {
subnet_ids = [aws_subnet.eks_subnet.id]
endpoint_public_access = true
endpoint_private_access = false
}
...
IaC로 가장 많이 쓰이는 terraform은 위와 같이 endpoint_public_access를 true로 하고 endpoint_private_access를 false로 설정합니다.
Public Access 배포 결과
위의 사진처럼 public하게 접근할 수 있는 eks cluster가 생성된 것을 확인하실 수 있습니다.
Cluster 정보 확인
kubectl cluster-info
위의 명령어를 통해 cluster 정보를 확인해보겠습니다.
특정한 endpoint가 보이는 것을 확인할 수 있는데요.
aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint
awscli를 통해서도 동일한 cluster의 endpoint도 확인하실 수 있습니다.
Cluster endpoint 접근
위에서 반환받은 endpoint로 접근할 수 있는데요. version 경로에 접근해보면 위와 같이 정상적으로 접근할 수 있는 것을 확인하실 수 있습니다. 즉, publicAccess를 허용해서 eks cluster를 배포하면 누구나 eks api를 통해 cluster에 접근할 수 있습니다.
Only Private endpoint
Custom VPC 내부에서 사용자 접근하기 때문에 더 이상 NLB의 public ip가 없습니다.
사용자가 명령어(kubectl)를 통해 cluster에 접근 시 흐름 정리
[접근] 사용자의 kubectl 명령어 → Privat Hosted Zone → EKS owned ENI → Control Plane(kube-apiserver) → EKS owned ENI → 워커노드의 Kubelet
: 명령을 하는 사용자가 Custom VPC 내부에 있기 때문에 privated Hosted Zone을 거쳐 EKS owned ENI를 통해 Control Plane의 kube-apiserver로 요청을 보냅니다.
( 즉, private endpoint 방법은 명령을 하는 사용자가 Customer VPC 내에서 Cluster에 접근해야 합니다. )
[응답] 워커노드의 Kubelet → Privat Hosted Zone → EKS owned ENI → Control Plane
: kubelet은 작업을 수행하고 워커노드의 상태를 다시 control Plane의 kube-apiserver로 보고합니다. 이때, AWS 내부의 private hosted zone을 통해서 EKS owned ENI를 통과해 Control Plane으로 전송됩니다.
PrivateAccess 설정
awscli
aws eks update-cluster-config --region $AWS_DEFAULT_REGION --name $CLUSTER_NAME --resources-vpc-config endpointPublicAccess=false,endpointPrivateAccess=true
앞서 배포한 Cluster 설정을 awscli를 통해 설정을 변경합니다. 이때 수정된 설정값은 endpointPublicAccess=false,endpointPrivateAccess=true 인데요. 반영되기까지 대략 5~6분정도 소요됩니다.
terraform
resource "aws_eks_cluster" "main" {
...
vpc_config {
...
endpoint_private_access = true
endpoint_public_access = false
}
}
terraform을 이용할 시엔 위와 같이 수정하시면 됩니다.
Private Access 배포 결과
위의 사진처럼 private으로 설정된 것을 확인하실 수 있습니다.
Cluster 정보 확인
kubectl cluser-info
kubectl 명령어를 통해 cluster 정보를 확인해보겠습니다.
아까와 다르게 bastion host에서 접근하면 cluster 내부에 접근할 수 없는 것을 확인하실 수 있습니다.
aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint
이번엔 aws cli를 통해 cluster 정보를 확인하고 그 중 endpoint를 응답받아보도록 하겠습니다.
aws cli는 동작 하는 것을 확인하실 수 있는데요. 이때는 kub api server를 거치지 않은 통신만 가능합니다.
PrivateAccess에서 kubectl이 작동하지 않는 이유
kubectl은 로컬 머신에서 실행되므로 VPC 외부에서 API 서버에 접근을 시도하기 때문에 EKS Cluster의 kube-apiserver에 연결할 수 없어 실패하게 됩니다.
PrivateAccess에서 AWS CLI가 작동하는 이유
AWS CLI는 AWS 내부 네트워크를 통해 EKS 서비스와 통신하기 때문에 EKS 서비스가 다시 클러스터의 API 서버와 통신하는 구조이기에 대부분의 클러스터 관련 작업은 실패하게 되지만, API 서버와 직접 통신이 필요없는 클러스터 정보 조회 등의 AWS API 호출만 성공합니다
cluster endpoint 접근
aws cli로 응답받은 endpoint로 접근 시 접근이 불가능한 것을 확인하실 수 있습니다.
Public + Private endpoint
endpoint는 NLB의 public IP주소가 사용되며, Worker Node를 위한 주소가 별도의 Private hosted zone으로 구성되어 EKS owned ENI로 매핑합니다.
사용자가 명령어를 통해 cluster 접근 시 흐름
[접근] 사용자의 kubectl 명령어 → 퍼블릭 도메인 → Control Plane(kube-apiserver) → EKS owned ENI → 워커노드의 Kubelet
[응답] 워커노드의 Kubelet → Privat Hosted Zone → EKS owned ENI → Control Plane
: kubelet은 작업을 수행하고 워커노드의 상태를 다시 control Plane의 kube-apiserver로 보고합니다. 이때, AWS 내부의 private hosted zone을 통해서 EKS owned ENI를 통과해 Control Plane으로 전송됩니다.
Public(IP제한)+Private 로 변경
awscli
aws eks update-cluster-config --region $AWS_DEFAULT_REGION --name $CLUSTER_NAME --resources-vpc-config endpointPublicAccess=true,publicAccessCidrs="$(curl -s ipinfo.io/ip)/32",endpointPrivateAccess=true
terraform
resource "aws_eks_cluster" "main" {
...
vpc_config {
...
endpoint_private_access = true
endpoint_public_access = true
public_access_cidrs = ["${data.http.myip.response_body}/32"]
}
}
data "http" "myip" {
url = "https://ipinfo.io/ip"
}
테라폼 코드는 위와 같습니다.
Public(IP제한)+Private 배포 결과
위의 사진처럼 private 및 public 으로 설정되었고, public access의 경우 bastion host의 ip로만 접근하도록 설정된 것을 확인하실 수 있습니다.
Cluster 정보 확인
kubectl cluser-info
kubectl 명령어를 통해 cluster 정보를 확인해보겠습니다.
public access로 bastion host의 ip 접근을 허용했는데 여전히 kubectl 명령어로 통신이 되지 않는데요. 이때는 Cluster의 보안그룹을 수정해줘야합니다.
보안그룹 설정
cluster 보안그룹에 Bastion Host의 Private IP 추가
aws ec2 authorize-security-group-ingress --group-id ${보안그룹ID} --protocol '-1' --cidr ${bastion host의 Private IP}
위와 같이 cluster 보안그룹에 bastion host의 private ip를 추가해야 통신이 가능합니다.
그런데 왜 bastion host의 public ip가 아닌 private ip일까요?
-> Bastion host에서 EKS API 서버로의 요청이 VPC 내부에서 이루어집니다. 이때, API 서버는 요청의 source IP를 확인할 때 private IP를 보게 됩니다. 따라서 보안그룹의 인바운드 규칙에는 bastion host의 private IP가 필요합니다.
Bastion Host에서 도메인 질의 시
Bastion host에서 질의할 때는 VPC 내부에서 DNS 질의가 발생하면 Route 53 Resolver가 처리합니다. 이때, VPC 내부에서의 접근이므로 private 엔드포인트 IP를 리턴합니다
로컬에서 도메인 질의 시
로컬 환경에서 질의할 때는 외부 DNS 서버를 통해 질의가 처리됩니다. 이때, VPC 외부에서의 접근이므로 public 엔드포인트 IP를 리턴합니다. 그렇기에 인터넷을 통한 접근에 필요한 public IP가 제공됩니다
Cluster 정보 확인
kubectl cluster-info
이제 다시 kubectl 명령어를 통해서 cluster 정보를 확인해보면, 아래의 사진과 같이 정상적으로 통신하는 것을 확인하실 수 있습니다.
cluster endpoint 접근
public Access로는 bastion host의 IP만 허용했기 때문에 로컬에서 endpoint로 접근 시 접근이 불가능한 것을 확인하실 수 있습니다.