728x90

브라우저의 인증서 정책이 나날이 변화하고 있습니다. 
내년부터 시행될 인증서 유효기간 200일 정책을 비롯하여 
Root 인증서의 유효기간 단축 등 이벤트가 넘쳐나고 있습니다.

오늘 포스팅을 Root 인증서의 유효기간 단축으로 인해
내년부터 영향권에 들어가는 GlobalSign 인증서 처리 관련한
Cross-Signed Root 인증서 관련 이야기입니다.

사실, 이 포스팅은 제 스스로 Cross-Signed Root 인증서가
어떻게 Root 인증서의 교체를 부드럽게 넘길 수 있게 해주는 것인지
잘 이해하지 못한 부분들을 정리해보는 글이라 보셔도 무방합니다.

크로스 싸인 루트 인증서(Cross-signed Root Certificate)

신뢰할 수 있는 루트 인증서는 보통 TLS Client에 탑재되어 있습니다. 
가장 널리 사용되는 TLS Client의 하나인 웹 브라우저가 대표적이고
Java의 truststore가 아마도 그 다음 정도로 익히 들어보셨을 TLS Client 입니다.

웹 브라우저는 물론이고 자바 애플리케이션도 
truststore에 미리 저장되어 있는 신뢰 할 수 있는 루트 인증서를 바탕으로
TLS 혹은 SSL과 관련된 모든 절차를 수행합니다. 

그런데 모든 인증서는 유효 기간이 정해져 있을뿐 아니라
루트 인증서의 Private Key가 유출되는 것과 같은 사고가 발생하면
제 아무리 루트 인증서라 하더라도 폐기가 필요합니다.
여기서 폐기는 truststore 에서의 삭제 및 해당 루트 인증서로 싸이닝된
모든 인증서의 폐기를 의미합니다. 

간혹 이런 일이 발생하기도 합니다.
이럴때 부작용을 막기 위해 "크로스 싸인 루트 인증서"가 활용됩니다.
이름 그대로 "다른 루트 인증서를 이용해 싸이닝한 루트 인증서"라는 의미입니다.

이렇게 싸이닝된 "크로스 싸인 루트 인증서"를 이용하면
루트 인증서의 교체에 필요한 작업과 절차를 부드럽게 적용할 수 있다고 하는데요
과연 이 절차는 어떻게 "부드럽게" 진행되는 것인지 궁금했습니다.

사실 Let's Encrypt 에서 비슷한 일이 몇 년전 있었지만 제대로 이해하지 못하고 넘어갔었습니다.
이번엔 제대로 이해해 보고자 공부(라고 쓰고 AI와 티키타카 했다고 읽습니다)해봤습니다.

신뢰 체인(Chain of Trust)

크로스 싸인 루트 인증서의 동작을 이해하기 위해서는 
TLS Client가 신뢰 체인(Chain of Trust)를
어떻게 만들고 검증하는지  이해해야 합니다.

TLS 세계에서의 일반적인 신뢰체인은 다음과 같습니다. 
- Root 인증서 : Self Signed 로 만들어진 최상위 인증기관의 검증된 인증서 
- Intermediate 인증서 : Root 인증서와 Leaf 인증서를 연결해주는 중간 인증서 
- Leaf 인증서 : 실제 도메인(예: www.naver.com)에 대해 발급된 최종 사용자용 인증서  

TLS 인증서는 보통 3단계로 구성되어 있고
이 흐름을 신뢰체인이라고 생각하면 됩니다.
이 포스팅에서 다루는 내용은 위 그림을 기준을 봤을 때
Root Certificate의 교체가 필요한 상황을 가정하고 있습니다.
(GlobalSign의 경우도 이 경우입니다)

크로스 싸인 루트 인증서 존재 유무에 따른 신뢰체인 검증 흐름

크로스 싸인 루트 인증서는 "새로운 루트 인증서를 기존 루트 인증서로 서명한" 인증서 입니다.
이 루트 인증서를 이용해 "원래의" 루트 인증서 변경에 따른
위험을 줄이고 점진적인 마이그레이션을 추구하는 것이 크로스 싸인 루트 인증서 사용의 목적입니다.

기존 흐름)
Leaf 인증서 - Intermediate 인증서 - Legacy Root 인증서
새로운 흐름)
Leaf 인증서 - Intermediate 인증서 - Cross-Signed Root 인증서 - Legacy Root 인증서

기존 흐름의 Intermediate 인증서는 Legacy Root 인증서로 싸이닝 되어 있습니다
오래된(=truststore가 업데이트 되지 않은) 브라우저 등은
Legacy Root 인증서를 이용해서 Intermediate 인증서를 검증합니다. 

반면 새로운 흐름에서의 Intermediate 인증서는 
Cross-Signed Root 인증서를 이용해 싸이닝 되어 있고 
Cross-Signed Root 인증서는 Legacy Root 인증서를 이용해 싸이닝 되어 있습니다.

여기서 중요한 것은 Cross-Signed Root 인증서는
Legacy Root 를 개체할 새로운 Root 인증서를 지칭한다는 것입니다. 
즉, 새로운 흐름에서 Intermediate 인증서는 
기존 흐름에서의 Intermediate 인증서와 달리
새로운 Root 인증서로 싸이닝된 인증서라는 점입니다. 

차이는 뭘까요?
Legacy Root 인증서가 만료 혹은 더이상 유효하지 않은 경우를 생각합시다.
Legacy Root 인증서가 무효화되면 기존 흐름은 더이상 유효하지 않습니다.
하지만 새로운 흐름은 문제 없이 인증이 됩니다. 

왜일까요?

TLS Client 는 똑똑합니다

이러한 변화가 가능한 이유는 브라우저를 비롯한 현대적인 TLS Client의 똑똑함(?)에 기인합니다. 
새로운 truststore를 탑재한, 혹은 탑재당한 TLS Client는
"새로운 흐름"을 검증하는 과정에서 "Legacy Root 인증서"를 통한 검증 단계를 거치지 않습니다.

즉, Intermediate 인증서가 Cross-Signed Root 인증서의 내용물인
새로운 Root 인증서를 이미 truststore에 보유중이라는 것을 인지한 순간
이후의 검증 단계는 이용하지 않게 됩니다. 

정리

복잡하게 설명했지만 정리는 간단합니다.
크로스 싸인 루트 인증서가 모든 이야기의 핵심입니다. 
Legacy Root 인증서로 싸이닝된 크로스 싸인 루트 인증서는
상황에 따라 상위의 Legacy Root 인증서 검증까지 가고, 가지 않고가 핵심입니다.

이 동작을 통해 크로스 싸이닝이 루트 인증서의 이전을 안전하게 지원하고
실제 TLS Client 역할을 수행하는 주체들이
truststore를 업데이트 하는 동안 발생할 수 있는 문제를 해결해 주는 것입니다.

 

728x90
728x90

인증서를 다루다보면 가장 많이 사용하는 것이 OpenSSL 입니다. OpenSSL 의 명령들중 자주 사용하는 것들을 기억해두면 생활이 편리해지고 퇴근시간이 빨라지는 장점이 있습니다. 서버나 로컬 터미널 환경에 미리 alias 로 몇 가지 등록해 두면 두고두고 편리하게 사용할 수 있는 명령들을 몇 가지 정리해 보았습니다. 


로컬 환경의 RSA 인증서의 Private Key 확인하기

$ openssl rsa -in private_key_file.key -check
RSA key ok
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
...

 

로컬 환경의 X509 인증서 (보통 SSL 인증서라 부르죠) 내용 확인하기

$ openssl x509 -in certificate_file.crt -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            11:22:33:aa:44:bb:55:66:77:88:99:cc
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign RSA OV SSL CA 2018
        Validity
            Not Before: Apr 22 03:16:05 2021 GMT
            Not After : May 23 03:16:05 2022 GMT
        Subject: C=KR, ST=Seoul-si, L=Kangseo-gu, O=NoPD Corp, CN=*.nopd.me
        ...

 

원격지 환경의 인증서 Trust Chain 확인하기

$ openssl s_client -showcerts -connect www.naver.com:443
CONNECTED(00000003)
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
verify return:1
depth=0 C = KR, ST = Gyeonggi-do, L = Seongnam-si, O = NAVER Corp., CN = *.www.naver.com
verify return:1
---
Certificate chain
 0 s:/C=KR/ST=Gyeonggi-do/L=Seongnam-si/O=NAVER Corp./CN=*.www.naver.com
   i:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
-----BEGIN CERTIFICATE-----
...

 

 

원격지 환경의 X509 인증서 상세 내용 확인하기

$ openssl s_client -connect www.naver.com:443 | openssl x509 -noout -text
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
verify return:1
depth=0 C = KR, ST = Gyeonggi-do, L = Seongnam-si, O = NAVER Corp., CN = *.www.naver.com
verify return:1
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            05:75:b5:1c:cb:25:fc:9c:ef:cb:6e:63:fe:1a:45:29
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=DigiCert Inc, CN=DigiCert SHA2 Secure Server CA
        Validity
            Not Before: May 30 00:00:00 2020 GMT
            Not After : Jun  8 12:00:00 2022 GMT
        Subject: C=KR, ST=Gyeonggi-do, L=Seongnam-si, O=NAVER Corp., CN=*.www.naver.com
        ...
        

 

 

 

728x90
728x90

근래에 제공되는 대부분의 서비스는 SSL 혹은 TLS 를 이용하여 보안된 채널로 통신이 수행되도록 하는 것이 일반적입니다. 하물며 개인이 만드는 토이 프로젝트부터 대학교에서 과제로 제출하는 웹 사이트도 HTTPS 를 사용하지 않는 경우를 찾아보기 힘듭니다. 네, 물론 이 와중에서 Non-secure 로 버티는 곳들도 <당연히> 있긴 합니다. 

예전에는 HTTPS 를 이용하기 위해 인증서를 구매해야 했고, 보통 년단위의 갱신을 하다보니 비용 부담이 있었습니다. 하지만, 3개월마다 주기적으로 인증서를 업데이트 받는 조건으로 도메인 단위 인증서 (Domain Validation) 를 무료로 발급해주는 렛츠인크립트 Let's Encrypt 의 대중화 이후, 인증서 구매 비용도 단지 핑계가 된지 오래입니다. 


하지만, 이런 인증서 구매와 별개로 서버측에 SSL 설정을 구성하고 적용하는 것은 생각보다 까다롭게 생각하는 경우가 많습니다. 보통 한번 설정해 두면 수정하지 않아서 보안 사고의 원인이 되기도 하고, 설정을 잘못하는 바람에 특정한 단말기들이 서비스에 접근하지 못하는 장애를 겪기도 합니다. 원체 그 파급력이 크다보니 <그리 어려운 일이 아님에도 불구하고> 인증서 교체에 대해서 전문가를 찾는 경우가 종종 생깁니다.

이러한 엔지니어들의 고충을 잘 알고 있는 곳이 모질라 재단이기 때문일까요? 모질라에서 제공하는 SSL 설정 생성기는 이 모든 두려움으로부터...는 아니겠지만, 기본적인 설정 실수로 장애가 발생하는 것을 막아줄 수 있는 여러분의 친구, 좋은 도구가 될 수 있을 것 같습니다. 

다양하다! 

일단 이 도구가 커버해주는 서버측 소프트웨어의 범주가 무척 넓습니다. 널리 사용되는 아파치나 nginx 에서부터 AWS 의 ALB, ELB 도 포함이 되어 있습니다. HAProxy 와 Go 기반으로 서버측 엔드포인트를 만들때 쓸 수 있는 옵션들도 제공하고 있어 왠만한 서버측 도구의 SSL 설정에 활용도가 높아 보입니다. 

가운데 위치한 Mozilla Configuration 은 SSL/TLS 의 어떤 버전을 지원할 것인가에 따라 선택 가능한 항목입니다. 이 항목의 변경은 설정 생성시에 추가되는 Cipher Suite 의 종류에 영향을 주는 부분입니다. SSL/TLS 버전이 상위로 갈 수록 취약한 암호화 알고리즘을 사용할 수 없게 됩니다. 하지만, 오래된 사용자들은 SSL/TLS 의 상위 버전 자체를 사용할 수 없는 경우도 있기 때문에, 사용자 분포에 따라 취약한 알고리즘을 써야 하는 경우도 있을 겁니다.

가장 오른쪽에는 각 서버 어플리케이션의 버전에 따라 달라진 부분을 반영하기 위해 버전 정보를 기입할 수 있는 입력창이 위치해 있습니다. HSTS 와 OCSP Stapling 을 사용할 것인지에 따라 옵션을 선택할 수 있게 되어 있는 것도 눈에 띕니다. 

# generated 2021-02-08, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1d, modern configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=modern&openssl=1.1.1d&guideline=5.6
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_certificate /path/to/signed_cert_plus_intermediates;
    ssl_certificate_key /path/to/private_key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;

    # modern configuration
    ssl_protocols TLSv1.3;
    ssl_prefer_server_ciphers off;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;

    # replace with the IP address of your resolver
    resolver 127.0.0.1;
}

 

TLS 1.3 을 기준으로 NGINX 를 위한 설정을 생성해 보았습니다. HTTP 로 인입된 경우 HTTPS 로 스킴을 바꾸도록 301 리디렉션 하는 서버 컨텍스트가 앞에 위치해 있고, 443 포트로 HTTP/2.0 을 지원하는 엔드포인트를 열고 있습니다. 센스있게 IPv6 를 위한 포트 바인딩도 함께 추가되어 있네요!

그 외의 지시자들은 일름에서 유추할 수 있는 것처럼 프로토콜 버전의 지정, 인증서 파일의 위치, 세션 티켓 사용을 위한 옵션들이 지정되어 있습니다. 서버측의 prefer_server_ciphers 가 off 로 생성된 부분은 그 의도가 있을텐데 (아마도 NGINX 에서 TLS 1.3 사용시 기본 Cipher Suite 의 영향?) 자세한 건 문서를 좀 살펴봐야 할 것 같네요.


우리가 코드를 수정하거나 서버의 설정을 변경할 때 늘 하는 말이 있습니다. <지금 니가 무슨짓을 하는지 모른다면, 아무것도 하지 말아라> 라는 말이 바로 그것입니다. 각 설정이나 코드가 존재하는 것은 다 이유가 있어서 입니다. (예, 정말 가끔 이유 없이 존재하는게 없진 않습니다만...) 자동 생성된 설정을 참고하고 사용하는 것은 좋지만, 추가된 설정 항목들이 "왜" 들어갔는지에 대해서는 한번쯤 문서를 찾아보고 고개를 끄덕인 다음 Ctrl-C, V 하는 아름다운 자세를 견지하시기 바랍니다!

 

 

728x90
728x90

두 번의 포스팅을 통해 VPC 와 Gateway 를 생성했습니다. 그럼 EC2 를 바로 만들면 되나요? 라고 생각하실 수 있겠습니다만 일단은 생성한 VPC 가 Gateway 를 통해 인터넷과 교감을 할 수 있도록 라우팅 테이블 Routing Table 을 설정하는 작업을 먼저 진행해 보겠습니다. 사실 순서는 큰 상관이 없지만 <네트워크에 대한 작업> 을 마무리하고 <서버에 대한 작업>을 한다고 생각하시면 좋겠습니다. 

 

AWS EC2 를 이용한 IPv6 지원 OpenVPN 구축 #1

코로나 바이러스의 두번째 웨이브가 한창입니다. 다행히 오늘(9/3) 기준으로 확진자 수가 200명 밑으로 내려오긴 했지만, 긴장의 끈을 놓기에는 여전히 확진자 수가 많습니다. 많은 기업들이 원격

ondemand.tistory.com

 

AWS EC2 를 이용한 IPv6 지원 OpenVPN 구축 #2

9월에 첫 포스팅을 올리고 시간이 너무 많이 흘렀습니다. 기억이 더 가물가물 해지기 전에 OpenVPN 구축 포스팅을 마무리 해볼까 합니다. 지난 포스팅에서 우리는 `IPv6 대역을 갖고 있는 VPC 생성`

ondemand.tistory.com


1.4 Routing Table 조정

라우팅 테이블 Routing Table 은 VPC 로 들어오는 트래픽과 나가는 트래픽에 대한 경로를 지정해 주는 역할을 합니다. 물론 라우팅 테이블만 설정했다고 하여 모든 통신이 정상적으로 이루어지는 것은 아닙니다. 말 그대로 경로에 대한 지정일 뿐, 실제 트래픽을 허용할 것인지는 Network ACL 과 Security Group 을 통해 IP 주소 대역, 포트 단위로 결정됩니다.

VPC 하위의 Route Tables 메뉴입니다

라우팅 테이블을 설정하기 위해서는 VPC 제품 하위 메뉴에 위치한 <Route Tables> 를 통해 진행할 수 있습니다. 기본적으로 VPC 가 생성되면 VPC 에 대한 기본 라우팅 테이블이 자동으로 생성됩니다. 기본 라우팅 테이블은 VPC 에 할당된 IPv4, IPv6 주소를 대상으로 VPC 내에서 (=local) 통신이 가능하도록 하는 정책만 들어 있는 상태입니다.

우리가 해야하는 일은 위 이미지의 핑크색 상자에 들어 있는 내용과 같이 외부로 부터의 트래픽 송수신을 위한 정책을 추가하는 것입니다. IGW (Internet Gateway) 로는 SSH 접근을 위해 IPv4 에 대한 정책을 추가했고, EIGW (Egress Only Internet Gateway) 에는 실제 v6 주소 목적지에 대한 VPN 터널링을 위해 IPv6 주소에 대한 정책을 추가했습니다.

정책 추가를 위해 라우팅 테이블 목록에서 IPv6 용으로 만든 VPC 에 할당된 기본 라우팅 테이블을 선택합니다. Actions 버튼을 누르지 않아도 화면 아랫쪽에서 <Routes> 탭을 선택하면 라우팅 테이블에 대한 상세 정책 목록이 출력됩니다. 정책 추가를 위해 <Edit routes> 버튼을 누르겠습니다. 

IPv4 의 모든 주소를 나타내는 CIDR block 은 0.0.0.0/0 으로 표기되며, IPv6 의 모든 주소를 나타내는 CIDR block 은 ::/0 으로 표기합니다. 목적지 주소에 v4, v6 에 대한 CIDR block 을 추가하고 v4 는 IGW 로, v6 는 EIGW 를 이용하도록 대상(Target) 제품을 지정해 줍니다. 이미 생성한 IGW 와 EIGW 가 드롭 다운 목록에 노출되기 때문에 설정은 쉽게 하실 수 있습니다. 경로 입력이 끝나면 우측 하단의 <Save Routes> 버튼을 누릅니다. 

라우팅 테이블 업데이트가 완료되었습니다!

 

1.5 IPv6 주소를 갖는 EC2 인스턴스 배포

네트워크의 구성이 끝났으니 이제 실제 OpenVPN 바이너리가 구동되고 목적이 v6 주소까지 터널링을 해줄 EC2 인스턴스를 생성해 보도록 하겠습니다. 사용자가 얼마나 많은지, 트래픽 규모가 어떠한지에 따라 인스턴스 타입이 결정되어야 하겠지만, 이 포스팅에서는 AWS 무료 티어에서도 사용할 수 있는 t2.micro 타입의 인스턴스를 사용하도록 하겠습니다. 소규모의 사용량이라면 이 인스턴스로도 큰 문제가 없습니다. 

EC2 인스턴스의 생성은 많이들 해보셨을 작업이기 때문에 주의할 점을 중심으로 설명드리겠습니다. EC2 생성 마법사의 세번째 단계에는 IP 주소 할당에 대한 정책을 선택하도록 되어 있습니다. 우리가 진행하는 OpenVPN 은 단일 인스턴스 환경이기 때문에, 해당 서버가 사용자들로부터 IPv4 를 통해 VPN 연결을 시도할 수 있어야 하고, IPv6 주소를 보유하여 v6 주소를 갖고 있는 목적지 서버와 연결할 수 있어야 합니다. 

 

이 목적을 달성하기 위해서는 <3. Configure Instance> 단계에서 하단에 있는 <Auto-assign Public IP> 와 <Auto-assign IPv6 IP> 를 Enable 로 선택하여 v4 와 v6 를 통해 공인 IP 를 사용할 수 있도록 해야 합니다. 그런데 IPv6 는 왜 <Public> 이라는 말이 없을까요? 기본적으로 IPv6 주소 체계는 Private / Public 를 가지고 있지 않습니다. 따라서 옵션의 이름도 단순히 <Auto-assign IPv6 IP> 라고 되어 있다는 점 참고하시기 바랍니다!

EC2 생성 마법사를 완료하고 인스턴스 생성을 기다립니다. 생성이 완료되면 위와 같은 화면을 볼 수 있게 됩니다. 다른 기본적인 사항은 특별히 확인할 내용이 없고, 네트워킹 Networking 탭을 중심으로 살펴보면 됩니다. 설명했던 것처럼 v4 는 Private, Public 의 주소가 할당되지만 v6 는 하나의 주소만 할당된 것이 보입니다. 이제 인프라의 준비가 끝났습니다. 


 

다음 포스팅에서는 OpenVPN 을 인스턴스에 설치하는 작업을 해보도록 하겠습니다. 

728x90

+ Recent posts