DevOps
AWS PrivateLink로 만드는 안전한 프라이빗 네트워크
Jason여기어때
2025년 10월 15일
원문에서 보기 ↗안녕하세요. 여기어때컴퍼니 SRE팀에서 클라우드 엔지니어링 업무를 하고 있는 제이슨 입니다.
최근 여기어때 고객센터 신규 구축 프로젝트를 진행하면서 세일즈포스(Salesforce) SaaS 솔루션을 AWS PrivateLink를 이용해서 구성하는 작업을 진행 했습니다.
이 과정에서 PrivateLink의 NLB(Network Load Balancer)가 Health Check에 실패하는 이슈를 겪었고, 이를 해결한 과정을 공유 하고자 합니다. 비슷한 문제를 겪고 계신 분들께 도움이 되었으면 좋겠습니다.
1. AWS PrivateLink란?
AWS PrivateLink는 AWS 서비스, 혹은 AWS에서 호스팅되는 서비스에 VPC(Virtual Private Cloud) 엔드포인트를 통해 퍼블릭 IP 및 인터넷을 거치지 않고 안전하게 프라이빗 네트워크로 접속할 수 있도록 해주는 기술입니다.
인터넷 게이트웨이, NAT 디바이스, VPN 연결 없이도 트래픽이 AWS 네트워크를 벗어나지 않기 때문에 보안이 강화됩니다.

by ChatGPT
2. AWS PrivateLink Architecture 구성
- 보안을 강화하기 위해 PrivateLink 전용 Private Subnet을 별도로 추가하고, 해당 Subnet을 제외한 다른 네트워크에서는 접속할 수 없도록 구성했습니다.

[AWS PrivateLink Architecture]
3. AWS PrivateLink Endpoint Service를 위한 NLB Health Check 이슈 발견
- PrivateLink를 신규 구축하는 과정에서 NLB의 Health Check가 실패하는 문제를 확인 했고 동일한 방식으로 구성하는 AWS API Gateway의 NLB도 Health Check 실패로 Unhealthy 상태인 것을 확인 했습니다.
- AWS API Gateway와 PrivateLink를 구축하게 되면 아래와 같이 NLB 생성해서 ALB(Ingress)를 TargetGroup에 추가하는 형태로 구성을 하게 됩니다.
- Health Check가 실패하여 Unhealthy 상태가 된다고 해서 반드시 서비스에 문제가 발생하지 않습니다.
- AWS의 ELB는 TargetGroup에 등록한 리소스가 Health Check 실패로 모두 Unhealthy 상태여도 서비스 Port가 정상적으로 응답하고 있다면 통신을 허용 합니다.

[AWS API Gateway와 VPC PrivateLink Architecture]
- AWS API Gateway

- AWS PrivateLink

4. NLB → ALB(Ingress) Health Check 실패를 해결하기 위한 과정
1) 테스트 환경 구성
- jason test eks cluster에서 테스트를 위해서 Ingress를 생성하고 NLB → ALB(Ingress) 환경을 구성 합니다.
- nginx가 있는 간단한 Pod를 띄우고 Service 구성해서 Ingress를 만들었습니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cpu-nginx-test-1-ingress
namespace: d-jason-test
annotations:
alb.ingress.kubernetes.io/group.name: jason-nginxingress
alb.ingress.kubernetes.io/scheme: internal
alb.ingress.kubernetes.io/security-groups: sg-0ece0272d8949102e, sg-0e23b60358e3f2f83
alb.ingress.kubernetes.io/security-groups-auto-add: sg-0ece0272d8949102e
alb.ingress.kubernetes.io/healthcheck-interval-seconds: "15"
alb.ingress.kubernetes.io/healthcheck-timeout-seconds: "5"
alb.ingress.kubernetes.io/healthcheck-path: "/"
alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=100
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:xxxxxxxxxxxxx:certificate/1938a1e7-8941-4e08-b5be-f4e7ee8bb978
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- host: dev-jason-nginx.xxxxxxxxx.xx
http:
paths:
- backend:
service:
name: cpu-nginx-test-1-svc
port:
number: 80
path: /
pathType: Prefix
- NLB에서 Health Check 실패로 Unhealthy 상태 확인

- Ingress의 정책 확인

- 테스트를 위해서 강제로 Health Check 실패가 되로록 환경 구성해서 확인 해보니 HTTP Code 404가 발생하면서 Health Check 실패가 되었네요.
- NLB에서 Health Check를 위해서 ALB로 통신 할 때 NLB가 출발지가 되기 때문에 Ingress 정책이 없다보니 기본값 정책을 이용하기 때문에 Http Code 404로 응답을 해줍니다.

2) Health Check 실패를 해결을 위한 과정
- Ingress에서 NLB ENI IP가 Source IP인 경우 Health Check를 위해서 고정 응답 200이 되도록 annotation을 추가해 줍니다.
- ALB와 다르게 NLB의 경우 고정IP이기 때문에 NLB에 할당된 ENI IP를 추가하거나 별도의 NLB Subnet이 존재한다면 NLB Subnet 대역을 추가해 주면 됩니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cpu-nginx-test-1-ingress
namespace: d-jason-test
annotations:
alb.ingress.kubernetes.io/group.name: jason-nginxingress
alb.ingress.kubernetes.io/scheme: internal
alb.ingress.kubernetes.io/security-groups: sg-0ece0272d8949102e, sg-0e23b60358e3f2f83
alb.ingress.kubernetes.io/security-groups-auto-add: sg-0ece0272d8949102e
alb.ingress.kubernetes.io/healthcheck-interval-seconds: "15"
alb.ingress.kubernetes.io/healthcheck-timeout-seconds: "5"
alb.ingress.kubernetes.io/healthcheck-path: "/"
alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=100
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:xxxxxxxxxxxx:certificate/1938a1e7-8941-4e08-b5be-f4e7ee8bb978
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/conditions.nlb-source-ip: >
[{"field":"source-ip","sourceIpConfig":{"values":["xxx.xxx.xx.xxx/32", "xxx.xxx.xx.xxx/32", "xxx.xxx.xx.xxx/32"]}}]
alb.ingress.kubernetes.io/actions.nlb-source-ip: >
{"Type":"fixed-response","FixedResponseConfig":{"StatusCode":"200","ContentType":"text/plain","MessageBody":"OK"}}
alb.ingress.kubernetes.io/backend-protocol: HTTP
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- host: dev-jason-nginx.xxxxxxxx.xx
http:
paths:
- backend:
service:
name: cpu-nginx-test-1-svc
port:
number: 80
path: /
pathType: Prefix
- http:
paths:
- backend:
service:
name: nlb-source-ip
port:
name: use-annotation
path: /
pathType: Prefix
- EKS의 Ingress 정책에 NLB의 ENI IP가 Source IP이면 고정 응답반환 200 정책이 생성 되었습니다.

- 확인해 보니 NLB → ALB(Ingress) Health Check가 정상적으로 Healthy가 되어 있는 것도 확인 할 수 있습니다.
- EKS의 Ingress의 경우 yaml 파일에 annotation를 추가해 줘야 하지만 ALB의 경우 리스너 규칙을 추가하는 방식으로 하면 됩니다.

- Pod에 있는 nginx에서 로그를 확인해 보니 200 OK 정상적으로 Health Check가 성공된 부분이 확인이 되네요.

5. 대안
- EKS의 Ingress와 ALB에 NLB의 Health Check를 위한 정책을 추가하는게 만약 부담 스럽다면 아래 처럼 HTTP Code가 200–404까지 Health Check가 성공 하도록 수정을 하면 됩니다.
- NLB- > ALB(Ingress) Health Check 원리는 이해 했으니 HTTP 404 Code도 성공으로 추가해 주면 최소한 NLB의 Health Check가 Unhealthy여서 미사용 ELB라고 착각하고 삭제하는 일은 방지 할 수 있습니다.


6. 추가 테스트
- API Gateway, PrivateLink 구성시 Endpoint인 NLB → ALB(Ingress) 상황에서도 Host 정보가 유지 되느냐를 추가로 테스트를 했고 NLB 로그와 테스트로 띄운 Pod의 nginx의 Access 로그를 확인 했을 때 Header에 Host 정보를 유지 하고 있어서 ALB와 Ingress에서 Http Host 기준의 리스너 규칙 정책도 문제 없이 사용 가능 합니다.
- NLB의 Access 로그를 확인 했을때 Host Header의 정보인 domain_name이 남는 부분을 확인 했습니다.

- PrivateLink 테스트를 위해서 만든 인스턴스에서 nginx 구성하고 ALB와 같이 Host Header 정책을 만들어서 확인 했고 정상적으로 응답하는 부분을 확인 했습니다.
- nginx에서 Host Header가 stage-b2b-xxx-gw.xxxxxxxxxx.xx이면 HTTP Code 503, dev-b2b-xxx-gw.xxxxxxxxxxx.xx이면 HTTP Code 301 응답을 하게 설정을 했고 테스트 했더니 Acccess 로그와 Client 로그에서 설정한 대로 응답하는 것을 확인 했습니다.


7. 마무리
추가 테스트를 통해 NLB의 ENI IP를 소스 IP로 하는 호출은 Health Check 외에는 없다고 판단 했습니다. 또한, NLB가 ALB Ingress 환경에서 Host 헤더를 정상적으로 유지하는 것을 확인 했습니다.
따라서 ALB나 EKS의 Ingress에서 HTTP Host 헤더를 기반의 리스너 규칙을 사용하여도 문제가 없다는 것을 확인 할 수 있습니다.
결론적으로, ALB(Ingress)에 NLB의 ENI IP를 소스 IP로 하는 Health Check 정책을 추가하는 것은 시스템에 큰 영향을 주지 않으면서도 문제를 해결하는 가장 효과적인 방법 입니다.
이상으로 AWS PrivateLink를 활용한 프라이빗 네트워크 서비스 구성과 Health Check 이슈 해결 방안을 살펴 보았습니다.
안정적이고 보안성 높은 네트워크 설계에 도움이 되었기를 바랍니다.