개발관련/삽질

hashicorp사의 Vault(볼트) - Tutorial-Real(With-REST-API) - 3

동팡 2021. 7. 5. 23:17

목차

  • 들어가며
  • Vault Real 서버 튜토리얼
  • 참고문헌

 

들어가며

본 게시물은 Vault 공식 문서의 내용과 필자의 생각을 정리하였다. Vault는 무엇인지, 어디에 사용하는지, 왜 사용하는지, 어떻게 사용하는지 서술한다. Vault를 처음 접하는 인원은 Vault의 흐름과 골격을 이해할 수 있는 시간을 갖는다. 또한 Vault를 실질적으로 사용해보는 시간을 갖는다. Vault는 Dev 서버 모드를 지원한다. Dev 서버 모드는 사전 설정이 되어있는 데모 서버라고 생각하면 좋다. 사용자는 해당 데모 서버에서 Vault를 학습할 수 있다. 시간이 괜찮으면 Vault HA를 구성한다(시간이 있으면...). 

 

본 게시물의 시리즈는 다음과 같다.

 

Vault Real 서버 튜토리얼

[Vault 최종 디렉토리 구성]

Vault 디렉토리에 존재하는 파일

  • config.hcl: Vault 엔진 설정 정보
  • data: 데이터를 보관하는 장소
  • keyinfo.txt: SSS 알고리즘으로 분할한 키와 Root 토큰 정보
  • start.sh: Vault를 기동하기 위한 쉘 스크립트
  • stop.sh: Vault를 종료하기 위한 쉘 스크립트

굵게 표시한 것은 필수적으로 구성해야 하는 것이며, 기울여서 표시한 것은 편리를 위해 구성한 것이다. 그러나 프로덕트 환경에서는 keyinfo.txt 파일은 별도 디바이스에 보관해야 한다. 

 

[환경 구성]

CentOS 기준, yum 명령어를 사용하여 Vault를 설치한다. 설치방법은 Vault Tutorial 페이지에서 확인할 수 있다.

$mkdir vault

$cd vault

$vi config.hcl
	
    storage "raft" {
	  path = "./data"
	  node_id = "node1"
	}

	listener "tcp" {
	  address = "127.0.0.1:8200"
	  tls_disable = "true"
	}

	api_addr="http://127.0.0.1:8200"
	cluster_addr="https://127.0.0.1:8201"
	ui = true

$mkdir data

 

아래와 같이 VAULT_ADDR 환경변수 설정

$vi ./.bash_profile
	VAULT_ADDR='http://127.0.0.1:8200'
	export VAULT_ADDR
			
$source ./.bash_profile

// 또는

$ export VAULT_ADDR='http://127.0.0.1:8200'

// 확인 
$set  | grep VAULT_ADDR

 

[Vault 서버 가동 및 초기화]

Vault 서버 가동

"-config"에는 config.hcl의 경로를 지정한다.

$vault server -config=/home1/irteamsu/vault/config.hcl &

 

Vault 서버 초기화 및 Unsealing

Vault 서버 가동 후 최초 1회 초기화 작업을 진행한다. 해당 초기화 작업으로 Vault 설정정보에 따라 SSS 분할키와 Root 토큰을 생성한다. 별도의 설정 정보가 없을 경우 threshold는 (3, 5)이다. 즉 5개의 분할키를 부여하며, 원본을 만들기 위해서는 최소 3개의 분할키가 필요하다. 필자의 경우 프로덕트 환경이 아니기 때문에 아래의 분할키와 Root 토큰을 keyinfo.txt 파일에 보관하였다. 

$vault operator init

2021-06-15T16:43:36.202+0900 [INFO]  core: pre-seal teardown complete
		Unseal Key 1: Iv9H20vmAUMkDaAfyuar2rSWyGnZgvBOhQPl7df4lrib
		Unseal Key 2: G7SnjSZPOaZwkMX9rvCyK8ssdoIMAdAYu+oDo1b9uZ+j
		Unseal Key 3: jNfpkii4QiJsuIUVwkuIm1jjIz+bzh5oalsfevXGs5Wc
		Unseal Key 4: NnruCilytFhgdQ4zCQmKeSrrV4e8Ijws663trVHAamyl
		Unseal Key 5: pqb+bP30/wAraxLITsnjza1ibDyqKIcAHTEZkDzf902W

		Initial Root Token: s.ZPBA2pFTJEtmlaUfIEHk1Lq6

		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.

서버 가동, 초기화 작업을 완료하였다. 그러나 Vault는 아직 "Sealed" 상태이다. 위의 분할키는 Vault의 상태를 "Unsealed" 상태로 전이할 수 있다. 

$vault operator unseal G7SnjSZPOaZwkMX9rvCyK8ssdoIMAdAYu+oDo1b9uZ+j
$vault operator unseal jNfpkii4QiJsuIUVwkuIm1jjIz+bzh5oalsfevXGs5Wc
$vault operator unseal NnruCilytFhgdQ4zCQmKeSrrV4e8Ijws663trVHAamyl

위의 작업을 완료하면 Sealed false 값을 확인할 수 있다. Root 토큰으로 로그인한 사용자는 "vault operator seal" 명령을 사용하여 Vault 서버에 Sealing을 할 수 있다. root 사용자의 경우, vault operator seal을 통해 sealing을 다시 할 수 있다. 이제 Vault를 마음껏 사용할 수 있다. 

 

[Vault 가동 스크립트 작성]

Vault를 기동할 때 "Unsealing" 절차는 필수이다. 해당 절차의 편리를 위해 스크립트를 작성한다. 스크립트는 아래와 같다.

start.sh

#!/bin/bash

partOfKey1=$1
partOfKey2=$2
partOfKey3=$3

if [ "$#" != 3 ]
then
		echo "argument is not 3"
		exit
else
		vault server -config=/home1/irteamsu/vault/config.hcl &

		sleep 1
		echo -ne '\n'

		vault operator unseal $1
		vault operator unseal $2
		vault operator unseal $3
fi

 

stop.sh

#!/bin/bash

pid=`ps aux | grep 'vault server' | grep -v grep | awk '{print $2}'`

if [ -z "$pid" ]
then
	echo "server is not running"
else
	echo "shutdown..."
	kill -9 $pid
fi

추가 분기를 사용하여 kill -9, -15 옵션을 결정할 수 있다. 필자는 그냥 "-9"를 사용하였다. 프로덕트 환경의 경우, "-15" 옵션을 위한 분기 사용을 권한다. 

 

[Vault 사용 - REST API - 서버 상태 확인]

$curl http://127.0.0.1:8200/v1/sys/init | jq

 

[Vault 사용 - REST API - auth method 활성화]

(Root 토큰을 환경변수에 지정한다(VAULT_TOKEN).)

$curl -X POST -H "X-Vault-Request: true" -H "X-Vault-Token: $VAULT_TOKEN" -d '{"type":"approle","description":"","config":{"options":null,"default_lease_ttl":"0s","max_lease_ttl":"0s","force_no_cache":false},"local":false,"seal_wrap":false,"external_entropy_access":false,"options":null}' http://127.0.0.1:8200/v1/sys/auth/approle

 

[Vault 사용 - REST API - 정책 추가]

$curl \
--header "X-Vault-Token: $VAULT_TOKEN" \
--request PUT \
--data '{"policy":"# Dev servers have version 2 of KV secrets engine mounted by default, so will\n# need these paths to grant permissions:\npath \"secret/data/*\" {\n  capabilities = [\"create\", \"update\"]\n}\n\npath \"secret/data/foo\" {\n  capabilities = [\"read\"]\n}\n"}' \
-D - http://127.0.0.1:8200/v1/sys/policies/acl/my-policy

커맨드 명령어를 사용하여, 추가한 정책을 확인한다.

$vault policy list

 

[Vault 사용 - REST API - SecretPath 생성]

$curl \
--header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{ "type":"kv-v2" }' \
-D - http://127.0.0.1:8200/v1/sys/mounts/secret

 

[Vault 사용 -REST API - 정책 기반으로 Role 생성]

$curl \
--header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{"policies": ["my-policy"]}' \
-D - http://127.0.0.1:8200/v1/auth/approle/role/my-role

커맨드 명령어를 사용하여, 추가한 Role을 확인한다.

$vault list auth/approle/role
$vault read auth/approle/role/my-role
$vault read auth/approle/role/my-role/role-id

REST API를 사용하여, 추가한 Role을 확인한다.

$curl \
--header "X-Vault-Token: $VAULT_TOKEN" \
http://127.0.0.1:8200/v1/auth/approle/role/my-role/role-id | jq -r ".data"

 

[Vault  사용 - REST API - Secret-ID 생성/확인]

$curl \
--header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
http://127.0.0.1:8200/v1/auth/approle/role/my-role/secret-id | jq -r ".data"
	
//응답
{
  "secret_id": "c7d3485f-403d-0c57-320d-3eb97697d85a",
  "secret_id_accessor": "b0e25931-9e7e-4a4d-80b6-11a0087671d5",
  "secret_id_ttl": 0
}

 

[Vault 사용 - REST API - AppRole 인증 및 클라이언트 토큰 반환]

ㄴㅇ

$curl --request POST \
--data '{"role_id": "93bfae74-3356-9b0d-08b3-8c2cdc76f55a", "secret_id": "c7d3485f-403d-0c57-320d-3eb97697d85a"}' \
http://127.0.0.1:8200/v1/auth/approle/login | jq -r ".auth"


// 응답
{
  "client_token": "s.DOqgLc4sIVKJjmgVIzCIJVeZ",
  "accessor": "eRxKIqBlT3eKsKRCfvt80sLO",
  "policies": [
	"default",
	"my-policy"
  ],
  "token_policies": [
	"default",
	"my-policy"
  ],
  "metadata": {
	"role_name": "my-role"
  },
  "lease_duration": 2764800,
  "renewable": true,
  "entity_id": "d624b3eb-0e52-fb88-439f-f456a8519fa2",
  "token_type": "service",
  "orphan": true
}

 

[Vault 사용 - REST API - 클라이언트 토큰으로 Secret 저장]

먼저 클라이언트 토큰을 환경변수에 저장한다. 

$export VAULT_TOKEN="s.DOqgLc4sIVKJjmgVIzCIJVeZ"

 

REST API를 사용하여 Secret을 저장한다.

$curl \
--header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{ "data": {"password": "my-long-password"} }' \
http://127.0.0.1:8200/v1/secret/data/creds | jq -r ".data"

이렇게 Dev 모드가 아닌 실제 서버를 설정하였다. 해당 서버는 vault 커맨드를 사용하여 제어할 수 있으며, REST API를 사용하여 제어할 수 있다. 본 게시글은 curl 명령과 함께 REST API를 사용하였다. 실질적으로 프로덕션 레벨에서는 클라이언트 토큰을 생성 후, Secret을 제어하는 것이다. 해당 사항은 Java/Spring환경을 구성한 후 테스트 예정이다.  

 

참고문헌

Vault 공식 튜토리얼 사이트