User Tools

Site Tools


ssl_인증서_문제의_해결_방법

리눅스에서 SSL 인증서 문제의 해결 방법(v0.94)

이 문서는 2년이 넘는 시행착오를 거치면서 얻은 정보를 바탕으로 다른 분들에게 도움을 드리고자 작성하였습니다. 공공기관의 전산망 보안 체계를 무력화하거나 우회하는 방법을 소개하는 것이 결코 아니니 오해가 없으시길 바랍니다. 그리고 간혹 국가정보원에서 특정 IP 주소(https://raw.githubusercontent.com/)에 대한 접근을 하지 못하게 지시하는 경우가 있습니다. 업무상 꼭 다운로드해야 되는 프로그램를 이런 사이트에서 배포하는 경우에는 해결할 도리가 없습니다.

컴퓨터를 구입해서 KRIBB 안에서 IP address를 발급받아 처음으로 웹브라우저를 실행한 사람이라면 누구나 다음의 화면을 만나게 되었을 것입니다. 대개는 이 화면에서 안내하는대로 몇 번의 클릭을 통해 SSL 인증서(파일명은 SSLPrism.crt)를 각자 PC에(정확하게는 웹브라우저) 설치하였을 것이고, 이후 윈도우에서 인터넷 작업을 하는데 별다른 어려움이 없을 것입니다. 설치 이후에도 http://sslcert.cc를 접속하면 다시 이 화면을 볼 수 있습니다. 하지만 퇴근 후 집에서 컴퓨터를 켠 다음에 같은 곳을 접속하면 이 화면은 나오지 않습니다. SSL 인증서는 'https'로 시작하는 URL을 갖는 웹 서버가 발급받아 갖고 있어야 하는 것인데 왜 사용자 PC에서 이를 다운로드하여 설치해야 하는 것인지 궁금하게 생각해 보신 일은 없으신지요? 또는 KRIBB내에 설치한 리눅스 컴퓨터에서 파일을 다운로드하는데 'SSL certificate'와 관련한 오류를 접한 일은 없으신지요? 이는 서로 연관된 문제입니다. 리눅스에서도 아마 처음으로 웹브라우저(보통은 Firefox)를 실행할 때 SSLPrism.crt를 설치하라는 메시지를 접하였을 터이고, 안내를 충실히 따르셨을 것입니다. 그런데 뒤에서 소개하겠지만 리눅스에서 다른 작업을 하려면 이것만으로는 잘 안되는 순간을 종종 만나게 됩니다.

SSL ePrisim이란?

SSL(보안 소켓 계층, Secure Socket Layer)는 웹사이트와 브라우저 사이에 전송된 데이터를 암호화하여 인터넷 연결의 보안을 유지하는 표준 기술입니다(참조). 다시 풀어서 이야기하자면 내가 접속하는 웹사이트가 위변조되지 않은 진짜인지를 검증하고, 클라이언트와 웹서버가 서로 주고받는 패킷을 암호화하여 제3자가 그 내용을 알지 못하게 만들어 주는 기술로서, 그 과정엣 SSL 인증서가 핵심 요소 중 하나로 쓰입니다. 그러나 기관의 전산망 '보안'의 입장에서는 내부의 민감한 정보가 외부로 빠져나가는지, 혹은 악성코드가 심겨진 패킷이 내부로 유입되는지를 점검할 필요가 있습니다. 이를 위해 암호화 트래픽을 복호화, 즉 암호를 푸는 솔루션을 구비하지 않을 수 없습니다. SSL ePrism은 수산INT라는 회사에서 시판하는 SSL 가시성 솔루션입니다(제품 정보). 편지를 써서 불투명한 봉투에 넣어서 부쳤는데 기관 보안 차원에서 이를 강한 불빛에 쪼여서 내용물을 들여다보는 것과 비슷한 상황인 것입니다. 현재로서는 어쩔 도리가 없습니다.

SSL을 이용하여 웹서버와 클라이언트가 서로를 확인하는 과정은 상당히 복잡합니다. 이를 이해하려면 꽤 깊은(?) 수준의 공부가 필요하고, 이를 다 알아야 할 이유는 없다고 생각합니다. 만약 관심이 있으시다면, SSL, TLS, 대칭키, 개인키, 암호호, 복호화, TLS handshaking, certificate bundle, certificate chain, CA cert 등의 용어를 구글에서 검색하여 꼼꼼하게 읽어 보십시오. 과거에 제가 블로그에 쓴 글(링크)을 방문하시면 공부하실 수 있는 자료의 링크가 나옵니다.

KRIBB 내에서 웹브라우저로 https://cran.rstudio.com을 접속한 뒤 주소창 왼쪽의 잠긴 자물쇠 표시를 클릭하여 인증서 정보를 한번 살펴보십시오. ePrism SSL이 최상위 인증기관인 것처럼 나옵니다. 아니, 새 창을 열 필요도 없습니다. 이 웹문서를 보고 계신 브라우저의 현재 주소창 왼쪽의 자물쇠를 클릭해도 마찬가지일 것입니다. 이번에는 리눅스 컴퓨터(KRIBB 내부)의 명령행 환경에서 다음을 입력해 보십시오.

$ echo quit | openssl s_client -showcerts -servername "cran.rstudio.com" -connect cran.rstudio.com:443 > test.ca-bundle
depth=1 C = KR, O = SOOSAN INT, CN = ePrism SSL
verify error:num=19:self signed certificate in certificate chain
verify return:1
depth=1 C = KR, O = SOOSAN INT, CN = ePrism SSL
verify return:1
depth=0 CN = cran.rstudio.com
verify return:1
DONE

자체 서명한 인증서라는 메시지와 함께 최상위 인증 기관이 수산INT이고 최상위 인증서는 ePrism SSL(=SSLPrism.crt)이라고 표현됩니다. 하지만 CRAN이나 이 문서를 서비스하는 웹서버는 수산 INT에서 SSL 인증서를 발급받지 않았습니다. 이번에는 똑같은 명령어를 집에서 한번 입력해 보십시오. CRAN 사이트에는 Amazon, 즉 다른 최상위 인증 기관과 인증서 이름이 나타날 것입니다. 사실은 이게 맞는 것입니다. 집 컴퓨터의 웹브라우저에서 해당 사이트를 접속한 다음 주소창 옆의 자물쇠를 클릭하여 인증서를 확인해 보아도 마찬가지일 것입니다.

$ echo quit | openssl s_client -showcerts -servername "cran.rstudio.com" -connect cran.rstudio.com:443 > test.ca-bundle
depth=2 C = US, O = Amazon, CN = Amazon Root CA 1
verify return:1
depth=1 C = US, O = Amazon, OU = Server CA 1B, CN = Amazon
verify return:1
depth=0 CN = cran.rstudio.com
verify return:1
DONE

왜 그래야만 하는지는 모르겠으나, 자체 서명한 인증서를 쓰는 웹사이트를 KRIBB 내부에서 접속하려고 하면 최상위 인증서는 ePrism SSL인 것으로 바뀌어서 내부 클라이언트에게 전달됩니다. 웹브라우저에서는 이미 이 인증서를 추가적으로 설치해 놓은 상태이므로 별 문제가 없지만, curl이나 wget, 명령행 환경의 R(특히 라이브러리 설치 시), 그리고 python, conda, git 등에서 등 https로 시작하는 URL 상의 파일을 가져오려고 할 때 숱하게 에러 메시지를 토해낼 것입니다. 아래에 보인 리눅스 환경의 wget 실행 오류 사례를 보십시오. 저는 이 메시지를 보는 것이 정말 지긋지긋합니다! KRIBB 내부에서는 이와 같이 https로 시작하는 특정 웹주소의 파일을 내려받으려면 에러가 발생하지만, 집 컴퓨터에서 테스트를 하면 다운로드가 잘 됩니다.

$ wget https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/014/706/575/GCF_014706575.1_ASM1470657v1/GCF_014706575.1_ASM1470657v1_genomic.gbff.gz
--2021-05-24 14:15:16--  https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/014/706/575/GCF_014706575.1_ASM1470657v1/GCF_014706575.1_ASM1470657v1_genomic.gbff.gz
ftp.ncbi.nlm.nih.gov (ftp.ncbi.nlm.nih.gov)을(를) 해석하는 중... 165.112.9.229, 165.112.9.228
접속 ftp.ncbi.nlm.nih.gov (ftp.ncbi.nlm.nih.gov)|165.112.9.229|:443... 접속됨.
오류: ftp.ncbi.nlm.nih.gov의 인증서를 확인할 수 없습니다. 발행자는 `CN=ePrism SSL,O=SOOSAN INT,C=KR'입니다:
  자기 자신이 서명한 인증서를 발견했습니다.
ftp.ncbi.nlm.nih.gov에 안전하지 않게 연결하려면 `--no-check-certificate'를 사용하십시오.

한글화가 잘 된 시스템에서 실행을 하니 친절한 메시지가 나옵니다 :)

문제를 해결할 수 있는 단편적인 해결책은 있습니다. 그러나...

wget 실행 시 '--no-check-certificate' 옵션을 주거나($HOME/.wgetrc 파일에 'check_certificate = off'를 선언해 두어도 좋음), pip install 실행 시 '--trusted-host pypi.org --trusted-host files.pythonhosted.org' 옵션을 주는 방법 등이 인터넷 검색을 하면 종종 보입니다. ~/.condarc file에 'ssl_verify: false'를 삽입하거나, ~/.Renviron 파일을 수정하는 등 각 애플리케이션마다 문제를 해결하는 방법이 하나씩 다 있을 정도입니다. 그러나 이는 완벽한 해결책이 아닙니다. 심지어 python 프로그램이 urllib(3)을 쓰는 경우 지정된 SSL 인증서를 쓰도록 스크립트를 수정하는 방법까지 알려져 있습니다(사례 링크). 그러나 저와 같이 python 프로그램을 설치 및 활용만 겨우 하고 그 문법을 모르는 사람에게는 별다른 도움이 되지 않습니다. 특히 wget은 명령행 환경에서 단독으로 쓰이지만 curl은 라이브러리를 통해서 다른 프로그램 혹은 스크립트 내부에서 파일 다운로드를 하는데 매우 널리 쓰입니다. 따라서 인증서를 회피하거나 바꿀 수 있게 옵션 또는 파라미터를 주기가 아주 적당치 않습니다.

가장 근본적인 방법은 system-wide한 인증서 설치 위치 정보를 이용하는 것입니다

리눅스에서는 SSLPrism.crt라는 인증서를 신뢰할 수 있는 것으로 인정하고 시스템 전체에 걸쳐 적용하도록 설치하는 공식적인 방법이 있습니다. 이 방법을 따른 뒤, 두 개의 환경변수를 선언하는 것으로 충분합니다. 관리자 권한으로 다음 설명을 따라서 실행해 보십시오. 'export…' 명령은 일반 사용자로서 실행해도 됩니다. 더욱 간단하게는 ~/.bashrc 파일에 삽입해 두면 됩니다.

CentOS

SSLPrism.crt 파일을 /etc/pki/ca-trust/source/anchors/에 복사한 뒤 update-ca-trust 명령을 실행합니다. 그러면 /etc/pki/tls/cert.pem 파일에 SSL Prism과 관련한 인증서가 맨 위로 올라갑니다. 그런 다음 .bashrc 파일에 다음 두 줄을 선언하십시오. 재로그인하여 지금까지 문제를 불러일으켰던 명령을 다시 실행해 보십시오.

export REQUESTS_CA_BUNDLE=/etc/pki/tls/cert.pem
export CURL_CA_BUNDLE=/etc/pki/tls/cert.pem

Ubuntu

우분투에서는 SSL 인증서 파일을 새로 등록하는 방법이 조금 다릅니다. SSLPrims.crt 파일을 /usr/local/share/ca-certificates/ 디렉토리에 복사한 다음 update-ca-certificates 명령을 실행합니다. 그런 다음 .bashrc 파일에 다음 두 줄을 선언하십시오. 재로그인하여 지금까지 문제를 불러일으켰던 명령을 다시 실행해 보십시오.

export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
export CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt

REQUESTS_CA_BUNDLE은 python을 위한 것이고(이것은 확실하지 않습니다), CURL_CA_BUNDLE은 curl과 그 관련 프로그램을 위한 것입니다. 파일 다운로드를 내부적으로 실행하는 대부분의 스크립트 혹은 애플리케이션은 이 두 개의 변수로 인하여 다 커버가 될 것입니다. SSLPrism.crt를 시스템에 설치하고 두 개의 환경변수에게 그 위치를 제대로 알려주기만 하면 에러를 발생하는 프로그램마다 옵션을 따로 줄 이유가 없습니다.

PYTHONHTTPSVERIFY 환경변수를 0으로 설정하면 python 스크립트가 파일을 다운로드할 때 SSL 인증서를 확인하는 절차를 생략할 수 있다는 글을 읽었습니다. 그러나 antiSMASH 5.x 설치에서 이는 작동하지 않았습니다. 따라서 파이썬 스크립트를 고쳐서 파일을 비로소 다운로드하는 경험을 2021년 5월 28일에 처음 하게 되었습니다. 이에 대한 것은 antiSMASH v5가 이렇게 설치하기 어려운 소프트웨어였던가?에 기록하였습니다.

Oxford Nanopore MinION Mk1C의 경우

우분투가 설치된 이 작은 장치는 유선 인터넷 설정 자체도 쉽지 않습니다. Wi-Fi가 되는 환경에 가지고 가서 어떻게 해서든 다른 컴퓨터를 통해 SSH로 진입해야 유선 인터넷 연결을 위한 고정 IP 주소를 설정할 수 있습니다. 그 다음에는 위에서 Ubuntu 환경의 인증서 설치 작업과 유사하게 진행하면 되는데, update-ca-certificates 패키지 자체가 설치되지 않은 상태일 것입니다. /etc/ssl/certs/ca-certificates.crt 파일을 다른 이름으로 백업한 뒤 SSLPrims.crt를 ca-certificates.crt라는 이름으로 바꾸어 놓았더니 비로소 연구소 환경에서도 Mk1C ⇔ 외부 인터넷 소통이 되는 것 같습니다(완벽하지는 않음).

wget은 아직 주의가 필요합니다

$ TARGET=https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/014/706/575/GCF_014706575.1_ASM1470657v1/GCF_014706575.1_ASM1470657v1_genomic.gbff.gz
$ /usr/bin/wget $TARGET # 다운로드에 문제가 없습니다
$ /opt/miniconda3/envs/tormes-1.2.1/bin/wget $TARGET
--2021-05-27 10:10:11--  
https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/014/706/575/GCF_014706575.1_ASM1470657v1/GCF_014706575.1_ASM1470657v1_genomic.gbff.gz
Resolving ftp.ncbi.nlm.nih.gov (ftp.ncbi.nlm.nih.gov)... 130.14.250.11, 130.14.250.10
Connecting to ftp.ncbi.nlm.nih.gov (ftp.ncbi.nlm.nih.gov)|130.14.250.11|:443... connected.
ERROR: cannot verify ftp.ncbi.nlm.nih.gov's certificate, issued by ‘CN=ePrism SSL,O=SOOSAN INT,C=KR’:
  Self-signed certificate encountered.
To connect to ftp.ncbi.nlm.nih.gov insecurely, use `--no-check-certificate'.

Conda tormes-1.2.1 environment에서 제공하는 wget은 인증서 문제로 에러 메시지를 토해냅니다. 왜 system-wide하게 설치된 인증서 정보를 사용하지 못하는 것일까요? 아마도 conda 환경에서 같이 딸려온 인증서 정보(/opt/miniconda3/envs/tormes-1.2.1/ssl 디렉토리에 있음)이 우선하기 때문인 것으로 생각됩니다. 다행스럽게도 같은 환경의 curl은 환경변수(CURL_CA_BUNDLE)의 설정을 잘 따라가는 것 같습니다.

그렇다면 /opt/miniconda3/envs/tormes-1.2.1/etc/wgetrc 파일을 건드려서 wget에 대해서만 업데이트된 인증서 정보(ePrism SSL 을 포함하고 있는)를 참조하도록 만들면 됩니다. 이 파일을 열어서 다음 라인을 추가해 주십시오. 이는 CentOS의 경우입니다.

# 다음의 줄을 /etc/wgetrc 또는 ~/.wgetrc에 넣으면 평소에 '--no-check-certificate' 옵션을 줄 필요가 없습니다.
# 단, 이 글에서 설명한 방법대로 인증서 정보를 전혀 수정하지 않은 경우에 그렇습니다.
ca_certificate=/etc/pki/tls/cert.pem

이제 /opt/miniconda3/envs/tormes-1.2.1/bin/wget 명령으로 $TARGET을 다운로드해 보십시오. 에러 없이 잘 될 것입니다.

이 문서는 완벽하지 않습니다!

이 문서는 제가 약 2년이 넘는 기간 동안 삽질을 하면서 단편적인 해결책으로 땜질만을 해 오다가 비교적 최근-2021년 5월 하순-에 (거의?) 완벽한 해결책을 찾아낸 것 같아서 지식의 공유 차원에서 작성한 것입니다. 저는 프로그래밍이나 보안의 전문가가 아니므로 당연히 오류가 있을 수 있습니다. 제 블로그에서 SSL, 인증서, certificate, 오류, error 등을 넣어서 검색을 해 보시면 약 2년이 넘는 기간 동안 제가 얼마나 많은 시행착오를 겪었는지를 적나라하게 보실 수 있습니다. 제 블로그에 덧글을 달아서 두 환경변수 설정에 대한 아이디어를 주신 분에게 깊은 감사를 드립니다. 작성자의 성함이 '지나가는이'로만 되어 있어서 보다 직접적으로 감사의 표시를 할 수 없음이 아쉽습니다. 덧글이 달린 블로그의 원문은 여기에 있습니다. 이 원문에는 제가 검색을 통해 주워담은 SSL 인증서와 접속이 형성되는 TLS handshaking 과정 등의 설명 자료 링크가 있으니 전반적인 공부에 도움이 될 것입니다. 당시에는 '지나가는이'님의 덧글을 잘 이해하지 못하고 있다가 최근에 비로소 그 변수의 위력을 알게 되었습니다.

혹시 이 위키문서 또는 바로 앞서 소개한 제 블로그의 문서 내용에 대하여 의견이 있으시면 언제든지 연락을 주십시오.

기타 참고 자료

ssl_인증서_문제의_해결_방법.txt · Last modified: 2023/06/29 14:47 by hyjeong