hashicorp vault (draft)
https://www.vaultproject.io/intro/index.html
What is Vault?
vault는 secrets 에 안전하게 접근할 수 있도록 하는 툴입니다. secret 은 API keys, passwords 또는 인증서 등 철저하게 제어하기를 원하는 모든 정보입니다. vault는 secret에 대해서 단일한 인터페이스를 제공하면서 상세한 접근 통제 및 audit 로그를 기록하는 기능이 있습니다.
현대의 시스템은 여러개의 secret에 접근이 필요합니다. database 비밀번호, 외부 서비스에 대한 API 키, 서비스 지향 아키텍쳐 통신을 위한 비밀번호 등. 누가 어떤 secret에 접근가능한지 이해하는 것이 매우 어렵고 플랫폼 의존적입니다. 전문화된 솔루션이 없다면 키 순환하는 기능 추가, 안전한 스토리지, 상세한 오딧 로그 남기는 것이 거의 불가능합니다. vault가 제공하는 기능이 이러한 기능입니다.
Secure Secret Storage
Dynamic Secrets
Data Encryption
Leasing and Renewal
Revocation
Use Cases
General Secret Storage
Employee Credential Storage
API Key Generation for Scripts
Data Encryption
Getting Started
https://www.vaultproject.io/intro/getting-started/install.html
Install Vault : 설치
Starting the Server : vault 시작
Secret write, read, delte
Secrets Engines → 해당 종류 확인 필요.
Dynamic Secrets : AWS Secrete Engine. AWS access key pair 생성해줌. revoke 하면 해당 secret 도 IAM에서 삭제가 됨.
Built-in Help
Authentication : Auth Methods로 github 인증 예제.
Policies : 특정 policy 생성 후 token 생성하는 예제. Policies를 auth methods(github)에 매킹하는 예제. github로 로그인시 기본 policy를 만들어서 적용.
Deploy Vault
- 실제 환경에 vault 구성시 설정하는 것 설명하고 있음. 설정, seal/unseal, scaling. physical backend로 consul 사용.
- 서버 시작하기, 초기화 하기(unseal key 5개 나오며 잘 보관해야 하며
Initial Root Token 도 확인필요
Vault 가 초기화 되었을 때 sealed 상태임. vault가 데이터를 어떻게 decrypt 하면 되는지 알려주는 것이 unsealing. vault 가 시작을 할 때마다 unsealing을 해야 하며 unseal key 에 대한 threshold 갯수만큼 필요하다.
마지막으로 initial root token으로 인증을 한다.
HTTP API : HTTP API 예제.
정리
Secrets Engines
https://www.vaultproject.io/docs/secrets/index.html
Secrets Engines : AWS, Consul, Databases, Key/Value, etc...
AWS
AWS secrets Engine
https://www.vaultproject.io/intro/getting-started/dynamic-secrets.html
$ vault secrets list | grep -q aws || vault secrets enable -path=aws aws $ vault write aws/config/root \ access_key=XXXXXXXXXXXXXXX \ secret_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Success! Data written to: aws/config/root $ vault write aws/roles/my-role policy=-<<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1426528957000", "Effect": "Allow", "Action": [ "ec2:*" ], "Resource": [ "*" ] } ] } EOF $ vault write aws/roles/ec2fullaccess \ arn=arn:aws:iam::aws:policy/AmazonEC2FullAccess $ vault write aws/roles/ec2readonlyaccess \ arn=arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess $ vault read aws/creds/my-role Key Value --- ----- lease_id aws/creds/my-role/0bce0782-32aa-25ec-f61d-c026ff22106e lease_duration 768h lease_renewable true access_key AKIAJELUDIANQGRXCTZQ secret_key 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 security_token <nil> $ vault read aws/creds/ec2fullaccess $ vault read aws/creds/ec2readonlyaccess
vault read aws/creds/my-role 를 실행하면 access_key, secret_key를 생성한다.
lease 설정하는 예
$ vault write aws/config/lease lease=5m lease_max=10m
policy 만들고 github team과 연동. organization은 자기에 맞게 변경해야 함.
$ vault policy write ec2admin -<<EOF path "aws/creds/ec2fullaccess" { capabilities = ["read"] } EOF $ vault policy write ec2user -<<EOF path "aws/creds/ec2readonlyaccess" { capabilities = ["read"] } EOF $ vault write auth/github/config organization=myorg $ vault write auth/github/map/teams/devops value=ec2admin $ vault write auth/github/map/teams/ygy value=ec2user
이제 github에서 Personal access tokens 을 생성한다. token 생성시 repo에 대해서 권한을 주지 않는 경우 조회 자체가 안되었다. 이 부분만 권한을 주면 될 듯 하다.
https://github.com/settings/tokens
일반 user의 경우 github에 Personal access tokens 을 먼저 생성한다. 그러고 나서 github의 token을 이용하여 로그인을 하고 필요한 권한을 read 하면 된다.
$ vault login -method=github token=xxxx $ vault read aws/creds/ec2fullaccess
Databases
https://www.vaultproject.io/docs/secrets/databases/mysql-maria.html
admin
$ vault secrets list | grep -q database || vault secrets enable database $ docker ps | grep -q mysql || docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mysql -d mysql:latest $ vault write database/config/my-mysql-database \ plugin_name=mysql-database-plugin \ connection_url="root:mysql@tcp(127.0.0.1:3306)/" \ allowed_roles="mysqlreadonly" $ vault write database/roles/mysqlreadonly \ db_name=my-mysql-database \ creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON *.* TO '{{name}}'@'%';" \ default_ttl="1h" \ max_ttl="24h" $ vault read database/creds/mysqlreadonly $ docker exec -it mysql mysql -uroot -pmysql -e 'select host,user from user' mysql $ vault policy write mysqlreadonly -<<EOF path "database/creds/mysqlreadonly" { capabilities = ["read"] } EOF $ vault policy write mysqlwrite -<<EOF path "database/creds/mysqlwrite" { capabilities = ["read"] } EOF $ vault token create -policy=mysqlreadonly $ vault token create -policy=mysqlwrite
user
# mysqlreadonly policy로 만들어진 token $ vault login XXXX $ vault read database/creds/mysqlreadonly # mysqlwrite policy로 만들어진 token $ vault login XXXX $ vault read database/creds/mysqlreadonly ... * permission denied
Auth Methods
https://www.vaultproject.io/docs/auth/index.html
Auth Methods : AppRole, AWS, GitHub(GitHub personal access token), LDAP, Tokens, Username&Password (외부 소스에서 읽어오지 못함), etc
GitHub 인증은 사람에게 유용함
GitHub
https://www.vaultproject.io/intro/getting-started/authentication.html 에서 github
$ vault auth list | grep -q github || vault auth enable -path=github github $ vault write auth/github/config organization=hashicorp $ vault write auth/github/map/teams/my-team value=default,my-policy
AppRole
https://www.vaultproject.io/docs/auth/approle.html : The approle
auth method allows machines or apps to authenticate with Vault Vault-defined roles. The open design of AppRole
enables a varied set of workflows and configurations to handle large numbers of apps. This auth method is oriented to automated workflows (machines and services), and is less useful for human operators.
대량의 apps 를 처리하기 위한 다양한 워크플로, 설정이 가능하다고 하며 자동화된 workflows에 촛첨이 맞추어져 있고 사람의 작업에 유용하지는 않다고 함.
https://www.vaultproject.io/guides/configuration/authentication.html 에서 Advanced Features 참고.
Approle을 쓰는 경우 어떻게 client app에 role ID, secret ID를 넘겨줄 것인가가 이슈임.
The Role ID is equivalent to a username, and Secret ID is the corresponding password. The app needs both to log in with Vault. Naturally, the next question becomes how to deliver those values to the expecting client.
A common solution involves three personas instead of two: admin
, app
, and trusted entity
. The trusted entity
delivers the Role ID and Secret ID to the client by separate means.
For example, Terraform as a trusted entity can deliver the Role ID onto the virtual machine. When the app runs on the virtual machine, the Role ID already exists on the virtual machine.
Trusted Entity 가 role ID, secret ID를 해당 client,app에 넘겨주는 것이다. Trusted Entity 는 Terraform, CM도구, jenkins 등이 될 수 있겠다. 이 과정에서 response wrapping 을 쓰면 편리하다. 그런데 일반 개발소스에서도 Trusted Entity를 이용할 수 있을까?
AppRole 이용한 예제
사전에 예제용으로 secret/mysql 을 생성한다.
$ vault write secret/mysql/prod mysql_password=test_password
https://www.vaultproject.io/guides/configuration/authentication.html 참고하여 설정
$ vault auth list | grep -q approle || vault auth enable approle $ cat <<'EOF' > jenkins-pol.hcl # Login with AppRole path "auth/approle/login" { capabilities = [ "create", "read" ] } # Read test data path "secret/mysql/*" { capabilities = [ "read" ] } EOF $ vault policy write jenkins jenkins-pol.hcl $ vault write auth/approle/role/jenkins policies="jenkins" \ secret_id_ttl=1m \ token_num_uses=10 \ token_ttl=60s \ token_max_ttl=5m \ secret_id_num_uses=5 $ vault read auth/approle/role/jenkins/role-id $ vault write -f auth/approle/role/jenkins/secret-id
App에서 사용하기 : role-id, secret-id 이용. 이 정보는 admin이 해당 app에 전달을 해 주어야 한다.
$ MY_VAULT_TOKEN=`vault write -field token auth/approle/login \ role_id="375805f4-a36f-f313-da0f-127cb6613283" \ secret_id="abb9e4fc-25ec-46ba-64e3-7b5a623ee010"` $ VAULT_TOKEN=$MY_VAULT_TOKEN vault read secret/mysql/prod $ VAULT_TOKEN=$MY_VAULT_TOKEN vault read -field mysql_password secret/mysql/prod test_password
trusted entity 이용하여 Role ID and Secret ID app에 전달하기
jenkins, saltstack 같은 trusted entity 가 vault 에서 필요한 role-id 를 읽을 수 있어야 하고 secret-id는 생성, 업데이트 권한도 있어야 한다.
$ cat <<'EOF' > trusted_entity.hcl # Read jenkins role-id path "auth/approle/role/jenkins/role-id" { capabilities = [ "read" ] } # Read jenkins secret-id path "auth/approle/role/jenkins/secret-id" { capabilities = [ "create","read","update" ] } EOF $ vault policy write trusted_entity trusted_entity.hcl $ vault token create -policy=trusted_entity
trusted entity and app
위에서 trusted_entity 정책을 가진 토큰을 생성하고 이 토콘을 이용하여 trusted entity에서 로그인을 하고 필요한 정보를 가져올 수 있도록 설정한다.
secret/mysql/prod 에 설정한 mysql_password 의 값은 사전에 설정이 되어 있어야 한다.
$ cat get_password.sh #!/bin/bash using_wrapping_token="yesa" trusted_entity_token="4b9caeeb-2afc-491f-7833-xxxxxxxxxxxxxx" vault login $trusted_entity_token > /dev/null role_id=`vault read -field role_id auth/approle/role/jenkins/role-id` if [ "$using_wrapping_token" = "yes" ]; then wrapping_token=`vault write -field wrapping_token -wrap-ttl=60s -f auth/approle/role/jenkins/secret-id` secret_id=`VAULT_TOKEN=$wrapping_token vault unwrap -format=json | jq -r ".data.secret_id"` else secret_id=`vault write -format=json -f auth/approle/role/jenkins/secret-id | jq -r ".data.secret_id"` fi MY_VAULT_TOKEN=`vault write -field token auth/approle/login \ role_id="${role_id}" \ secret_id="${secret_id}"` #VAULT_TOKEN=$MY_VAULT_TOKEN vault read secret/mysql/prod vault login $MY_VAULT_TOKEN > /dev/null vault read -field mysql_password secret/mysql/prod $ ./get_password.sh test_password
실제 app에서 활용하기
사람은 github 정보를 통해서 권한관리를 하고 SERVER/CI는 app-id를 이용하여 관리하는 경우의 사례.
https://infinum.co/the-capsized-eight/hiding-secrets-in-vault
여기서는 관리해야 할 secrets가 많기 때문에 아래의 naming conventions 사용.
rails/#{git_repository_name}/#{environment}
위 예를 보면 애플리케이션의 비밀번호 config/application.yml , DBMS 관련한 정보 config/database.yml 를 별도의 파일에 빼어 놓는다.
이 파일들은 버전관리시스템에서 관리하지 않는다. (.gitignore 설정)
애플리케이션 배포를 할 때 배포 스크립트에서 secret 관련한 정보를 vault에서 가져와 해당 설정파일을 만드는 형태이다.
.secret 파일 예제 : secret 들어간 파일 명과 vault 에서 사용하는 path 정보가 들어 있다.
# file where your secrets are kept depending on your environment gem :secrets_file: config/application.yml # vault 'storage_key' where your secrets will be kept :secrets_storage_key: rails/my_project/
github 에서 여러가지 이용한 예제
github 인증은 활성화를 하고 organization 설정을 했다고 가정을 함.
아래의 경우는 github 에서 devops팀에 ec2admin, jenkins 라는 policy를 허용해주는 설정임.
$ vault write auth/github/map/teams/devops value=ec2admin,jenkins Success! Data written to: auth/github/map/teams/devops
policy를 각 권한별로 관리할 수도 있고 (AWS 별도, 소스코드 비밀번호 별도 등) 각 팀별로 만들 수 있다. (devops에 A, B 권한 설정)
참고
관리용 스크립트
테스팅 편리하게 사용하기 위한 스크립트 모음.
vault init 을 하고 unseal을 하며 init하면서 만든 root token 으로 로그인을 한다.
수동으로 할 경우에는 export VAULT_ADDR='http://127.0.0.1:8200' 을 해 주어야 한다.
vault init
$ cat <<'EOF' > init.sh #!/bin/bash vault_init_file=".vault_init_info" dpkg -l | grep -q jq || apt install -y jq dpkg -l | grep -q kbtin || apt install -y kbtin export VAULT_ADDR='http://127.0.0.1:8200' if ! test -f $vault_init_file ; then if vault operator init | ansi2txt > $vault_init_file ; then ./unseal.sh fi else vault status fi
unseal
$ cat <<'EOF' > unseal.sh #!/bin/bash vault_init_file=".vault_init_info" if ! test -f $vault_init_file ; then echo "can't find $vault_init_file" exit 1 fi check_sealed=`vault status -format=json | jq -r .sealed` if [ "$check_sealed" = "true" ]; then unseal_keys=`grep "Unseal" $vault_init_file | awk '{ print $4 }'` for unseal_key in $unseal_keys; do vault operator unseal $unseal_key > /dev/null done fi EOF
root token 얻고 로그인
$ cat <<'EOF' > get_root_token.sh #!/bin/bash vault_init_file=".vault_init_info" if ! test -f $vault_init_file ; then echo "can't find $vault_init_file" exit 1 fi token=`grep Root $vault_init_file | awk '{ print $4 }'` echo "Please type this command" echo echo "export VAULT_ADDR='http://127.0.0.1:8200'" echo "vault login $token" #export VAULT_ADDR='http://127.0.0.1:8200' #vault login $token #vault write secret/hello value=world excited=yes EOF
HA
Storage Backend 에서 HA 지원하는 것은 Consul, Zookeeper, etcd이다. 이중 HashiCopr Supported는 Consul만 된다. Zookeeper, etcd 를 사용하고 있지 않다면 Consul과 같이 써야 한다.
https://www.vaultproject.io/docs/concepts/ha.html Storage Support 참고. s3의 경우 HA 지원하지 않는다. (https://www.vaultproject.io/docs/configuration/storage/s3.html)
https://www.vaultproject.io/docs/concepts/ha.html
Vault supports a multi-server mode for high availability.
The successful server node then becomes the active node; all other nodes become standby nodes. At this point, if the standby nodes receive a request, they will either forward the request or redirect the client depending on the current configuration and state of the cluster -- see the sections below for details. Due to this architecture, HA does not enable increased scalability. In general, the bottleneck of Vault is the data store itself, not Vault core. For example: to increase the scalability of Vault with Consul, you would generally scale Consul instead of Vault.
vault에서 high availability를 위해 여러 대의 서버를 운영하는 것을 지원한다. 현재 운영중인 서버 노드가 active node가 되고 나머지 노드는 standby 노드가 된다. 스탠바이 노드에서 요청을 받으면 설정에 따라서 요청을 포워드 하거나 redirect를 한다. 이런 구조 때문에 HA는 확장성을 높이지는 않는다. 일반적으로 vault 에서 병목이 생기는 것은 vault 자체가 아니고 데이터를 저장하는 부분이다. consul과 함께 vault를 사용하는 경우 확장성을 높이려면 일반적으로 consul을 확장한다.
vault HA 구성하는 것과 관련해서는 아래 문서에 자세히 나와있다.
https://www.vaultproject.io/guides/operations/vault-ha-consul.html
vault 에서 HA 구성시 연관되어 있는 옵션은 cluster_address, api_addr, cluster_addr 이다.
cluster_address : this should be set to address that you prefer the Vault servers perform intra-server communications on. vault 서버간에 통신을 하는 address
api_addr : this should be set to the address which client (API) requests are to be redirected to. 클라이언트 요청을 redirect 할 주소
cluster_addr : this parameter is specifically for HA request forwarding between Vault servers and needs to be a address routable between all Vault servers in a full URL format with port. vault 서버간에 HA 요청을 포워딩할 때 사용함.
그런데 consul을 쓰는 경우 이 부분을 따로 설정하지 않아도 여러 대의 vault 서버를 띄우는 경우 자동으로 acitve/standby 구성을 한다. standby 서버에 접근하려는 경우에는 자동으로 active 서버로 request forwarding 을 한다. 만약 로드밸런서를 이용하여 vault에 접근하려는 경우에는 api_addr을 로드밸런서의 정보로 변경해야 할 것이다.
외부 로드밸런서를 쓸 경우에는 active node를 체크하기 위해 특정 url을 체크해야 한다. 이경우 http://<Vault Node URL>:8200/v1/sys/health 에 대해서 200으로 응답을 한다.
https://www.vaultproject.io/guides/operations/reference-architecture.html#load-balancing
참고자료
vault use case : https://sreeninet.wordpress.com/2016/10/01/vault-use-cases/
Example usage of HashiCorp Vault secrets management https://github.com/hashicorp/vault-guides
https://github.com/bruj0/vault_jenkins
https://www.reddit.com/r/devops/comments/7ou98v/how_to_use_hashicorp_vault_to_store_secrets_and/
docker-compose로 vault, consul, jenkins 올림. 테스팅 용도로 좋음.
jenkins에서 테스팅을 하려면 https://github.com/jenkinsci/hashicorp-vault-plugin 설치해야 함. 아직 jenkins를 잘 몰라서 어떻게 실행하는지는 잘모르겠음.
아래 AWS 문서가 vault tree 구조 설계할 때 도움이 될 듯 함.
파라미터를 계층 구조로 조직
/Environment/Type of computer/Application/Data
/Dev/DBServer/MySQL/db-string13
KMS, Paramter Store 이용하여 secrets 관리하는 AWS 예제