2019년 4월 3일 수요일

SSL과 관련한 conda 설치 에러 - anaconda3 [해결]

(2019년 4월 10일: 아무래도 정확하지 않은 정보를 가지고 섣불리 글을 쓴 것은 아닌지 걱정이 된다. 기본 개념부터 다시금 되짚어 보아야 하겠다. 본문은 2019년 4월 11일 최종 수정되었다.)

공공연구기관에서는 멀쩡히 작동하던 서버가 왜 기업 전산망 내부에서는 몽니를 부리는가? 4년 3개월 동안 아무런 장애 없이 나와 동고동락하던 서버를 정식으로 반출허가를 받아서 파견지로 힘들게 들고 나왔는데 왜 이런 일이 벌어지는 것일까? 달라진 것이라고는 네트워크 설정을 바꾸고 그리드 엔진을 삭제한 것뿐이다.

그동안 잘 사용해 오던 anaconda2 환경에 새로운 bioconda 패키지를 설치하려는데 도무지 되질 않는다. anaconda3을 새로 설치한 다음 conda 자체를 업데이트하고자 시도하였으나 다음과 같은 에러 메시지가 나왔다. Firefox에서 http 사이트를 연결하면 (다 그런 것은 아니지만) 안전한 연결이 아니라고 하면서 화면이 뜨지 않는다.

# conda install conda
Solving environment: failed

CondaHTTPError: HTTP 000 CONNECTION FAILED for url 
Elapsed: -

An HTTP error occurred when trying to retrieve this URL.
HTTP errors are often intermittent, and a simple retry will get you on your way.

If your current network has https://www.anaconda.com blocked, please file
a support request with your network engineering team.

SSLError(MaxRetryError('HTTPSConnectionPool(host=\'repo.anaconda.com\', port=443): Max retries exceeded with url: /pkgs/r/noarch/repodata.json.bz2 (Caused by SSLError(SSLError("bad handshake: Error([(\'SSL routines\', \'tls_process_server_certificate\', \'certificate verify failed\')])")))'))
처음에는 그저 사내 전산망을 보호하는 방화벽에서 443번 포트가 막혀서 그런가 보다하고 관리자에게 이를 풀어줄 것을 요청하면 될 것이라 생각했었다. 그런데 구글에서 내가 해결할 방안이 없을지 검색을 거듭한 결과 이는 SSL(Secure Socket Layer) 인증서와 연관된 문제라는 생각이 들었다. 나와 비슷한 문제를 겪는 사람이 의외로 많이 있었다. 이번에야말로 SSL 인증서가 무엇이고 왜 중요한지를 알아볼 수 있는 마지막 기회라고 생각하고 공부를 하기로 마음을 먹었다. 그렇지 않으면 영원히 초보 리눅서를 벗어날 수 없다! CD-ROM으로 슬랙웨어를 설치하던 것이 94년쯤이었나, 25년이 넘어가는 지금까지도 별로 실력이 늘지를 않았다.

웹 서버와 브라우저 사이의 안전한 접속을 보장하는 SSL을 알아보자. 다음의 동영상(유튜브 링크)을 한번 감상하고, 그 다음에 나열한 웹사이트를 찬찬히 읽어보라. (1) 데이터를 암호화하여 중간에 나쁜 의도를 가진 사람이 이를 가로채도 내용을 알아볼 수 없게 하는 것, 그리고 (2) 웹 브라우저가 접속한 서버가 가짜가 아닌지를 확인하는 것이 주된 목적이다.


인증 기관의 인증서 목록이 없거나 모르는 기관에서 발급한 인증서일 경우 "curl"은 인증서 검증 에러를 발생시키고 작업을 중단한다고 한다(curl에 신뢰하는 인증기관 인증서 추가하기). 아마 conda 명령어도 비슷한 심경으로 작업을 중단했을 것으로 생각한다. 정확한 것인지 자신은 없지만 내가 생각하는 문제의 원인은 이러하다. SSL 인증서는 웹사이트 자체에, 그리고 Verisign, Comodo 등 인증기관에 같이 존재한다.
엄밀히 말해서 위 아래 단락의 밑줄을 친 부분은 정확하게 기술한 것은 아니다. 만약 이를 문자 그대로 해석한다면, 웹 서버와 최상위 인증기관에 같은 인증서가 두 벌 존재하여 접속 시에 이것이 서로 일치하는지를 확인하는 것처럼 여겨지기 때문이다. 하위 단계의 인증서에는 이것이 어디에서 발급되었는를 보여주는 정보가 들어있다. 상세한 것은 Get your certificate chain right 웹사이트를 참고하라.
웹브라우저는 https로 주소가 시작되는 웹서버에서 인증서를 가져온 다음 인증기관의 것과 같은지 비교를 한 뒤 동일함이 검증되면 다음 그림과 같이 채워진 자물쇠 그림과 함께 안전한 웹사이트임을 나타낸다. 자물쇠를 클릭하면 인증서 정보가 보이고 이를 파일로 export할 수 있다.



그러면 어떻게 해야 하는가? 임시 방편으로는 인증서 검증 작업을 하지 않게 만드는 것이 있겠다. 물론 보안 측면에서는 별로 권장할만한 일은 아니다. 다음의 방법은 StackOverflow의 conda update CondaHTTPError: HTTP None에서 힌트를 얻은 것이다. no가 아니라 false를 써야 한다는 글도 있었다. 이 해결책은 꽤 많이 알려져 있다. 이 명령에 대한 설명이 필요하면 conda config --describe ssl_verify를 입력하라.

# conda config --set ssl_verify no
SSL 인증서와 관련한 원인은 이곳에서 알아볼 수 있다. 아마도 공인되지 않은 자체 인증서를 제시하는 웹서버가 문제의 주요 원인이 아닐까 한다. 보다 근본적인 해결 방법은 ssl_verify 기능을 아예 꺼 버리는 것이 아니라, 해당 웹사이트에서 자체 인증서를 가져다가 저장하는 것이다. 아래의 사례는 git에 해당하는 것이지만 conda도 크게 다르지 않을 것이다. conda가 파일을 가져올 때 curl을 쓰기 때문이다(확인을 해 봐야 함).

Installing self-signed certificates into Git cert store

자체 인증서를 쓰는 사이트를 회사 방화벽이 막는지는 잘 모르겠다. 내가 겪는 문제는 CentOS 6.10이 설치된 리눅스 머신에서만 일어나고 있기 때문이다. 사무용 PC에서는 전혀 문제가 없는데, 방화벽이 리눅스와 윈도우를 가려서 작동할리는 없다. 리눅스 배포판이 문제인가? 하지만 바로 지난주까지는 정부출연연구소 내부에서 별 문제가 없었는데? 이를 확인하려면 리눅스를 좀 더 최신 버전 혹은 다른 배포판(예: 우분투)로 업그레이드하면 되는데 20 테라바이트쯤의 데이터를 잠시 다른 곳으로 옮기려면 보통 일이 아니다. 우분투 16.04가 설치된 집 컴퓨터를 들고 출근해서 똑같이 테스트하면 어떨까? 그러면 이것이 CentOS 버전과 관계가 있는 문제인지를 알 수 있을 것이다.

문제가 되는 웹사이트에서 인증서를 export하여 파일로 저장한 다음 그 위치를 .condrc 파일 내에 ssl_verify: corp.crt 형식으로 지정하는 것이 좀 더 근본적인 방식이다.

하지만 이렇게 장광설을 늘어놔 봐야 무슨 소용이 있겠는가? 내일 출근을 해서 테스트를 하기 전까지는 알 수 없다.

타워형 케이스 안에 6개의 6TB HDD가 있고 5개는 RAID로 묶여있는 상태이다. 장애 여부가 LED로 표시되지 않으니 만약 어느 하나에 문제가 생기면 어떻게 찾을까? 이렇게 26년차 초보 리눅서를 괴롭히는 또다른 문제는 RAID 관리에 관한 것이다. 결국은 제대로 경력을 갖춘 서버 관리자를 채용하여 더 큰 일을 도모하는 것이 정답이지만 바이오 기업 혹은 연구소에서 이런 인력을 좋은 조건을 제시하며 채용하는 것은 썩 쉽지가 않다.

2019년 4월 4일 업데이트

'conda config --set ssl_verify no'의 다음의 편법이 잘 작동함을 확인하였다. .condarc 설정 파일은 홈 디렉토리에 존재하는데, 이 명령을 실행함으로 인해서 다음과 같이 바뀌었음을 알 수 있다.

channels:
  - conda-forge
  - bioconda
  - defaults
ssl_verify: false
그러면 좀 더 안전한 방법을 실제로 실행에 옮겨보기로 하자. 나에게 고통을 안겨주었던 https://repo.anaconda.com/으로 가서 인증서 내보내기를 실행하였다. 파일 형식은 'Base 64로 인코딩된 X.509(.CER)'로 하였고 anaconda.cer라는 이름으로 저장하였다. 그 다음은 아래에 보인 것과 같이 실행하였다. .condarc 파일의 ssl_verify가 수정되었음을 알 수 있다.

# conda config --set ssl_verify ./anaconda.cer
# cat ./condarc
channels:
  - conda-forge
  - bioconda
  - defaults
ssl_verify: ./anaconda.cer
실수로 인증서 파일을 지우면 곤란하므로 .conda와 같은 숨겨진 디렉토리에 인증서를 두는 것이 좋을 것이다. 그런데... 잘 안된다. www.anaconda.com conda.anaconda.org repo.anaconda.com 등 한 사이트에서 인증서를 받아서 설치하면 다른 사이트가 막히고, 또 그것을 해결하면 다른 사이트가 막히고.. 각 사이트를 돌아가면서 접근이 안된다는 메시지가 나오는 것이다. 그러면 각 사이트에서 전부 인증서를 받아서 하나의 파일로 어떻게든 만들어야 한다는 이야기인가? 정말로 모르겠다. cert (or CA) bundle이라는 말이 종종 나오는데 도대체 어떻게 해야 할까?
CA bundle이란 루트 및 중간 단계 인증서의 묶음이다. 여기에 서버 인증서까지 포함하면 인증서 체인이 된다. conda 설정에서 ssl_verify ≠ false인 경우 제공해야 하는 것은 CA bundle이거나 혹은 trusted CA의 인증서이다. (CA bundle is a file that contains root and intermediate certificates. The end-entity certificate along with a CA bundle constitutes the certificate chain. [What is CA bundle?])

드디어 해결!

구글을 뒤지고 뒤져서 해결을 하였다. 웹브라우저에서 X.509(.cer)로 내보낼 수 있는 인증서는 한 장이다. 바로 아래에 있는 PKCS #7 인증서(.p7b)는 인증 경로에 있는 인증서를 전부 포함할 수 있다고 한다. 하지만 이 형식은 conda가 인식하지 못한다. 그래서 openssl을 사용하여 여러 인증서가 줄줄이 연결된 pem 포맷으로 전환해 보았으나 계속 에러가 발생하였다(참조 사이트: How to convert a certificate into the appropriate format). .pem 파일의 용도는 다음의 설명을 참조하라.

.pem file is a container format that may just include the public certificate or the entire certificate chain (private key, public key, root certificates). 출처

.cert .cer .crt - A .pem (or rarely .der) formatted file with a different extension, one that is recognized by Windows Explorer as a certificate, which .pem is not. 출처

그러면 웹브라우저를 거치지 않고 인증서들을 한번에 가져올 수는 없을까? 방법이 있다. 다음은 그 전체 과정을 보여준다. -showcerts 옵션을 주지 않으면 서버 인증서만 출력이 된다.

# echo quit | openssl s_client -showcerts -servername "www.anaconda.com" -connect www.anaconda.com:443 > cacert.pem
depth=1 C = KR, O = Somansa, CN = Somansa Root CA
verify error:num=19:self signed certificate in certificate chain
DONE
# conda config --set ssl_verify cacert.pem 
# conda update conda
Collecting package metadata: done
Solving environment: done

# All requested packages already installed.

# conda install -c bioconda trimmomatic
...성공!
(Somansa는 SSL 인증서 인증기관이 아니다. 그런데 왜 Root CA라고 표시되는 것일까? 이 회사에 대한 자세한 사항은 아래의 4월 6일 업데이트 참조.)

openssl 명령어를 이런 용도로 사용하는 힌트를 구한 웹사이트 주소를 잊어버려서 여기에 고마움을 표하지 못하는 것이 정말 아쉽다. 마치 에러가 있는 것처럼 나오지만(자체 인증서) cacert.pem 파일은 잘 만들어진다.

단, anaconda2에서는 여러 인증서가 하나로 합쳐진 cacert.pem을 인식하지 못하는 것으로 보인다. 이를 개별 파일로 분리하여 특정 디렉토리에 넣은 다음 ssl_verify에 대응하는 값으로 공급해도 잘 되지는 않는다.

CustomValidationError: Parameter ssl_verify = 'cacert.pem' declared in <> is invalid.
ssl_verify value 'cacert.pem' must be a boolean, a path to a certificate bundle file, or a path to a directory containing certificates of trusted CAs.

종합적인 결론을 내리자면, 아마도 사내 방화벽은 자체인증서만을 보유한 웹사이트에 접근하는 것을 싫어하는 것 같다. conda에서 인증서 확인 기능을 아예 끄는(ssl_verify: false) 위험한 방법을 동원하지 않고도 얼마든지 conda(curl..)를 즐길 수 있다!

이번에 겪은 작은 사고가 아니었더라면 웹사이트 인증서와 openssl에 대해 공부를 하는 기회를 갖지 못했을 것이다.

참고할만한 국문 사이트를 소개하면서 이틀에 걸친 포스팅을 마친다.


OpenSSH(Secure Shell)는 OpenSSL(Secure Socket Layer)과 다르다^^(SSH vs. SSL: 바보 같은 설명 참조)

https://www.openssh.com/

그러면 내 위키사이트도 인증서를 발급받아야 하지 않을까?

당연한 이야기이다. 돈이 드는 방법, 돈이 들지 않는 방법 전부 가능하다. 내가 사용하는 hostinger에서는 다음의 자료를 제공하고 있다. 큰 돈이 드는 것이 아니니 조만간 인증서를 설치하는 것이 좋겠다.
그런데 Conda documentation을 보면 내가 고민했던 것의 기본적인 원리에 대한 것이 대부분 설명되어 있다. 에러에 대처하는 직접적인 방법은 나오지 않지만 말이다.

2019년 4월 6일 업데이트: 소만사?

회사 네트워크 내부에서 conda update와 관련하여 문제가 되었던 웹사이트의 인증서 정보를 브라우저에서 살펴보니 Somansa라는 회사의 이름이 보였다. 난 이것이 인증서를 발급하는 회사라고 생각했었다. 그런데 집에서 같은 웹사이트에 접속하여 인증서 정보를 찾아보면 다른 회사이름이 나오는 것이었다(COMODO ECC Domain Validation Secure Server CA 2). 어라? 소만사가 무엇을 하는 회사인가? 아! 정보보안 솔루션(웹키퍼 SG(T-Proxy, 프록시 서버, 얼마만에 듣는 용어인가!))을 제공하는 국내 회사였다. 소만사라는 이름은 '소프트웨어를 만드는 사람들'에서 유래한 것이라 한다. 아주 쉽게 말해서 실수 혹은 악의적으로 기업의 정보를 SSL로 암호화하여 빼내는 것을 찾아내어 차단하는 하드웨어·소프트웨어 일체형 장비를 판매하는 곳이었다. '암호화 트래픽 가시성 확보'라는 용어가 이런 곳에 쓰이는 말이었다. 즉 Somansa의 웹프록시 서버가 SSL로 암호화되어 들어오는 정보를 복호화한 뒤 다시 암호화하여 내부 클라이언트로 보내는 과정에서 이를 완벽하게 되돌려놓지 못하는 것이 conda 업데이트(bioconda 패키지의 설치를 포함하여) 불능 문제의 원인이었던 것으로 보인다. 좀 더 정확하게 말하자면 bad handshake라는 에러 메시지가 많은 단서를 제공하고 있음을 나중에 알게 되었다.

SSL이 양날의 검이라는 말을 이제 조금 이해할 수 있었다. 암호화 및 인증서를 통해서 내가 접속한 웹서버가 가짜가 아님을 확신할 수 있고, 또한 사용자와 웹서버 사이에서 전달되는 패킷이 중간에 유출되어도 나쁜 의도를 가진 제3자가 이를 해독하지 못하게 한다. 그러나 실수나 악의에 의해서 '내'가 만약 기업 내부의 정보를 외부로 빼내려 한다면? 이를 막기 위한 DLP(Data Loss Prevention)의 한 방법이 바로 소만사와 같은 회사가 제공하는 솔루션이었던 것이다.

사용자 정보의 보호를 위하여 편지봉투를 밀봉하여 전달하였더니, 기밀사항을 유출하는지 알 수가 없게 되었고 이에 따라서 봉투를 아예 쓰지 못하게 하거나, 혹은 햇볕에 비추어서 내용물을 들여다보는 기술이 생긴 것과 비슷한 이치라고 하겠다.

항생제를 함부로 쓰면 감염성 세균의 내성도 이에 따라서 똑같이, 아니 그 이상으로 증가한다. 진화적 군비경쟁이 IT 분야에서도 똑같이 벌어진다.


댓글 없음: