AWS S3 에서 직접 다운로드 금지하기

AWS S3 의 객체를 직접 다운로드를 보안상 금지해야 하는 경우가 있다. 이를 위해서 AWS S3 에 정책을 다음과 같이 하면 된다.

s3:GetObject 액션에 대해서 거부 정책을 적용하고 Referer 를 이용해서 특정 URL 을 지정해주면 된다.

AWS S3 HTTPS 강제

AWS S3 와 통신을 하는 방법으로 HTTP, HTTPS 두가지 방법이 있다. 하지만 HTTPS 만으로 통신을 하기 위해서는 다음과 같이 정책을 지정해 줘야 한다.

참고: AWS Config 규칙 s3-bucket-ssl-requests-only를 준수하려면 어떤 S3 버킷 정책을 사용해야 합니까?

AWS ATHENA 로 VPC FLOW LOG 분석하기 – 2

이전 글에서 AWS 의 Athena 를 이용한 VPC Flow Log 를 어떻게 분석하는지에 대해서 이야기 했다. VPC Flow Log 생성부터, S3 버킷 생성, Athena 데이터베이스와 테이블 그리고 Lambda 를 이용한 파티션 추가까지 비교적 많은 부분을 손봐야 했다.

이 방법은 파티션 작업을 Lambda 를 이용하는 방법으로 하루에 한번 실행시키도록 하고 있다. 하지만, AWS 에서는 이마져도 필요 없는 방법을 제공하는데, 그것이 바로 파티션 프로젝션(Partition Projection) 이다.

AWS 메뉴얼 주의사항

파티션 프로젝션을 하기 위해서 AWS 메뉴얼을 보고 따라했는데 되지 않는다. 정확히는 테이블 생성이 되지만 Athena 에서는 보이지 않는다.

Athena 의 데이터베이스는 Glue 를 이용한다. AWS Glue 가 가보면 Athena 의 테이블을 볼 수 있는데, AWS 메뉴얼대로 파티션 프로젝션을 생성하면 Glue 에는 나오지만 Athena 에는 안나온다. 이는 Glue 에서 S3 저장소를 인식하지 못해 나오는 문제다.

다음의 메뉴얼에는 문제가 있다.

일단 위 메뉴얼에는 파티션 프로젝션이 무엇인지를 설명하고 있다.

위 내용을 요약하면 버킷의 구조가 다음과 같다는 것이다.

이런 구조에서 파티션 프로젝션을 걸어주면 자동으로 날짜시간으로 파티션이 형성된다.

VPC Flow Log 의 파티션 프로젝션

그렇다면 이제 VPC Flow Log 에 파티션 프로젝션을 걸어 테이블 생성해 보자.

위 쿼리문으로 테이블을 생성하면 AWS Glue 에서는 테이블이 생성되지만 Athena 에는 나오지 않는다. 그리고 AWS Clue 에서 테이블 속성을 보면 S3 저장소와 연결되어 있지 않다.

왜 그럴까?

파티션 프로젝션을 연결할때에는 S3 저장소에 저장된 위치는 물론이고 S3 에 저장된 값의 속성도 지정해 줘야 한다. 대표적인 것이 다음과 같은 것이다.

  • Row format delimited
  • Stored as inputformat
  • outputformat

파티션 프로젝션 없이 테이블을 생성할때에는 이 옵션을 지정해 주지 않았다. 그러면 Default 값이 지정되는데, 대부분 잘 맞는 것이였다.

하지만, 파티션 프로젝션을 할 경우에 속성들을 지정해주지 않으면 아무것도 안된다. 다음과 같이 파티션 프로젝션 테이블을 생성해준다.

위와같이 할 경우에 파티션 프로젝션 테이블이 잘 생성된다. 이렇게 생성하고 난 후에 AWS Glue 에서 테이블의 속성을 보게 되면 정상적으로 S3 버킷과 연결이 되어 있고 각종 속성들이 설정되어 있는 것을 볼 수 있다.

AWS Athena 로 VPC Flow Log 분석하기 – 1

AWS Athena 는 로그 분석 서비스로 Hive 와 같다. 가장 많이 쓰이는 부분이 VPC Flow Log 를 분석하는데에 Athena 를 이용하는 방법이다. 이 글에서는 어떻게 VPC Flow Log 를 Athena 를 통해서 분석하는 알아 본다.

VPC Flow Log 설정

VPC Flow Log 설정은 간단하다. VPC 에서 Flow logs 탭에서 설정하면 그만인데, 다음과 같은 파라메터를 필요로 한다.

  • Destination Type: S3
  • Destination Name: S3 로 지정했을 시에 S3 Bucket 이름.
  • Log record format: AWS default format
  • Log file format: Text (default)
  • Partition logs by time: Every 24 hours (default)

여기서 중요한 것은 밑에서 3가지 정도다. Log record format 을 바꿀 경우에 Athena 테이블 생성시에 맞춰야 한다. Partition logs by time 을 24 시간으로 하면 S3 버킷 안에서 2022/08/29 형식으로 폴더가 생성되면서 VPC 로그가 전송 된다. 하루에 한번 폴더를 생성하면서 로그가 쌓인다는 뜻이다. 만일 Every 1 hours (60 minutes) 으로 할 경우에 2022/08/29/09 폴더가 생성되면서 로그가 쌓인다. 이 폴더의 구조는 나중에 Athena 에서 파티션 프포젝션(Partition Projection) 을 설정할때에 참고하게 된다.

또, S3 버킷으로 전송할 경우에 S3 의 암호화를 SSE_S3 로 할 것을 권장한다. CMK 로 할 경우에 로그가 쌓이지 않을 가능성이 있다. 또, 향후에 권한지정에서 CMK 권한을 함께 줘야하는 복잡함이 있을 수 있다.

S3 버킷 확인

필자의 VPC Log 설정으로 인해서 S3 에는 다음과 같은 형태로 S3 에 로그가 쌓이고 있다.

버킷 이름만 지정해주면 그 안에 AWSLogs/계정ID/vpclfowlogs/ap-northeast-2/ 가 자동으로 생성되며 그 안으로 year/month/day 순으로 생성된다.

앞에서 VPC Flow Logs 설정할때에 Partition logs by time 에서 Every 24 hours (default) 로 지정했기 때문에 날짜별로 생성된다.

Athena 작업

작업그룹(Workgroups) 생성

먼저 Athena 에서 필요한 것이 작업그룹(Workgroups) 이다. 기본적으로 Primary 가 기본 생성되어 있지만 하나 생성한다. 생성할때에 필요한 것은 다음과 같다.

쿼리 결과를 받을 S3 를 지정해야 한다. 만일 암호화가 필요하다면 SSE_S3 를 권장한다. CMK 도 가능하지만 Role 설정을 잘 해줘야 한다.

데이터 사용량을 적절하게 조절해 주길 권장한다. 덮어놓고 좋다고 No limit 로 하는 순간 돈이 술술 나갈 것이다. 이 데이터 사용량은 얼마든지 설정을 변경할 수 있다.

Database 생성

Query Editor 로 이동해 화면 오른쪽 상단에서 앞에서 생성한 작업그룹(Workgroup) 으로 변경해 준다.

그러면 Workgroup 이 변경 된다. 이제 다음과 같이 Database 를 생성해 준다.

위 쿼리문은 화면안에 쿼리입력창에 입력하고 ‘Run’ 을 클릭해주면 된다.

이렇게 하면 데이터베이스가 생성이 된다. 그리고 왼쪽에 Database 부분에서 새로 생성한 데이터베이스를 선택해 준다.

위와같은 상태가 된다면 이제 테이블을 생성해야 한다.

Table 생성

이제 Table 을 생성해야 한다. 테이블을 생성할때에 중요한 것이 VPC Flow Log 의 S3 저장소와 데이터 컬럼들이다. 다음과 같다.

테이블을 생성할때에 컬럼을 지정해 줘야 하는데, VPC Flow Log 설정할때에 record format 을 AWS Default Format 을 지정했는데, 그 포맷은 위와 같다. 이 컬럼들은 S3 에 저장된 파일을 열었을 때에 맨 처음 나오는 행에 컬럼헤더 값들이다. 정확히는 ‘_’ 가 ‘-‘ 로 보면 정확하다. Athena 테이블은 ‘-‘ 를 ‘_’ 로 변환된다.

중요한 것은 Partitioned BY 부분에 date 부분이다. 테이블을 파티셔닝을 하기 위한 기준이 되는 컬럼을 추가하는 것이다. 이 파티션 컬럼은 S3 에 저장되는 VPC Flow Log 에는 없는데 파티셔닝 테이블을 생성할때에 이름처럼 생성된다.

위 쿼리문을 실행해 테이블을 생성한다.

파티션 생성

만일 파티션이 없다면 쿼리 시간이 길어진다. VPC Flow Log 의 경우 날짜로별로(yyyy/MM/dd) 쌓이는 것에 창안해 파티션을 날짜별로 생성하도록 할 것이다. 다음과 같이 파티션을 생성해준다.

이렇게 하면 2022/08/29 에 해당하는 버킷에 내용이 파티션으로 입력 된다.

파티션을 이용하면 데이터 조회시에 그 범위가 줄어든다. 정확하게는 데이터 스캔(Data Scan) 범위를 줄일 수 있어서 쿼리 속도를 높여줄 뿐만 아니라 스캔 범위가 줄어들기 때문에 데이터를 긁어오는 양도 줄게되어서 비용을 아낄 수 있다.

앞에서 만든 테이블의 경우 date 컬럼은 date 테이터 타입임으로 다음과 같은 쿼리가 가능하다.

date 타입이기 때문에 문자열을 date 타입으로 해줘야 한다.

파티션 생성 문제

파티션을 생성하면 문제가 하나 있다. 날짜별로 하나하나 다 생성해 줘야 한다. 시간은 흐르고 날짜는 변경될 것이다. 내일이 되면 다른 날짜로 S3 에 폴더가 만들어지고 거기에 데이터가 쌓일 것이다. 그러면 Athena 에서 그 날짜에 맞는 S3 저장소의 파티션을 생성해줘야 한다.

매일매일 하루에 한번 이것을 해야 한다고 생각하면 힘들다.

이것을 자동으로 하는 방법은 존재한다. Lambda 를 이용하는 것이다.

Lambda 작성하기

Lambda 실행을 위한 Role 생성

Lambda 를 작성해 자동으로 매일매일 하루에 한번 파티션을 생성하도록 해보자. Lambda 를 실행하기 위해서는 먼저 Lambda 실행을 위한 Role 이 필요하다.

Lambda 실행을 위한 Role 을 위와같이 생성해 준다.

Lambda 생성

Lambda 는 여러가지 언어로 작성될 수 있는데, 여기서는 Python 을 이용했다.

Lambda 를 실행하는 Roles 는 앞에서 작성한 Roles 를 지정해 준다.

EventBridge Rule 생성

EventBridge 에서 Rule 를 생성해 매일 자정 0시 0분에 람다를 실행하도록 설정해 준다.

KST 를 위한 Athena 테이블 View 생성

Athena 에 vpc_flow_logs 테이블에 start, end 컬럼은 unixtime 이지만 UTC 기반이다. 이것을 KST 기반으로 보기 위해서는 연산이 필요한데, 그것을 아예 View 만들어 놓으면 좋다.

이제는 vpc_flow_logs_kst 뷰(view) 에 질의를 하면 start, end 컬럼의 데이터가 KST 시간으로 표신된다.

결론

지금까지 VPC Flow Log 생성에서부터 Athena 를 이용하는 방법, 더 나가 자동으로 파티션을 생성하도록 Lambda 까지 작성해봤다.

하지만, Lambda 작성도 필요없는 방법이 있다. 파티션 프로젝션(Partition Projection) 이라고 불리는 방법인데, 이것은 처음 테이블을 생성할때에 S3 의 날짜 폴더 구조를 기반으로 자동으로 파티션을 인식시키는 방법이다. 이렇게 하면 Lambda 를 이용해 파티션을 수동으로 생성해줄 필요가 없게된다.

Spring Boot, error: constructor … in class .. cannot be applied to given types 오류

Spring Boot 로 프로그램을 작성하고 난 후에 Compile 단계에서 다음과 같은 오류를 만날 수 있다.

에러 코드를 보면 new 연산자를 이용해 Employee 객체를 생성하는 부분인데, 이부분이 문제가 된다는 것이다. required: no arguments 라고 나오지만 Employee 는 다음과 같이 되어 있다.

@AllArgsConstructor 어노테이션을 줘서 자동으로 모든 객첵 멤버변수를 인자로 받는 컨스트럭터를 생성하도록 하고 했다. 이것은 Lombok 을 이용한 것으로 다음과 같이 gradle 에서 의존성을 줬다.

문제는 Eclipse 나 IDE 툴에서는 SpringBoot 애플리케이션이 잘만 실행되지만 정작 컴파일을 할려고 하면 위와같은 오류가 나오는다는 것이다. 아무리 봐도 소스코드상에서는 아무런 문제가 없는데도 이런다면 다음과 같이 gradle 에서 annotationProcessor 를 추가해주면 된다.

Maven 을 사용할 경우에는 아무런 문제가 없었지만, Gradle 을 사용하면서 Lombok 을 사용한다면 반드시 annotationProcessor 를 추가해줘야 한다.

IntelliJ 에서는 설정에서 “Enabling Annotation Processing” 체크하면 된다.

컨테이너에서 Java 힙 덤프 뜨기

Kubernetes 에서 Java 애플리케이션을 운영할때에, Java 힙 덤프를 떠야하는 경우가 있다. 하지만 다음과 같이 덤프를 떠지지 않는다.

“Unable to get pid of LinuxThread manager thread” 오류가 발생한다.

이 오류가 나오는 이유는 Java 애플리케이션의 Pid 값이 1이기 때문이다. 이를 해결하는 방법을 소개한다.

Container 이미지에 tini 설치, 배포

먼저 Openjdk 의 컨테이너 이미지에 tini 프로그램을 설치해야 한다. 이 tini 라는 프로그램은 인자값을 받은 프로그램을 실행 시켜 준다. 이렇게 하면 tini 는 Pid 1을 가지지만 tini 가 실행시킨 프로그램은 1보다 큰 Pid 값을 가지게 된다.

문제는 Openjdk 에 tini 라는 프로그램이 없다. 더군다나 아무 컨테이너 이미지에 이것을 설치할 수 있는게 아니라 Alpine 기반 이미지에서 쉽게 설치가 가능하다. Alpine 에서는 패키지로 제공하기 때문에 명령어로 간단하게 설치할 수 있다.

Dockerfile 을 다음과 같이 수정한다.

apk 명령어를 이용해 tini 를 설치해주고 ENTRYPOINT 에 실행 명령어에 tini 를 넣고 인자값으로 java 애플리케이션 명령어를 넣는다.

이렇게 컨테이너 이미지를 제작하고 배포를 한다.

tini 프로그램 이 후 Pid

tini 프로그램으로 Java 애플리케이션이 어떻게 실행되는 다음과 같이 확인 할 수 있다.

jcmd 뿐만 아니라 jstat, jmap 등 모든 명령어를 사용할 수 있다.

mod_jk, SEVERE: Invalid message received with signature 해결

Apache 2.4 에 mod_jk 를 설치하고 Tomcat 9 와 AJP 연결 설정을 했다. 그런데, 어찌된 영문인지 AJP 연결이 되지 않으면서 다음과 같은 에러 메시지만 나왔다.

mod_jk 설정과 Tomcat 9 의 연결 설정은 아무런 문제가 없음에도 이런 오류가 발생하는 이유를 몰랐는데, 문제는 아주 단순했다.

address=”::1″

Tomcat 9 의 서버 설정인 server.xml 에 ajp 설정은 다음과 같다.

기본 설정값으로, address 에 할당된 값이 문제가 된다. address 에 값을 “0.0.0.0” 으로 바꾸던지 아니면 서버 IP 주소로 변경해 주면 된다.

secret=””

Tomat 9 에서 AJP 연결에서 주의해야 할 것이 secret 이다. 변경사항이기도 한데, ‘secretRequired=true’ 가 기본값으로 설정되어 있어 secret 값을 줘야 한다. 이것은 AJP 연결을 하기 위한 일종의 키값으로 mod_jk 설정에서도 해줘야 한다.

위와같이 secret 값이 일치해야지만 연결이 된다.

강남의 MSP 회사들이 IT를 망치고 있다

강남에 MSP 회사들이 많이 있다. Managed Service Provider 라고, 리셀러 개념이라고 하기에는 좀 애매하지만 그외 비슷한 회사들이라고 보면 된다.

아무래도 많은 회사들이 이 MSP 에 기술지원을 받기를 원한다. 왜냐하면 트렌드 자체가 그렇게 흘러가고 있고 이들에 대한 수요가 많다보니 MSP 에 대한 기대가 있는 것이다. 문제는 이러한 회사들이 썩 좋은 방법으로 사업을 영위하고 있지 않다는데 있다.

위험의 외주화.

우리 사회에서 지난 몇년간 나왔던 말들이 ‘위험의 외주화’ 이다. 원청이 위험성이 높은 일에 대해서 외주를 주어 그와 관련된 법망과 사회적, 도덕적 책임을 회피하는 수단으로서 계약을 하는 형태… 그래서 원청에 대한 처벌을 강화해야 한다는 것이 ‘중대재해보호법’ 의 요체다.

이 위험이라는 단어가 가지는 의미는 매우 다양하다. 제조업의 경우에, 특히나 뉴스에 보도되는 경우에는 대부분 제조업이 많이 나오는데 목숨일 잃는 경우이지만 IT 의 경우에는 그야말로 프로젝트의 위험요소를 말한다.

A 라는 회사가 Cloud 로 전환 작업을 위해서 MSP 에 프로젝트를 위임하게 된다. A 라는 회사는 당연히 전문적인 식견과 인력으로 전문스러운 뭔가를 기대할 게 당연한 것이다. 하지만 MSP 회사에서는 사람을 또 뽑는다.

니들의 PL 을 알아?

Project Leader. 많은 프로젝트를 경험하면서 느낀 거지만 PL 은 아무나 해서는 안된다. PM 의 경우에는 꼭 반드시 어떤 기술적인 능력을 기대하지는 않는다. 그냥 대충 IT 에 몸을 담았던 사람정도면 그만이다. 일종의 말이 통하는 사람 정도이면 그만이다. PM 의 경우에는 프로젝트 자체의 비지니스에 대한 처리를 많이 하기 때문에 실제로 구현되어지는 프로젝트의 기술적인 부분까지 신경쓰기는 사실상 힘들다. 고객과의 협상도 PM 이 하는 일이기 때문에 PM 이 사실상 피곤한 직위에 속한다.

하지만 PL 은 이야기가 달리진다. PL 은 프로젝트에 대한 기술적인 이해가 반드시 있어야 한다. 문제는 이 프로젝트에 대한 기술적인 이해라는 것이 반드시 ‘기술’ 만 이해한다고 되는게 아니다. 이 기술들이 전체적인 요구사항에 잘 조합되어지고 있는지에 대한 사항들을 주로 살펴야 하는게 PL 이다. 예를들어, 숲에 나무를 가지고 하트모양을 만든다고 할 경우에, 나무에 대해서 알 필요는 없지만 그렇다고 몰라서도 안되고 그 나무들이 하트모양이 되도록 잘 정리 정돈이 되고 있는지 조성하는 과정에서 잘 살펴야 한다.

기술적인 내용을 세세하게 알 필요는 없지만 큰 틀에서 숲을 볼 줄 알아야, 그 숲이라는게 숲을 구성하는 각 요소들이 있기 때문에 그걸 알고 있어야 한다, 프로젝트가 잘 굴러가게 되어 있다.

PM 도 프로젝트의 승부를 가르는 결정적인 인물이라면, PL 도 실체적인 프로젝트의 승패를 가르는 인물이기도 하다. 그만큼 책임이 매우 크다는 것이다. 프로젝트에 책임에서 벗어날 수 없는 인물들이 PM, PL 이다.

그런데, 강남에 MSP 회사들은 PL 을 프리랜서로 뽑고 있다. 프리랜서가 PL 을 못한다는 이야기가 아니다. 앞에서 이야기했듯이 프로젝트를 책임질 인물이기 때문에 어찌보면 고객사 A 에 대한 예의가 아닌 거다. 자본주의 사회에서 거래계약이란게 뭐든 못할까 만은 적어도 프로젝트를 책임질 회사가 직접 나서는게 아니라 PL 을 프리랜서에게 위임한다는게 과연 정당하다고 볼 수 있나…

마치 제조업에서 위험의 외주화 정도는 아닐지라도 도의적이나 도덕적으로 별로 바른 경우는 아니다.

내 손에 피는 안 묶힌다.

왜 PL 을 프리랜서들에게 맡길려고 하는 걸까? 그들이 보기에, 한눈에 봐도 프리랜서에게 PL 을 맡기는 건 문제가 있다는 인식은 다 깔려 있다. 그런데도 이렇게 하는 이유는 다음과 같다.

‘고상한 척’ 가면놀이

강남의 MSP 회사의 경우 외주 프리랜서들을 직접 뽑지 않는다. 2차 업체라고해서 그들이 프리랜서를 물고 온다. 대부분 잡코리아, 사람인에 공고를 내서 지원하는 사람들을 대리고 오는데, 면접을 MSP 에서 보게 된다.

MSP 에 협력 업체도 인맥이지만, MSP 에서 수주하는 많은 프로젝트들 또한 인맥인 경우도 많다. 그렇지 않은 경우도 있지만 워낙 강남의 이름있는 MSP 하면 몇개 없기 때문에 업계에서도 알아서 찾아오는 경우도 있지만 그런 경우는 많지 않다.

대부분 A 업체 프로젝트 담당자와 MSP 담당자들은 대부분 인맥이 있거나 한 경우이다 보니, 서로 얼굴을 붉히는 일은 피할려고 하는 경향이 있다. 회사 생활을 하다보면 직위가 높을수록 어떤 문제에 직접 나서는걸 회피하는 경향을 보이는데, 복잡하고 스트레스가 심한 어떤 문제에 그 사람이 노출될 경우에 들어나는 인성과 능력을 무서워하는 경우가 아주 많다. 직위가 높으면 고상해지는 인간들이 대부분인 이유라고 보면 된다.

이 MSP 회사들도 마찬가지다. 프로젝트에 직접 관여하는 경우에 그런 ‘고상한 인품’ 을 유지하기가 상당히 힘든 경우다. 프로젝트를 직접 관리할 경우에 어떻게든 A 회사에게 싫은 소리도 해야하는 경우가 있고 직접 거의 매일매일 그 사람들과 이야기를 해야하는데 A 회사 사람들이 마냥 MSP 회사에 듣기좋은 소리만 할 경우는 많지 않다.

더군다나 A 회사와 인맥이라도 있는 날에는…. 힘든 일이 한두가지 아니게 된다.

‘우리는 고객사 편’

PL 를 하다보면 고객의 요구사항을 변경해야 하는 경우가 생긴다. 잘 모르니까 고객들은 어디서 주워들은 이야기를 가지고 해달라고 하는 경우도 부지기수다. 이럴 경우에 프리랜서라면 한계가 있기 때문에 수행사 MSP 회사에서 적극적으로 중재를 해야한다.

하지만 MSP 회사가 적극적으로 중재를 할려고 할까? 대부분 ‘PL 프리랜서’ 를 교체하는 방향으로 가닥을 잡는다. 심각한 건 프리랜서를 ‘능력없는 인간’, ‘성격이 안된 인간’ 쯤으로 평가하면서 교체를 한다는 문제다.

면접한번 보고 현장에 투입시키고는 그 사람들 다신 얼굴 볼 일도 생기지 않는데, 어떻게 해서 프리랜서에 저런 낙인을 찍을 권리가 생기는지?

문제가 있다는 것을 알면서도 그것을 프리랜서에 문제로 귀속시키고 교체, 그렇게 함으로써 고객의 요구사항을 변경시키는 일들을 하는 곳이 MSP 다. 그들에게는 그렇게 하는 것이 훨씬 편하니까… 프리랜서가 고객의 잘못된 요구사항에 대해서 중재를 요구하면 그건 능력이 없는 것이거나 ‘사업이란게 원래 그런건 줄 몰랐냐?’, ‘세상 덜 살았네… PL 할 인물이 못되네’ 식의 결론을 내리게 훨씬 쉽다.

이렇게 쉽게 생각하는 건 그렇게 해는 것이 너무나도 쉽고, 두번째는 프리랜서에 대한 인식이 그렇기 때문이다. 프리랜서는 본인들이 돈주고 산 사람이라는 인식이 있기 때문에 뭐든 시키면 다해야 한다는 사고를 하게 된다. 하지만 그렇지가 않지…

프리랜서의 권리는 의외로 막강하다. 하지만 그것을 주장할 경우에 계약해지를 종용하는데, 사실 다 위법한 것이지… 정당한 사유 없이 계약해지를 할 경우에 배상의무가 있다. 하지만 그런 인식이 없는 곳이 강남의 MSP 다.

사회변화는 고상하고 IT 도 제대로 안 굴러간다.

뉴스를 보면 사내에 성폭행 사건을 다루는 뉴스가 나온다. 그럴때마다 너도나도 가해자를 비난하면서 정의로운 글들을 많이 본다. 더군다나 회사측의 대응에 대해서 맹비난을 하곤 한다. 피해자편에 서서 대응을 했어야 했는데 그렇지 않고 피해자에게 ‘조용히 있어라’ 식의 대응을 했기 때문이겠지.

하지만 대부분의 한국사회가 대부분 부당함에 대해서 뭉쓰고, 모르쇠로 일관하는 일이 비일비재하다는 것쯤은 알아야 한다. 뉴스에 나오면 분노하면서도 정작 자신에게 혹은 자신과 관계된 주변에서 그런일이 발생할 경우에, 성폭력 피해자의 회사처럼 행동게 한국 사회 아니겠나..

강남의 MSP 회사들이 요즘 벌이는 일들이 이와 유사하다. 위험의 외주화는 물론이거니와 고객에게는 적어도 고상한 이미지를 구축해야하고 그러다보니 고객과의 마찰에 있어서 적극적인 중재를 하려고하지 않는다.

본인들은 고상해야 하고 적어도 피는 뭍히지 말아야 한다는 얄팥한 사고로 사람들을 뽑아대고 있으니…

제대로 된 인간들이 없다. 그져 인맥…… 그러니까 프로젝트 투입되서 보면 MSP 가 요구하는 그 엄청난 스펙에 비해 초보급 만도 못한애 구축된 아키텍쳐를 보게된다. 더 웃긴건 본인들이 구축했으니 잘 구축했다고까지 자랑질… 제 정신들이 아닌거지..

VIM lightline 플러그인

vim 을 사용할때에 필요한 것이 상태바(Status Bar) 다. 보통은 airline 을 많이 쓰는데, 여러가지 의존성이 필요해서 사용하기에 쉽지가 않다.

lightline 은 의존성이 복잡하지 않고 간단하게 사용할 수 있다. 다음과 같이 .vimrc 에 설정을해주면 된다.

t_Co=256 설정과 아래 두가지 부분의 설정이 핵심으로 보면 된다.

Elasticsearch 보안 – 인증서

Elasticsearch 가 버전이 높아짐에 따라 인증서에 대한 이해가 필요하게 되었다. 사실 이 인증서가 필요한 이유가 Elastic 에서 배포하는 X-Pack 중에 Security 플러그인 때문인데, 이 Security 를 활성화 하게 되면 TCP, HTTP 통신을 TLS 통신을 하도록 강제하고 있다.

문제는 Elasticsearch 자바 기반이며, 따라서 생성하는 파일이 여느 다른 인증서와는 다른 면도 있다. ‘다른 면도 있다’ 라고 표현한 이유는 일반적인 PEM 형식의 보안키와 인증서를 모두 지원하지만 여전히 자바 세계에서만 통용되는 방법을 여전히 고수하고 있기 때문이다.

keystore 파일

최신 버전의 Elasticsearch 7 을 설치하게 되면 /etc/elasticsearch/elasticsearch.keystore 파일 하나만 생성되게 된다.

이 파일은 key/value 형식으로 계정 정보가 들어가 있다. 이 내용을 적는 이유는 Java Keystore 파일과는 다르다는 것을 말하기 위함이다. Elasticsearch 을 설치하고 나서 Security 를 활성한 후에 계정에 대한 패스워드를 작성하는 절차를 밟는다.

계정에 대한 패스워드를 자동 생성하도록 한 것인데, 이렇게 생성된 내용들은 elasticsearch.keystore 파일에 key/value 형식으로 저장된다.

이렇게 저장된 key 값들은 elasticsearch-keystore 명령어를 통해서 볼 수 있다.

PKCS#12(확장자 p12) 파일

확장자가 p12 파일을 보게 된다. 이 파일은 PKCS#12 형식의 파일인데, 인증서와 개인키를 포함한 형태의 데이터 파일이다. Elasticsearch 7 에서는 루트 인증서(CA 인증서) 와 서버 인증서를 다음과 같이 제작해 사용 한다.

elastic-stack-ca.p12 은 CA 인증서 인데, openssl 을 이용해서 PKCS12 파일을 읽어볼 수 있다.

패스워드를 입력하지 않았기 때문에 패스워드 입력 문구에서는 그냥 Enter 를 치면 된다. 그러면 위와같이 Private Key, Certificate 내용이 나온다. Certificate 부분을 따로 때어내서 파일로 저장하고 Openssl 명령어를 이용해 인증서를 읽으면 다음과 같다.

CA:TRUE 라고 명백하게 나오고 있다.

그러면 CA 인증서를 가지고 만들어진 /usr/share/elasticsearch/elastic-certificates.p12 파일도 내용을 확인해 보자.

위 내용을 보면, Private Key 1개, Certificate 2개 로 나온다. 이건 인증서 체인 파일인게 분명하다. Certificate 부분만 따로 때어서 보면 다음과 같다.

확인 결과, 하나는 인증서이고 하나는 CA 인증서인 것으로 확인된다. 그러니까 elastic-certificate.p12 파일은 Private Key, CA 인증서, 서버 인증서 이렇게 3가지를 모두 가지는 파일이다.

PEM 형식 파일

Elasticsearch 에서는 PEM 형식의 파일도 함께 지원 한다. PEM 형식은 가장 흔하게, 널리 사용되는 인증서 파일 포맷 형식이다. elasticsearch-certutil 명령어를 이용해서 작성할 수 있다.

위와같이 zip 파일 형태로 생성된다. 압축을 해제하면 다음과 같이 파일이 생성된다.

ca 디렉토리가 생성되는데, 보면 Private Key 파일과 CA 파일이 별도로 생성된 것을 알 수 있다.

이렇게 작성된 파일을 가지고 서버 인증서를 다음과 같이 생성할 수 있다.

역시나 압축된 형태의 파일로 출력이 된다. 압축을 해제해 보자.

instance.crt 인증서 파일의 내용을 살펴보자

서버 인증서임을 알수 있다.

인증서 활용

PKCS#12 형식과 PEM 형식의 인증서를 활용하는 방법은 다르다.

PKCS#12 형식은 다음과 같이 설정 한다.

PEM 형식은 다음과 같다.

SAN 인증서

지금까지 설명한 방법으로 인증서를 작성할 경우에 한가지 문제가 있을 수 있다. 이 인증서들은 SAN 인증서가 아니기 때문에 모든 도메인에서 통용될 수 있다. 앞에 인증서 내용을 보면 SAN 이 없다. 하지만 SAN 인증서라야만 하는 보안성을 요구된다면 SAN 인증서를 만들어 사용해야 한다.

SAN 인증서를 작성할때에 주의 사항은 Elasticsearch Stack 에서 사용할 모든 도메인, 혹은 IP 주소를 기재해야 한다. 그렇지 않으면 절대로 통신을 할 수가 없게 된다.

먼저, CA 인증서가 필요하다. 이 CA 인증서는 앞에 PEM 형식의 CA 인증서를 만들고 압축을 해제해 놓는다. 그리고 다음과 같이 instance.yml 파일을 작성한다.

이 파일에서 ip, dns 항목이 보이는데, 둘 중 하나만 있어도 된다. 어짜피 인증서에서 SAN 항목에서 IP Address, DNS 둘중하나가 들어가 있고 매칭이되면 인증서를 쓸 수 있다.

이제 다음과 같이 인증서를 작성해 생성한다.

정상적으로 생성이 되었을 것이다. 압축을 해제해 보자

instance.yml 파일에서 이름부분이 디렉토리로 생성되면서 각각 인증서와 key 값이 생성되어 있다. 이 인증서들은 SAN 부분이 instance.yml 에 따라서 하나의 IP, 하나의 DNS 만 들어가 있다.

SAN 이 뭔지를 안다면 굳이 이렇게 다 분리할 필요는 없다는 생각을 하게 된다. 멀티도메인 인증서를 사용하면 도메인에 *.systemv.local 처럼 생성하면 될 것이고, 그러면 하나의 인증서를 가지고 여러곳에서 함께 사용이 가능해 진다. 위 예제에서는 각각의 용도에 맞게 딱 1개의 도메인과 IP 에 한해서 허용하도록 작성되었을 뿐이다.

PEM 형식의 Key 는 PKCS#12 형식으로 사용해야할 때가 있다. 이때는 다음과 같이 openssl 명령어를 이용해서 변환할 수 있다.