Skip to main content

· 4 min read

Google의 code review tool인 Gerrit 사용시 기존의 label인 Code-Review, Verified 이외에 사용자 정의 label이 필요한 경우가 있다.

내 경험으로는 CI를 위해 custom label이 필요했었는데 특정 label의 point로 build 여부를 결정짓는데 사용했다.

Custom label이 필요한지 여부를 판단하는 것은 어디까지나 SCM 정책에 따라 달라질 수 있고 그 설정과 관리는 대부분의 사용자들과는 관계가 없는 부분이다.

 

1. Project clone

Custom label을 적용하고자 하는 특정 project (저장소)를 clone 한다.

Gerrit의 branches 메뉴를 보면 refs/meta/config 라는 reference가 존재하는데 일반적으로 master branch가 항상 있는 경우 refs/meta/config를 checkout 하지 않으면 보이지 않는다.

비어있는 project를 대상으로 하면 (branch가 없음) clone 하면 바로 유일한 reference인 refs/meta/config의 내용이 나타난다.

 

2. project.config 수정

refs/meta/config에는 project.config와 groups 파일이 있는데 (모든 경우를 살펴본 것은 아니라서 다른 파일이 추가되어 있을 수도 있음)

groups 파일에는 access control에 추가되어 있는 관계된 group 정보가 포함되어 있고 custom label 설정과는 관계가 없다.

project.config 파일을 열어보면 access control에 대한 내용과 project 일반적인 설정들이 포함되어 있는데 (description 등) 추가할 label에 대한 내용을 정의한다.

보통 이런 형태로 작성하면 되는데

[label "test label"]

function = NoOp

value = 0 Do Not Build

value = +1 Build Now

추가 상세 설정은 Gerrit 문서를 참조해서 진행한다.

function을 NoOp으로 설정한 경우 submit 여부를 결정하는데 test label이 영향을 미치지 않는다. (기존 정책에 따라 submit 여부가 결정됨)

value는 설정한대로 부여할 point의 범위가 결정되는 역할을 한다.

 

3. Commit / Push

소스코드와 동일하게 저장소 변경사항이 발생했으므로 commit을 하고 push를 한다. (Push 할 때 refs/meta/config를 지정하는 것은 기본)

Gerrit의 branches 에서 refs/meta/config의 내용을 확인해 변경사항이 제대로 반영되었는지 확인이 되면 Access Control 메뉴에서 설정할 때 내가 추가한 test label 설정이 가능한 것을 확인할 수 있다.

 

4. 결론

일반 개발자들이나 사용자들은 어쩌면 알 필요가 없는 기능이다.

하지만 이런 것도 Gerrit이 제공한다.

알아두면 CI 구성이나 SCM 정책을 좀 더 유연하거나 강화시키는데 도움이 될것이라고 본다.

국내에서는 이런 custom label 사용보다 사실 Gerrit이 제공하는 기본 기능, 정책들만이라도 잘 지킬 수 있기를 희망한다.

· 3 min read

Azure에서 VM 생성시 disk size가 30GB 밖에 되질 않는다.

운영체제가 올라가는 disk이고 다른 data 들을 위한 공간은 disk를 하나 더 생성해서 붙여도 되겠지만 그럴 경우 linux는 추가로 mount를 해야 하고 내가 원하는 경로로 설정하기 위해서는 다른 작업을 거쳐야 할 수 있다.

이런 경우 운영체제가 올라가 있는 disk 자체를 resizing 할 필요성이 생기는데 (아무리 그래도 사실 30GB는 작다. 왜 최초 VM 생성시에 disk size를 지정할 수 없을까?) MSDN이나 기타 여러 곳의 자료들을 보면 내용이 좀 복잡하다. 보통 이런 것 같다.

1. VM 삭제

2. VHD download

3. VHD resizing (별도의 tool을 이용)

4. VHD upload

5. VM 다시 생성

다른 과정이야 그냥 넘어간다 하더라도 download / upload가 걸린다. 30GB 짜리를 다운로드하고 늘려서 다시 업로드를 해야 한다니.

그래서 더 조사를 해봤더니 역시 나와 같은 고민을 하는 사람이 있었고 그 양반이 괜찮은 솔루션을 제시해 놨다.

그 과정은 아래와 같다.

1. VM shutdown

2. VM 삭제 (삭제할 때 drive는 유지하는 옵션을 골라야 한다)

3. VM의 disk 삭제 (삭제할 때 VHD를 유지하는 옵션을 선택한다. 그럼 VHD 파일은 storage에 그대로 남아있게 됨)

4. WindowsAzureDiskResizer로 VHD resizing (Azure storage에 올라가 있는 그대로 resizing 됨)

5. Disk 생성 (이제부터는 거꾸로 반복, resizing된 VHD로 disk를 생성한다)

6. VM 생성 (5의 disk를 선택하고 원래의 VM 내용대로 설정한다)

 

결론

VHD 파일을 분석해서 괜찮은 툴을 만들고 그걸 오픈소스로 공개한 Maarten Balliauw 덕분에 좀 편해졌다.

그래도 VM 삭제하고 다시 생성해야 하는 과정이나 애초에 disk size 선택이 불가능한 부분은 개선이 필요해 보인다.

 

참조

1. Expanding an Existing Azure VM System Drive : 여기에 설명된 과정에 백업이 있는데 별로 중요하지 않거나 귀찮다면 skip 해도 무방하다

2. Tales from the trenches: resizing a Windows Azure virtual disk the smooth way

· 6 min read

AWS, Azure 등을 사용하면서 로그 확인중에 누군가가 지속적으로 SSH 로그인 시도를 하는 것을 확인했다. IP를 확인해보니 대부분은 중국이었는데 개중엔 네팔도 있더라. 다른 계정은 알기가 어려우니 당연한 거겠지만 항상 root 계정으로 로그인을 시도했는데 그냥 두어도 무슨 문제가 있겠냐 싶었지만 뒤돌아서면 찜찜한게 마음에 걸려서 아래의 방법을 사용해보기로 했다.

 

1. ACL 설정

ACL에 특정 IP와 subnet을 등록해서 접근을 제어하는 방식을 일반적으로 많이 사용하는 것 같다. 원격지 또는 클라우드 환경에서 중요한 보안을 강화할 수 있는 간단하면서도 확실한 방법이라는 생각을 한다. 현재 사용하는 Azure에서는 설정이 매우 간단하다. 사실 복잡할 이유도 없다. 리스트에 넣기만 하면 되는거니까. Azure에서는 AWS와 달리 Endpoints 항목에서 열어놓을 port를 설정하는데 (AWS는 Security group 이라는 이름으로 관리한다) 현재 문제가 되는 서비스가 SSH라서 SSH에 대한 ACL만 설정했다.

acl

위 그림처럼 모든 IP에 대해서는 접근을 거부하고 특정 subnet에 대해서만 허용하도록 했는데 subnet이 다른 환경에서 접근이 필요한경우 ACL에 추가 설정을 해야 하겠다는 생각이 들었다. 집이나 카페에서 접속하는 경우도 있고 때에 따라서는 테더링으로 연결하는 경우도 있는데, 또 나 혼자만 SSH로 접속할게 아니지 않는가. 이렇게 환경이 변경될 때마다 리스트를 추가하는건 귀찮은 일이 아닐 수 없다. 그래서 다른 방법을 생각해야만 했다.

 

2. VPN

ACL에서 관리할 리스트를 최소로 줄이기 위해서는 Azure에 접근하는 경로를 최소한으로 줄이면 된다. 하지만 실제는 여러 경로이기 때문에 여러 경로를 최소한으로 줄일 수 있는 방법을 찾으면 되는 건데, 여러 방법이 있을 수 있지만 우선은 VPN을 구성해 보기로 했다. (RDP로 특정 서버에 접속해서 할 수도 있겠다는 생각을 하는데 VPN에 비해 상대적으로 귀찮을 것 같다) 구성하면 아래와 같은 그림이 된다.

vpn

난 VPN server를 구축하면 되고 SSH 접속이 필요한 사용자들은 VPN에 연결한 후 SSH를 사용하면 된다. VPN server의 IP에 대해서만 접근을 허용하도록 ACL에 subnet을 추가하면 불편함도 좀 덜고 동시에 SSH 로그인 시도는 막을 수 있다.

 

3. VPN 구성

공유기에도 VPN server 기능을 할 수 있는게 있다는 것 같은데 불행히도 가지고 있는 공유기들은 지원하지 않았다. 그래서 그냥 ubuntu 12.04에 설정하기로 했는데 2가지 방법을 시도해봤다. 많이 사용한다는 OpenVPN을 (이름도 마음에 든다) 우선 적용해봤는데 설정이 약간 복잡하고 몇가지 문제가 있었다. 가장 큰 걸림돌 중 하나가 OS X이나 Windows에 기본으로 사용 가능한 VPN 연결 기능에서 프로토콜을 지원하지 않는 것이었다. 별도의 client tool을 사용해야만 하는 것 같은데 VPN 연결마저도 귀찮을 수 있는데 따로 툴을 설치해야 한다는건 더 귀찮을 것 같았다. 그래서 pptpd를 사용하기로 했다. Ubuntu에 사용되는 pptpd는 OpenVPN에 비해 설정도 상대적으로 간단했다. 설정했던 내용은

(1) apt-get으로 pptpd 설치

(2) VPN에 연결하는 client에 분배할 IP 대역 설정 (/etc/pptpd.conf)

(3) 네임서버 설정 (/etc/ppp/pptpd-options)

(4) VPN 계정 및 허용 IP 설정 (/etc/ppp/chap-secrets)

(5) IP forwarding 설정 (/etc/sysctl.conf)

(6) iptables masquerade 설정

 

VPN 구성하다보니 네트웍 부분에 대해 더 깊게 알아야겠다는 생각이 든다.

· 6 min read

이 글이 작성된 해는 2014년도입니다. 최근(2016년 ~) 유행하고 있는 추천서비스 등과는 관련이 없는 내용이고 개인적인 필요에 의해서 뭔가 실험하고 작성한 내용이에요. 방문자가 별로 없는 블로그이지만 검색 등을 통한 이 글로의 유입량이 많아서 혹시 오해가 있을까하여 미리 밝혀둡니다.


복수의 아이템이 들어있는 자료구조에서 추첨을 해야하는 경우가 있다. 보통 추첨을 한다하면 무작위로 선택되어야 하는데 때에 따라서는 특정 아이템의 선택 확률을 높여야 할 수도 있다.

 

언어에 따라 조금 차이가 있기는 하지만 보통 random number 생성에 관계된 API들은 수학과 관련된 package로 묶여 있거나 연산에 특화된 기능들끼리 모여있다. 따라서 단순 random number 생성 이외의 기능, 가중치를 고려하는 부분은 직접 구현할 수 밖에 없다. 또는 가중치 고려가 가능하게 만들어진 오픈소스 라이브러리가 있을지도 모르겠는데 그리 복잡하지 않을 것 같아 직접 구현하기로 했다.

 

1. 가중치를 통해 선택확률 높이기

아래의 그림을 보면 윗 부분은 가중치가 1로 동일한 상태이고 아래는 특정 아이템에 가중치를 더 높임으로써 선택될 확률을 높인 상태이다. 칸으로 구별된 bar를 다루게 될 아이템이 담겨있는 자료구조로 보자. 각 칸에는 하나의 아이템이 담겨있고 좌측을 시작으로 우측으로 갈 수록 index가 높다고 하자. random_weight

 

이렇게 하는 것이 어떻게 선택될 확률을 높일 수 있을까?

Java를 기준으로 random number 생성을 살펴보면 단순히 Math.random() 호출시 0과 1사이에 있는 double 값을 생성해서 돌려주게 되어있다. (정확히 0.0 이상 1.0 미만의 값) Random number의 range를 0 ~ total weight로 설정하면 위 그림의 bar 상단에서 좌측에서 우측으로 증가하는 1차원 그래프를 상상해볼 수 있다. 즉 생성된 random number 가 찍히는 점의 아래에 있는 아이템이 선택될 수 있다.

Weight가 동일한 경우는 그래프에서 차지하는 영역이 동일하기 때문에 random number가 동일한 확률로 생성된다면 아이템이 선택될 확률도 동일하다고 볼 수 있다. 반면에 특정 아이템의 weight가 높은 경우 차지하는 영역이 넓어지기 때문에 그만큼 그 영역안에서 random number가 생성될 가능성이 다른 영역에 비하면 높아진다.

 

2. 그렇다면 구현은 어떻게 할까?

위 그림과 그래프를 상상해보면 구현은 간단하다. 각 아이템이 갖는 가중치를 모두 더해서 Math.random() 등으로 random number를 생성할 때 0부터 가중치합 사이의 값이 생성되도록 한다. (역시 언어에 따라 다르지만 random number 생성시 seed 값을 설정할 수 있어야 random number 생성의 중복을 방지할 수 있다. Java의 경우 Math 보다는 Random class를 사용하는게 나을 것으로 판단됨) 그렇게 생성된 random number를 가지고 자료구조에서 index를 증가시키며 각각의 아이템이 가진 가중치를 뺀다. (가중치를 빼지 않고 더해서 하는 방법도 있을텐데 그 경우 random number와의 비교구문이 약간 달라져야 할 것이다) 그렇게 진행하다보면 어느 순간 random number가 0이나 음수가 되는데 그 때의 아이템이 가중치에 따라 선택된 아이템이 된다. Pseudo code로 간단하게 작성하면 아래와 같다.

List<Item> list = getItemList();
double total = getTotalWeight(list);
for(int i = 0; i < list.size(); i++) {
total -= list.get(i).getWeight();
if(total <= 0) {
selectedIndex = i;
break;
}
}
return list.get(selectedIndex);

· 4 min read

아래와 같은 단순한 구조를 가진 service에서 android app (Phonegap)이 AJAX로 API server와 SSL 통신을 하고 있다. SSL 설정은 reverse proxy 역할을 하는 NginX에 되어 있는 상태였는데 개발단계에서는 나타나지 않았던 문제가 app publish 이후에 발생해서 현상과 해결책을 정리해본다.

android_ssl

 

1. 현상

App에서 API call을 했는데도 오류나 정상 응답이 떨어지지 않는다. API server 쪽에서 로그를 확인해보니 호출된 기록이 없다. 전혀 호출되지 않는다고 판단할 수 있었다. 혹시나 싶어서 NginX의 로그도 확인해봤는데 access 자체를 하지 않는 것으로 보였다. (호출 후 access log, error log 모두 기록되는게 없음)

두번째 이상한 현상은 android app의 manifest에서 debuggable 설정에 따라 API 호출이 되거나 되지 않는다는 사실이었다. debuggable이 true (debug mode)인 경우에는 API 호출에 문제가 없었는데 publish를 위해 packaging 하려고 debuggable을 false로 바꾸면 호출이 불가능했다.

 

2. 조사

Stackoverflow에서 힌트를 찾았는데 자문자답한 사용자의 얘기로는 android app의 debug mode에서는 인증서 확인을 하지 않는데 그렇지 않은 경우 SSL 인증서를 엄격하게 검사한다고 한다. (http://stackoverflow.com/questions/14363994/android-debuggable-false-causing-jquery-ajax-post-to-fail-in-cordova-phonegap-ec) 그래서 링크된 ssl checker로 API service되는 url (NginX가 처음 받는 url)을 검사해봤더니 다른건 문제가 없었는데 인증서 체인이 제대로 되어있지 않았다. Root CA 인증서가 없다는 내용의 메세지와 함께.

 

3. 해결

Startssl에서 인증서를 발급받아 사용하고 있었는데 생각해보니 도메인에 대한 인증서와 그에 맞는 private key는 발급받았는데 startssl(CA)에 대한 인증서는 없었다. Startssl에서 안내하는대로 ca.pem, sub.class1.server.ca.pem을 추가로(내가 사용하는게 startssl의 class1 certificate) 받아서 기존의 인증서를 합쳐 인증서 체인을 만들고 NginX에 설정했다. (https://www.startssl.com/?app=42)

설정 이후에 다시 SSL 검사를 해보니 아래처럼 문제있던 부분이 정상. Android app도 수정없이 제대로 호출되는 걸 확인했다.

ssl_check

 

 

4. 결론

나의 경우엔 CA의 인증서 하나를 누락한 경우지만 개발할 때 self sign된 인증서를 사용하는 경우도 있는데 이 경우에도 publish 할 때에는 반드시 교체해야 한다. 이 부분은 사실 개발할 때 문제가 없었기 때문에 간과하고 넘어가기 쉬운 부분인데 publish 이전에 packaging 해서 한 번 확인은 해봐야 할 것 같다. 아니면 Android developer site에서 발견한 StrictMode class를 이용하는 것도 방법이 될 수 있을 것 같다. (http://developer.android.com/reference/android/os/StrictMode.html)

· 4 min read

부모님용으로 무작정 구매했다.

SD 카드도 필요해서 마트에 가서 Sandisk 8GB짜리 하나도 집었다. 할인해서 7000원대.

Class도 적혀있지 않고 bulk인 것처럼 생겼는데 그냥 써볼거라 문제되지 않을거라 생각했었다. 하지만 어떤 것들은 사용할 수 없는 것 같기도 하다. (SD Card compatibility list)

1. Raspbian 준비

공식 페이지에서 Raspbian (데비안 계열 raspberry pi용 linux os) 이미지를 다운로드 받은 후 (엄청 느림, http://www.raspberrypi.org/downloads) dd command로 부팅 가능한 SD card를 만들었다. Guide에는 좀 헷갈리게 되어있는데 /dev/disk_n_s_n_ 형태가 아닌 /dev/disk_n_ 경로를 사용해야 한다.

2. 기타 장치 준비 (PS/2 문제)

Display는 HDMI로만 연결 가능하다. 무선 인터넷은 나중에 설정하면 가능한 것 같기도 한데 Model B의 경우 우선은 유선으로만 가능하다. 키보드와 마우스를 연결해야 하는데, Model B는 USB Port가 2개 뿐이고 PS/2 port는 보이지 않는다. 아쉬운대로 PS/2 to USB 젠더를 이용해서 전원을 연결해봤다. (Raspberry pi는 USB 전원을 연결하자마자 부팅된다. 별도 전원버튼 없음)

boot_log

사진처럼 여느 리눅스처럼 부팅로그가 나타나고 설정 화면으로 이동하는데 로그상으로만 보면 문제점은 없었으나 키보드를 인식하지 못했다. 자료를 찾아보니 PS/2 type 키보드나 마우스의 경우 소모전력 문제로 Raspberry pi에서는 인식이 잘 안되는 것 같다. 특정 젠더나 별도 전원이 있는 hub 같은 걸 사용하면 되는 경우도 있는 것으로 보이나 내가 사용한 젠더로는 인식 불가.

USB용 키보드도 가격이 꽤 나가고 USB port 수도 제한적이라 USB용 RF를 사용하는 키보드/마우스 콤보를 구매했다. (핫트랙스에서 17,900원) 바로 사용가능했음.

3. 인터넷

부팅 / 설정을 끝내고 X window를 띄웠다.

xwindow

X window에 포함된 기본 브라우저 중 하나인 Midori를 실행해서 이메일 확인 및 몇가지 검색을 해봤는데 좀 답답한 감은 있지만 사용못할 수준은 아니다. (SD Card를 class 높은 걸로 바꿔서 다시 해 볼 예정)

4. 기타

최초 부팅 후 설정을 마치지 않더라도 ssh 접속이 가능하다. 접속 계정 정보는 pi / raspberry 이며, sudoer로 등록되어 있는 것 같으니 root 계정을 꼭 사용할 필요는 없다. 또 키보드/마우스, 모니터가 없어도 ssh 접속 상태에서 기본 설정을 진행할 수 있다.

· 6 min read

빌드와 배포를 자동화하는 작업을 진행하는 도중에 Database에 data를 쓰고 업데이트 하는 기능이 필요하게 되었다. 이 경우 여러가지 방법이 있을 수 있지만 최대한 간단하게, 추가 개발없이 진행하고 싶었다. (Shell script에서)

1. 과거에 사용했던 방법들

간단히 Java로 DB와 connection을 맺고 CRUD를 하는 모듈을 개발해서 사용했던 적이 있다. Jar로 묶어 놓으면 script에서는 jar에 parameter만 몇 개 넘겨서 실행하면 가능했다. 하지만 난 그 당시의 소스를 가지고 있지 않고 간단하더라도 개발을 추가로 하기가 귀찮았다. 시간도 없었고.

두번째로 groovy script를 사용했었다. Groovy 자체가 java와 유사한 부분이 많기 때문에 작성이 어렵지 않았고 그렇게 만들어진 groovy script를 shell에서 호출하는 것도 어렵지는 않다. 하지만 역시 추가로 script를 구현하는게 번거롭고 어딘가에 script를 보관하고 사용해야 한다는게 마음에 걸렸다. 난 단지 하나의 shell script로만 해당 기능을 구현하고 싶었다.

마지막으로 사용해봤던 방법은 REST API를 구현하고 shell script에서는 curl을 이용해 REST API를 호출하는 방법인데, 꽤 괜찮은 방법이 아닌가 생각했었지만 역시 REST API를 구현해야 하는 부담이 있었다. 하지만 대규모 개발이 아니라면 node.js로 충분히 할만하다. (간단하면 개발하는데 그리 오래 걸리지도 않는다)

2. Command line에서 query 실행하기

그동안 사용할 일이 없었기 때문에 MySQL client 실행옵션 중에 -e가 있다는 걸 이번에 알았다. -e 옵션은 뒤에 오는 query 문을 실행해주는 역할을 하는데 이 옵션만 사용하더라도 단 한 줄의 명령으로 원하는 기능을 수행하게 만들 수 있다.

3. Password prompt

한 줄의 명령으로 원하는 기능에 근접했지만 항상 password prompt가 뜨는 문제에 봉착했다. expect를 사용하거나 하면 되겠지만 그것보다 간단한 방법을 원했다. 그리고 찾은게

mysql -uuser_id -ppassword

-p 옵션에 password를 붙여쓰면 따로 묻지 않는다. 그 사이에 공백이 있다면 password prompt를 띄우라는 걸로 인식하고 뒤에 있는 password를 사용하려는 DB schema로 인식한다.

4. Inserted id를 알고 싶어요

또 다른 문제. DB에 insert 하고 특정 작업 이후에 insert된 레코드를 update 해야 했는데 id 이외에 유일한 값을 특정하기가 어려웠다. 강제로라도 유일한 값을 만들수는 있을 것 같았는데 그것을 위해 DB 구조를 변경해야 할 것 같아서 마음에 들지 않았다. 그래서 생각한 방법은 insert 이후에 아래의 query를 바로 실행하는 것이었다.

select last_insert_id();

마지막으로 추가된 id를 알려준다.

5. Shell script에서 text로 된 query 결과를 parsing 해야 하는가?

위의 문제를 해결하니 다른 문제가 등장했다. MySQL client에서 직접 select query를 실행하면 결과를 mysql만의 형태로 돌려준다는 것이었다. Json이나 xml과 같은 정규화된 문자열이 아니라 특수문자로 column의 경계가 그려진 문자열들. 처음엔 이것을 parsing 해야 하나 생각했는데 말도 안되는거라 생각했다. 의미도 없고. 그래서 찾은게 -s와 -N 옵션인데, -s는 silent를 -N은 column name 출력을 하지 않는다. 어차피 마지막에 추가된 id만 알면 되기 때문에 column은 단 하나뿐이고 진정 내가 원하는 것은 그 column의 값일 뿐이다. 두 옵션을 사용해 query를 실행하면 id만 달랑 떨어진다.

6. 결과

mysql -uuser_id -ppassword db_schema -s -N -e "insert_query_with_last_insert_id"

위의 형태로 실행하면 password를 묻지도 않고 insert를 한 후 추가된 id만 받을 수 있다. 단 한줄만으로.

Password가 공개될 여지가 있는데 insert 하려는 값을 parameter로 받는 별도의 script 파일로 만들어서 읽기권한을 제어하는 방법을 사용하는게 어떨까 생각한다. 그게 간단하니까.

· 4 min read

Amazon의 S3 서비스를 사용할 때 기본 설정만으로는 upload 한 파일에 대한 접근이 안된다.

Permission 설정이 있길래 건드려 보기도 했는데 permission 만으로는 해결할 수 없었다.

이 부분은 조금 이상하다. 많은 사람들이 permission 설정만으로 접근 권한 제어가 가능할거라 인식할 거라고 보기 때문이다.

또 서비스들이 계속 변경되어서 그런지 검색을 통해 얻는 정보들이 부정확한 것들이 많아서 정리해보기로 했다.

1. 현상

Browser로 간편하게 확인해보기 위해 image를 upload 했다.

그 image의 properties를 확인하면 기본 정보들이 표시되는데 그 중에 link를 열어보면 아래와 같은 화면이 나타난다.

 

XML 형태로 output을 내주고 있는데 AccessDenied로 표시하고 있다.

access_denied

2. Policy 설정

결론부터 얘기하면 모든 resource는 기본적으로 private이라 policy 설정을 해야 접근이 가능한 것으로 보인다. Policy는 (S3에서 얘기하는) bucket 마다 설정이 가능한데, 하위의 디렉토리나 각각의 파일에 대해서는 설정할 수 없다. Bucket의 Properties를 열고 Permission 항목을 확인하면 bucket policy 추가하는 버튼이 있다.

버튼을 눌러보면 텍스트 입력 팝업이 나타나고 하단에 AWS Policy Generator가 보이는데 처음이라 policy의 형식을 잘 모르니 generator를 사용해봤다. Generator를 열어서 필요한 입력 필드에 원하는 정보를 입력한다.

s3_policy

Principal은 policy 적용 대상(사용자)을 의미하는데 익명 사용자에 대해 지정하고 싶다면 *로 입력하고, ARN (Amazon Resource Name)은 표시된 형식대로 입력한다. (arn:aws:s3:::<bucket_name>/<key_name>) Action은 S3에 대한 약간의 지식이 필요한데, 이미지 표시 및 다운로드 (어차피 같은 의미)만 테스트 해볼 것이므로 GetObject를 선택한다. ARN의 key_name은 resource에 대한 key를 의미하는 것으로 보인다. 나의 경우엔 특정 디렉토리에 있는 모든 image를 대상으로 하므로 arn:aws:s3:::my_bucket/sub/dir/* 형태로 입력했다.

모든 필드를 채워서 Generate Policy 버튼을 누르면 S3에서 원하는 형식의 텍스트를 표시해준다. 복사해서 이전의 Bucket Policy Editor에 붙여넣기 한 후 저장하면 적용됨.

3. 결과

아까 전 AccessDenied 응답을 받았던 link를 그대로 열어보면 image가 제대로 browser에서 표시된다. 다른 사용자나 특정 referer에 대한 허가, 거부 등의 세밀한 조정이 필요할 수 있겠다 싶은데 그 부분은 Example Cases for Amazon S3 Bucket Policies를 좀 더 참고해봐야한다.

· 6 min read

이전에 pull request 한 것에 대한 메일이 왔다.

1. Commit에 대한 comment

스크린샷 2014-02-10 오후 2.20.31

누군가가 github에서 내가 올려둔 pull request에 comment를 달았는데 같은 내용이 메일로 온 것이다. 내용은 내가 수정할 때 사용한 ENT_IGNORE라는 option (flag)가 보안 이슈가 있는 건데 사용한 특별한 이유가 있냐는 것이었다. 앞서도 언급했지만 난 PHP를 잘 모른다. Flag list들을 문서에서 참고했을 때 있으면 좋을 것이라고 생각했던 것이었는데 그게 보안 이슈가 있는지는 미처 몰랐다.

추가로 comment 단 사람이 관련 문서도 함께 수정해 달라고 요청했다. 문서가 있는지도 몰랐네.

스크린샷 2014-02-10 오후 2.21.09

그리고 contribution 해준게 고맙단다. 사실 나도 고맙다. 내 입장에서는 경험을 쌓는건데 그걸 또 고맙다고 하니까. 뭔가 훈훈하다.

2. 정보 수집

제기된 보안 이슈는 정말 그런 것일까? 문제가 된 ENT_IGNORE에 대한 자료를 찾아보자. 우선 사용한 함수 htmlentities에 대한 문서부터 다시.

스크린샷 2014-02-10 오후 2.30.46

아. 문서(http://kr1.php.net/htmlentities) 자체에도 언급이 되어있다. may have security implications 라고. 왜 미처 저 부분을 못 봤는지...(공식 API 문서에도 언급된 부분이라 신뢰도는 높다고 판단된다) 보안 이슈에 대해 더 자세히 확인하고 싶지만 생략하기로 한다. 기술적인 부분 보다는 open source 활동과 과정에 대한 정리가 지금은 중요하다고 생각하기 때문이다.

3. 작업

어찌되었든 혹시나 해서 넣어둔 flag인데 빼도 문제가 없는지 검토해 보기로 한다. 제거하는 것으로 코드를 수정한 후에 문제가 없는지 테스트를 진행했다. 다행히 ENT_IGNORE를 제거함으로 인해 발생하는 문제는 없었는데 또 다른 문제를 발견할 수 있었다. AChecker가 XML을 생성하면서 정의되지 않은 entity가 포함되는 경우가 있었는데 이에 대한 정의가 없었기 때문에 정상적인 XML로 인식되지 못했다. 그래서 보너스로 그 부분까지 함께 수정. 그리고 commit / push.

4. Pull request에 대한 update

이전에 올린 pull request를 제거하고 다시 등록해야 하나 고민을 했다. 고민을 하면서 최소한 이전에 comment 단 사람에게 댓글은 달아줘야겠다는 생각이 들어서 github에 가보니...

스크린샷 2014-02-10 오후 2.23.51

 

이전의 comment 아래에 내가 fork한 저장소로 push 했던 수정사항이 자동으로 달려있다. Comment에 수정할 파일과 라인넘버까지 명시되어 있었기 때문에 그 부분을 수정한 commit을 자동 감지하는 것인지, 원래 pull request로 등록한 branch에 대한 모든 변경사항들이 pull request가 close 되기 전까지 자동으로 update 되는게 맞는지는 좀 더 살펴봐야 하겠지만 일단 예상했던 자잘한 작업을 안해도 되기 때문에 무척 편리하다는 생각이 들었다.

마지막으로 수정한 부분에 대한 comment를 달아줬다. 영작이 이상하더라도 문제 삼지는 말자. 원래 영어를 잘하지도 못하고 native도 아닌데 우선은 의사전달만 제대로 되면 큰 문제는 없다고 본다. 그래도 영어공부는 계속 해둬야 겠다는 생각은 한다.

 

역시 이 작업까지 마치고 다음을 기다리기로 했다.

· 4 min read

역시 메일이 왔다. 참 재미있는 세상이 아닌가? 어디에 있는지도 모르고 얼굴도 모르는데 하나의 공통된 주제 때문에 메일을 주고 받을 수 있다니.

1. Merged and beautiful work

메일의 내용은 단순한 메세지였다. Merged #41. 41번째 merge인 것이다. 메일 본문이 어차피 github에 등록된 comment이니 github으로 가본다.

스크린샷 2014-02-10 오후 2.55.17

별 문제가 없었는지 (사실 문제의 여지가 별로 없다. 비즈니스 로직을 수정한 것도 아니고 단순히 버그가 있는 부분을 약간 고친 것에 불과하니까) 내 pull request를 받아줬다. 그래서 merge를 했다. 내가 수정한 부분을 모르는 타인이 받아줬다는 것도 상당히 흥미로운데, beautiful work라고 지나가는 말로라도 한 마디 던져준다. 그래 고맙다. 너네도 beautiful work를 많이 해왔구나. 역시 훈훈하다.

Open source 마다 차이가 있다고 알고 있지만 한두건의 commit 만으로는 contributor로 등록되지 않을 수 있다고 어디선가 봤던 기억이 있는데 혹시나 싶어 contributor list를 열어봤다.

스크린샷 2014-02-10 오후 2.55.46

우오오...젠장. Contributor에 들어있다. 내가 한 건 단지 몇 개 고친 것 뿐인데 기여했다고 인정해주다니. 혹시 pull request 받아들여지기만 하면 자동으로 등록되는거 아닌가? 모르겠지만 여하튼 기쁘다.

2. Open Source 활동은 자격증을 취득하기 위한 과정이 아니다.

AChecker와 관련된 작업을 마치고 생각을 해보았다. 이게 사실 자랑할 거리는 아니지 않는가? 라고. 계속 기록했지만 PHP를 잘 아는 것도 아닌데다가 엄청나게 좋은, 효율적인, 아름다운 코드를 나열한 것도 아니고 많은 부분을 수정하거나 하지 않았기 때문에 내 현재의 능력을 표현하지는 못할거라는 생각이 든다. 그렇기 때문에 '나 contributor, 혹은 committer에요' 라고 내세울만한 그런 일은 아닌 것 같다.

하지만 내가 이런 저런 부분에 관심이 있으며, 흥미와 재미를 느끼고 있다는 점에 대해서는 어필하는 것은 충분히 가능하다고 생각한다. 실제로 업무 이외에 작은 시간을 쪼개서 진행을 했고 이런저런 과정을 거쳐 얻은 성과이기도 하고 그 과정 자체가 충분히 재미있었기 때문에 앞으로도 이런 활동을 지속하게 될 것 같다.

 

Open source 활동은 자격증을 취득하기 위한 과정이 아니다. 그냥 그 과정 자체를 즐기는 과정이다. 정도로 결론내릴 수 있지 않을까.

AChecker에 또 수정할 부분이 보여서 pull request 하러 간다.