어느순간부터 티스토리 계정이 로그인되어 있음에도 불구하고 필명과 비밀번호를 직접 입력하는 방식으로만 댓글을 남길 수 있는걸 발견했다.

티스토리 버그인줄 알고 그러려니 했는데 하루이틀 만에 안 고쳐져서 찾아보니 버그는 아니고.. 2차 도메인 문제라고...

참고: [안내] 2차 도메인 사용 시 유의사항


블로그 관리 - 좌측 하단 설정 - 블로그 에서 기본 도메인인 ***.tistory.com 주소로 접속을 하면 일단 원래대로 정상 이용이 가능하다.


브라우저 보안정책이 강화되면서 다른 도메인간 쿠키 공유 같은게 막힌 것 같고, 그로 인해 로그인 세션 유지가 안되는 듯...

공지에서 개선방안을 찾고 있다고 하니 곧 해결해주겠징...

SSO 같은 느낌으로 다른 도메인간 세션 공유를 해주는 방식으로 만들어주면 될 것 같긴 한데,, 완전 새로운 기능 추가이다 보니 오래 걸리나부다..ㅠㅠㅠ

E5885 커스텀 펌웨어 글을 찾아보면 많은 듯 많지 않다.

대략 정리를 해보면,

한국 커뮤니티 안에서는 클리앙의 따끈따끈 님이 가장 활발하신 것 같다. 이런저런 시도도 많이 해보시고, 그걸 또 공유까지 열심히..

자잘한 글도 많이 남기셨지만,
화웨이 모바일 LTE 라우터 E5885의 펌웨어 교체하기 1편 - S/W 준비
화웨이 모바일 LTE 라우터 E5885의 펌웨어 교체하기 2편 - H/W 준비
화웨이 모바일 LTE 라우터 E5885의 펌웨어 교체하기 3편 - 펌웨어 올리기

요 3개 글에 정말 많은 내용이 있다.

영문 자료로는 화웨이 LTE 라우터의 커스텀 펌웨어 관련된 전반적인 내용이 있는 git
https://github.com/Huawei-LTE-routers-mods

하지만 너무 불친절해..ㅠㅠ 결과적으로 얻을 수 있는 정보가 거의 없음..

그 외엔 영문 자료 조차도 거의 없다. 대부분 러시아 사이트의 한 포럼에 대부분의 내용이 있는 것 같다.

https://4pda.ru/forum/index.php?showtopic=842340

구글 번역기의 힘을 빌리면 얼추 읽을만 하다.

파일을 다운받으려면 회원가입을 해야하는데, 회원가입/로그인/비밀번호 찾기 시마다 러시아어로 숫자를 써두고 맞추라는 무시무시한 캡챠가 있다... 숫자는 4자리 숫자인데, 운 좋으면 그림 맞추기로 성공할 수 있지만, 날림체에다가 줄바꿈이 엉망이라 러시아어를 아는 친구도 읽기가 어렵다고...ㅠㅠ


펌웨어 작업을 시도하기 전 사전조사 차원에서 여러번 검색해봤는데, 검색 할때마다 필요한 내용을 바로바로 찾기가 어려워서 다시 정리를 해봄.

1. 부트모드 진입 작업

가장 진입 장벽이 높은 작업인 것 같다.

부트모드로 진입하기 위해 케이스에 가려진 부분을 쇼트시켜야하는데, 분해가 만만치 않다...

분해를 하지 않고 구멍을 뚫는 방법이 있으며 이 역시 클리앙의 따끈따끈님이 잘 정리해서 올려주셨다

화웨이 E5885 분해 없이 부트 모드 진입하는 방법


전원이 꺼진 상태에서 usb 연결을 하면 자동으로 전원이 켜지는데, 제대로 쇼트된 상태라면 켜지지만 화면에 아무것도 뜨지 않는다.

너무 오래 하고 있으면 또 다른 모드로 진입한다고 본 것 같으니 5~10초 후에 떼도록.


2. 펌웨어 다운로드 환경 구축

Mac 에선 드라이버가 없어서 인식이 안되는 것 같고, Windows 에서는 드라이버를 깔아주면 되는 것 같지만..
그냥 속편하게 가상머신을 쓰는게 나은 것 같다.

위 따끈따끈 님의 강좌에서는 VMWare를 썼지만, 난 VirtualBox 를 사용하였음.


VirtualBox 를 설치하고, Extension Pack 까지 추가해준다.


우분투는 알아서 설치하자. desktop image 말고 gui가 없는 server install image 를 설치해도 됨.

이 후 vm 설정에서 usb 관련 옵션을 수정해준다.

 


클리앙 강좌에서는 레지스트리 추가에 해당하는 내용일 것 같은데, 특정 USB를 바로 가상머신에 연결하게 하는 설정이다.

이름을 비롯한 나머지 값은 중요하지 않고 제조사 ID(VID), 제품 ID(PID) 가 중요함. 혹시 모르니 리비전(REV) 정도는 넣어둬도 되고.

첫번째 부트 모드에 들어갔을때는 VID: 12d1 PID: 1443 REV: 0001
펌웨어 플래싱 전 부트로더를 올린 후에 생기는 건 VID: 12d1 PID: 1c05 REV: 0102

아무 이름으로 둘 다 추가해주도록 하자.

이 설정을 하지 않고 일단 연결한 다음 가상머신 설정에서 물려줘도 된다. 클리앙 글에서는 문제가 생길 수도 있다는 것 같던데.. 난 괜찮은 것 같았음.


우분투 내에서는 필요한 프로그램을 빌드하는 정도만 하면 끝

sudo apt install git make gcc zlib1g-dev

git clone https://github.com/forth32/balong-usbdload
cd balong-usbdload; make;

git clone https://github.com/forth32/balongflash
cd balongflash; make;


3. NVRAM 백업

펌웨어와 NVRAM을 백업할 수 있다.

NVRAM의 경우 IMEI나 시리얼 같은 정보와 함께 기기마다 다 다른 radio calibration 값이 들어 있으니 꼭 백업을 권장하였음.
혹시나 날려먹으면 다른 사람의 값을 덮어 씌울 순 있지만, 기기마다 다르기 때문에 이전과 같은 퍼포먼스가 안나올 수 있다고 한다.

Huawei E5885 current firmware backup manual. 이 gist 를 참고하면 된다.

busybox 를 넣어주는 usb로더를 한번 로드해주면, E5885에 telnet으로 접속이 가능해져서 sdcard에 관련 자료를 백업하는 방식.


4. 커스텀 펌웨어 구하기

직접 커펌을 만들어보고 싶어서 한참을 뒤져봤는데.... 잘 모르겠다... 왠지 자존심 상해...

애초에 "커스텀 펌웨어"가 왜 필요한지도 잘 모르겠다..
위 백업에 사용했던 방법처럼 라우터 쉘에서 이것저것 수정하는 방법으로도 이것저것 가능한 것 같은데...

뭐는 할려면 커스텀 펌웨어를 올려야된다는 말도 있고, 이미 너무 많은 시간을 투자해서 그냥 커펌을 올리기로 결정.


포럼을 다 읽어보니, 문제가 되는 펌웨어도 있고.. 커펌도 새로운 버전들이 계속 나오는 것 같다.

몇개 되지도 않지만, 내가 고른건 bay3255 란 사용자가 배포한 펌웨어.

현 시점(20년 6월 30일)에서는 20년 5월 22일에 배포한
E5885Ls-93a_UPDATE_21.191.69.00.00.baymod.v8.fw 펌웨어가 최신이다.

위에서 말했듯이 파일을 다운받기 위해선 러시아 숫자를 뚫고 회원가입이 필요함...


5. 펌웨어 플래싱

여기까지 왔다면 어려울게 없다. NVRAM 백업 했던 것에 이어 한발짝 더 나아갈 뿐...

cd balong-usbdload
sudo ./balong-usbdload -p /dev/ttyUSB0 -c usblsafe-e5885.bin

잠시 기다리면 화면에 다운로드 표시가 나오고 /dev/ttyUSB1 장치가 잡힌다.

cd ..
sudo ./balongflash/balong_flash -p /dev/ttyUSB1 ./E5885Ls-93a_UPDATE_21.182.63.00.148_WEBUI_21.100.37.00.148_NE5.ZIP

이 커펌이 부팅화면을 바꿔버려서 화웨이 로고 대신 'Wake up, Neo...' 라고 나온다.
그냥 강좌대로 잠시 기다렸다가 재부팅!


WPS 버튼을 3초정도? 눌렀다 떼면 히든 메뉴가 나온다.
신기하게 원래 나오던 한글들도 여전히 잘 나옴...

Fix TTL 을 설정한 후 패킷 캡쳐해보니 잘 된다. ㅎㅎㅎ

내일은 OpenVPN 연결 해봐야지...


각종 셀룰러 버전을 사모으다가, '그냥 동글이 하나 있으면 좋겠는데?!' 라는 생각으로 구매하게 된 LTE 라우터, E5885

USB 스틱버전과 이것 중에 고민하다가 중고나라에 먼저 올라오는걸로 구매하였다.

보통 LTE 라우터를 구매하면, 통신사에는 자급제 LTE 폰으로 등록을 하고 휴대폰용 무제한 요금제를 사용하게 된다.
등록시 타블렛이나 라우터로 등록을 하게 되면 이런저런 제한에 걸리게 됨.

통신사별로 좀 특징이 있는데,

KT
내가 산 E5885는 KT에 출시된 기기라 KT는 얘가 LTE 라우터라는걸 안다. 따라서 전용 요금제 밖에 가입이 안되고 그 요금제가 별로인 것 같아서 제외.

SK
SK는 전산망에 없는 장비의 경우 자동으로 연결이 안된다. 복불복으로 되는 경우도 있다는데, 상담원과 전화를 해서 꼭 직접 등록을 해줘야 함.
처음에 상담원이 '연결은 잘 되었는데, 타사에서 이용 중인 기기라고 나온다. 해지를 먼저 해줘야 한다.' 라고 잘못된 정보를 줘서 한참 헤맸음... 
친절한 다른 직원이 퇴근도 안하고 잘 해결을 해주었다. 고맙다고 홍보라도 해주고 싶지만, 라우터를 폰으로 등록한게 찔림...

LG
안써봐서 모르겠지만 전 주인이 잘 썼다고 한다. LG 쓸걸...


보통 U+알뜰모바일 GS25 요금제 - GS25(15GB+/100분) 를 많이 이용하는 것 같던데,
난 SK망이 쓰고 싶어서 몇천원 더 비싼 다른 별정 통신사의 SK 무제한 요금제를 이용하였다.


기본 제공 용량인 15G까지는 잘 썼는데.. 몰랐던게, LTE 라우터도 이 장비가 직접 인터넷을 쓰는게 아니고 여기서 뿌려주는 인터넷을 다른 장비가 받아서 사용을 하다보니, 핫스팟/테더링 판정이 난다.

즉, 핫스팟 속도나 용량 제한이 걸릴 수 있다는 소리..

코로나 때문에 격리되는 동안 라우터를 사용했었는데, 그것도 모르고 200Kbps 밖에 안나오는 속도에 엄청 마음 고생을ㅠㅠㅠ


통신사마다 핫스팟을 구분하는 방식이 조금 다르다고 한다.

KT는 잘 모르겠고,

SK는 IP 프로토콜의 TTL 값으로 구분을 한다.
Time To Live의 준말로, 공유기 등 네트워크 장비를 하나 지날때마다 값을 1씩 빼다가 0이 되면 그냥 패킷을 없앰으로써 네트워크 설정이 잘못된 경우나 잘못 만들어진 패킷이 영원히 네트워크를 떠돌지 않도록 구분하는 값이 있다.

보통 64 정도의 값을 많이 사용하는데, 휴대폰에서 출발한 패킷이 64라는 값을 가지고 통신사 기지국에 도달한다면, 테더링된 장비의 경우 휴대폰을 한번 거쳐서 지나가기 때문에 1이 줄어서 63이 된다. (이런걸로 구분할 생각을 하다니, 똑똑한 놈들) 

LG는 APN 값으로 구분을 한다. 폰이 직접 접속하는 APN과, 테더링 장비가 접속하게 되는 APN이 다르다는 듯...
휴대폰의 경우에도 갖가지 방법으로 이 설정을 변경하여 속도제한 없이 사용하는 경우가 있는데, E5885의 경우엔 애초에 테더링 APN 설정이 없어서 상관이 없는 것 같다. (즉 LTE 라우터를 쓸거면 LG를 쓰자!)


커스텀 펌웨어를 올리면 TTL 을 재지정한다거나, 라우터 단에서 VPN 연결을 해버려서 우회하는 방법이 있다.

다만 상당히 번거로우니,, 그냥 혹시나 사용할 사람이 있다면 U+ 요금제를 사용하는걸 추천...


난 이렇게 된 김에 VPN 등에도 관심이 생겨서 커스텀 펌웨어에 도전해볼 예정.

0. 용어 정리

PKI (Public Key Infrastructure); 공개키 기반 구조

X.509: 공개키 인증서와 인증 알고리즘을 사용하기 위한 PKI 표준

PKCS (Public Key Cryptography Standards): Private Key를 저장하는 문법에 관한 표준
            PKCS#1, PKCS#8, PKCS#12 등을 사용

CRL (Certificate Revocation List), OCSP (Online Certificate Status Protocol): 인증서 유효성 점검을 위한 표준/방법

CA (Certificate Authority): 인증 기관

ASN.1 (Abstract Syntax Notation One): 추상 구문 기법, 네트웍상의 데이터 교환을 정의한 프로토콜

RSA (Rivest–Shamir–Adleman): 공개키 암호시스템의 하나

ECDSA (Elliptic Curve Digital Signature Algorithm): 타원곡선을 이용한 전자서명 알고리즘


0-2. 인코딩/파일 종류 정리

참고로 당연히 아래에 적는 확장자는 참고용으로 강제사항은 아님.
PEM 포맷의 개인키를 my.key.pem, my.key, key.pem 등등 저장하기 나름.

인코딩에 따른 구분

 종류

 확장자

 설명

 DER (Distinguished Encoding Representation)

 .der

 ASN.1을 표현하는 방식의 종류. (바이너리로 저장됨)

 PEM (Privacy Enhanced Mail)

 .pem

 Base64로 인코딩된 ASCII 텍스트
 (표준으로 더 자주 사용됨)


내용에 따른 구분

 종류

 확장자

 설명

 Private Key

 .key

 개인키

 Certificate

 .cer (Windows 주로 사용)
 .crt (*NIX 주로 사용)

 인증서

 PKCS #12

 .p12, .pfx

 하나의 파일에 개인키, 인증서 등을 같이 저장하는 방식에 대한 표준

 Certificate Signing Request

 .csr

 인증서 발급을 위해 내 개인키 서명을 CA에게 보내기 위한 파일

 Serial .srl

 CA가 인증서를 발급할 때 Serial 을 관리하기 위한 파일



1. OpenSSL 명령어

* 기본 config 경로: /etc/pki/tls/openssl.cnf

1) Private Key 생성

openssl genrsa -out key.pem 2048


[옵션]

-des, -seed, -aes256, ...: 해당하는 방식으로 키 암호화. 미사용시 암호화 X

-passout pass:PASSWORD: 키를 암호화할 경우 암호 지정. 미사용시 입력 프롬프트가 뜸

-f4 (0x10001), -3: E value 지정. 기본값: -f4

1024, 2048, 3072, 4096, ...: Private Key Bit 크기. 아래 부록 참고




2) CSR 생성

openssl req -new -key key.pem -out my.csr


[옵션]

-md5, -sha1, -sha256, ...: 서명에 사용할 Digest. 기본값은 버전마다 다르고 적당히 sha256 사용.
            전체 목록은 openssl dgst -h

-subj: 인증서 주제 설정. 미사용시 입력 프롬프트 표시
    예시) -subj "/C=KR/O=sho/CN=SHO Certificate"

 필드

 의미

 예시

 /C=

 국가

 KR

 /ST=

 State, 한국이라면 시/도

 Seoul

 /L=

 Location

 Yongsan

 /O=

 Organization, 회사명

 회사

 /OU=

 Organization Unit, 부서명

 부서

 /CN=

 Common Name

 SHO Root CA, blog.ioate.kr 등




3) CSR로부터 인증서 생성

X.509 V3 확장 설정

(아래에서 사용할 ca.ext, end.ext 파일)

Web TLS 인증서 (CA용) - ca.ext

basicConstraints = critical, CA:TRUE
#basicConstraints = critical, CA:TRUE, pathlen:0

subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
keyUsage = cRLSign, keyCertSign


Web TLS 인증서 (End-entity, 사이트용) - end.ext

basicConstraints = critical, CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = DNS:blog.iolate.kr, IP:1.1.1.1


CA 인증서 생성

openssl x509 -req -days 3650 -extfile ca.ext -signkey key.pem -in my.csr -out root.crt


[옵션]

-set_serial 1: 시리얼 값 지정. 미지정시 임의값 생성

-md5, -sha1, -sha256, ...: 서명에 사용할 Digest.
            전체 목록은 openssl dgst -h
            직접 신뢰 설정을 하는 Root CA 가 아니라면, sha256 사용. sha1 등 취약한 digest 사용시 브라우저에서 경고함


End-entity 인증서 생성

openssl x509 -req -days 365 -extfile end.ext -CA root.crt -CAcreateserial -CAkey my.key -in my.csr -out end.crt
openssl x509 -req -days 365 -extfile end.ext -CA root.crt -CAserial root.srl -CAkey my.key -in my.csr -out end.crt


[옵션]

-CAcreateserial: 시리얼 자동 지정 및 시리얼 파일 생성 (.srl)

-CAserial root.srl: CAcreateserial 로 한번 발급한 이후에는 이 옵션으로 시리얼 생성 파일 입력

-md5, -sha1, -sha256, ...: 서명에 사용할 Digest. sha256 사용. sha1 등 취약한 digest 사용시 브라우저에서 경고함



4) 생성된 파일 정보 확인

CSR / 인증서 / 개인키

openssl [req/x509/rsa] -noout -text -in [my.csr/end.crt/my.key]
openssl [req/x509/rsa] -noout -modulus -in [my.csr/end.crt/my.key] | openssl md5



2. 부록

Private Key 비트 크기

출처: https://en.wikipedia.org/wiki/Key_size

(대략적 요약)

* 128bit AES가 충분한 보안 수준으로 고려되었지만, 양자 컴퓨터의 등장 후 비밀 문서에 256bit 사용 권고

* 1024bit RSA와 80bit 대칭키 /
   2048bit RSA와 112bit 대칭키 / 
   3072bit RSA와 128bit 대칭키 /
   15360bit RSA와 256bit 대칭키  가 서로 보안 수준이 비슷하다고 판단됨.

* 1024bit RSA는 2006~2010년에 취약해짐.
   2048bit RSA는 2030년까지 유효할 것으로 판단.
   2030년 이후에는 3072bit 사용 권고


3. 참고

Wikipedia, OpenSSL 문서, 등등...

(그때그때 정리해둔 문서를 다시 정리한거라 참고 URL이 없음..ㅠ)

Tibero DB 를 사용할 일이 있었는데, tbAdmin이 구려서 직접 연결해서 데이터를 가져와야할 일이 있었다.

심지어 마땅한 다른 언어를 사용할 수 없어서 Excel VBA로......


윈도우 기준으로 ODBC를 시스템에 등록하고, 해당 드라이브를 이용해서 연결하면 된다.


1. ODBC 등록

ODBC 설치법은 인터넷에 검색하면 많이 나오지만, 인스톨러를 사용해서 등록하라고 하는데,,, 왠지 마음에 안들어서 수동등록함.

우선 필요한 ODBC 파일은.. 검색하면 어디서 구할 수 있는지 잘 나온다. (tbAdmin 에는 없다., 서버를 소스코드(tar.gz)로 받았을 경우 client/win32/lib/libtbcli.dll, libtbcli.lib 에 있음)

.lib도 필요한지 아닌지 잘 모르겠지만 일단 이름이 같으니까 같이 챙겨서, 삭제되지 않을 적당한 곳에 잘 꽁쳐놓자.


이후 cmd를 관리자모드로 열어서 아래 명령어 입력. 드라이버 이름(Tibero 6)이나 경로는 필요에 따라 수정해주면 된다.

odbcconf /A {INSTALLDRIVER "Tibero6|driver=D:\odbc\libtbcli.dll"}
64bit 시스템이라면, 32bit 로 등록해야 한다.
%windir%\syswow64\odbcconf /A {INSTALLDRIVER "Tibero6|driver=D:\odbc\libtbcli.dll"}


2. Excel VBA 에서 연결

도구 - 참조 에서 Microsoft ActiveX Data Objects 6.0 Library 체크 후 확인한 후 아래 코드 참고해서 작성.

Driver={Tibero 6} 는 위에서 ODBC 등록시 사용한 드라이버 이름을 사용하면 된다.


Dim conn As New ADODB.Connection
conn.Open "Driver={Tibero6};Server=x.x.x.x;Port=xxxx;UID=user;Database=sid;Password=pwd;"

Dim rs as New ADODB.Recordset
rs.ActiveConnection = conn
rs.Open "SELECT * FROM table;"

Do Until (rs.EOF = True)
...
    rs.MoveNext
Loop

rs.Close


대충 이런식으로 사용.

이 후로는 다른 DB 사용할 때랑 비슷하다. 연결 문자열 정도만 참고하면 될 듯?

cloud9 을 사용하거나,, 뭐 여튼 필요할떄만 쓰는 aws 인스턴스의 경우엔 ip 주소를 매번 확인해줘야하는 번거로움이 추가된다.
따라서 부팅시에 Route 53 A레코드를 변경해주는 스크립트를 작성해보았음.

IAM 권한도 적절히 필요하겠지만, 난 cloud9 instance를 사용해서인지, aws가 알아서 credential 을 관리해줘서 생략.
필요하다면 아래 참고 글 링크를 확인해보자.

아래 파이썬 스크립트를 적절한 곳에 만들어 주고, 상단 변수 역시 설정해준다. 난 ~/route53/update.py 라고 만들었음.
특정 인스턴스의 public ip 를 구해온 다음, 지정한 url의 A레코드 값을 변경(없으면 생성)해주는 코드이다.
호스팅 영역 ID는 Route 53 에서 해당 도메인 이름(ex.com)을 선택하면 볼 수 있고, URL 은 호스팅 영역 내에서 생성하는 서브도메인을 포함한 이름(abc.ex.com)의 형태를 입력해주자.

INSTANCE_REGION="ap-southeast-1"
INSTANCE_ID="i-~~~~~~~~~~"
DOMAIN_ZONE="호스팅 영역 ID (ZGWP~~~~~~)"
URL="사용할 도메인 (abc.ex.com)"

import boto3

client_ec2 = boto3.client('ec2', region_name=INSTANCE_REGION)
r = client_ec2.describe_instances(InstanceIds=[INSTANCE_ID])

ip = r['Reservations'][0]['Instances'][0]['PublicIpAddress']

client_route53 = boto3.client('route53')
client_route53.change_resource_record_sets(
    HostedZoneId=DOMAIN_ZONE,
    ChangeBatch={'Changes': [{
        'Action': 'UPSERT',
        'ResourceRecordSet': {
            'Name': URL,
            'Type': 'A',
            'TTL': 300,
            'ResourceRecords': [{'Value': ip}]
        }
    }]}
)

그 다음 이 스크립트를 부팅시 실행되도록 설정한다. 여러가지 방법이 있지만 난 crontab을 이용하였음.

crontab -e

@reboot sleep 30 && /usr/bin/python3 /home/ec2-user/route53/update.py

경로 등은 알아서 수정해주자.
난 혹시 몰라서 30초 딜레이를 줬는데 안줘도 될 수도.

1번 테스트 해봤는데 일단 잘 된다. ㅎㅎ

참고
Auto-Register EC2 Instance in AWS Route 53

보통 요즘 나오는 탈옥툴에 사용될텐데...
ipa 의 코드사인을 다시 하는 방법.

iOS App Signer 라는 앱이 있는데.. 왜인지 이걸로 하면 안된다. https://dantheman827.github.io/ios-app-signer/

--------------------

 

난 보통 소스코드를 받아서 xcode 를 이용하는 방법으로 했는데, 이번에 그게 좀 여의치 않아서 찾아봄.
예전 방법이 많이 올라와있는데 그것들은 안되더라.

 

개발자 인증서는 키체인에 들어있는걸 가정하고, Profile 은 애플 개발자 홈페이지에서 다운받으면 됨.
와일드카드를 쓰더라도 앱 아이디가 중복되면 안된다는 것 같은데,, 문제가 생기면 Info.plist 에서 앱 아이디도 바꿔주자

 

# entitlements 정보 추출
security cms -D -i path/to/MyProfile.mobileprovision > provision.plist
/usr/libexec/PlistBuddy -x -c 'Print :Entitlements' provision.plist > entitlements.plist

# 압축풀고 기존 사이닝 제거
unzip MyApp.ipa
rm -rf Payload/MyApp.app/_CodeSignature

# 프로파일 넣어주기 및 사이닝
cp path/to/MyProfile.mobileprovision Payload/MyApp.app/embedded.mobileprovision
codesign -f -s "iPhone Developer: Some Body (XXXXXXXXXX)" --entitlements entitlements.plist Payload/MyApp.app

# 프레임워크가 있다면 그것들도 다시 사이닝
codesign -f -s "iPhone Developer: Some Body (XXXXXXXXXX)" --entitlements entitlements.plist Payload/MyApp.app/Frameworks/*

# 패키징
zip -qr app-resigned.ipa Payload

대충 이런 과정을 거치면 된다.

 

이 후 앱스토어에서 Apple Configurator 2 라는 앱을 받아서, USB 연결된 장비에 생성된 ipa 를 던져주면 설치됨.

 

설치 이후에 아이콘이 어둡고 실행이 안된다면 사이닝이 잘못되었거나 profile 에 해당 기기가 포함이 안된 경우.

 

참고
https://stackoverflow.com/a/37172815

AWS Lambda 에서 Python 을 쓰면서, AWS 서버에 설치되지 않은 패키지를 사용할 때에는 함수에 포함해서 업로드를 해줘야한다.

 

pip -t 옵션으로 패키지 다운로드 경로를 지정해서 람다 함수 루트에 패키지를 다운받아주면 되지만,

이 경우 디렉토리가 지저분해짐.

 

해결책은 당연하게도, 임의의 폴더를 만들어서 패키지를 다운받고, 해당 경로를 환경변수에 추가해주면 된다.

mkdir packages
# python3 -m pip install [package name] -t ./packages/
python3 -m pip install -r requirements.txt -t ./packages/

 

이 후 Python 핸들러 함수에서 환경변수 추가하기 위한 코드를 파일 최상단에 삽입

import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'packages'))

 

이렇게 하고 packages 폴더는 잊어버리거나 .gitignore 등에 추가해주면 된다.

 

+ 배포 스크립트

AWS Lambda 로 업로드 할때, 난 아래와 같은 스크립트를 만들어서 사용함. (2zip.sh)

 

동작 방식은

1. 몇몇 예외 파일을 제외하고 압축파일 생성

2. aws-cli 를 이용하여 업로드 후

3. 해당 압축파일 삭제

 

#!/bin/bash
LAMBDA_FUNC="Lambda 함수 이름"
zip -rq lambda.zip . -x *__pycache__* 2zip.sh env.sh requirements.txt CONFIG
aws lambda update-function-code --function-name $LAMBDA_FUNC --zip-file fileb://lambda.zip > /dev/null 2>&1
rm lambda.zip

-x 옵션의 인자 등은 상황과 필요에 따라 적절하게 수정을 해주자.

이건 정리용.


1. Root CA 생성

# CA private key 생성
openssl genrsa -out ca.key 2048

# CA request 생성
openssl req -new -key ca.key -out ca.csr -subj "/C=KR/O=TIM Lab/CN=My VPN CA"

# CA 인증서 생성
echo "basicConstraints = critical, CA:TRUE
subjectKeyIdentifier = hash
keyUsage = digitalSignature, keyCertSign, cRLSign" > ca.ext

openssl x509 -req -days 3650 -extfile ca.ext -set_serial 1 -signkey ca.key -in ca.csr -out ca.crt

# 필요없는 설정파일과 csr 제거
rm ca.ext ca.csr


2. ta.key, dh2048.pem 생성 

openssl dhparam -out dh2048.pem 2048
openvpn --genkey --secret ta.key


3. 서버용 인증서 생성

# private key 생성
openssl genrsa -out cert.key 2048

# csr 생성
openssl req -new -key cert.key -out cert.csr -subj "/C=KR/O=My Organization/CN=VPN Server"

# CA 인증서/키로 인증서 생성
echo "basicConstraints = critical, CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth" > cert.ext

openssl x509 -req -days 3650 -extfile cert.ext -CA ca.crt -CAcreateserial -CAkey  ca.key -in cert.csr -out cert.crt

# 필요없는 설정파일과 csr 제거
rm cert.ext cert.csr

# 서버 인증서, 키 등 이동 / 복사
cp ca.crt /etc/openvpn/ca.crt
cp cert.key /etc/openvpn/server.key
cp ta.key /etc/openvpn/ta.key
mv cert.crt /etc/openvpn/server.crt



4. 클라이언트용 인증서 생성

사실 서버 인증서 생성과 큰 차이 없다. X.509 의 설정파일 내용 정도?
# private key 생성
openssl genrsa -out cert.key 2048

CERT_NAME="Gildong Hong"

# csr 생성
openssl req -new -key cert.key -out cert.csr -subj "/C=KR/O=My Organization/CN=$CERT_NAME"

# CA 인증서/키로 인증서 생성
echo "basicConstraints = critical, CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = digitalSignature" > cert.ext

openssl x509 -req -days 3650 -extfile cert.ext -CA ca.crt -CAcreateserial -CAkey  ca.key -in cert.csr -out "clients/$CERT_NAME.crt"

# 필요없는 설정파일과 csr 제거
rm cert.ext cert.csr



5. ovpn 설정파일 만들기

exec 3> VPN.ovpn

echo "client
remote SERVER_HOST PORT

dev tun
proto udp
resolv-retry infinite
nobind
cipher AES-256-CBC
auth SHA256
key-direction 1
persist-key
persist-tun
remote-cert-tls server
verb 3

;redirect-gateway def1 bypass-dhcp
;auth-user-pass
" >&3

printf "\n\n<ca>\n" >&3
cat ca.crt >&3
printf "</ca>\n\n<tls-auth>\n" >&3
cat ta.key >&3
printf "</tls-auth>\n\n<cert>\n" >&3
cat "clients/$CERT_NAME.crt" >&3
printf "</cert>\n\n<key>\n" >&3
cat cert.key >&3
printf "</key>" >&3

exec 3>&-


OpenVPN 은 기본적으로 사용자별로 인증서를 생성해서 연결하도록 하고 있다.


그러다보니 설정파일에 ca, tls-auth, cert, key 4개의 파일이 추가로 따라다니게 되는데 관리하기 조금 번거로운 면이 있다.

물론 각각 ovpn 파일안에 임베딩해버릴 수 있지만...


아이디, 비밀번호로 로그인하는 방법이 있길래 진행해보았다.


먼저 OpenVPN 서버 설정에서 아래 두 문구를 추가한다.

client-cert-not-required
auth-user-pass-verify "/etc/openvpn/userauth/verify.sh" via-file

첫번째 줄은 클라이언트 인증서가 필요없게 하는거고, 두번째줄은 비밀번호를 체크할 스크립트를 지정한다.

저 파일은 내가 만들어줘야하며, 경로는 어디두던 크게 상관없음.


다만 user nobody / group nogroup 설정을 했을 경우 OpenVPN 데몬이 nobody / nogroup 권한으로 작동하기 때문에, 권한에 유의해주면 된다. 읽기 권한이나 실행 권한 등이 없으면 비밀번호 체크를 할 수 없다.

비밀번호 체크 과정에 root 권한이 필요하다면 권한을 낮추는 해당 설정을 제거해주자.


스크립트 경로 뒤의 via-file 은 OpenVPN 에서 사용자가 입력한 아이디와 비밀번호를 넘겨줄 방식을 정한다.

via-file 로 할 경우 임시 파일을 생성하면서

username
password

이렇게 두 줄로 된 파일을 생성한다.


(via-env 로 할 경우 환경변수에 넣어준다는데, 사용자명은 들어오는데 비밀번호는 어디있는지 모르겠더라...)



해당 스크립트에서 아이디와 비밀번호를 읽어서, 성공했다면 exit 0 을, 실패했다면 에러코드와 함께 프로그램이 종료되면 된다.



이제 비밀번호 체크를 위한 스크립트를 만들자.

방식은 다양하니 직접 만들면 되겠지만 내 스크립트를 참고 삼아 올려둠.


아래 URL 에 들어가보면 다른 스크립트들도 있다.


나는 user.pass 파일에

사용자명=SHA1비밀번호
사용자명=SHA1비밀번호

꼴로 저장을 해두고, 이를 검사하는 방식으로 작성하였다.


verify.sh 코드는 이렇게.

#!/bin/bash
passfile="/etc/openvpn/userauth/user.pass"
logfile="/var/log/openvpn/userauth.log"

username=`head -n 1 $1`
password=`head -n 2 $1 | tail -1`

hashed=`echo -n $password | sha1sum | awk '{print $1}'`
userpass=`cat $passfile | grep $username= | awk -F= '{print $2}'`

if [ "$userpass" = "$hashed" ]; then
        echo "`date +'%Y-%m-%d %H:%M:%S'` - auth success: $username" >> $logfile
#       echo "ok"
        exit 0
fi

echo "`date +'%Y-%m-%d %H:%M:%S'` - auth fail: $username" >> $logfile
#echo "not ok"
exit 1



그리고 client 설정 파일에는 cert 와 key 를 없애고, auth-user-pass 옵션을 추가해주면 된다.



----------

이 다음으로, Local 사용자 계정으로 로그인하는걸 시도해보았다.


보통 shadow 파일을 읽어서 비교를 많이 하던데, 나는 PAM Authentication 을 이용해보았다.

PAM 인증을 할때 root 이어야만 제대로 작동하는 것 같으니, 서버 설정에서 user nobody 옵션은 주석처리 해주자. (혹은 스티키 비트를 넣어주거나..)



PAM 인증을 하는 c 프로그램을 제작하였고, 로그를 남기기 위해 간단한 쉘 스크립트를 같이 이용하였음.

verify.sh

#!/bin/bash
pam_auth="/etc/openvpn/userauth/pam_auth"
logfile="/var/log/openvpn/userauth.log"

pam_result=`$pam_auth $1`
ret=$?

echo "`date +'%Y-%m-%d %H:%M:%S'` $pam_result" >> $logfile
exit $ret



pam_auth.c ( https://gist.github.com/iolate/a58b73a023b35d5f181814de2f4ffccd )

// gcc -o pam_auth pam_auth.c -lpam

#include <security/pam_appl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int custom_converation(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) {
	// Provide password for the PAM conversation response that was passed into appdata_ptr
	struct pam_response* reply = (struct pam_response* )malloc(sizeof(struct pam_response));
	reply[0].resp = (char*)appdata_ptr;
	reply[0].resp_retcode = 0;

	*resp = reply;
	return PAM_SUCCESS;
}

int main(int argc, char *argv[]) {
	if (argc != 2) {
		fprintf(stderr, "Usage: %s [filepath]\n", argv[0]);
		exit(1);
	}
	
	FILE* fp;
	char* username = NULL;
	char* password = NULL;
	size_t len = 0;
	ssize_t read;
	
	fp = fopen(argv[1], "r");
	if (fp == NULL) {
		fprintf(stderr, "%s: Cannot open '%s'\n", argv[0], argv[1]);
		return 1;
	}
	
	read = getline(&username, &len, fp);
	if (read == -1) {
		fclose(fp);
		return 1;
	}
	username[strlen(username)-1] = '\0'; // remove LF
	
	read = getline(&password, &len, fp);
	if (read == -1) {
		fclose(fp);
		return 1;
	}
	password[strlen(password)-1] = '\0'; // remove LF
	
	fclose(fp);
	
	// PAM Authentication
	struct pam_conv conv = {custom_converation, password};
	pam_handle_t* pamh = NULL;

	int retval = pam_start("whoami", username, &conv, &pamh);

	if (retval == PAM_SUCCESS)
		retval = pam_authenticate(pamh, 0); // is user really user?

	//if (retval == PAM_SUCCESS)
	//	retval = pam_acct_mgmt(pamh, 0); // permitted access?

	if (retval == PAM_SUCCESS) {
		fprintf(stdout, "Authenticated - %s\n", username);
	} else {
		fprintf(stdout, "Not Authenticated - %s\n", username);
	}

	pam_end(pamh, 0);
	return retval;
}


pam_auth 를 컴파일하기 위해선 pam development 패키지가 필요하니 설치하고 컴파일 해주자.

Ubuntu 기준 아래의 방법으로 진행하면 됨.

sudo apt install libpam0g-dev
gcc -o pam_auth pam_auth.c -lpam



verify.sh 를 간단히 수정하면, 두가지 방식을 동시에 사용하는 것도 가능하다.


참고

https://forums.openvpn.net/viewtopic.php?t=24907

https://medium.com/@nqbao/openvpn-auth-user-pass-verify-example-8d99023f08f7


https://unix.stackexchange.com/a/153323

http://www.linux-pam.org/Linux-PAM-html/adg-example.html

+ Recent posts