2021년 4월 30일 금요일

.wgetrc 파일에 CA 인증서 파일 위치를 지정하여 'https://'로 시작하는 URL의 파일 다운로드하기

https://~(443 port)로 시작하는 URL의 파일을 리눅스 명령행(wget 사용)에서 다운로드할 때 에러가 발생하면 '--no-check-certificate' 옵션을 제공하면 된다는 것을 이제는 상식적으로 알고 있다. 하지만 왜 윈도우에서는 문제가 없을까? 집에서 테스트를 하면 왜 잘 될까? 리눅스 환경에서 프로그램이 자체적으로 다운로드를 실시할 때 알아서 진행되게 할 수는 없을까? 

이에 대한 고민을 2018년부터 해 왔고 부분적으로는 해결 방법을 찾았지만 체계적인 지식이 부족하여 늘 애를 먹다가 TORMES pipeline의 업그레이드를 계기로 진지하게 접근해 보기로 하였다.

간단히 설명하면 이러하다. SSL(TLS가 더 정확한 용어일지도 모름)은 서버와 클라이언트 사이에서 패킷을 암호화하여 주고받음으로써 외부에서 이를 가로채도 무슨 의미인지 알 수 없게 만드는 것이 목적이다. 또 다른 목적은 내가 접속하는 웹사이트가 가짜가 아님을 확인해 주는 것이다. 보안 전문가의 견해로는 SSL에 대한 나의 해석이 100% 정확하지 않을 수도 있지만, 일반인 수준에서는 이 정도로 이해하면 된다.

그런데 패킷이 암호화되어서 돌아다니게 되니 기관의 보안 관리 입장에서는 내부의 중요한 정보가 빠져나가도 알 수가 없게 되었다. 그래서 이를 감시하는 SSL 복호화 솔루션을 쓰게 된다. SOMANSA니 SOOSAN INT니 하는 회사가 바로 이런 네트워크 보안 솔루션을 제공하는 곳이다. 이런 보안 솔루션이 적용되는 전산망 내부에서 인터넷을 쓰려면 이들 회사에서 제공하는 CA 인증서를 받아서 웹브라우저에 설치해야 한다. 처음에는 이를 이해하지 못했었다. 왜냐하면 SOMANSA나 SOOSAN INT는 원래 인증서를 발급하는 기관이 아니기 때문이다. 기업에서 2년 동안 근무할 때에는 SOMANSA의 것을, 한 뒤 연구소에 돌아와서 처음으로 인터넷을 연결했더니 SOOSAN INT의 SSLPrisim.crt라는 파일을 웹브라우저에 설치하라고 한다. 이 파일은 일종의 CA(certificate authority 또는 root certificate) 역할을 한다. 웹브라우저의 주소창에 sslcert.cc라는 곳을 치면 자동으로 다운로드할 수 있다. 리눅스의 파이어폭스에서도 똑같은 일을 하면 된다.

만약 모든 인터넷 접속(파일 다운로드 포함) 작업을 웹브라우저에서 한다면 이렇게 하는 것만으로도 문제가 없다. 그런데 리눅스에서는 wget, curl 등을 써서 명령행에서 파일을 가져올 일이 많다. 또한 conda, curl, R, pip 등 자체적으로 https:// 위치에 있는 파일을 가져오는 명령어가 있는데, 웹브라우저(SSLPrism.crt를 이미 알고 있는)는 전혀 경유하지 않으므로 문제가 생긴다.

https:// 위치에 있는 모든 파일을 가져오는데 문제가 생기는 것은 아니다. 테스트를 해 본 결과 자체 인증서를 쓰는 웹사이트만 그러한 것 같다. 예를 들어 보자.

$ wget https://cran.rstudio.com
--2021-04-30 09:28:19--  https://cran.rstudio.com/
cran.rstudio.com (cran.rstudio.com)() 해석하는 중... 52.84.166.5, 52.84.166.79, 52.84.166.102, ...
접속 cran.rstudio.com (cran.rstudio.com)|52.84.166.5|:443... 접속됨.
오류: cran.rstudio.com의 인증서를 확인할 수 없습니다. 발행자는 `CN=ePrism SSL,O=SOOSAN INT,C=KR'입니다:
  자기 자신이 서명한 인증서를 발견했습니다.
cran.rstudio.com에 안전하지 않게 연결하려면 `--no-check-certificate'를 사용하십시오.

OpenSSL 명령어를 사용하여 접속 테스트를 해 보아도 같은 종류의 메시지가 나온다. 

$ echo quit | openssl s_client -showcerts -servername "cran.rstudio.com" -connect cran.rstudion.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

자체 서명한 인증서를 쓴다는 것이고, 직장 전산망을 보호(?)하는 ePrism SSL VA 장비는 이를 차단하는 것으로 보인다.만약 같은 웹사이트에 대해서 집에서 wget 명령어를 실행하면 어떻게 될까? 아무런 문제가 없이 다운로드가 잘 이루어진다. OpenSSL 명령어에 대한 결과는 이러하다.

$ echo quit | openssl s_client -showcerts -servername "cran.rstudio.com" -connect cran.rstudio.com:443 > test.ca-bundle
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

접속한 사이트가 자체 인증서를 쓰는지의 여부는 화면상으로 출력되지는 않는다. 파일로 리다이렉트한 CA bundle에는 혹시 그런 내용이 기록되는지는 아직 확인해보지 않았다.

SSLPrism.crt 파일은 자체 인증서를 쓰는 웹사이트임을 알게 된 경우에 사용하는 대체용 CA 인증서일 것이라는 생각이 들었다. 리눅스 혹은 윈도우 웹브라우저에서 이 사이트를 접속한 뒤 주소창 왼쪽의 잠겨진 자물쇠를 클릭하여 인증서 정보를 확인하여 보라. 발급자는 ePrism SSL로 나타난다.


자, 그러면 리눅스 명령행에서 wget 명령어가 SSLPrism.crt 파일을 이용하게 만들면, 매번 '--no-check-certificate'를 쓸 일이 없을 것이다. ~/.wgetrc 파일을 편집하여 사용자가 원하는 설정 사항을 기록하면 된다고 하여 그대로 따라해 보았다.

$ echo 'ca-certificate=~/SSLPrism.crt' > .wgetrc
$ wget https://cran.rstudio.com
--2021-04-30 09:05:11--  https://cran.rstudio.com/
cran.rstudio.com (cran.rstudio.com)() 해석하는 중... 52.84.166.102, 52.84.166.5, 52.84.166.64, ...
접속 cran.rstudio.com (cran.rstudio.com)|52.84.166.102|:443... 접속됨.
HTTP 요청을 전송했습니다. 응답을 기다리는 중입니다... 200 OK
길이: 850 [text/html]
다음 위치에 저장: `index.html'

index.html                          100%[======================================>]     850  --.-KB/s    / 0s       

2021-04-30 09:05:11 (27.9 MB/s) - `index.html' 저장됨 [850/850]

옳거니! SSLPrism.crt 파일을 이렇게 하여 웹브라우저가 아닌 다른 애플리케이션이 쓰도록 만들어 보았다. 이것으로 만족할 수 있는가? 전혀 그렇지 않다. 겨우 wget 명령어에 대해서만 개별적인 CA 인증서를 적용하게 만들었기 때문이다.

명령행을 위한 인증서 설치 방법

시스템 전체에 적용할 수 있는 인증서 설치 방법을 알아보자. 참고한 웹사이트는 다음과 같다. update-ca-certificates 유틸리티를 사용하여 SSLPrism.crt를 설치하는 것이 핵심이다.


작동이 잘 됨을 확인하기 위해 조금 전에 설정한 .wgetrc 파일을 지웠다.

$ rm .wgetrc index.html
$ sudo mkdir /usr/local/share/ca-certificates/kribb
$ sudo cp SSLPrism.crt /usr/local/share/ca-certificates/kribb
$ sudo update-ca-certificates 
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
$  wget https://cran.rstudio.com
--2021-04-30 09:58:14--  https://cran.rstudio.com/
cran.rstudio.com (cran.rstudio.com)() 해석하는 중... 52.84.166.79, 52.84.166.5, 52.84.166.102, ...
접속 cran.rstudio.com (cran.rstudio.com)|52.84.166.79|:443... 접속됨.
HTTP 요청을 전송했습니다. 응답을 기다리는 중입니다... 200 OK
길이: 850 [text/html]
다음 위치에 저장: `index.html'

index.html                            100%[=============================>]     850  --.-KB/s    / 0s       

2021-04-30 09:58:14 (24.7 MB/s) - `index.html' 저장됨 [850/850]

잘 작동한다!  그러나 아직 안심을 하기는 이르다. Conda, git, pip, R(패키지 업데이트) 등의 명령이 잘 돌아가는지 전부 확인을 해 보지는 못했기 때문이다. TORMES v1.2.1를 지우고 새로 설치해 보니 CA 인증서를 업데이트한 것만으로 모든 명령어(443번 포트에서 파일을 다운로드하는)에 전부 대응하는 것은 아니었다. 이에 대해서는 다시 한번 확인을 한 다음 새 글에서 정리하겠다.

TORMES 1.2.1의 재설치 테스트

SSLPrism.crt를 system-wide하게 설치했다고 해서 https:// 위치의 파일을 가져오는 모든 응용프로그램이 다 정상적으로실행될까? TORMES를 재설치하는 과정에서 알아보았다. 역시나 그렇지는 않았다. 최소한 wget은 오류 없이 실행이 된다. 그러나 파일을 다운로드하는 기능이 포함된 파이썬 스크립트 quast-download-silva와 quast-download-busco는 작동을 하지 않아서 wget으로 직접 다운로드한 뒤 target 위치에 복사를 해야 된다. tormes-setup에서 treeio와 ggtree 및 기타 패키지를 받아오려면 명령행에서 CURL_CA_BUNDLE 환경변수를 선언하거나 ~/.Renviron에서 설정을 해야 된다. 이 변수가 가리킬 CA bundle  파일을 만드는 과정은 여기에 설명하였다.

마지막으로,  git가 SSL 인증 과정을 건너뛰도록 'git config --global http.sslVerify false' 명령을 주거나(~/.gitconfig 파일에 기록) 'export GIT_SSL_NO_VERIFY=0'을 실행해야 한다(참조글 링크). TORMES의 설치 과정에서 나오는 오류 - 아직 이해하기 어려운 - 는 다음과 같다. 실제 데이터를 이용한 tormes 실행에서는 특별한 문제가 발생하지 않았다.

# tormes-1.2.1 환경 셋업 과정에서
...
ClobberError: This transaction has incompatible packages due to a shared path.
  packages: bioconda/noarch::abricate-1.0.1-ha8f3691_1, bioconda/noarch::mlst-2.19.0-hdfd78af_1
  path: 'LICENSE'
...

# tormes-setup 스크립트의 마지막 부분인 RDPToos 설치 과정
...
BUILD SUCCESSFUL
Total time: 4 seconds
(cp Framebot/dist/FrameBot.jar Clustering/dist/Clustering.jar SequenceMatch/dist/SequenceMatch.jar classifier/dist/classifier.jar AbundanceStats/dist/AbundanceStats.jar ReadSeq/dist/ReadSeq.jar SeqFilters/dist/SeqFilters.jar ProbeMatch/dist/ProbeMatch.jar KmerFilter/dist/KmerFilter.jar Xander-HMMgs/dist/hmmgs.jar AlignmentTools/dist/AlignmentTools.jar ./; cp -r */dist/lib/* lib/; rm -r classifier/dist/)
cp: 방금 만든 'lib/ReadSeq.jar''AlignmentTools/dist/lib/ReadSeq.jar'로 덮어쓰지 않음
cp: 방금 만든 'lib/commons-cli-1.2.jar''AlignmentTools/dist/lib/commons-cli-1.2.jar'로 덮어쓰지 않음
cp: 방금 만든 'lib/ReadSeq.jar''Clustering/dist/lib/ReadSeq.jar'로 덮어쓰지 않음
...

도대체 update-ca-certificates로 수동 설치한 인증서를 쓰는 응용프로그램은 wget 말고 뭐가 더 있는지 모르겠다!


댓글 없음: