OpenSSL을 Ubuntu에서 설치하고 업데이트하는 방법

OpenSSL 을 Ubuntu 16.04에서 설치하고 업데이트하는 방법

OpenSSL은 SSL과 TLS 프로토콜의 오픈 소스 구현입니다. OpenSSL을 Ubuntu 장치에서 설치하고 업데이트하는 것은 무척 간단하며, 이 글은 그에 대한 내용을 다룰 것입니다.

OpenSSL을 설치하고 업데이트하기

OpenSSL의 설치를 시작하기 전에, 현재 버전의 OpenSSL을 다음 명령어로 가져옵니다.

$ openssl version
OpenSSL 1.1.0h  27 Mar 2018

그 후, OpenSSL의 최신 버전을 다음 명령어로 다운로드 받습니다. 좌측 링크를 눌러 다운로드 항목 중에 적절한 버전을 선택합니다. openssl-1.x 형식으로 된 것 중에 최신을 권장하지만, pre가 붙은 버전은 정식 출시 버전이 아니므로 문제가 생길 우려가 있습니다.

버전이 낮은데도 지속적으로 갱신되는 버전이 있는데, 이는 LTS 버전으로, 앞으로 업데이트를 자주하지 않고 최신 기능이 필요하지 않으면서 안정적으로 쓰고 싶은 사람에게 적절합니다.

원하는 항목을 브라우저에서 링크만 복사하여 아래 wget 명령 우측에 채워줍니다. 여기서는 openssl 1.1.1 pre7 버전을 설치하는 모습입니다.

$ cd /usr/src
$ wget https://www.openssl.org/source/openssl-1.1.1-pre7.tar.gz
--2018-06-19 08:49:17--  https://www.openssl.org/source/openssl-1.1.1-pre7.tar.gz
Resolving www.openssl.org (www.openssl.org)... 202.43.57.191, 2600:140b:5000:1af::c1e, 2600:140b:5000:1ab::c1e, ...
Connecting to www.openssl.org (www.openssl.org)|202.43.57.191|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 8308876 (7.9M) [application/x-gzip]
Saving to: ‘openssl-1.1.1-pre7.tar.gz’

openssl-1.1.1-pre7.tar.gz   100%[=================================================>]   7.92M  4.00MB/s    in 2.0s

2018-06-19 08:49:26 (4.00 MB/s) - ‘openssl-1.1.1-pre7.tar.gz’ saved [8308876/8308876]

다운로드가 완료되면, 다운 받은 압축 파일을 다음과 같이 풀어줍니다.

$ tar -zxf openssl-1.1.1-pre7.tar.gz

수동으로 컴파일하기 위한 준비 작업이 필요합니다. 다음 명령으로 빌드 도구를 설치해주세요. 아래 명령에 파일을 찾을 수 없다는 오류가 발생하면, 우선 우분투 패키지 업데이트부터 실시합니다.1

$ sudo apt install build-essential

이어서 OpenSSL 컴파일 후 설치 및 업그레이드를 하기 위해서 다음 명령을 사용합니다. cd 명령어 뒤에 디렉토리명은 정확해도 되지만, 여기서는 편의를 위해 와일드카드로 간편하게 들어갔습니다. 둘 이상 존재한다면, 정확한 디렉토리명을 지정해주세요.

$ cd openssl*
$ ./config

참고로 위 ./config 대신 ./Configure --help를 참고하여 원하는 옵션을 더 넣을 수 있습니다. 특정 Cipher는 기본적으로 빠져있어서 이런 작업을 미리 해둬야 설치 후 사용 가능한 경우도 있습니다. 보통의 경우 위 명령으로 충분합니다.

이 작업이 끝나면, make 명령으로 OpenSSL의 설치를 준비합시다.

$ make

컴파일이 다 끝나면, make test 명령을 쳐줍니다.

$ make test

다양한 평가 항목이 완료되면, 루트 권한을 갖고 install을 시작합니다.

$ sudo make install

에러에 대한 언급이 없다면, 성공적으로 설치된 것입니다.

아래는 오류 발생시 따라합니다.

여기서부터 링크를 잘 걸어야 잘 실행할 수 있습니다. openssl 명령 실행시 error while loading shared libraries: libcrypto.so.1.1 등의 오류가 발생할 수 있습니다. libssl.so 또한 마찬가지입니다. 이 때 libcrypto.so와 libssl.so를 /usr/lib/usr/local/lib에 위치한 파일을 향하게 심볼릭 링크를 만들어야 합니다. 각 경로에 들어가서 파일이 (그것도 링크가 아닌 실행 가능한 파일로서) 실존하는지 확인합니다. 기존에 존재하던 예전 버전의 쓰레기가 있다면 제거합니다.

$ sudo rm /usr/lib/libcrypto.so*
$ sudo rm /usr/lib/libssl.so*
$ sudo ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/libcrypto.so
$ sudo ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/libssl.so
$ sudo ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/libcrypto.so.1.1
$ sudo ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/libssl.so.1.1

그리고 방금 설치한 openssl이 bin 폴더에 바로 저장될 수도 있지만, 다른 곳에 만들어졌을 수 있습니다. 위 make install에서 bin 파일이 어디 만들어졌는지 확인하고, 원래의 openssl을 치워버리고 링크해야 합니다.

$ sudo mv /usr/bin/openssl /root/
$ sudo ln -s /usr/local/bin/openssl /usr/bin/openssl

간단한 설치와 업데이트 방법이죠? OpenSSL은 기본적인 암호화 기능과 다양한 유틸리티 기능을 제공합니다. https 서비스 연결, ssh 터미널에도 쓰입니다. 또한, 명령줄을 통해 온라인 인증서에서 정보를 검증하고 추출하는데도 쓰일 수 있습니다.

사견으로, 빌드 난이도는 nginx보다도 낮은, 무척 쉬움에 속하며 아무래도 종속성이 낮은 원시 코드에 가까워서 그런 것 같습니다. 그러나 시스템 설치 단계에서 기존 버전과 충돌을 처리하는 방법에서 고민해야하는 부분이 많으므로, 시스템 백업을 사전에 한 후 도전하길 강력하게 권합니다.

IIS에서 cipher 보안 개선하여 SSLLabs 고득점 노리기

IIS 의 SSL은 안전하지 않다?

Windows 10 1607, 그것도 Server 2016 1607이라는 나름대로 최신1 버전을 사용중이면서 IIS 를 지난 게시물에서 세팅한 바 있습니다. 그러나 그런 과정을 거쳐서 Let’s encrypt를 설정했는데도 불구하고 뭐가 부족했는지 SSLLabs에서는 가차없는 점수를 주었네요. 무엇이 문제일까요?

RC4를 써서는 안 되는 이유

RC4 암호화는 1987년 설계된 스트림 암호입니다. 스트림 암호인 만큼 빠르게 적용할 수 있고, 그간 널리 쓰여온 바가 있지만 이제는 사용을 권하지 않는다고 합니다. 다양한 취약점이 발견되었으며, 암호의 복잡도가 충분히 높지 않아서 무력화되기 쉬우며, 이 취약점이 바로 무선랜 암호화인 WEP를 신용할 수 없게 하는 주요 원인이기도 합니다. 그래서 새로운 SSL 프로토콜에서는 도입되지도 않았으며, 그런 낡은 것을 IIS 는 여전히 지원한다는 점에서 HTTPS 보안에 대한 점수를 크게 감점하게 된 것입니다.

Cipher 선택에 따라 좌우되는 보안

SSL에 대한 그간의 글에서 언급하였던 보안 사이퍼(cipher)는 암호화 방법을 의미합니다. 서버가 암호화할 줄 알아야 하겠지만, 클라이언트도 복호화할 줄 알아야만 올바르게 정보를 전달할 수 있을 것입니다. Cipher는 암호화 알고리즘으로 정의되며, 그 종류는 무척 다양합니다. 개중에는 최신식 고급 보안을 가진 것도 있는가 하면, 옛날부터 쓰던 것이라 취약점이 알려질대로 알려진 낡은 것도 있습니다.

물론 가장 최신의 알고리즘을 쓰면 더욱 안전한 건 당연하겠지만, 모든 브라우저를 만족시킬 수 없기 때문에, 옛날 OS에서는 에러 메시지만을 보게 될 것입니다. 그런 점을 고려하여 호환성과 안전 두 가지의 균형점을 갖춰보고자 합니다. 즉, 이 글은 조금 더 실용적으로 포장된 기존의 글 재탕으로 보셔도 될지 모릅니다.

IIS 에서 Cipher 선택하기

[시작]→[실행]을 들어가서 ‘gpedit.msc’를 실행하면 그룹 정책이 뜹니다. 그룹 정책에서 다음 경로로 들어갑니다.

컴퓨터 관리\관리 템플릿\네트워크\SSL 구성 설정

SSL Cipher Suite Order 항목을 눌러서 ‘사용’을 누르면 아래 입력칸이 한 줄로 있습니다. 한 번 기본값 전체를 살펴보겠습니다.

TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_RC4_128_SHA,
TLS_RSA_WITH_RC4_128_MD5,
TLS_RSA_WITH_NULL_SHA256,
TLS_RSA_WITH_NULL_SHA,
TLS_PSK_WITH_AES_256_GCM_SHA384,
TLS_PSK_WITH_AES_128_GCM_SHA256,
TLS_PSK_WITH_AES_256_CBC_SHA384,
TLS_PSK_WITH_AES_128_CBC_SHA256,
TLS_PSK_WITH_NULL_SHA384,
TLS_PSK_WITH_NULL_SHA256

RSA + PSK WITH NULL 있는 거 실화냐 / ECDSA랑 AES 붙을 때 자신감 있는 NULL

후순위이긴 하나 RC4는 물론 별다른 암호화가 없는 것으로 보이는 것도 보입니다. 이것이 보안의 허점을 노출하는 것으로 봐도 무방하겠습니다.

Windows에서 제안하는 변경점

Windows에서도 관련된 정보를 공개하고 있습니다. 여기 서술대로라면, 일단 크게 봐서 두 가지에 주의해야 합니다.

  • 일부 cipher는 HTTP/2 버전 연결을 미지원하므로 통신에 실패합니다. HTTP/1.1보다 HTTP/2가 지원하는 브라우저에선 서버 연결 속도에서도 압도적으로 낫기에 충분히 고려해봐야 합니다.2
  • SCH_USE_STRONG_CRYPTO시 Yes 되어 있는 것은 안전한 것으로 보고 있습니다. 그러나 여기서 Yes여도 SSLLabs의 깐깐한 판단으로는 WEAK에 속할 수 있습니다.

여기서 SCH_USE_STRONG_CRYPTO가 Yes인 것만 골라서 넣어보겠습니다.

TLS_PSK_WITH_AES_256_GCM_SHA384,
TLS_PSK_WITH_AES_128_GCM_SHA256,
TLS_PSK_WITH_AES_256_CBC_SHA384,
TLS_PSK_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256

그리고 다시 SSLLabs 테스트를 받으니 여전히 WEAK 판정은 존재합니다. RC4를 없애니 랭크도 A로 올랐군요.

문제가 된 cipher를 추려내보겠습니다.

TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA

해당 cipher를 제거하고 넣으면 되겠군요. 추가적으로 최신 브라우저의 우선순위에 맞게 순서를 재배열하였습니다.

TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_PSK_WITH_AES_256_GCM_SHA384
TLS_PSK_WITH_AES_128_GCM_SHA256
TLS_PSK_WITH_AES_256_CBC_SHA384
TLS_PSK_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256

HSTS 설정을 올바르게 하면 점수가 오를 것이다

이제 Cipher를 무결하게 만들고, 마지막 단계로 HSTS 설정을 하여 A+를 노려보겠습니다.

SSL이 강제될 사이트에서 HTTP Response Headers를 들어갑니다.

[Add…]를 눌러서 새로운 항목을 추가합니다.

다음과 같이 Strict-Transport-Security를 지정합니다. 이 값을 지정하고 헤더로 전송되면, 사용자 클라이언트 브라우저에선 향후 이 사이트에 대한 요청을 반드시 HTTPS로만 하게 되며 더욱 안전한 통신이 가능해집니다.

단, 추후 인증서를 해지하거나 만료되면 사이트에 아예 접속할 수 없을 수 있으니 이 설정에 유의하고 인증서가 없어지거나 만료되지 않도록 갱신 및 관리에 항상 신경써야 합니다.

Name: Strict-Transport-Security
Value: max-age=31536000

SSLLabs는 최소한 120일(10368000초) 이상 주어야 한다고 하며, 이상적인 값은 1년(31536000초)라고 합니다.

또한 평문 전송시 이러한 값을 전송해서는 안 되므로, redirect 전용 사이트 하나를 만들고 SSL 전용 사이트로 지정한 메인 사이트에서만 이러한 설정을 하는 것이 좋겠습니다.

저런, A+가 아직 나오지 않았어요

IIS의 한계랄까 안타까운 부분입니다. 이 부분에 대한 대응을 또 하나씩 해봅시다.

  • SHA1과 RC4 등 RC가 Cipher에 없음을 확인했습니다.
  • OCSP Stapling은 기본적으로 IIS가 챙기는 부분으로 별도의 설정은 불필요합니다. 다만, Must Staple 옵션을 적용할 방법이 보이지 않는군요.
  • Forward Secrecy는 ECDHE와 DHE를 지원한다면 저절로 robust support 될 것입니다.
  • TLS_FALLBACK_SCSV: 브라우저가 폴백(차선책) 시도를 할 수 있게 하여 구식 보안으로 다운그레이드하여 보안성을 약화시키는 것을 방지하는 기능입니다. 적절히 처리하지 못하면 POODLE 공격으로 이어질 수 있는데요. 안타깝게도 이 기능은 IIS에서 지원되지 않습니다.
    • 대신 TLS1.2 버전을 단독 지원함으로써 낮은 버전의 보안 연결을 원천적으로 봉쇄할 수 있습니다.
    • TLS1.2만 허용하게 되면서 버려지는 지원 기기의 예시는 다음과 같습니다.
      • Android 4.3 이전의 기기들
      • Baidu 2015년 1월 이전 버전
      • XP의 IE63~IE8
      • Vista의 IE7~IE8
      • Windows 7의 IE8~IE10 (Windows 7 현재 최신은 IE11)
      • Windows Phone 8.0의 IE8
      • Java 6, Java 7
      • OS X 10의 Safari 6.x

이 조치의 결과 A+를 획득하는데 성공했습니다. 그러나 버려지는 기기가 너무 많은 게 흠인 것 같습니다.

IIS 7에서 LetsEncrypt 설정하기

LetsEncrypt 는 무료 인증서 발급으로 https 확산에 혁혁한 공을 세운 단체입니다.1

특히 Certbot이라는 훌륭한 도구 덕분에 Linux 계열에서 Apache를 쓰든 Nginx를 쓰든 상관 없이 명령 몇 줄로 인증받는 시대가 열렸습니다.

그러나 윈도우에서는 공식적으로 LetsEncrypt 설치를 하는 방법이 제공되지 않습니다. 하지만 소스가 충분히 공개되어 있기에 누구든지 LetsEncrypt 인증 서버에 인증을 요청하고 인증서를 발급할 수 있습니다.

그러면 그냥 명령 쳐서 발급받으면 되잖아.

라고 하기엔 LetsEncrypt 인증서의 기간이 90일 이내로 짧기 때문에 자동 실행으로 갱신받아야만 하고, 그런 일을 대신해줄 프로그램은 필수입니다.

그런 역할을 해줄 프로그램을 소개해볼까 합니다.

Certify The Web

https://certifytheweb.com/

현재는 3.0.11 Stable 버전과 4.0의 Alpha 버전으로 나뉘어 있습니다. Alpha4가 문제가 있어서 Alpha3로 재공개했다는군요.

설치는 꽤 빠르게 이루어집니다.

메인 화면은 이렇게 생겼습니다.

바로 New Certificate를 눌러서 새로운 인증서를 발급해봅시다.
참고로 정식 버전이 아닌 경우에 상용으로 쓰지 말라고 경고가 여러 차례 뜹니다.

 

LetsEncrypt측에 전달할 나의 이메일을 적습니다.

만료 시기 도래 등 인증서에 특이사항이 있을 경우 향후 알려줄 수 있습니다.
이 기능은 리눅스 콘솔 버전 certbot과 완전히 동일하군요.

 

현재 IIS에서 작동중인 사이트를 선택합니다. 여러 곳에 쓰고 싶다면 여러 사이트를 모두 선택해도 되고, 사이트 선택 없이 발급만 할 수도 있습니다.
Request Certificate 버튼을 누르면 인증서 발급이 완료됩니다. Settings에 들어가서 갱신 일정도 올바른지 확인하세요.

이렇게 하면 IIS의 SSL 인증서에 LetsEncrypt가 올라가는 것을 확인할 수 있고, 향후에도 간단하게 변경할 수 있습니다.

단순히 HTTPS 통신에만 쓰는 것이 아니라, 원격 배포 기능과 FTP SSL 등 인증서가 필요한 분야가 많이 있으므로 폭넓게 활용할 수 있겠습니다.

한계

무료 버전은 5개의 사이트만을 관리할 수 있습니다. 프로 라이센스로 3개 사이트 더 추가하려면 약 50달러, 엔터프라이즈 라이센스로 100개 사이트 더 추가하려면 349달러네요. 여러 개 구매도 가능하다니 프로에 프로를 끼얹어도 되겠습니다.

문제 해결

  • 테스트 버튼을 눌러봤는데 실패할 수 있습니다. 외부 접속 체크시 DNS 확인이 올바르지 않을 수 있습니다. 인터넷 상황이 문제 없고 포트 바인딩이 되어 있으며 경로에 방화벽이 가로막지 않고 있다면, 과감히 Request Certificate를 눌러보세요.
  • 그 외에 Cloudflare 같은 DNS 서비스를 이용하고 있다면,  API Key를 발급받아서 넣고 이 앱에서 DNS-01 방식으로 체크를 요구할 수 있습니다. 이렇게 하면 서버의 파일 저장 공간에 임시 acme 테스트 없이 더 빠르고 문제 없이 도메인 소유 및 매치 여부를 확인할 수 있습니다. 와일드 카드 인증서(4 버전 이상) 발급시 DNS 인증이 필요할 것입니다.
python

certbot 등 python에서 모듈 에러가 뜬다면 꼭 살펴볼 점

Letsencypt (certbot) 설정을 업데이트하면서, 이전에 한 Ubuntu의 대형 시스템 업데이트가 이것저것 망가뜨렸음을 알 수 있었다.

사실 리눅스의 상당 부분은 python 코드가 지탱하고 있다고 해도 과언이 아닌데(심지어 yum이나 apt-get도 포함한다), certbot 또한 예외가 아니다.

그냥 실행만 했을 뿐인데, 잘 되던 실행 파일이 이런 무참한 에러를 발생시키고 있었다.


:~$ sudo certbot
Traceback (most recent call last):
  File "/usr/bin/certbot", line 11, in 
    load_entry_point('certbot==0.21.1', 'console_scripts', 'certbot')()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 561, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2631, in load_entry_point
    return ep.load()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2291, in load
    return self.resolve()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2297, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 10, in 
    import josepy as jose
  File "/usr/lib/python3/dist-packages/josepy/__init__.py", line 41, in 
    from josepy.interfaces import JSONDeSerializable
  File "/usr/lib/python3/dist-packages/josepy/interfaces.py", line 8, in 
    from josepy import errors, util
  File "/usr/lib/python3/dist-packages/josepy/util.py", line 4, in 
    import OpenSSL
  File "/usr/lib/python3/dist-packages/OpenSSL/__init__.py", line 8, in 
    from OpenSSL import crypto, SSL
  File "/usr/lib/python3/dist-packages/OpenSSL/crypto.py", line 16, in 
    from OpenSSL._util import (
  File "/usr/lib/python3/dist-packages/OpenSSL/_util.py", line 6, in 
    from cryptography.hazmat.bindings.openssl.binding import Binding
  File "/usr/lib/python3/dist-packages/cryptography/hazmat/bindings/openssl/binding.py", line 156, in 
    Binding.init_static_locks()
  File "/usr/lib/python3/dist-packages/cryptography/hazmat/bindings/openssl/binding.py", line 137, in init_static_locks
    cls._ensure_ffi_initialized()
  File "/usr/lib/python3/dist-packages/cryptography/hazmat/bindings/openssl/binding.py", line 124, in _ensure_ffi_initialized
    cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)
  File "/usr/lib/python3/dist-packages/cryptography/hazmat/bindings/openssl/binding.py", line 84, in build_conditional_library
    if not getattr(lib, condition):
AttributeError: cffi library '_openssl' has no function, constant or global variable named 'Cryptography_HAS_MEM_FUNCTIONS'

cffi library ‘_openssl’ has no function, constant or global variable named ‘Cryptography_HAS_MEM_FUNCTIONS’

보통 함수가 오류가 나고, 라이브러리를 제대로 된 것을 내놓으라는 위와 같은 오류가 발생하면,
파이썬 모듈을 다시 설치하면 해결되기 마련이다.

$ pip install cryptography

그러나 이 경우, 아무리 pip에서, 구글링했던 대로 cryptography를 다시 설치하더라도 문제가 해결될 기미가 보이지 않았다.

-U 옵션을 붙여서 강제 업그레이드를 하든말든 변화는 없었다.

그러다가 python 2.7이라는 표기와 python3라는 표기에 주목하게 되었다. 이미 2.7과 3에 3.5로 맨날 갈아엎으면서 기존 호환성이 무너지다보니 요즘 리눅스에선 다 설치하는게 추세가 됐다는 예의 그 문제다.

pip 실행 파일은 python 2.7에 대해서만 수정하고 있었으나, certbot은 python3를 필요로 하고 있으며 정상적으로 python3에서 실행될 수 있도록 다음과 같은 스크립트를 갖고 있다.

#!/usr/bin/python3
# EASY-INSTALL-ENTRY-SCRIPT: 'certbot==0.21.1','console_scripts','certbot'
__requires__ = 'certbot==0.21.1'
import re
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(
        load_entry_point('certbot==0.21.1', 'console_scripts', 'certbot')()
    )

이제 해답은 명확해졌다. pip가 2.7에 모듈을 무의미하게 지웠다깔았다 하는 사이, python3는 문제가 전혀 해결되지 않았던 것이다.

$ sudo apt-get install python3-setuptools
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
  python-setuptools-doc
The following NEW packages will be installed:
  python3-setuptools
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 215 kB of archives.
After this operation, 944 kB of additional disk space will be used.
Get:1 http://ppa.launchpad.net/certbot/certbot/ubuntu xenial/main amd64 python3-setuptools all 33.1.1-1+certbot~xenial+1 [215 kB]
Fetched 215 kB in 1s (109 kB/s)
Selecting previously unselected package python3-setuptools.
(Reading database ... 109834 files and directories currently installed.)
Preparing to unpack .../python3-setuptools_33.1.1-1+certbot~xenial+1_all.deb ...
Unpacking python3-setuptools (33.1.1-1+certbot~xenial+1) ...
Setting up python3-setuptools (33.1.1-1+certbot~xenial+1) ...

easy_install python3 버전을 깔기 위해 ubuntu에선 이 명령을 입력하면 된다. 설치된 easy_install3를 활용하여 pip도 같이 설치한다.

$ sudo easy_install3 pip
Searching for pip
Reading https://pypi.python.org/simple/pip/
Downloading https://pypi.python.org/packages/11/b6/abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/pip-9.0.1.tar.gz#md5=35f01da33009719497f01a4ba69d63c9
Best match: pip 9.0.1
Processing pip-9.0.1.tar.gz
Writing /tmp/easy_install-wmqoi3hf/pip-9.0.1/setup.cfg
Running pip-9.0.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-wmqoi3hf/pip-9.0.1/egg-dist-tmp-b7xxe23x
warning: no previously-included files found matching '.coveragerc'
warning: no previously-included files found matching '.mailmap'
warning: no previously-included files found matching '.travis.yml'
warning: no previously-included files found matching '.landscape.yml'
warning: no previously-included files found matching 'pip/_vendor/Makefile'
warning: no previously-included files found matching 'tox.ini'
warning: no previously-included files found matching 'dev-requirements.txt'
warning: no previously-included files found matching 'appveyor.yml'
no previously-included directories found matching '.github'
no previously-included directories found matching '.travis'
no previously-included directories found matching 'docs/_build'
no previously-included directories found matching 'contrib'
no previously-included directories found matching 'tasks'
no previously-included directories found matching 'tests'
creating /usr/local/lib/python3.5/dist-packages/pip-9.0.1-py3.5.egg
Extracting pip-9.0.1-py3.5.egg to /usr/local/lib/python3.5/dist-packages
Adding pip 9.0.1 to easy-install.pth file
Installing pip script to /usr/local/bin
Installing pip3 script to /usr/local/bin
Installing pip3.5 script to /usr/local/bin

Installed /usr/local/lib/python3.5/dist-packages/pip-9.0.1-py3.5.egg
Processing dependencies for pip
Finished processing dependencies for pip

설치가 잘 된 듯 하니, 셸에서 실행 가능한지 확인해보자.

$ which pip3
/usr/local/bin/pip3

이처럼 절대 경로를 잘 표시해주고 있다. pip3 명령을 통해 cryptography 모듈을 깔아보자. 버전으로 난리치지 않게 U 옵션을 잊지 말고 넣어서, 강제로 업그레이드를 하도록 하자.

$ sudo pip3 install -U cryptography
The directory '/home/yeon/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/home/yeon/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Collecting cryptography
  Downloading cryptography-2.1.4-cp35-cp35m-manylinux1_x86_64.whl (2.2MB)
    100% |████████████████████████████████| 2.2MB 451kB/s
Collecting idna>=2.1 (from cryptography)
  Downloading idna-2.6-py2.py3-none-any.whl (56kB)
    100% |████████████████████████████████| 61kB 3.7MB/s
Collecting asn1crypto>=0.21.0 (from cryptography)
  Downloading asn1crypto-0.24.0-py2.py3-none-any.whl (101kB)
    100% |████████████████████████████████| 102kB 3.1MB/s
Collecting cffi>=1.7; platform_python_implementation != "PyPy" (from cryptography)
  Downloading cffi-1.11.4-cp35-cp35m-manylinux1_x86_64.whl (419kB)
    100% |████████████████████████████████| 419kB 833kB/s
Requirement already up-to-date: six>=1.4.1 in /usr/lib/python3/dist-packages (from cryptography)
Collecting pycparser (from cffi>=1.7; platform_python_implementation != "PyPy"->cryptography)
  Downloading pycparser-2.18.tar.gz (245kB)
    100% |████████████████████████████████| 256kB 1.8MB/s
Installing collected packages: idna, asn1crypto, pycparser, cffi, cryptography
  Found existing installation: idna 2.5
    Uninstalling idna-2.5:
      Successfully uninstalled idna-2.5
  Found existing installation: asn1crypto 0.22.0
    Uninstalling asn1crypto-0.22.0:
      Successfully uninstalled asn1crypto-0.22.0
  Running setup.py install for pycparser ... done
  Found existing installation: cryptography 1.9
    Uninstalling cryptography-1.9:
      Successfully uninstalled cryptography-1.9
Successfully installed asn1crypto-0.24.0 cffi-1.11.4 cryptography-2.1.4 idna-2.6 pycparser-2.18

무언가 잘 진행되는 것 같이, 진행률 표시도 된다.

$ sudo certbot
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx

Which names would you like to activate HTTPS for?
-------------------------------------------------------------------------------

이후, 거짓말처럼 모든 것이 잘 작동하고 있다.

yeon.me TLS

[번역글] SSL과 TLS 배포 모범 사례

SSL / TLS는 놀라울만큼 간단한 기술입니다. 배포하기 쉬우며, 안 될 때를 제외하면 그냥 쉽게 작동합니다. 가장 큰 문제는 암호화가 보통 올바르게 배포되기 쉽지 않다는 점입니다. TLS가 적절한 보안을 보장하려면, 시스템 관리자와 개발자는 반드시 올바른 서버 설정과 앱 배포에 노력을 기울여야만 합니다.

2009년, TLS가 어떻게 쓰이는지, TLS 도구와 문서를 어떻게 개선할지를 알기 위해서 우리는 SSL Labs에서 일하기 시작했습니다. 그 결과 몇 가지 목표에 달성했는데, TLS 사용에 대한 전세계적인 통계와 온라인 평가 도구를 만들었으나, 문서 부족은 여전히 눈에 띕니다. 이 문서는 그 문제의 해법을 위한 첫 걸음입니다.

우리 목표는 안전한 사이트와 웹 애플리케이션을 배포하는데, 관리자와 프로그래머가 가능한 최소의 시간을 들이도록 명확하고 간결한 설명서를 제공하는 것입니다. 명확함을 추구하고자, 우리는 완성도를 희생하고, 특정 추가 주제도 건너뜁니다. 실질적이고 따라하기 쉬운데 요점을 두었습니다. 더 자세한 정보를 원하시는 분께는, 6장에서 유용한 정보를 제공합니다.

yeon.me TLS

“[번역글] SSL과 TLS 배포 모범 사례” 더보기