Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Vault의 PostgreSQL 시크릿 백엔드

지난달에 Vault 서버를 구성하고 기본적인 사용방법을 정리했는데 generic 시크릿 백엔드만 사용했으므로 다른 백엔드를 사용해보자. 여러 백엔드를 다 써본 것은 아니지만 대부분 비슷하므로 백엔드를 하나 사용해보면 어떤 식으로 동작하는지 대충 예상할 수 있다.

generic 시크릿 백엔드는 이미 가지고 있는 정보를 저장하는 방식이라면 그 외에 다른 백엔드는 대부분 서비스를 연결해서 필요할 때 시크릿 정보를 동적으로 발급받아서 사용하는 방식이다. 동적으로 발급받는다는 동작이 말로 설명하기가 어려운데 실제로 한번 보면 이해할 수 있을 거라고 생각한다.

PostgreSQL 시크릿 백엔드

PostgreSQL 시크릿 백엔드를 사용하면 PostgreSQL 데이터베이스에 접근이 필요할 때 인증 정보를 동적으로 Vault에서 받아서 접속에 사용할 수 있다.

이전 글에서 설명한 대로 Vault 서버가 설정되어 있고 루트 토큰으로 인증한 상태라고 해보자.(이전 글 1, 2 참고)

$ vault mount postgresql
Successfully mounted 'postgresql' at 'postgresql'!

PostgreSQL 시크릿 백엔드가 잘 마운트되었다. 마운트 목록을 보면 확인할 수 있다.

$ vault mounts
Path         Type        Default TTL  Max TTL  Description
cubbyhole/   cubbyhole   n/a          n/a      per-token private secret storage
postgresql/  postgresql  system       system
secret/      generic     system       system   generic secret storage
sys/         system      n/a          n/a      system endpoints used for control, policy and debugging


PostgreSQL 시크릿 백엔드 구성

개발 중인 서버 애플리케이션에서 사용 중인 데이터베이스가 127.0.0.1:5432에 있다고 해보자.(이는 데모를 위해서이고 실제로는 Vault와 같은 로컬에 있지 않을 것이다.) 이제 vault write postgresql/config/connection에 다음과 같이 커넥션 정보를 저장하면 된다. 계정과 비밀번호가 모두 postgres이고 app이 데이터베이스 이름이다.

vault write postgresql/config/connection \
> connection_url="postgresql://postgres:postgres@127.0.0.1:5432/app?sslmode=disable"


The following warnings were returned from the Vault server:
* Read access to this endpoint should be controlled via ACLs as it will return the connection string or URL as it is, including passwords, if any.

이제 Vault가 데이터베이스에 접근할 권한을 갖게 되었다 여기서 새로운 계정을 만들 것이므로 이 계정(여기서는 postgres)이 사용자를 관리할 수 있는 GRANT OPTION 권한을 가지고 있어야 한다. 마지막에 나온 안내 메시지는 이 경로를 통해 커낵션 정보를 볼 수 있으니 ACL로 잘 관리하라는 주의 메시지일 뿐이다.

시크릿 백엔드 설정이 완료되었으므로 roles을 추가하면 된다. 다음은 app이라는 role을 추가하는 명령어다. 당연히 필요에 따라 여러 가지 role을 만들 수 있다.

$ vault write postgresql/roles/app \
> sql="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"{{name}}\";"
Success! Data written to: postgresql/roles/app

위의 app role에 지정한 sql은 실제 PostgreSQL에서 Role을 만들 때 사용할 명령어이다. 위에서 보듯이 새로운 Role을 만들고 해당 데이터베이스의 테이블에 모든 권한(ALL PRIVILEGES)을 주었다. Role을 만들 때 위 SQL 문을 사용하는 것이므로 원하는 조건에 맞게 권한 등을 설정할 수 있고 {{ }}안에 있는 값은 Vault가 자동으로 채워주는 것입니다.

PostgreSQL 시크릿 백엔드의 사용

원래는 postgresql/에 대한 ACL 권한을 주고 인증관리를 해야 맞지만 여기서는 편의상 그냥 사용하도록 하겠다.

$ vault read postgresql/creds/app
Key             Value
---             -----
lease_id        postgresql/creds/app/647a4a14-a91f-9c33-c19f-a79acc2d4625
lease_duration  768h0m0s
lease_renewable true
password        f2ba0b61-b2fd-2559-c22b-5c405a00e0eb
username        root-3c25cbde-ca0b-84b9-3e75-1ab466a258e3

generic 백엔드에서 값을 읽어 오듯이 postgresql/creds/app에서 인증정보를 읽어오면 된다. 마지막의 app은 앞에서 만든 role의 이름이다. 여기서 postgresql/creds/app에 값을 저장한 적이 없으므로 앞에서 설정한 대로 SQL을 실행하고 새로 만들어진 usernamepassword를 반환해 준다.

여기서 발급받은 정보로 접속하면 정상적으로 접속되는 것을 확인할 수 있다.

$ psql -h 127.0.0.1 -p 5432 -d app -U root-3c25cbde-ca0b-84b9-3e75-1ab466a258e3
Password for user root-3c25cbde-ca0b-84b9-3e75-1ab466a258e3:
psql (9.6.1)
Type "help" for help.

app=>

개발할 때 대표적인 비밀 정보 중 하나가 데이터베이스 계정정보이다. 서버의 코드가 유출되는 경우가 많지는 않으니 소스코드에 하드 코딩되어 있는 경우가 많고 따로 관리한다고 하더라도 어딘가에는 하드 코딩이 되어 있어야 한다. 서버 애플리케이션을 이미 운영하기 시작하고 나면 이 계정정보는 바꾸기가 쉽지 않다. 개발하면 개발자들이 퇴사 등으로 바뀌게 마련이고 데이터베이스는 네트워크 등으로 접근이 차단되어 있는 데다가 개발자들이 이미 알고 있는 계정정보로 퇴사 후에 뭔가 한다는 것을 말하는 건 아니지만, 정보는 이렇게 빠져나가는 거고 보안은 누군가를 의심해서 하는 건 아니다. 이런 상황은 개발의 생산성을 낮추지 않으면서도 계정정보를 잘 관리할 방법이 별로 없으므로 하는 방식인데 이를 Vault에 넣는다면 전체 데이터베이스 계정 관리하나만 Vault에 넣어두고 개발자나 서버 애플리케이션을 필요할 때 발급받아서 사용할 수 있으므로 관리하에 둘 수 있고 혹여 유출된다고 하더라도 Vault에 저장한 메인 정보가 유출된 게 아니라면 revoke 하면 그만이다.

위에서는 만료시간이 768시간 즉, 32일로 설정되어 있다. 이 시간이 앞에서 입력한 SQL 문에 {{expiration}}에 들어가므로 계정 자체가 이 시간 내에만 유효한 계정으로 만들어지므로 이 시간도 정책에 따라 잘 설정해야 한다. 이 값은 vault write postgresql/config/lease lease=10h lease_max=24h 명령어로 원하는 값으로 바꿀 수 있는데 아직 lease 시간이 되면 어떻게 되고 어떤 정책으로 운영해야 할지는 아직 테스트해보지 못했다.

2017/02/09 03:03 2017/02/09 03:03