728x90

M1 silicon 맥북에서는 안되는게 참 많습니다. 새로운 CPU 아키텍쳐라서 여기저기서 패키지들이 오동작하거나 설치가 안되는 문제들이 많이 발생합니다. 오늘의 주인공인 파이썬 cryptography 패키지도 마찬가지입니다. 그나마 이 녀석은 에러가 나름 명확한 친구임에도 문제를 해결하기 위해 적지 않은 시간을 쏟아야 했습니다.

우선 에러 메세지 보고 가시겠습니다. :-) 이 에러 메세지는 pip install -r requirements.txt 를 수행하는 동안 발생헀고 requirements.txt 에는 cryptography가 기술되어 있었습니다. (드라마 24시에서 Following takes place... 하는 느낌이네요)

Building wheels for collected packages: cryptography
  Building wheel for cryptography (PEP 517) ... error
  ERROR: Command errored out with exit status 1:
...
...
 ...
    clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -iwithsysroot/System/Library/Frameworks/System.framework/PrivateHeaders -iwithsysroot/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/Headers -arch arm64 -arch x86_64 -Werror=implicit-function-declaration -I/Users/nopd/project/venv/include -I/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/include/python3.8 -c build/temp.macosx-10.14.6-arm64-3.8/_openssl.c -o build/temp.macosx-10.14.6-arm64-3.8/build/temp.macosx-10.14.6-arm64-3.8/_openssl.o -Wconversion -Wno-error=sign-conversion
  build/temp.macosx-10.14.6-arm64-3.8/_openssl.c:575:10: fatal error: 'openssl/opensslv.h' file not found
  #include <openssl/opensslv.h>
           ^~~~~~~~~~~~~~~~~~~~
  1 error generated.
  
      =============================DEBUG ASSISTANCE=============================
      If you are seeing a compilation error please try the following steps to
      successfully install cryptography:
      1) Upgrade to the latest pip and try again. This will fix errors for most
         users. See: https://pip.pypa.io/en/stable/installing/#upgrading-pip
      2) Read https://cryptography.io/en/latest/installation.html for specific
         instructions for your platform.
      3) Check our frequently asked questions for more information:
         https://cryptography.io/en/latest/faq.html
      =============================DEBUG ASSISTANCE=============================
  
  error: command 'clang' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for cryptography
Failed to build cryptography
ERROR: Could not build wheels for cryptography which use PEP 517 and cannot be installed directly

 

화려한 에러 메세지이지만 결론은 설치가 잘 안되었다 입니다. DEBUG ASSISTANCE의 내용은 평이합니다. PIP가 구버전이라 그럴 수 있으니 업데이터 해보고 cryptography 설치 가이드 문서를 읽어 본 다음, faq에 단서가 있을지도 모르니 찾아보라는 내용입니다. TL;DR 하자면 아래의 한줄이 모든 것을 이야기 해주고 있었습니다.

build/temp.macosx-10.14.6-arm64-3.8/_openssl.c:575:10: fatal error: 'openssl/opensslv.h' file not found

 

Trouble Shoot #1 - Install separate openssl with brew

구글 검색을 통해 살펴봤던 문서를 종합해보면 M1 silicon 기종에 선탑재되어 나오는 openssl이 cryptography 빌드에 필요한 버전과 상이하다고 합니다. 실제로 M1 silicon 탑재 기종에서 openssl version 명령으로 버전을 확인해보면 LibreSSL 이 설치되어 있는 것을 알 수 있습니다. 아래와 같이 brew 를 이용해 openssl 을 별도로 설치해 보도록 하겠습니다. 공식 가이드에서 안내하는 1.1 버전을 지정해서 설치 진행했습니다. 

cryptography 설치 가이드의 안내  (https://cryptography.io/en/latest/installation/)

% openssl version
LibreSSL 2.8.3
% brew install openssl@1.1 rust
Updating Homebrew...

 

Trouble Shoot #2 - Uninstall cffi then install cryptography again

별도의 openssl 설치와 혹시 몰라서 rust(cryptography는 rust를 사용합니다)를 설치하는 작업이 끝나면 이제 파이썬 패키지중에서 C언어를 호출할 때 사용되는 cffi 도 삭제후에 다시 설치해 주도록 하겠습니다. 아래의 명령을 순서대로 터미널에서 입력하면 cryptography 가 설치됩니다. 제 경우 cryptography를 3.3.1 버전으로 지정해서 사용할 일이 있어서 버전을 지정했습니다만 그렇지 않은 경우에는 버전 정보를 빼고 설치하면 되겠습니다. 

% pip uninstall cffi
% LDFLAGS=-L$(brew --prefix libffi)/lib CFLAGS=-I$(brew --prefix libffi)/include pip install cffi --no-binary :all:
% LDFLAGS="-L$(brew --prefix openssl@1.1)/lib" CFLAGS="-I$(brew --prefix openssl@1.1)/include" pip install cryptography==3.3.1

 

문제가 해결되었습니다. 비슷한 이슈를 겪는 분들은 정리된 내용대로 패키지 삭제, 재설치를 진행해 보시기 바랍니다. 영어로 된 자료도 흥미롭게 읽을 수 있다면 보다 깊은 내용과 관련 링크가 공유된 stackoverflow 의 아래 스레드를 읽어 보시면 도움이 되겠습니다!

 

Installing Cryptography on an Apple Silicon M1 Mac

Help! I'm trying to install cryptography on my m1. I know I can run terminal in rosetta mode, but I'm wondering if there is a way not to do that. Output: ERROR: Command errored out with exit st...

stackoverflow.com

 

Hope this helpful to someone who experiencing similar issue.

728x90
728x90

웹 기반의 서비스를 제공한다면 SSL 인증서의 사용은 이제 필수 아니 기본이 되었습니다. Let's Encrypt 와 같은 선택지가 생기면서 비용때문에 SSL 기반의 HTTPS 통신을 제공하지 않는 다는 것은 더이상 변명이 되기도 힘든 시기입니다. 물론 서버의 성능 이야기를 한다면 <정말 아주 약간>의 배려를 해줄 수 있긴 합니다만 근래의 컴퓨팅 파워와 비용을 생각하면 그리 와닿지는 않는 변명입니다. 

이렇게 SSL 인증서 사용이 기본이 되고 있지만 SSL 인증서를 서버에 설치하고 적용하는 것은 여전히 까다롭습니다. 까다로운 것은 다름아닌 익숙하지 않음에서 비롯된다고 생각합니다. 개발은 늘 하는 일이지만 SSL 인증서는 아주 짧으면 3개월부터, 보통은 1년, 길면 2년정도 되어야 한 번 할까 말까한 작업이기 때문입니다. 눈치 채셨겠지만, 이 기간은 인증서를 교체해야 하는 주기와 일치합니다. 

이렇게 인증서가 잘 설치되었는지, 인증서에는 문제가 없는지 확인하는 것이 DevOps 시대에는 필수가 되었습니다. 그렇지만 언급했던 것처럼 <어쩌다 한 번 하는 작업> 이다보니 무언가 공부를 하기도 애매하고, 공부를 해두었다 하더라도 정작 필요한 시점에는 써먹지 못하는게 현실입니다. 여기에 더하여 운영중인 서버에 인증서를 적용하는 전후에 무엇을 어떻게 확인하는게 좋은지도 사실 적당한 레퍼런스가 없습니다. 


퍼블릭으로 공개된 서버의 인증서 점검

가이드 드리고 싶은 내용은 1) 운영중인 서버의 인증서 상황 점검과 2) 교체하려는 인증서 구성이 문제 없는지 어떻게 확인하는가 하는 점입니다. 1) 번과 같이 운영중인 서버의 인증서 상황 점검은 무척 쉽습니다. Mac 이나 Linux 환경을 사용하고 있다면 openssl 명령 혹은 어플리케이션을 이용하여 도메인 혹은 IP 를 가지고 있는 서버에 설치된 인증서를 쉽게 확인할 수 있습니다. 

// 인증서 정보 확인
% openssl s_client -connect www.naver.com:443

CONNECTED(00000003)
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert Global Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, CN = DigiCert SHA2 Secure Server CA
verify return:1
depth=0 C = KR, ST = Gyeonggi-do, L = Seongnam-si, O = NAVER Corp., CN = *.www.naver.com
verify return:1
---
Certificate chain
...

openssl 을 이용하여 `s_client` 옵션을 주고 `-connect` 에 확인하고자 하는 도메인 정보와 포트정보 (보통은 443이죠) 를 넣으면 구성되어있는 인증서 체인정보 (서버 인증서 > 중간 인증서 > 루트 인증서) 와 인증서의 상세한 정보를 확인할 수 있습니다. 웹 브라우저로 접근 가능한 HTTPS 를 사용하는 모든 도메인 / 서버에 대해서는 이 명령을 통해 인증서 정보를 확인할 수 있습니다. 

 

교체하려는 인증서 점검

인증서를 교체하기 위해서는 인증서 발급기관, 속칭 CA 로 부터 인증서를 발급받아 전달받게 됩니다. 보통 서버에 인증서를 설치하기 위해서는 1) 서버 개인키와 2) 서버 공개키 + 공개키를 인증할때 사용한 중간 인증서의 공개키를 합친 파일 을 서버에 설치하게 됩니다. 설치된 파일은 Apache Server 나 nginx 와 같은 웹 서버의 설정(configuration) 파일에 설치된 경로, 파일 정보, 사용할 Cipher Suite 정보등을 기술하게 됩니다. 

서버에 인증서 파일을 업로드 하고 설정 변경을 해서 아무런 문제가 없다면 얼마나 좋을까요? 결국 사람이 하는 일이다보니 실수가 생기거나 오류가 생기는 경우가 발생하곤 합니다. 그러면 드는 생각이 <교체하려는 인증서 파일을 미리 확인해 볼 수 없나?> 하는 것일겁니다. 앞서 본 것처럼 openssl 을 이용해서 파일 단위로 구성된 인증서를 미리 확인해보는 방법은 없을까요?

아래의 코드는 서버에 배포하기 위해서 중간 체인 인증서와 서버 인증서를 합친 파일을 점검해주는 간단한 스크립트 입니다. 서버에서 사용하고 있는 인증서를 `openssl s_client` 명령으로 확인한 것처럼 서버 인증서, 중간 인증서가 문제 없는지, 혹은 체인이 어떻게 구성되어 있는지를 확인할 수 있는 스크립트입니다. 참고로 스크립트의 출처는 kdecherf.com/blog/2015/04/10/show-the-certificate-chain-of-a-local-x509-file/ 입니다. 

#!/bin/bash

chain_pem="${1}"

if [[ ! -f "${chain_pem}" ]]; then
    echo "Usage: $0 BASE64_CERTIFICATE_CHAIN_FILE" >&2
    exit 1
fi

if ! openssl x509 -in "${chain_pem}" -noout 2>/dev/null ; then
    echo "${chain_pem} is not a certificate" >&2
    exit 1
fi

awk -F'\n' '
        BEGIN {
            showcert = "openssl x509 -noout -subject -issuer"
        }

        /-----BEGIN CERTIFICATE-----/ {
            printf "%2d: ", ind
        }

        {
            printf $0"\n" | showcert
        }

        /-----END CERTIFICATE-----/ {
            close(showcert)
            ind ++
        }
    ' "${chain_pem}"

echo
openssl verify -untrusted "${chain_pem}" "${chain_pem}"

스크립트를 만들고 chmod u+x #파일명# 으로 실행 가능하게 만드시기 바랍니다. 실행 가능한 스크립트가 되었다면 `./#스크립트파일명# #인증서파일명#` 형식의 명령을 통해 로컬에 존재하는 파일 형태의 인증서 + 중간 인증서를 s_client 옵션을 이용한 것처럼 검증할 수 있게 됩니다. 문제가 없다면 서버에 배포하고 웹 서버를 reload 하면 되겠지요!

728x90
728x90

플러터 Flutter 는 크로스 플랫폼 어플리케이션 개발을 위한 UI 툴킷이다 보니 애플 iOS 와 안드로이드 운영체제를 위한 개발 환경을 각각 구성해야 합니다. 그 중, iOS 개발을 위해서는 아래의 조건이 충족되어야 합니다. 

  • Xcode 설치를 위한 MacOS 운영체제
  • Xcode 의 완전체 (Full Installation) 설치
  • 기타

 

플러터 의사 선생님의 진단 (Flutter Doctor)

저는 맥북 프로를 쓰고 있었고 Xcode 역시 설치가 되어 있어서 플러터 닥터 Flutter Doctor 가 점검하여 누락된 부분들을 제시된 명령을 이용해서 설치할 수 있었습니다. 이전에 올렸던 플러터 환경 구성 포스팅에서 보았던 플러터 의사 선생님의 진단서를 다시 한 번 인용해 보겠습니다. 

Xcode 의 완전체 설치는 문제가 없었는데 cocoapod 를 설치하는 과정에 문제가 발생했습니다. (참고로, cocoapod 는 Objective-C 나 Swift 를 이용한 개발시 외부 라이브러리에 대한 외부 라이브러리 개발을 위한 종속성 관리 도구 입니다.)

 

에러 메세지 분석

환경에 따라 나오는 에러의 경로 복잡도(?)는 달라질 수 있습니다. 이게 무슨 에러인가 하고 천천히 읽어보니... 로컬 환경에 설치되어 있는 openssl 을 찾지 못해서 발생하는 것으로 추정되었습니다. `NoMethodError` 라는 메세지 때문에 헷갈렸습니다만, `image not found` 와 `NilClass` 에서 단서를 얻어 "적당한 버전이 설치가 되지 않았거나, 경로가 잘못되었나 보군?" 하는 생각에 도달했습니다. 

$ sudo gem install cocoapods
Password:
ERROR:  Loading command: install (LoadError)
	dlopen(/usr/local/Cellar/ruby/2.4.2_1/lib/ruby/2.4.0/x86_64-darwin16/openssl.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib
  Referenced from: /usr/local/Cellar/ruby/2.4.2_1/lib/ruby/2.4.0/x86_64-darwin16/openssl.bundle
  Reason: image not found - /usr/local/Cellar/ruby/2.4.2_1/lib/ruby/2.4.0/x86_64-darwin16/openssl.bundle
ERROR:  While executing gem ... (NoMethodError)
    undefined method `invoke_with_build_args' for nil:NilClass

에러 메세지에 나온참조 경로를 일단 찾아보기로 했습니다. "Libbrary not loaded" 메세지 뒤에 나온 경로의 libsll.1.0.0.dylib 파일이 존재하는지를 확인해 보았습니다. 네, 예상대로 파일이 존재하지 않았습니다. 

$ ls /usr/local/opt/openssl/lib/libssl.1.0.0.dylib
ls: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib: No such file or directory

이 파일은 openssl 의 하위 구성 파일이니 MacOS 의 패키지 매니저인 brew 를 이용해서 설치된 openssl 의 정보를 확인해 보기로 했습니다. `brew list [패키지명]` 을 이용해서 아래와 같이 경로를 확인할 수 있었습니다. 

$ brew list openssl
/usr/local/Cellar/openssl/1.0.2s/.bottle/etc/ (8 files)
/usr/local/Cellar/openssl/1.0.2s/bin/c_rehash
/usr/local/Cellar/openssl/1.0.2s/bin/openssl
/usr/local/Cellar/openssl/1.0.2s/include/openssl/ (75 files)
/usr/local/Cellar/openssl/1.0.2s/lib/libcrypto.1.0.0.dylib
/usr/local/Cellar/openssl/1.0.2s/lib/libssl.1.0.0.dylib
/usr/local/Cellar/openssl/1.0.2s/lib/engines/ (12 files)
/usr/local/Cellar/openssl/1.0.2s/lib/pkgconfig/ (3 files)
/usr/local/Cellar/openssl/1.0.2s/lib/ (4 other files)
/usr/local/Cellar/openssl/1.0.2s/share/man/ (1683 files)

gem install 명령에서는 /openssl/lib/... 경로를 참고하고 있었지만 실제 설치된 openssl 라이브러리는 /openssl/1.0.2s/lib/... 경로였습니다. 아마도 개별적으로 HTTP2 지원 등을 위해서 별도로 설치했던 것이 Symlink 변경이나 특정한 환경변수? 에 업데이트가 되지 않은 것인가 하는 의심이 들었습니다.

 

잘못된 경로의 수정

결국은 brew 가 관리하는 패키지이니 일단 brew 에서 패키지에 대한 경로를 바꿔줄 수 있도록 `brew switch [패키지명] [버전]` 명령을 이용해서 경로를 재수정 해주었습니다. 

$ brew switch openssl 1.0.2s
Cleaning /usr/local/Cellar/openssl/1.0.2s
Opt link created for /usr/local/Cellar/openssl/1.0.2s

이제 잘 되었을까요? 플러터 의사 선생님이 알려준 명령을 이용하여 cocoapods 를 다시 설치해 보았습니다. 이번에는 문제 없이 잘 설치가 되는 것을 확인할 수 있었습니다. 

$ sudo gem install cocoapods
Password:
Fetching: concurrent-ruby-1.1.7.gem (100%)
Successfully installed concurrent-ruby-1.1.7
Fetching: i18n-0.9.5.gem (100%)
Successfully installed i18n-0.9.5
Fetching: thread_safe-0.3.6.gem (100%)
Successfully installed thread_safe-0.3.6
Fetching: tzinfo-1.2.7.gem (100%)
...
...
...
Parsing documentation for cocoapods-1.9.3
Installing ri documentation for cocoapods-1.9.3
Done installing documentation for concurrent-ruby, i18n, thread_safe, tzinfo, activesupport, nap, fuzzy_match, httpclient, algoliasearch, ffi, ethon, typhoeus, netrc, cocoapods-core, claide, cocoapods-deintegrate, cocoapods-downloader, cocoapods-plugins, cocoapods-search, cocoapods-stats, cocoapods-trunk, cocoapods-try, molinillo, atomos, CFPropertyList, colored2, nanaimo, xcodeproj, escape, fourflusher, gh_inspector, ruby-macho, cocoapods after 63 seconds
33 gems installed

 

플러터 환경 구성 뿐만 아니라 Xcode 개발 환경을 구성하는데 있어서 cocoapods 설치 문제가 발생한다면 위의 방법으로 경로 정보 수정을 해보시기 바랍니다. 

728x90
728x90
요즘 웹 업계가 난리입니다. 사실상 표준처럼 사용되고 있는 오픈소스 라이브러리인 OpenSSL 에서 취약점이 발견되면서 SSL 터널링과 관계 없이 사용자의 민감한 정보가 노출될 수 있는 문제가 확인되었기 때문입니다. OpenSSL 라이브러리에 대한 패치와 기존에 발급된 인증서 갱신도 중요하지만 Heartbleed 가 왜 이리 큰 이슈가 되는지 아는 것도 중요해 보입니다.

워낙 관련된 문서들이 많이 나왔고 테크 블로그나 IT 전문 매체에서도 잘 다루어 준 덕분에 이해하기 어렵지 않지만 누군가에게 이걸 다시 설명하라고 하면 구차하고 잡다한 이야기를 늘어놓게 되지요. 간단하게 정리된 웹 사이트가 있어서 소개해 드리면서 해당 사이트가 그림으로 이해하기 쉽게 그려둔 그림을 공유해 봅니다. 이해가 아주 깔끔하게 되네요!

출처 : Forumsys (http://www.forumsys.com/api-security/how-to-fix-openssl-heartbleed-security-flaw/)

 
평상시 사용자들이 브라우저로 TLS/SSL (쉽게 말해 HTTPS 요청이라고 생각하시면 됩니다) 터널링을 맺고 나면 OpenSSL 라이브러리는 생성된 세션이 유효함을 확인하기 위해 5바이트의 HELLO 메세지를 전송하는 Heartbeat (심장박동?) 를 전달하게 됩니다. 클라이언트 (보통 브라우저겠죠) 와 서버는 지속적으로 이 행위(?)를 반복하며 채널을 유지합니다.

출처 : Forumsys (http://www.forumsys.com/api-security/how-to-fix-openssl-heartbleed-security-flaw/)


그런데 이번에 발견된 OpenSSL 의 문제점은 Heartbeat 를 5바이트 이상으로 전송하더라도 이에 대해서 서버가 같은 바이트 크기만큼 메모리의 정보를 읽어서 응답하는 데에 있습니다. 악의적인 사용자가 서버의 메모리에 저장된 특정한 주소의 정보들을 쉽게 추출해낼 수 있는 방법이 생긴 것이지요. 이의 해결을 위해서는 OpenSSL 라이브러리를 갱신하고 발급된 인증서를 재발급 받는 등의 절차가 필요합니다. 보다 자세한 내용은 원문을 참고하시기 바랍니다!





728x90

+ Recent posts