HashiCorp의 비밀정보 관리 도구 Vault의 구성에서 Vault의 기본적인 개념과 서버를 구성하는 방법을 살펴보았다. 이 설명도 꽤 길었지만, 아직 Vault를 어떻게 사용하는지 감이 잘 안 올 것이라고 생각하는데 이번에는 실제로 Vault를 어떻게 사용하는지 살펴보자.
Vault 서버에서 데이터 읽고 쓰기
앞에서 초기화를 할 때 root token이라는 것을 하나 받았다. 이는 Vault 서버의 루트 권한이 있는(서버의 모든 작업을 할 수 있고 sealed 상태로 바꿀 수도 있지만, unseal을 할 수는 없다.) 토큰이다. 일단 이 토큰으로 Vault를 사용해 보자. 토큰은 VAULT_TOKEN
환경변수에 저장하면 vault
클라이언트에서 사용할 수 있다.
$ export VAULT_TOKEN=c0ccbf61-cd7b-bd98-dabe-f319247cedd8
앞에서 비밀정보를 저장하려면 시크릿 백엔드를 만들어야 한다고 했는데 이 시크릿 백엔드를 파일시스템처럼 마운트해서 사용한다. 마운트를 하면 경로가 생성되고 그 경로에 원하는 정보를 저장하면 된다. 기본적으로 마운트된 백엔드가 있으니 vault mounts
로 확인해 보자.
$ vault mounts
Path Type Default TTL Max TTL Description
cubbyhole/ cubbyhole n/a n/a per-token private secret storage
secret/ generic system system generic secret storage
sys/ system n/a n/a system endpoints used for control, policy and debugging
cubbyhole/
는 토큰마다 생성되는 스토리지로 연습용이라고 생각하면 된다. secret/
은 gerneric
타입이라고 되어 있는데 이는 generic 시크릿 백엔드라는 의미이고 바로 사용을 할 수 있도록 기본적으로 하나가 있는 것이다. 추가설명을 하자면 generic 시크릿 백엔드는 secret
경로에 마운트한 것이다. sys/
는 시스템용으로 ACL 정책이나 관리 정보가 여기에 저장된다.
secret
에 시크릿 백엔드가 마운트되어 있으므로 여기에 구분하기 쉬운 경로를 생성해서 vault write
로 데이터를 저장하면 된다.
vault write secret/database/postgres host=127.0.0.1 \
port=5432 db=test username=postgres password=postgres \
desc="테스트용 데이터베이스"
Success! Data written to: secret/database/postgres
데이터를 읽어올 때는 vault read
데이터가 저장된 경로를 지정하면 된다.
$ vault read secret/database/postgres
Key Value
--- -----
refresh_interval 768h0m0s
db test
desc 테스트용 데이터베이스
host 127.0.0.1
password postgres
port 5432
username postgres
$ vault read -format=json secret/database/postgres
{
"request_id": "f0775db9-82d9-2fa2-5052-e999a0b3eed2",
"lease_id": "",
"lease_duration": 2764800,
"renewable": false,
"data": {
"db": "test",
"desc": "테스트용 데이터베이스",
"host": "127.0.0.1",
"password": "postgres",
"port": "5432",
"username": "postgres"
},
"warnings": null
}
결과를 JSON으로 받고 싶다면 -format=json
옵션을 추가하면 된다.
원하는 경로를 찾기가 어려울 때는 vault list
를 사용하면 하위에 있는 경로를 볼 수 있다.
$ vault list secret
Keys
----
database/
$ vault list secret/database
Keys
----
postgres
데이터 관리를 쉽게 할 수 있도록 새로운 시크릿 백엔드를 연결하고 싶다면 vault mount
를 사용하면 된다. 다음은 account/
경로에 generic 시크릿 백엔드를 연결한 것이다.
$ vault mount -path=account generic
Successfully mounted 'generic' at 'account'!
$ vault mounts
Path Type Default TTL Max TTL Description
account/ generic system system
cubbyhole/ cubbyhole n/a n/a per-token private secret storage
secret/ generic system system generic secret storage
sys/ system n/a n/a system endpoints used for control, policy and debugging
ACL 정책
여태까지는 루트 토큰을 사용했는데 루트 토큰은 권한이 너무 많으므로 일반적인 사용사례를 생각하면 이 토큰은 관리용으로 보관해 두고 개인이나 애플리케이션별로 토큰 등을 발급해서(혹은 인증 백엔드로 발급할 수 있게 해서) 사용할 것이다. 그러자면 ACL을 설정해서 사용자가 접근 가능한 정보만 볼 수 있도록 해야 한다. Vault에서는 이를 정책(policy)이라고 부른다.
$ vault policies
default
root
기본으로 생성된 정책은 root
와 default
가 있다.
새로운 권한을 만들려면 먼저 정책을 hcl 파일(혹은 JSON 파일)로 작성해야 한다. 아래의 내용으로 policy.hcl
파일을 만들어 보자.
path "account/*" {
capabilities = ["create", "update", "read"]
}
이는 account/
하위의 모든 경로에서 생성, 수정, 읽기가 가능하다는 정책이다. capabilities
에는 다음의 내용
create
: 경로에 값을 생성한다.read
: 경로의 값을 읽는다.update
: 경로의 값을 바꾼다.delete
: 경로의 값을 제거한다.list
: 경로에서 키의 이름을 읽는다.list
로 조회할 때 반환되는 키 정보는 정책에 따라 필터링 되지 않으므로 키 이름에 민감한 정보를 넣지 않도록 조심해야 한다.sudo
: root로 보호된 경로를 얻는다.sudo
는 특수 기능을 부가하는 것이므로 별도로read
,update
등을 지정해 주어야 한다.deny
: 해당 경로에 접근을 차단한다. 이는 sudo나 다른 설정과 관계없이 모두 차단한다.
앞에서는 path
를 하나만 설정했지만 여러 개 설정해서 복잡한 경로에도 특정 부분만 권한을 주거나 권한을 빼거나 할 수 있다. 이제 앞에서 만든 policy.hcl
파일을 이용해서 정책을 생성해보자.
$ vault policy-write owner policy.hcl
Policy 'owner' written.
$ vault policies
owner
default
root
위 명령어는 owner
라는 이름으로 정책을 생성한 것이다. 구분하기 쉽게 정책 이름을 잘 정하면 좋고 정책이 잘 적용된 것을 볼 수 있다.
인증 백엔드
앞에서도 설명했지만 인증 백엔드를 사용하려면 새로운 인증을 추가해야 한다. Vault에서 제공하는 인증 백엔드 중에 자신에게 적합한 타입을 골라서 사용하면 되고 꼭 하나만 사용해야 하는 것은 아니다.
$ vault auth -methods
Path Type Default TTL Max TTL Description
token/ token system system token based credentials
vault auth -methods
명령어로 사용 중인 인증 백엔드의 목록을 볼 수 있다. 여태까지 토큰 인증 백엔드는 기본적으로 포함되어 있다. 새로운 토큰을 발급받으려면 vault token-create
를 사용하면 된다.
$ vault token-create
Key Value
--- -----
token 681b522a-5689-519f-bde0-3cddf334f35a
token_accessor 91e7588f-a0a0-70aa-6cca-0583fc2f8cbe
token_duration 0s
token_renewable false
token_policies [root]
token
의 토큰을 사용하면 되고 token_accessor
의 용도는 정확히 모르겠다. 여기서는 현재 사용 중인 토큰이 루트 토큰이므로 같은 정책인 root
정책이 적용된 것을 볼 수 있다. 앞에서 만든 owner
정책으로 토큰을 생성하려면 -policy
옵션을 사용하면 된다.
vault token-create -policy=owner
Key Value
--- -----
token 276fbe3f-4026-d054-8eae-c2897ecba1b8
token_accessor 8548431b-95ef-db7b-2c9d-fb8b6c57a566
token_duration 768h0m0s
token_renewable true
token_policies [default owner]
여태까지는 VAULT_TOKEN
환경변수로 토큰을 지정했지만 vault auth
명령어로 로그인할 수도 있다.
$ vault auth 276fbe3f-4026-d054-8eae-c2897ecba1b8
Successfully authenticated! You are now logged in.
token: 276fbe3f-4026-d054-8eae-c2897ecba1b8
token_duration: 2764532
token_policies: [default owner]
이 토큰은 account/
에 권한이 있는 owner
정책이 적용된 토큰이므로 실제로 사용을 해보자.
$ vault write account/twitter username=outsideris password=test
Success! Data written to: account/twitter
$ vault read account/twitter
Key Value
--- -----
refresh_interval 768h0m0s
password test
username outsideris
목록 조회 기능이나 다른 경로를 사용하려고 하면 권한 거부가 일어나는 것을 볼 수 있다.
$ vault list account
Error reading account/: Error making API request.
URL: GET http://127.0.0.1:8200/v1/account/?list=true
Code: 403. Errors:
* permission denied
$ vault read secret/database/postgres
Error reading secret/database/postgres: Error making API request.
URL: GET http://127.0.0.1:8200/v1/secret/database/postgres
Code: 403. Errors:
* permission denied
추가로 새로운 인증 백엔드를 추가해보자. 여기서는 간단한 사용자명/비밀번호 인증 백엔드를 추가해 보겠다. owner
에는 백엔드를 추가할 기능이 없으므로 앞에서 사용하던 루트 토큰을 다시 사용해보자.
$ vault auth-enable userpass
Successfully enabled 'userpass' at 'userpass'!
userpass
인증 백엔드가 활성화되었으므로 이를 통해 새로운 사용자를 추가할 수 있다.
$ vault write auth/userpass/users/outsider password=asdf policies=owner
Success! Data written to: auth/userpass/users/outsider
이제 생성한 계정으로 로그인을 해보자. vault auth
만 사용하면 토큰 인증이므로 -method=userpass
를 지정해야 한다.
$ vault auth -method=userpass username=outsider password=asdf
Successfully authenticated! You are now logged in.
The token below is already saved in the session. You do not
need to "vault auth" again with the token.
token: ae75f594-70a0-ae40-af7d-2449e0d1f46f
token_duration: 2764800
token_policies: [default owner]
성공적으로 인증이 되고 토큰이 발급된 것을 볼 수 있다.
에필로그
최근에 새로운 도구를 여러 가지 만져보고 있지만, Vault는 꽤 맘에 드는 것 중 하나이다. 실제로 사용하려면 경로 정책도 정해야 하고 개발단계나 CI, 배포 등에서 사용하기 위해 Vault와 통합하는 작업을 해야 하지만 보안에 집중한 도구라서 이 부분에서 신뢰가 가고 사용성도 상당히 고려했다는 느낌이 든다. 여기서는 모든 명령어를 vault
클라이언트를 사용했지만, 이 모든 기능은 RESTful API가 동시에 제공되기 때문에 용량이 꽤 되는 Vault를 설치하기 부담되는 곳에서도 curl 등으로 정보를 얼마든지 조회할 수 있다. 설명이 꽤 길었지만, 상당히 잘 만들어진 도구라고 생각한다.
보안이 중요하다는 부분에는 누구나 동의하겠지만, 보안을 강화하려면 노력과 비용이 많이 들고 대부분은 이 노력과 비용을 실무자한테 전가하기 때문에 불편한 보안 장벽 내에서 생산성을 내기 위해서 오히려 보안이 약해지는 문제가 생긴다고 본다. Vault 같은 도구로 개발환경이나 CI, 배포에 잘 통합을 한다면 기존과 거의 차이 없는 환경에서 비밀번호를 주기적으로 바꾼다거나 실수로라도 외부에 유출되지 않도록 잘 관리한다거나 하는 것이 가능할 것이라고 본다.
Comments