詳細検索

ELB와 클라이언트 인증으로 SSL 전송, nginx로 SSL 종료를 통해 ProxyProtocol으로 소스 IP를 얻는 방법

아바타
글쓴이 komi

ELB와 클라이언트 인증으로 SSL 전송, nginx로 SSL 종료를 통해 ProxyProtocol으로 소스 IP를 얻는 방법
日本語에서 번역 • 원문 보기

안녕하세요. 제목이 길지만, 오랫동안 성공해왔기 때문에 수요가 있는지는 모르겠지만, 기록해 보겠습니다.

시간 될 때 꼭 해줘.

목적은 외부 ELB→nginx(SSL 종료 및 클라이언트 인증)→ 내부 ELB→앱에 있습니다

즉, 클라이언트를 인증하고 싶지만 ELB에는 인증이 없어서 tcp443을 포워딩하고 nginx로 처리합니다. 하지만 상위 서버가 가져갈 수 있는 소스 IP가 ELB의 IP이기 때문에, ELB에서 ProxyProtocol을 활성화하고 ProxyProtocol을 듣고 소스 IP를 기록하는 동안 nginx로 SSL 종료를 하고 싶습니다.

securityGroup이나 인스턴스 생성 같은 부분은 생략하세요.

1. awscli에서 ELB 생성, 프록시 프로토콜 설정

참고문헌:

프록시 프로토콜 지원 활성화 또는 비활성화 - elastic load balancing 지금 VPC 내 여러 AZ에서 ELB 시도 (2) - awscli 사용 - Yohei no days Devotion XP

- ELB 생성
프로필=xxxxx
elbname-ext=xxxx-elb
Securitygrops="SG-xxxxxxxx SG-yyy" 
Subnets="subnet-xxxxxxxx subnet-yyy" 
sudo bash -c "AWS ELB create-load-balancer --load-balancer-name ${elbname-ext} --listeners Protocol=TCP,LoadBalancerPort=443,InstanceProtocol=TCP,InstancePort=443 --subnets ${subnets} --security-groups ${securitygrops} --profile ${profile}" 

*외부 ELB는 TCP443에서 TCP443으로만 전송하도록 설정되어 있으며 인증서는 포함하지 않습니다.

Elbname-int=yyyy-elb
Securitygrops="SG-xxxxxxxx SG-ZZZZZZZZ" 
sudo bash -c "AWS ELB create-load-balancer --load-balancer-name ${elbname-int} --listeners Protocol=TCP,LoadBalancerPort=80,InstanceProtocol=TCP,InstancePort=8xxx --subnets ${subnets} --security-groups ${securitygrops} --scheme internal --profile ${profile}" 
・헬스체크 설정
sudo bash -c "AWS ELB Configure-Health-Check --load-balancer-name ${elbname-ext} --health-check Target="TCP:443",Interval=30,Timeout=5,UnhealthyThreshold=2,HealthyThreshold=10 --profile ${profile}" 

sudo bash -c "AWS ELB Configure-Health-Check --load-balancer-name ${elbname-int} --health-check Target="TCP:80",Interval=30,Timeout=5,UnhealthyThreshold=2,HealthyThreshold=10 --profile ${profile}" 
인스턴스 등록
instances-ext="i-xxxxxxxx i-yyyy" 
인스턴스스-int="i-zzzzzzzz i-aaa" 
Sudo bash -c "AWS ELB register-instances-with-load-balancer --load-balancer-name ${elbname-ext} --instances ${instances-ext} --profile ${profile}" 
Sudo bash -c "AWS ELB register-instances-with-load-balancer --load-balancer-name ${elbname-int} --instances ${instances-int} --profile ${profile}" 
프록시 프로토콜 활성화

정책 생성

sudo bash -c "AWS ELB create-load-balancer-policy --load-balancer-name ${elbname-ext} --policy-name EnableProxyProtocol --policy-type-name ProxyProtocolPolicyType --policy-attributes 속성명=ProxyProtocol,AttributeValue=true --profile ${profile}" 
정책을 검토하세요
sudo bash -c "AWS ELB set-load-balancer-policies-for-backend-server --load-balancer-name ${elbname-ext} --instance-port 443 --policy-names EnableProxyProtocol --profile ${profile}" 

비활성화하고 싶다면, '--policy-names []'의 빈 명세를 지정하여 비활성화할 수 있습니다

프록시 프로토콜이 활성화되었는지 확인하세요

Sudo bash -c "AWS ELB Describe-Load-Balancers --load-Balancer-Name ${elbname-ext} --profile ${profile}" 
"백엔드 서버설명": [ 
{ 
"인스턴스포트": 443, 
"정책명": [ 
"임시 프로토콜 활성화" 
]
}

2. Nginx 구성 설정에 대하여

하지만 세부 사항은 생략하고 관련 설정만 추가하겠습니다. '프록시-프로토콜' 설정은 '재시작'에 반영되어야 하므로 로그인 확인 시 nginx의 '재시작'을 수행해야 합니다.

참고문헌:

Nginx와 프록시 프로토콜 사용 | chris lea module ngx_http_realip_module #355 (프록시 프로토콜 지원) - nginx

실제 nginx 구성 파일

(성공 시점의 버전은 1.7.4-1입니다)

/etc/nginx/nginx.conf
----------------------------------------------- 
log_format 주요 '$proxy_protocol_addr - $remote_user [$time_local] "$request" ' 
'$status $body_bytes_sent "$http_referer" ' 
'"$http_user_agent" "$http_x_forwarded_for"' 
'$http_x_userid - $http_x_signature - $http_x_sessionkey "$request_body"'; 
----------------------------------------------- 

*'$remote_addr' 대신 '$proxy_protocol_addr'로 변경됨 *관련 부분만 발췌 포함 (http_x_sessionkey 등은 '마스터링 Nginx'에서 복사 붙여넣기, 필요 없으면 삭제해 주세요)

/etc/nginx/conf.d/ssl.conf
----------------------------------------------- 
서버 { 
# 리스닝 443 기본 SSL; 
리스닝 443 기본 SSL proxy_protocol; 

server_name <%= node['nginx']['servername1'] %>; 
set_real_ip_from <%= node['nginx']['set_real_ip_from'] %>; 
real_ip_header proxy_protocol; 

ssl_certificate /etc/nginx/<%= node['nginx']['sslcrt1'] %>; 
ssl_certificate_key /etc/nginx/<%= node['nginx']['sslkey1'] %>; 

ssl_prefer_server_ciphers 계속해; 
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
공유ssl_session_cache WEB:10m; 
ssl_session_timeout 10m; 
ssl_ciphers RC4: HIGH:!aNULL:! MD5:@STRENGTH; 

## 클라이언트 인증 설정
ssl_verify_client 말해; 
ssl_verify_depth 3; 
ssl_client_certificate /etc/nginx/<%= node['nginx']['clientcrt'] %>; 
# ssl_crl /etc/nginx/<%= node['nginx']['clientcrl'] %>; 

리졸버 <%= node['nginx']['resolver'] %> 유효=5s; 
resolver_timeout 3인조; 

위치 / { 
proxy_set_header X-FORWARDED-PROTO https; 
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
proxy_set_header X-Real-IP $remote_addr; 
proxy_connect_timeout 10점대; 
proxy_read_timeout 10세; 
proxy_pass http://<%= @upstream1 %>:<%= @upstreamport %>$request_uri; 

## 클라이언트 인증서를 백엔드 서버로 전달하세요. 
# proxy_set_header ssl_client_cert $ssl_클라이언트_cert; 

# 루트 /usr/share/nginx/html; 
# 인덱스 index.html index.htm; 
}
}
----------------------------------------------- 

*위 명령 중 '프록시 프로토콜'과 관련된 지침은 다음과 같습니다: '듣기', 'set_real_ip_from', 'real_ip_header'.

※<%= .. %>로 포함된 부분은 속성(변수)이며, 셰프 레시피가 실행될 때 설정된 값으로 대체되며 실제 값과 다릅니다. @の変数はroleとenvironmentで吸収しきれずdata_bags 등. *'set_real_ip_from'는 VPC의 세그먼트 주소(예: 10.0.0.0/17)를 지정합니다. ELB의 실제 주소를 작성해야 하지만, 식별할 수 없으며 자동으로 흔들립니다. *'ssl_crl' (파괴 증명 목록) 이 주석은 불확정한 상황에 의한 것입니다.

**'ProxyProtocol'을 해석할 수 있는 버전은 1.5.12 이상입니다. 그 아래에는 'configtest'라는 오류가 있습니다. **1.4 시스템에서는 '--with-proxy-protocol' 소스에서 빌드할 필요가 없고, 1.7임에도 불구하고 빌드하지 않고 기본 패키지로 구현할 수 있었습니다. *상류에서 멈추고 리졸버를 추가했습니다. nginx의 이름 해상도는 마스터링 Nginx P94가 설정된 변수에 넣을 때마다 해결되며, 그 외에는 해석기 변수에서 지정된 ttl 타이밍에 질문하는 것으로 보입니다. 해석기는 upstream과 *_pass에서 지정된 이름을 처음 해석하는 데만 필요한 것 같습니다.

1.7 시리즈(메인라인 1)용 YUM 저장소

내용은 다음과 같습니다. chef 관점에서 보면, epel의 진입을 막기 위해 패키지 리소스에 'options "--disablerepo=epel"'을 작성해야 합니다.

[응긴스]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/6/$basearch/ 
GPGCHECK=0
가능하기=1

3. 접근 기록의 출처 IP 확인

로그인
SSH nginx-SRV1-Dev
SSH nginx-SRV2-Dev
견진성
rpm -qa|grep nginx
sudo service nginx configtest
sudo service nginx restart
수도(Sudo) 서비스 NGINX 상태
Sudo netstat -lnptu
chkconfig --list nginx
ELB에 추가한 후 InService가 되면, 브라우저에서 접근해 로그를 확인하세요
$ sudo tail -f /var/log/nginx/access.log
119.xxx.xxx.xxx - - [2014년 8월 12일:04:39:28 +0000] "GET / HTTP/1.1" 400 648 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, 게코와 유사) 크롬/36.0.1985.125 사파리/537.36" "-" - - - - "-" 
119.xxx.xxx.xxx - - [2014년 8월 12일:04:39:28 +0000] "GET /favicon.ico HTTP/1.1" 400 648 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, 게코처럼) Chrome/36.0.1985.125 Safari/537.36" "-" - - - - - "-" 

연결 소스의 글로벌 IP가 이렇게 나왔으니, '프록시 프로토콜' 측면에서 성공한 것으로 보입니다. 클라이언트 인증에 대해서는 더 이상 설명할 수 없지만, 양해 부탁드립니다.

개인적으로는 복잡한 상황에 적응하기 어려웠지만, 기사에 링크된 Chris Lea 페이지에 적힌 대로 해야 한다는 것과 ELB 프로토콜의 잘못된 명세를 따라야 한다는 것을 깨달았습니다. 이 내용을 함께 설명한 기사를 찾지 못해 직접 작성했습니다. nginx 사용자 회의 행사에서 개발자 Igor가 SSL을 사용하고 싶다면 새 버전을 추천한다는 의미를 직접 배웠습니다. 특정 기기를 사용하고 싶을 때 유용할 수 있습니다.

읽어주셔서 감사합니다. 누군가에게 도움이 된다면 기쁠 것 같아요.

Related Articles