2019년 4월 18일 목요일

CentOS 7로 업그레이드하기

연말까지는 되도록 업그레이드를 하지 않고 CentOS 6.10로 버티려고 했었으나 땜질 처방만으로 유지하는 것에는 한계가 있다고 생각하여 단호하게 업그레이드를 하기로 결심하고 즉시 실행에 옮겼다. 업무용(대부분 생명정보 분석용) 프로그램의 설치가 쉬운 Ubuntu 16.04로 갈아타는 문제도 한참을 고민하였지만 공용 서버로서 안정적이고 보수적인 운영을 원한다면 CentOS 7이 나을 것으로 최종 결정을 하였다.

언제나 그렇듯이 한 번의 시도에 흡족할 수준으로 설치가 되지는 않았다. 리눅스를 설치할 때마다 늘 혼동스러운 것은 하드디스크의 파티션 과정이다. 완전 자동으로 파티션을 하도록 만든 다음 설치를 마치고 났더니 /은 겨우 50 GB에 불과하고 나머지를 전부 /home으로 만든 것이 아닌가. 추가로 설치할 응용 프로그램이 상당히 많은데 이를 전부 심볼릭 링크로 만들 수는 없는 노릇이다. 다시 설치를 시도하였다. 요즘도 swap 파티션이 꼭 필요한 것인가하는 생각이 들기도 하고... 자동으로 생성한 파티션에서 swap 크기가 이 얼마였는지 확인을 해 보지 않고 재설치를 하고 말았다. df 명령으로는 swap 파티션이 보이지 않으므로 swapon -s 명령을 써야 한다(오늘 알게 된 사실).

'Swap 파티션의 크기는 대략 메모리의 두 배'라는 옛날의 기준을 수백 기가 바이트의 메모리가 장착된 요즘의 컴퓨터에도 적용해야 할까? 그렇지는 않으리라. 내 컴퓨터의 메모리는 256 GB이다.

Red Hat Enterprise Linux 권장 swap 크기는 어떻게 되나요?

16 GB면 충분한 것을, 무려 100 GB나 잡아 놓았다!!

CentOS 7로 업그레이드를 하니 예전에 즐겨 사용하던 palimpsest 디스크 유틸리티는 보이지 않고 거의 비슷한 외관의 gnome-disk-utility가 있다. 100 GB나 되는 공간이 swap으로 떡하니 자리를 차지하고 있는 것을 보니 안타깝다. 그놈 디스크 유틸리티(혹은 gparted)에서 구동 중인 하드디스크의 파티션을 조정하는 것이 가능한 것 같다(참고). 다만 바뀐 UUID를 수동으로 다시 맞추어 주어야 한다.

OS를 새로 설치하니 UID와 GID가 바뀌어서 NFS로 물린 시놀로지 NAS의 자료를 고치기가 어렵게 되었다. 계정명은 동일하지만 ID는 501에서 1001로 바뀌었으니 디렉토리와 파일이 주인을 잃은 상태가 되었다. 같은 시스템 안에 있던 RAID 공간에 있던 것들은 chown 명령으로 복구를 하였지만 NFS로 물린 것은 이렇게 고쳐지지 않는다. usermod 혹은 groupmod 명령어를 쓰는 것은 별로 권장할 일이 아닌 것 같다. 왜냐하면 홈 디렉토리 이외의 것에 대해서는 자동으로 고쳐지지 않기 때문이다. 또한 여기에 새로 만드는 파일 및 디렉토리의 권한은 777이 된 상태이다. NAS쪽에서 설정을 바꾸어야 하는 것일까? 보안과 squash 필드의 의미를 정확히 아는 것이 필요하다.

로컬 네트워크(NFS) 내에서 Synology NAS의 파일에 액세스하는 방법

아직도 해결할 일이 많이 남았다.

2019년 4월 11일 목요일

회사 프록시 서버 뒤에서 docker pull을 실행하지 못하는 문제에 도전해 보자

프록시(proxy) 서버란 네트워크 서비스의 중계 역할을 하는 장비를 일컫는다. 과거에는 IP 주소를 세탁하고 접속이 차단된 곳을 둘러서 연결하게 만드는 뭔가 음험한 물건으로만 생각했었다. 원래 이 장비는 네트워크 트래픽을 줄이기 위한 목적으로 쓰는 것이라 하였다. 즉, 한번 접속해서 가져왔던 정보를 프록시 서버의 캐시에 저장해 둔 뒤, 같은 내용을 클라이언트에서 요청하는 경우 캐시의 것을 재전송함으로써 다시 원격 서버에 연결을 할 필요가 없게 만드는 것이다.

도대체 프록시 서버가 나와 무슨 관계가 있을까? 집에서 편히 앉아서 고속 인터넷망으로 접속을 하는 경우라면 프록시 서버의 존재에 신경을 쓸 필요가 없다. 그러나 회사 내 전산망이라면 사정은 다르다. 업무와 무관한 웹사이트의 접속을 차단하고, 중요 내부 정보의 유출을 막기 위한 보안 차원에서 프록시 서버를 사용하는 경우가 많다고 한다.

과연 나는 프록시 서버를 통해서 외부에 접속하는 것일까? Am I behind a proxy? 사이트에 접속을 하면 프록시 서버가 있는지를 알 수 있다고는 하지만, 이러한 서비스가 항상 프록시 서버의 존재 여부를 정확하게 검출하는 것은 아니다. 

기업의 입장에서 프록시 서버를 도입하여 운용하는 것을 뭐라고 할 수는 없다. 다만 HTTPS 트래픽을 복호화하여 필요한 '차단' 혹은 '기록(이것을 실제로 하는지는 잘 모른다)' 조치를 취한 다음 다시 암호화하여 내부로 돌려보내는 암호화 트래픽 복호화·가시성 장비(예: 소만사 HTTPS프록시)가 그렇게 만족스럽게 작동하지는 않는다는 것이다. SSL 가시성이라고 좋게 표현하지만, TLS(Transport Layer Security, SSL과 거의 같은 의미) interception이라고 써 놓으면 왠지 마뜩찮아 보인다.
보이지 않는 것은 보호할 수 없다.
멋진 말이기는 한데, 한편으로는 찝찝하다. 예를 들어 내가 소유한 은밀한 사진들을 비밀스런 사설 금고에 보관하고 싶은데, 이를 맡아주는 사람은 그 사진을 투명한 비닐백에 넣어 오지 않으면 안된다고 하는 것과 무엇이 다른가. '공공의 이익에 부합되지 않은 것을 보관해 줄 수는 없으니 금고지기는 내용물을 꼭 보아야 되겠다'라는 논리와 비슷하다. 물론 이 짧은 글을 통해서 이에 대한 논쟁을 확대하고 싶지는 않다.

어찌되었든 내가 앉아있는 책상 위의 컴퓨터에서 외부 세계로 HTTPS 접속을 한 뒤 인증서 정보를 열어보면 Somansa가 Root CA인 것으로 바뀌어서 나온다. 물론 소만사는 최상위 인증기관이 아니다. 소만사의 '공인되지 아니한' 루트 인증서는 업무용 컴퓨터(윈도우)를 세팅하는 과정에서 웹 브라우저에 설치가 되었다. 전산 담당자가 해 준 것인가, 저절로 한 것인가? 그건 잘 모르겠다. 변경(변조?)된 루트 인증서 정보에 보이는 Somansa라는 회사명으로 짐작하건대 아마도 이 회사의 프록시 서버가 변경을 했을 것이다. 이러한 루트 인증서 변경이 일어진다는 것을 안 것은 며칠 되지 않았다. 구글을 검색해 보면 이는 이미 잘 알려진 일이다.

[StackOverflow] Can proxy change SSL certificate? - 네, 그렇습니다!

문제는 리눅스 서버를 사용할 때이다. conda, curl, docker 등 https://(433번 포트)를 사용하는 서비스마다 연결이 제대로 되지 않아서 무척 애를 먹었다. 앞의 두 개는 각 프로그램의 고유한 설정 파일에 Somansa 루트 인증서를 넣어서 해결을 하였으나 docker는 도무지 해결이 되지 않았다.

$ docker pull ubuntu:16.04
Pulling repository ubuntu
Get https://index.docker.io/v1/repositories/library/ubuntu/images: x509: certificate signed by unknown authority

[StackOverflow] Docker : Get https://registry-1.docker.io/v2/: x509: certificate signed by unknown authority를 비롯한 많은 글에서 이에 대한 질문과 답변을 볼 수 있었다.
We have also a proxy. For monitoring our https connection to avoid malwares, our proxy creates a certificate on the fly for the secured connection between a station and the proxy. Then another secured connection is done between the proxy and the website. The message indicates that the certificate produced by the proxy was signed by an unknown authority: the "fake authority" which generates the certificates.
CentOS 6의 경우 소만사의 루트 인증서 파일을 받아다가 /etc/pki/ca-trust/source/anchors/ 아래에 복사한 다음 update-ca-trust force-enable와 update-ca-trust extract 명령을 차례로 실행한 뒤 docker 서비스를 재시동하면 된다는데 도무지 성공의 기미가 없다.
(인증서 파일을 받으려면 웹브라우저에서 내보내기를 하거나 openssl 프로그램을 쓰는 방법이 있다.)
남은 방법은 어떻게 해서든 docker image를 받아서(프록시 서버 영향을 받지 않는 다른 장비에서 docker pull 사용) 파일로 만든 뒤 이를 작업하고자 하는 리눅스 서버로 전송하여 docker load -f tar_file을 하는 것뿐이다. 네트워크를 거치는 docker pull만 아니라면, 일단 받은 이미지 파일을 docker run으로 올리는 데에는 문제가 없다. 혹은 docker pull 명령어를 쓰지 않고 이미지를 다운로드하는 유틸리티인 docker-drag(python 2.7 필요)을 쓰는 방법도 가능하다고 한다. 이는 검색에 검색을 거듭하여 겨우 알아낸 것인데([StackOverflow] How do I download docker images without using the pull command?), 아직 절반의 성공일 뿐이다. 왜냐하면 ubuntu:14.04 및 ubuntu:16.04를 다운로드하여 docker run을 하는 것은 성공하였지만...

$ python docker_pull.py ubuntu:14.04
Creating image structure in: tmp_ubuntu_14.04
e082d4499130: Pull complete [67148830]
371450624c9e: Pull complete [72650]
c8a555b3a57c: Pull complete [363]
1456d810d42e: Pull complete [162]
Docker image pulled: library_ubuntu.tar
$ docker load -i library_ubuntu.tar 
$ docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu                          14.04               7dc2e660bb0c        4 weeks ago         188.1 MB
hello-world                     latest              c72cc8666399        3 months ago        1.84 kB
anvio_jeong180710_cog           latest              bf09cd455d01        9 months ago        3.936 GB
... 중간 생략...
phacnml/plasmidprofiler_0_1_6   latest              ae30d10d24fc        2 years ago         6.564 GB
$ docker run --rm -it ubuntu:14.04 /bin/bash
root@d604c684d26c:/# df -h
Filesystem                                                                                         Size  Used Avail Use% Mounted on
/dev/mapper/docker-8:19-12583470-d604c684d26c2cfaf0f3e234dd867535d306734b37c4c35884bfa7673fe489ea  9.8G  219M  9.1G   3% /
tmpfs                                                                                              127G     0  127G   0% /dev
shm                                                                                                 64M     0   64M   0% /dev/shm
/dev/sdb3                                                                                          5.3T  1.9T  3.2T  37% /etc/hosts

qiime2/core:2018.11을 다운로드할 때에는 'IOError: Not a gzipped file'이라는 에러 메시지가 나면서 실패를 했기 때문이다.

같은 링크에서 소개한 download-frozen-image-v2.sh는 golang, jq 등 생소한 것들을 같이 설치해야 하는 문제로 테스트에 시간이 걸리고 있다. 이에 대해서는 나중에 기록할 예정이다. 이 두 가지 유틸리티 외에도 Downloading Docker Images from Docker Hub without using Docker를 살펴보면 좋은 아이디어가 많으니 참고해 보도록 한다.

download-frozen-image-v2.sh의 활용법(아직은 실패)

위에서 소개한 URL에서 스크립트를 다운로드한다. 추가적으로 jqgo가 필요하다. 두 프로그램 전부 리눅스용 바이너리로 배포되는 것을 받아서 사용하였다. 

curl은 anaconda2 base environment에서 재설치하였고, 문제의 Somansa 루트 인증서는 /opt/anaconda3/ssl/에 설치하였다. 인증서 재설치에 관해서는 curl에 신뢰하는 인증서 추가하기를 참조하였다. 그러나 qiime2은커녕 docker-drag로 받아서 잘 돌아가던 ubuntu 이미지조차 잘 실행되지 않는다.


$ ./download-frozen-image-v2.sh temp_download ubuntu:16.04
Downloading 'library/ubuntu:16.04@16.04' (4 layers)...
#######################################################

Download of images into 'temp_download' complete.
Use something like the following to load the result into a Docker daemon:
  tar -cC 'temp_download' . | docker load
$ tar -cC 'temp_download' . | docker load
Error response from daemon: could not find image: Prefix can't be empty

에혀~ 나도 모르겠다. 동료가 윈도우 Hiper-V 환경에서 받은 도커 이미지를 제공해 주어서 이것을 리눅스 서버로 갖고 들어와서 사용해 보았다. qiime2만 생각한다면 bioconda로 설치를 해 두었으니 실행을 하는 데에는 무리가 없다. 그러나 앞으로의 확장 가능성을 생각한다면 docker를 피해나갈 수는 없을 것이다.

2019년 4월 16일 업데이트

CentOS의 버전이 너무 오래된 것이 문제라는 생각이 든다. 현재의 docker 설치 안내문서(Get Docker CE for CentOS)를 읽어보면 다음과 같이 기재되어 있다.

OS requirements
To install Docker CE, you need a maintained version of CentOS 7. Archived versions aren’t supported or tested.

이제 진지하게 CentOS 6을 버리고 7로 업그레이드하는 것을 생각해 보도록 하자.

2019년 4월 9일 화요일

아직 끝나지 않은 HTTPS/SSL 문제

Conda 활용에서 걸림될이 되는 SSL 인증 관련 문제는 대충 해결이 되었다. 하지만 docker와 git는 아직 해결이 되지 않은 상태이다. git 명령의 경우 아쉬운대로 직접 압축파일(.ZIP)을 받아다가 수동 설치하는 것으로 땜질 처방을 하였다.

pip까지도 불만을 토해낸다. 무슨 파이썬 패키지가 설치되었는지를 알고 싶어서 pip list를 하면 다음과 같은 성가신 메시지가 나온다.

$ pip list
Package    Version  
---------- ---------
biopython  1.72     
certifi    2018.8.24
ls-bsr     dev      
numpy      1.15.2   
pip        18.0     
setuptools 40.4.3   
wheel      0.32.0   
Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /simple/pip/ (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:719)'),)) - skipping
(py35) [hyjeong@tube LS-BSR-master]$ pip list --trusted-host pypi.org --trusted-host files.pythonhosted.org

팁 - 파이썬 패키지 설치할 때 SSL 인증 오류 해제 방법에서 힌트를 얻었다. 홈 디렉토리의 .pip/pip.conf에 다음의 내용을 추가하거나,


[global]
trusted-host = pypi.org
               files.pythonhosted.org

혹은 pip install 혹은 pip list 명령을 수행할 때 --trusted-host pypi.org --trusted-host files.pythonhosted.org 옵션을 주면 된다.


오후에 쓴 업데이트

직원의 도움으로 git 문제는 해결을 하였다. conda base environment에서 curl과 git를 업데이트한 다음, 인증서를 수동 설치하였다. git의 인증서 관련 설정을 변경하는 방법은 git에서 https repository 연결시 SSL 인증서 오류 해결법을 참조하였다.

인증서 체인이니 번들이니 하는 것의 개념을 아직 완벽하게 이해한 것이 절대로 아니다! 앞으로도 갈 길이 멀다. 다음의 사이트가 매우 유용하므로 이를 참조하자.

Get your certificate chain right

2019년 4월 5일 금요일

사람 헷갈리게 만드는 conda 환경 설정

Conda의 공식 문서 사이트의 사용자 가이드와 Anaconda 웹사이트의 Conda 4.6 Release 문서가 미묘하게 달라서 혼동을 유발하고 있다. conda init 명령이 바로 그것이다. 공식 문서 사이트에는 이에 대한 언급이 거의 없다.

Anaconda를 설치할 때, 로그인 스크립트에 conda 환경을 만들어 주는 코드(설치 디렉토리 하위의 /etc/profile.d/conda.sh)를 삽입할 것인지를 묻는다. 그렇지 않은 경우에는 PATH 환경변수의 맨 앞에 anaconda의 bin 디렉토리를 추가하라고 지시한다.
[참고] conda.sh를 로그인 스크립트에서 시동하면 잘 되지만, 명령행에서 source (PATH)/conda.sh를 쳐서 실행하면 잘 되지 않는다. 그러한 경우 environment 이름 없이 그냥 conda activate라고만 치면 된다(How do I activate a conda environment in my .bashrc?).
그런데 몇 가지 environment와 프로그램을 업데이트하고 conda 자체도 업데이트하였더니, 어느 순간에서부터 conda init SHELL_NAME을 실행하라는 메시지가 나오는 것이다. 이는 Anaconda의 Conda 4.6 Release의 맨 앞에 잘 설명이 되어 있다. 이 명령을 실행하면 .bashrc의 뒷부분에 다음과 같은 짤막한 코드를 삽입하게 된다.

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/opt/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/opt/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/opt/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/opt/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

또 다른 문제는 .condarc 설정 파일에 관한 문제이다. Conda 공식 문서를 보면 conda config 명령을 처음 실행할 때 홈 디렉토리에 이 파일이 생성되며, root environment에 있는 .condarc는 홈 디렉토리의 것에 우선하여 작동한다고 하였다.

The conda configuration file, .condarc, is an optional runtime configuration file that allows advanced users to configure various aspects of conda, such as which channels it searches for packages, proxy settings and environment directories.
The .condarc file is not included by default, but it is automatically created in your home directory the first time you run the conda config command.
.condarc file may also be located in the root environment, in which case it overrides any in the home directory.
anaconda2에서는 여기에 소개한 그대로 잘 작동하는 것 같았다. 그런데 anaconda3를 설치하고 몇 가지 작업을 하였더니 또 어느 순간부터는(아마도 conda 자체를 업데이트한 다음이 아닐까?) root environment에 무엇이 있든 상관이 없이 홈 디렉토리의 .condarc가 적용되는 것이다. 여기에서 root environment란  conda를 설치한 최상위 디렉토리를 의미한다. 즉 설치 과정에서 PREFIX=/opt/anaconda2로 정의되는 위치이다. <= 밑줄을 친 부분은 나중에 확인해보기 바란다. conda 버전에 따라서도 약간 다른 것 같다.

혹시 착각이 아니었을까? 확인을 위하여 anaconda2로 들어간 다음, anaconda 설치 root environment의 .condarc 파일을 수정하였다. 그러고나서 conda config --show를 했더니 바뀐 내용이 출력된다. 그런데 최신 (ana)conda에서는 오로지 홈 디렉토리에 있는 .condarc가 최우선이다.

Root environment라는 용어도 약간의 혼동을 초래한다. 이것은 conda를 설치하는 디렉토리를 말하는가, 혹은 conda create -n MYENV라고 실행하여 만들어내는 environment 부류 중에서 가장 기본이 되는 환경을 의미하는가? 후자에서 '기본 환경'이라 함은 최초로 conda create -n을 실행하기 전, 처음으로 anaconda를 설치했을 때의 환경을 말한다. Conda의 어떤 버전 문서에서는 root environment라고 부르다가, 최근 문서에서는 base environment라고 불리는 것 같다.

별 일이 아니라 생각했었는데 의외로 고려할 사항이 많다.

2019년 4월 7일 업데이트

Conda 공식 문서의 Troubleshooting 섹션에 SSL connection errors[1]에 대처하는 방법이 나온다. 이는 지난 며칠 동안 나를 괴롭혔던 문제(SSL과 관련한 conda 설치 에러)에 대한 직접적인 해결책이기도 하다. 내가 접한 에러 메시지를 그대로 복사하여 구글에서 검색을 하였을 때 이 페이지가 나오지 않았기 때문에 해결책을 알아내느라 고생을 한 것이다. 다음은 [1]에서 인용한 것이다. System-wide configuration file인 .condarc는 위에서 인용한 것과 같이 root environment에 있는 것인가?

When using conda config, the user's conda configuration file at ~/.condarc is used by default. The flag --system will instead write to the system configuration file for all users at /.condarc. The flag --env will instead write to the active conda environment's configuration file at/.condarc. If --env is used and no environment is active, the user configuration file is used.

2019년 4월 4일 목요일

13,495원을 내고 SSL 인증서를 구입하다

Hostinger에서 호스팅하는 내 위키 사이트를 더욱 안전하게 이용하기 위해 SSL 인증서를 구입하여 설치하였다. 한번 13,495원을 지불하고 평생 유지된다고 하니 투자해서 아까울 것은 없다.

실제 위키 사이트는 genoglobe.kr의 서브도메인에 있다.

이 사이트는 꽤 많은 정보를 계속하여 기록함은 물론 로그인 정보를 보내야 하기 때문에 SSL 인증서를 설치하여 https://로 시작하는 주소로 접속하게 하는 것이 매우 바람직하다. 그러나 나의 공식 홈페이지에 해당하는 http://genoglobe.com/은 로그인 기능이 없고 포함하는 정보도 매우 적으므로 그대로 두기로 하였다. 이 사이트에는 나에게 이메일을 보내는 폼이 있지만 설마 누가 여기에다가 국가 기밀이나 영업 기밀을 적어서 보내겠는가?

아직 남은 과제는 http://로 내 위키 사이트를 접속해도 강제로 https://...로 보내는 것이다. 이것은 hostinger tutorial을 참조하여 .htaccess를 편집하면 된다.

How to Force HTTPS

이 튜토리얼의 내용을 요약하자면 내 웹사이트로 들어오는 모든 요청이 https://로 강제로 보내지게 하려면 최상위 .htaccess 파일에 다음의 세 줄을 넣어 저장한 뒤 웹브라우저의 캐쉬를 지우고 재접속을 하면 된다. 주의할 것은 'RewriteEngine On' 라인이 .htaccess 파일 안에 단 한번만 존재해야 한다는 점.

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

.htaccess 파일을 잘못 건드리면 웹사이트가 아예 접속이 되지 않으므로 매우 주의를 기울여야만 한다. Hostinger 파일 관리자에서 수정을 완료한 다음 웹브라우저에 내 도메인 정보를 넣으니 저절로 https://로 접속이 된다.

hostinger.kr의 억지스런 우리말 번역을 보면 웃음이 날 지경이다.

'수색'이나 '시작하다' 정도면 그래도 준수하다.

'확인해 봐' 네, 네... 알겠습니다.


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 분야에서도 똑같이 벌어진다.


2019년 4월 2일 화요일

회사 생활 이틀째

(이보다 앞서서 벤처기업에서 약 2년 반, 그리고 정부출연연구소에서 16년 3개월을 일했다)

일찍 퇴근하여 숙소로 돌아왔다. 창밖으로 내다보이는 높다란 건물에는 아직 일을 마치지 못한 직장인이 많은지 대부분의 사무실에 불이 켜진 상태이다.


비교적 긴장감이 적은 공공연구기관에서 직장 생활을 하다가 새로운 경험을 하고 싶어서 기업체로 온지 이틀이 지났다. 생존 혹은 생계를 위한 마지못한 선택도 아니요, 정해진 시간이 지나면 다시 돌아갈 곳이 있다는 점에서 어쩌면 매우 배부른(?) 결정이었는지도 모르겠다. 대전을 제2의 고향 삼아서 인생의 절반을 훌쩍 넘도록 살다가 다시 수도권으로 돌아와서 지하철로 출퇴근을 하노라니 정말 새로운 기분이다. 생각을 해 보니 나는 모든 학창생활 기간 동안 걷거나 자전거로 통학을 하였고 그 이후로는 승용차를 이용했기 때문에 전적으로 대중교통을 이용하여 출퇴근을 한 적이 거의 없었다. 아주 최근에는 버스를 자주 타기는 했었다.

바삐 오가는 사람들은 광역시에서 만나는 사람들보다 왠지 더 바쁘고 세련되어 보인다. 과연 이번 기업 근무 경험에서 어떤 것을 얻어가게 될 것인가? 기대감과 불안감이 공존하는 묘한 기분이 느껴진다. '하늘에서 비가 돈처럼 내려도 요리조리 피해다니는' 나의 성격 속에 과연 기업가 정신('entrepreneurship')이라는 것이 깃들어 있을까? 이것은 타고나는 것일까, 아니면 만들어지는 것일까? 어떤 사람은 할 일이 이것밖에 없어서 사업을 하게 되었다고 ㅇ농담 반 진담 반으로 말하기도 한다.

많은 어려움에도 불구하고 개인이 가장 많은 자율성을 누릴 수 있는 기회는 창업을 하여 기업을 운영할 때가 아닌가 한다. 이렇게 일구어 나간 기업이 큰 고목나무처럼 수백년, 아니 그 이상을 존속하기를 바라지만, 기업에도 분명 수명이 존재한다. 매년 포춘지가 발표하는 500대 기업을 보면 평균 수명은 40년 정도라고 한다. 상공회의소가 발표한 우리나라 기업의 평균 수명은 23.8년. 왜 이렇게 짧은가? 이는 경영자들이 변화하는 환경에 대처하여 지속적인 혁신을 하지 못하기 때문으로 여겨진다.

내가 이번 4월부터 일하는 곳은 바이오·제약 분야의 중견기업이다. 이 분야는 까다로운 규제를 통과해야 하고 성공할 가능성도 극히 낮다. 그러나 제대로 성공만 한다면 그동안의 모든 노력을 충분히 상쇄하고도 남는 수익을 보장한다. 그런데 문제는 좋은 제품을 만들어서 그 매출액으로 수익을 내는 것이 아니라, 자신이 보유한 지분을 훨씬 높은 가격에 처분하여 이익을 실현하는 것이 '정도'이다. 난 사회주의자는 아니지만, 창업교육 등에서 이러한 원칙을 듣고서도 100% 납득을 하지 못하였다.

주식의 처분을 통해 이익을 실현하려면, 상당한 지분을 갖는 주주가 아니면 소용이 없다. 성공적인 IPO(기업공개)의 혜택이 그 기업의 직원에게는 별로 돌아가지 않는 것이다. 그것이 주식회사가 현재 돌아가는 원리이다.

나는 기업이 더 많은 사람에게 번영과 자유를 주었으면 좋겠다고 생각한다. 여기서 자유란 빈곤으로부터의 자유, 더 나은 제품 또는 기술을 통해 얻는 기쁨과 즐거움을 의미한다. 그럼에도 불구하고 기업이 만들어내는 가치에 무임승차를 하는 사람은 되도록 적었으면 좋겠다.  앞으로의 경험을 통해 기업이라는 것에 대한 내 나름대로의 철학을 갖게 될 것으로 기대한다. 그 철학에 따라서 창업을 해서 성공을 해야 되겠다는 생각이 들 수도 있고, 그렇지 않을 수도 있을 것이다.

창조하고 개척하는 사람이 될 것인가, 비평가가 될 것인가?

그 어떤 결론을 내리든, 나에게는 소중한 경험이 될 것이다. 두 곳을 오가며 생활을 하느라 비용은 더 들지만 충분히 투자할만한 가치가 있는 수업료라고 생각한다. 그리고 기업 근무를 하는 동안 대부분의 블로그 집필은 퇴근 후 집에서 하게 될 것이다. 어차피 보안 등의 문제로 근무 중에는 개인적인 일을 하기가 곤란하기 때문이다.

오디오 기기를 하나도 들고 오지 못했다. 그래도 인터넷 라디오와 주워온 멀티미디어 스피커가 있어서 귀의 심심함을 달래고 있다.