[개발팁] 암호나 안전한 정보를 저장하기 위한 소프트웨어 금고 (Vault)

사용자가 암호 등을 안전하게 보관하기 위한 금고 (Safe 또는 Vault)를 만드는 개념은 쉬울 것 같으면 서도 쉽지 않습니다. 
로컬에 어떤 식으로 저장을 하더라도 해당 소스가 공개되어 있고 저장하는 방식을 알게되면 역으로 해독이 가능하기 때문입니다.

또한 해당 기능을 이용하는 사용자에게 정말로 안전한 금고라고 안심을 시켜야 하는데,
누군가가 인정해 주지 않고 그냥 노출되지 않은 개인 코드로 짜 놓았다면
그것을 안전한지 인정할 사용자는 많지 않습니다.

그런 의미에서 여러 가지 것을 살펴보았는데,

HashiCorp 라는 회사의 Vault 라는 것이 있었습니다.

해당 서비스는 별도의 서비스로 서버에 돌리는 것이므로 당연히 docker 로 컨테이너가 된 것이 있겠거니 하고
찾아서 테스트를 해 보았는데, 정작 제대로 돌아가는 것은 많지 않았습니다.

Docker compose로 구성되어 있으면서 Backend  저장소는 역시 같은 회사의 consul 이라는 분산 시스템 코디네이션 서비스 시스템을
이용하도록 되어 있는 것이 대부분 이었습니다.

잘 돌아가는가 싶었는데 결국은 해당 컨테이너를 다시 내렸다고 올리면 기존 내용이 사라지는 등의 문제점이 있었습니다.

결국은 "Docker + Consul + Vault: A Practical Guide" 의 블로그 내용을 참고로 나름대로 최신 버전의 Vault와 Vault UI를
이용할 수 있도록 작업하여 이를 Github에 공유해 놓았습니다.

해당링크로 들어가시면 됩니다.

실행방법은 docker 및 docker-compose가 설치되어 있는 시스템에서 (저는 개인 맥북프로 및 ESXi 서버에 Photon Linux 에서 동작시켜
보았습니다) 다음의 내용을 git으로 받으면 됩니다.

git clone https://github.com/mcchae/docker_consul_vault.git

서비스로 동작하는 컨테이너는 모두 4개이지만 그 중에 3개만 상시로 돌고 backup 이라는 것은 필요 시 실행시키도록 되어 있습니다.

3개의 서비스는

consul: Vault의 백엔드 저장소
vault: Vault 서비스
webui: Vault의 Web UI

으로 구성되어 있습니다.

start.sh 를 실행시키면,

docker-compose up
으로 해당 컨테이너를 실행시키고,

dhv 다커 마운트 폴더에 key.txt 가 없으면 scripts/setup.sh 를 실행시키고,
아니고 있으면 scripts/unseal.sh 를 실행시킵니다.

scripts/setup.sh 가 하는 역할은,

vault operator init
명령으로 나온 것을 dhv/keys.txt 에 저장합니다.
(실제로는 위의 init 해서 나온 키는 root 키로 무엇이던 할 수 있는 키 입니다)
절대로 위의 키가 노출되지 않도록 해야 합니다.

그 내용은 다음처럼 되어 있습니다.

Unseal Key 1: QJflxzyxRGNYs8zxhCFcllTxCsENCk0dGA7wWncbjckG
Unseal Key 2: Xf2lYAB9esjEWxHub1V621K68lvZV0/djPNiX7jZ28uS
Unseal Key 3: AKBEP/TaYwb+gqxvEwN62VHRNlCjT4Nc3e6zgyqf2erP
Unseal Key 4: cWMDmRXjuAFagr3PtdEFWLJYV0r2CssWBfDwemxDN+zi
Unseal Key 5: r2YVS0rNbrznmP7kWiYWAFIGT9S57Bet1qQfrrMLPQvg

Initial Root Token: s.4pFCu3fy2NZd32ADRAMkgvyw

Vault initialized with 5 key shares and a key threshold of 3. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 3 of these keys to unseal it
before it can start servicing requests.

Vault does not store the generated master key. Without at least 3 key to
reconstruct the master key, Vault will remain permanently sealed!

It is possible to generate new unseal keys, provided you have a quorum of
existing unseal keys shares. See "vault operator rekey" for more information.
backup_token: 7VXGZJxRZFCYn13jYOvwe2UC

최초 서버를 기동시키면 초기화(init) 되어 있지 않고, 잠겨 (sealed) 되어 있는 
상태인데 위에서 처럼 vault operator init 명령을 하면, 초기화되었지만,
여전히 잠겨(sealed) 되어 있는 상태입니다.

이 때, 위의 Unseal Key 다섯 개 중, 3개를 넣어줘야만 비로서 동작가능한 잠김해제 (Unsealed) 상태로
바뀌게 됩니다.
실제 안전한 환경을 위해서는 위의 Unseal Key를 각각 다섯명의 사람에게 나누어주고,
잠김 해제를 위하여 적어도 임의의 세명에게 키를 받아 잠김해제를 시키도록 하면 됩니다.

위에 잠김 상태에서는 root 암호가 잠겨 있으므로 아무리 통째로 데이터를 복사한다 하더라도
그 실제 내용은 파악할 수 없다 합니다.

잠김 해제 요청 명령은,

vault operator unseal {Unseal Key}

라고 하면 됩니다.

만약 docker-compose down 으로 다시 해당 컨테이너들을 다 내린다 하더라도 
다시 기동하였을 때에는 이전에 가지고 있던 Unseal Key로 재 unseal을 하면
dhv/consul 저장소에 있던 금고 내용을 안전하게 재 사용할 수 있습니다.

그 밖에 최초 동작할 상황에서 setup.sh 에서는 다음과 같은 작업을 진행합니다.

vault login {Initial Root Token} 

으로 로그인 한 다음,

vault policy write admin ./config/admin.hcl
admin.hcl 이라는 정책을 만들고

vault auth enable  userpass
vault write auth/userpass/users/webui password=webui policies=admin
Vault Web UI 사용자를 위한 webui/webui 라는 ID/암호 를 만듧니다.

vault token create -display-name="backup_token" | awk '/token/{i++}i==2' | awk '{print "backup_token: " $2}' >> ./dhv/keys.txt
그리고 백업을 위한 토큰을 만들어 dhv/key.txt 의 마지막에 추가합니다.

scripts/backup.sh 는

docker-compose run backup consul-backup -i consul:8500 -t $(grep 'backup_token:' ./dhv/keys.txt | awk -v RS='\r\n' '{printf $2}') backup_$(date +%Y-%m-%d)
라는 명령어를 실행시켜 dhv/backup/backup_yyyy-mm-dd 로 백업파일을 생성합니다.

결국 지금까지의 것은,

start.sh 를 실행시키면 모두 자동으로 행해지는 작업입니다.

해당 docker 서비스를 돌리는 서버의 방화벽에 8000, 8200 포트를 열어주고,
외부에서 해당 서버의 8000 번으로 http 접속을 웹브라우저에서 확인해 보면,

위와 같은 UI가 나타나며,

webui / webui 로 ID와 암호를 넣고 "LOGIN"을 하면,

위와 같은 UI 화면이 나타납니다.

왼편에 Policies 를 선택하고 "New Policy"를 선택하고

위와 같이 mytest 라는 정책을 하나 추가합니다. (sudo 는 빼 줍니다)

vault policy write {policy.hcl}
처럼 CLI로도 가능합니다.

그리고 좌측의 메뉴에서 "Secret Backends  +" 에 있는 "+"를 눌러 위에서 처럼 kv의 myroot 를 만들어 주었습니다.
mytest 라는 정책은 myroot 이외에는 접근할 수 없도록 했습니다.

이제는 특정 그룹이나 프로그램 또는 사용자가 해당 금고에 접근하게 할 수 있는 토큰을 만들어 보겠습니다.

왼쪽 token을 선택하고 상단에 "NEW TOKEN"을 누릅니다.

위와 같은 식으로 myuser-00 이라는 이름의 토큰을 만들어 보았습니다. 최대 사용 수는 2개로 제한했고, TTL은 2시간으로 했습니다. (정말 2번인지 좀더 연구를 해 보아야 합니다)

주의할 것은 정책에 mytest 라는 정책에 default 정책을 포함시켜 만들었습니다.

그러면 위에서 처럼 "New token code"가 보이면 이를 클립보드에 복사하여 사용합니다.

터미널 CLI에서 사용하는 방법은, 다음과 같은데

CLI를 사용하기에 앞서 한가지 주의할 점은 위에 있는 CLI에서 vault 명령은 실제 docker-compose에서 value 컨테이너 안에 있는 vault 명령을 실행해야 한다는 것입니다.
이를 위해서 다음과 같은 식으로 alias를 ~/.bash_profile.sh 에 넣어 두었습니다.

alias vault='docker-compose -f /root/docker_consul_vault/docker-compose.yml exec vault vault "$@"'


위의 토큰으로 vault login 을 다시해 보는 것입니다.

해당 토큰 정보를 확인하는 것은,

vault token lookup 으로 확인할 수 있습니다. 해당 id 가 접속 키 인데요, Web UI 에서는 안 보이더군요.

이제 CLI에서 

vault write myroot/hello/world foo=bar

라는 명령으로 볼트에 해당 위치에 저장했는데요,

이를 UI에서 확인해 보면,

위에서 처럼 해당 kv (Key/Value) path 가 보이고 해당 world를 확인해 보면,

잘 들어가 있음을 확인할 수 있습니다.
위에 UI는 admin 권한을 가지고 있기 때문에 해당 내용을 모두 원본으로 확인할 수 있는 것입니다.

UI 상으로도 값을 넣거나 수정하고 삭제할 수 있습니다.

이제는 hvac 라는 파이썬 모듈을 이용하여 파이썬 프로그램에서 금고를 사용할 수 있는 방법입니다.

# cat sample_env.sh
export VAULT_TOKEN="s.uPWf8Vm2dukb1W5BpSSJzheK"
export VAULT_URL="http://192.168.99.240:8200"

위와 같은 식으로 VAULT_TOKEN 과 VAULT_URL 을 만들어 줍니다.

. sample_env.sh
명령으로 현재 쉘에 해당 환경변수가 인식되도록 하고나서,

VAULT_TOKEN은 마지막으로 로그인했던 내용이구요,
VAULT_URL의 IP는 위에 docker-compose를 돌린 호스트의 IP를 의미합니다.

그리고 hvac를 설치하고,

pip install hvac

다음과 같이,

# cat vault_sample.py
import os
import hvac
import time

#client = hvac.Client()
print('VAULT_URL=%s' % os.environ['VAULT_URL'])
print('VAULT_TOKEN=%s' % os.environ['VAULT_TOKEN'])
client = hvac.Client(
    url=os.environ['VAULT_URL'],
    token=os.environ['VAULT_TOKEN']
)
print('is_authenticated? %s' % client.is_authenticated())
client.write('myroot/hello/world', key1='val1', key2='val2')
print(client.read('myroot/hello/world'))
client.logout()

라는 샘플을 만들어,

실행해보면,

잘 실행되는 것을 확인할 수 있습니다.
이제는 위에 금고 서비스를 동작시키고 나서 금고를 잘 활용하는 일만 남았군요..


어느 분께는 도움이 되셨기를..

[MacOS] 특정 웹페이지 내용을 PDF로 만들기 (여러 PDF 하나로 명령어로 합치기)

그동안 여러 휴대용 읽는 기기를 이용하고 있었지만, 마지막으로 사용하면서 가장 애용하는 것이 바로"Onyx 10.1인치 이북리더"가 아닌가 싶습니다. 장점으로 출퇴근 시에 책처럼 읽을 수 있는 장점이 있습니다.그런데 말입니다. 어떤 웹페이지에 매뉴얼이 있어 이것을 책처럼 읽고 싶은데,무슨 방법이 있을까 찾아 보았지만, 이상하게도 특별한 방법이 ... » 내용보기

[Python] pyfiglet 으로 ASCII art 문자를 출력해 보기

위의 그림처럼 터미널에서 무언가 큰 글자가 나오는 것과 같은 것을 본 경우가 있으실 겁니다.또는 ASCII art 로 검색을 해 보시면,위와 같은 이미지를 나타내거나,사진 픽셀이 마치 터미널 화면에 나타나듯이 보이는 것도 있습니다.그런데 글자 같은 경우 figlet 이라는 아스키 문자를 큰 그래픽 문자처럼 보여주는 곳이 존재합니다.(위에 예에서... » 내용보기

[SONY] 맥에서 알파7III ARW raw 파일을 JPEG로 변환

쏘니 알파 7 III 에서 찍힌 사진을 raw 로 저장하면 *.ARW 라는 확장자로 저장됩니다.이것을 맥에서 JPEG 로 변환하려면 exiftool 이 필요합니다.다음과 같이 homebrew로 설치하면 됩니다.$ brew install exiftool설치를 완료하고 사진임시 라는 폴더에 ARW raw 파일들이 있다고 하면다음과 같은 명령으로 간단하게 변... » 내용보기

[macos] 맥에서 윈도우공유 (삼바) 터미널 명령어로 해 보기

맥의 터미널에서 윈도우의 공유폴더 또는 samba로 공유된 폴더 (FreeNAS에서 공유하기 참조)하기 위한명령어를 몇 번 찾았었는데, 다음과 유사하게 해 보았었습니다.mount_smbs //user:passwd@host/shared_folder /Volumes/shared_folder그런데 Authentication Error 가 뜨더군요.그래서,op... » 내용보기

구글애드텍스트