2021년 5월 20일 목요일

Conda 환경이 참조하는 SSL 인증서의 위치는 어디에 있는가? - 방황의 끝

SSL 인증서와 관련한 문제로 2년이 넘게 고생을 해 왔고 이제야 어렴풋하게 이해를 했다고 생각했지만, 오늘 무릎을 치면서 '유레카!'를 외치는 발견을 또 하게 되었다. 늘 눈앞을 가로막고 있는 듯했던 무식의 장막을 하나 더 걷어냈다는 기쁨을 나 혼자 간직할 수가 없어서 이렇게 블로그에 기록을 남긴다. 2년이라는 시간 동안 걷어낸 장막 뒤에는 이보다 훨씬 더 두꺼운 콘크리트 벽이 자리를 잡고 있을지도 모르는 일이지만..

한국생명공학연구원의 전산망 내에서 일을 하는 사람이라면 수산 아이앤티라는 회사에서 제공하는 SSLPrism.crt라는 파일을 웹브라우저에 설치해야 한다. 윈도우에서만 일을 한다면 이것으로 대부분의 업무를 다 볼 수 있다. 리눅스도 웹브라우저에서 SSLPrism.crt 파일을 설치하면 된다. 생명(연)에서 컴퓨터를 구입하여 처음으로 인터넷에 접속을 하면 이 과정이 거의 자동으로 이루어지니 보통은 별로 신경을 쓰지 않아도 된다. 생명(연)에서 안내하는 것은 딱 여기까지이다. 아래에 분홍색으로 표시한 텍스트는 수많은 시행착오와 검색으로 알아낸 사실이다.

소만사니 수산 아이앤티니 하는 회사의 장비가 하는 일은 https://로 시작하는 웹사이트와 내부 사용자가 주고받는 정보를 복호화(즉 암호를 푸는)하는 일이다. 사용자를 보호해 주는 것이 아니라, 사용자가 기관의 민감한 정보를 유출하는지를 감시하기 위한 것이다!(내가 이해하는 것이 100% 정확한 것은 아닐 수도 있음). 다시 말하자면 기관 차원의 보안을 위한 솔루션인 것이다. 만약 접속하고자하는 외부 사이트가 자체 서명한 인증서를 쓰는 경우, 이 장비를 거치면서 최상위 인증서가 SSLPrism.crt인 것으로 바뀌어서 내부로 전달된다. 왜 이렇게 되어야 하는지는 내가 알지 못한다. 이때 전산망 내부에 있는 사용자가 SSL 인증서와 관련한 수많은 오류를 만나게 되는 것이다. 특히 nanopore 구동 관련 software를 설치하면서 많은 어려움을 겪을 것이다. 이것은 방화벽에서 포트를 여는 문제로 완벽하게 해결되지 않을 것이다. 단, 윈도우 환경에서 일반적인 업무를 보는 사람은 별다른 문제를 접하지 않는다...

하지만 리눅스에서는 웹브라우저만을 이용하여 https:// 위치에 있는 파일을 가져오는 것이 아니다.  wget, curl,  그리고 파이썬의 urlopen() 등 많은 애플리케이션이 웹브라우저를 경유하지 않고 직접 외부의 자료를 갖고오게 만든다. 웹브라우저에서 설치한 인증서는 이러한 상황에서 다른 애플리케이션에게 도움을 주지 못한다. 따라서 SSLPrims.crt는 CentOS의 경우 update-ca-trust라는 별도의 프로그램을 이용하여 시스템 전체에 걸쳐 작동하도록 설치해야 한다. 방법은 단순하다. SSLPrism.crt 파일을 /etc/pki/ca-trust/source/anchors/ 디렉토리에 복사한 뒤 update-ca-trust 명령을 실행하면 된다. 물론 이 두 단계의 작업을 하려면 관리자 권한이 필요하다. 이렇게 하면 /etc/pki/tls/cert.pem과 /etc/pki/tls/certs/ca-bundle.crt 두 개의 파일 제일 앞에 SSLPrism.crt 인증서가 위치하게 될 것이다.

이렇게만 해 놓으면, wget 명령에서 '--no-check-certificate', 그리고, curl 명령에서 '--cacert' 등의 파라미터를 설정할 필요가 없다.

그런데 conda 환경 내에서는 system-wide한 인증서 위치를 참조하지 않는 것을 뒤늦게 발견하였다. SILVA database를 다운로드하는 다음의 사례를 보자. 위의 것은 conda 환경에 설치된 wget 명령을(다운로드 실패), 아래는 시스템에 존재하는 /usr/bin/curl을 이용한 것이다(다운로드 성공). 

(base) $ curl https://ftp.ncbi.nlm.nih.gov/genomes/all/GCA/014/706/575/GCA_014706575.1_ASM1470657v1/GCA_014706575.1_ASM1470657v1_genomic.fna.gz > test.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
curl: (60) SSL certificate problem: self signed certificate in certificate chain
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

(base) $ /usr/bin/curl https://ftp.ncbi.nlm.nih.gov/genomes/all/GCA/014/706/575/GCA_014706575.1_ASM1470657v1/GCA_014706575.1_ASM1470657v1_genomic.fna.gz > test.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 1576k  100 1576k    0     0   578k      0  0:00:02  0:00:02 --:--:--  578k

그렇다면 conda 환경에서 참조하는 SSL 인증서의 위치는 도대체 어디인가? 'Conda +  SSL + 에러'라는 키워드로 구글 검색을 하면 대부분 .condarc 파일에서 'ssl_verify: false'라고 설정을 하라는 답이 얻어진다. 이것은 conda package를 설치 또는 업데이트할 때의 문제이다. Conda 환경 내에서 개별적으로 돌아가는 애플리케이션이 외부 파일을 가져오고자 할 때 겪는 인증서 문제와는 다른 이야기이다.

테스트를 위해 새로 설치한 miniconda 디렉토리의 하위를 뒤져 보았다. ca-certificates라는 conda package가 설치된 곳을 찾아야 한다. 그것은 바로 다음의 위치였다. 그리고 개별적인 conda 환경은 env/환경명/conda-meta/ca-certificates-2020.12.5-ha878542_0.json 파일을 통해서 자기가 어떤 인증서를 참조하고 있는지를 명시하였다.

/opt/miniconda3/pkgs/ca-certificates-2020.12.5-ha878542_0/ssl

여기에는  cacert.pem과 cert.pem(cacert.pem의 심볼릭 링크) 파일이 존재한다. 당연히 이 파일은 SSLPrisim 인증서를 전혀 알지 못한다. 시스템 전체에 적용되는 /etc/pki/tls/cert.pem 파일을 이 위치의 cacert.pem으로 덮어 씌워버렸다. 

결과는 예상한 바와 같다. Conda 환경에 설치한 wget으로 SILVA database가 무사히 다운로드되었다. 오늘 얻은 하나의 깨달음이 또 다른 '무지의 늪'을 재발견하도록 나를 이끌지도 모르는 일이지만...

TORMES-1.2.1 재설치 테스트

오늘 확인한 바를 최종 점검하기 위해 miniconda3에 tormes-1.2.1을 새롭게 설치해 보았다. SSL 인증서와 관련하여 손을 댄 것은 바로 위에서 언급한 ca-certificates 디렉토리 이하를 고쳐서 system-wide하게 설치된 인증서를 쓰도록 만든 것이 전부이다. quast-download-busco를 실행할 때 BUSCO DB의 위치가 영구적으로 바뀌어서 다운로드가 되지 않는다는 에러를 제외하면 R 패키지 설치까지 전부 완벽하게 끝났다. 아래에 보인 에러는 SSL 인증서와는 관계가 없다. 좀 이상한 것은 세 개의 tar.gz 파일을 wget(/usr/bin/wget이 아니라 tormes 환경에서 설치한 것)으로 다운로드하면 문제가 생기지 않는다는 것이다.

Downloading BUSCO database...
Downloading bacteria database (file: bacteria.tar.gz)...

ERROR! Failed downloading bacteria database (url: https://busco.ezlab.org/v2/datasets/bacteria_odb9.tar.gz), QUAST functionality will be limited! Exception caught: HTTP Error 301: Moved Permanently
You can try to download the file manually, place it in /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco/bacteria.tar.gz and restart QUAST
WARNING: Failed to download bacteria database from https://busco.ezlab.org/v2/datasets/bacteria_odb9.tar.gz and unpack it into /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco
  Downloading BUSCO database...
Downloading eukaryota database (file: eukaryota.tar.gz)...

ERROR! Failed downloading eukaryota database (url: https://busco.ezlab.org/v2/datasets/eukaryota_odb9.tar.gz), QUAST functionality will be limited! Exception caught: HTTP Error 301: Moved Permanently
You can try to download the file manually, place it in /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco/eukaryota.tar.gz and restart QUAST
WARNING: Failed to download eukaryota database from https://busco.ezlab.org/v2/datasets/eukaryota_odb9.tar.gz and unpack it into /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco
  Downloading BUSCO database...
Downloading fungi database (file: fungi.tar.gz)...

ERROR! Failed downloading fungi database (url: https://busco.ezlab.org/v2/datasets/fungi_odb9.tar.gz), QUAST functionality will be limited! Exception caught: HTTP Error 301: Moved Permanently
You can try to download the file manually, place it in /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco/fungi.tar.gz and restart QUAST
WARNING: Failed to download fungi database from https://busco.ezlab.org/v2/datasets/fungi_odb9.tar.gz and unpack it into /opt/miniconda3/envs/tormes-1.2.1/lib/python3.6/site-packages/quast_libs/busco

만일 tormes 환경 설치 과정 중에 'ClobberError: This transaction has incompatible packages due to a shared path.'라는 보기 싫은 에러 메시지가 나온다면, 'conda clean --all'을 실행하라. 이 명령은 index cache, lock file, 쓰지 않는 cache package 및 tarball을 삭제하여 깔끔한 환경을 만들어 준다.

이것만 기억해 두자. conda에서 새로운 환경을 설치했다면, 어느 버전의 ca-certificates를 참조하는지를 확인하여 이것을 고치면 된다. 지금 설치되어 있는 것만 하여도 이렇게 많으니 말이다...


2021년 5월 24일 업데이트

Conda의 ca-certificates가 제공하는 인증서 파일을 바꿔치기하는 것은 임시방편은 될 수 있지만 그렇게 현명한 방법은 아니다. 이렇게 하여 일부 패키지의 설치 또는 파일의 다운로드에는 성공할 수 있을지 모르나, 'conda update conda'를 실시하게 되면 인증서 파일의 크기가 맞는지 꼼꼼하게 확인하기 때문이다.

SafetyError: The package for ca-certificates located at /opt/miniconda3/pkgs/ca-certificates-2020.12.5-ha878542_0
appears to be corrupted. The path 'ssl/cacert.pem'
has an incorrect size.
  reported size: 263774 bytes
  actual size: 217320 bytes

따라서 2021년 5월 23일에 작성한 글 Bactopia test - 방황의 끝(2)에서 설명한 방법을 따르는 것이 현명할 것이다.

댓글 없음: