본문 바로가기
Security/Vault

HashiCorp Vault 란? 개념부터 설치까지

by wlsdn3004 2023. 4. 8.
728x90
반응형

 

기업에서는 AWS API key, 데이터베이스 비밀번호, 인증서 등 다양한 중요 정보들을 안전하게 보관하고 관리해야 할 필요가 있다. 하지만 중요한 정보들이 점차 늘어나면 관리에 어려움을 겪게 된다. 이때 Vault를 사용하면 이러한 중요 정보들을 중앙에서 안전하게 저장하고 관리할 수 있다.

 

Vault란?

HashiCorp Vault는 데이터 암호화와 접근 제어를 통해 비밀 정보 관리를 위한 소프트웨어 도구이다. 비밀 정보(예: API 키, 비밀번호, 인증서)를 안전하게 저장하고, 사용자 인증과 권한 부여를 통해 엄격하게 제어하며, 감사할 수 있다. Vault는 클라우드 환경과 같은 동적 인프라에서 사용하기에 적합하며, 다양한 인증 방법과 통합되어 보안을 강화하는 데 사용된다.

 

Vault의 핵심 워크플로우는 다음과 같다.

Vault workflow

  1. 인증(Authenticate)
    클라이언트가 누구인지 확인하고 인증이 완료되면 토큰을 생성한다.
  2. 검증(Validation)
    신뢰할 수 있는 외부 소스를 통해 클라이언트를 검증한다.
  3. 권한 부여(Authorize)
    클라이언트를 Vault 보안 정책과 일치시키고, 액세스 권한을 부여한다.
  4. 액세스(Access)
    클라이언트의 ID와 관련된 정책에 기반하여 토큰을 발급하여 비밀, 키, 암호화 기능 등에 접근할 수 있는 액세스 권한을 부여한다. 이후 클라이언트는 Vault 토큰을 사용할 수 있다.

 

Vault의 주요 기능은 다음과 같다.

  • 임의의 키/값 비밀을 안전하게 저장하고 암호화하여 영구 저장소에 기록한다.
  • AWS나 데이터베이스 등에서 필요한 경우 Vault에서 즉시 비밀을 생성할 수 있다.
  • 암호화 파라미터를 정의할 수 있어서, 데이터를 별도 저장 없이 암호화/복호화할 수 있다.
  • Vault의 모든 Secret에는 lease가 연결되어 있어, 이를 자동으로 폐기 및 갱신할 수 있다.
  • Vault는 단일 Secret 뿐만 아니라, 특정 유저가 읽은 모든 Secret이나 특정 타입의 모든 Secret 등을 폐기할 수 있다. 이는 키 롤링 및 침입 대응을 위한 시스템 보안에 도움이 된다.

 

 

이번 포스팅에서 실습을 통해 Vault를 설치하는 과정을 다룬다.

설치 대상은 AWS EKS 환경이며 Helm Chart를 통해 설치한다.

 

구성은 아래와 같다.

HA Vault Cluster(raft)

 

설치할 Vault의 버전은 다음과 같다.

  • Helm Chart 버전 : 0.23.0
  • APP 버전 : 1.12.1

 

구성 실습


Vault의 데이터를 저장할 backend storage는 raft 방식을 통해서 ha로 구성할 것이다.

Raft 란?
Raft는 분산 시스템에서 일관성을 유지하기 위한 합의 알고리즘 중 하나로, 클러스터 내의 서버 간에 데이터 일관성을 보장하고 다수결 합의를 기반으로 리더 서버를 선택하여 동작한다. Raft는 다운되거나 장애가 발생한 서버를 자동으로 복구할 수 있으며, 높은 가용성과 안정적인 운영을 보장한다.

 

Vault의 Helm Chart repository를 등록 후 설치한다.

## vault repo 등록
$ helm repo add hashicorp https://helm.releases.hashicorp.com

## vault 설치
$ helm install vault hashicorp/vault -n vault \
--create-namespace \
--set='server.ha.enabled=true' \
--set='server.ha.raft.enabled=true'

 

정상으로 설치되었는지 확인한다.

$ helm list -n vault
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
vault   vault           1               2023-04-08 07:22:24.978229251 +0000 UTC deployed        vault-0.23.0    1.12.1

$ kubectl get all -n vault
NAME                                        READY   STATUS    RESTARTS   AGE
pod/vault-0                                 0/1     Running   0          39s
pod/vault-1                                 0/1     Running   0          39s
pod/vault-2                                 0/1     Running   0          39s
pod/vault-agent-injector-7b797687f7-gjlss   1/1     Running   0          39s

NAME                               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
service/vault                      ClusterIP   10.100.238.148   <none>        8200/TCP,8201/TCP   39s
service/vault-active               ClusterIP   10.100.209.183   <none>        8200/TCP,8201/TCP   39s
service/vault-agent-injector-svc   ClusterIP   10.100.250.205   <none>        443/TCP             39s
service/vault-internal             ClusterIP   None             <none>        8200/TCP,8201/TCP   39s
service/vault-standby              ClusterIP   10.100.62.240    <none>        8200/TCP,8201/TCP   39s

NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/vault-agent-injector   1/1     1            1           39s

NAME                                              DESIRED   CURRENT   READY   AGE
replicaset.apps/vault-agent-injector-7b797687f7   1         1         1       39s

NAME                     READY   AGE
statefulset.apps/vault   0/3     39s

 

아직 READY 상태가 0/1로, sealed상태이기 때문에  Readiness probe를 통과하지 못한 것이다.

seal상태는 Vault의 데이터 보호 상태이며 unseal 상태에서 데이터를 읽고 쓸 수 있다. unseal 상태가 되면 1/1로 변경된다.

 

Vault pod 내부로 접근하여 상태를 확인해 보자.

$ kubectl exec vault-0 -n vault -- vault status
Key                Value
---                -----
Seal Type          shamir
Initialized        false
Sealed             true      ## seal 상태 확인
Total Shares       0
Threshold          0
Unseal Progress    0/0
Unseal Nonce       n/a
Version            1.12.1
Build Date         2023-03-23T12:51:35Z
Storage Type       raft
HA Enabled         true
command terminated with exit code 2

$ kubectl exec vault-1 -n vault -- vault status
Key                Value
---                -----
Seal Type          shamir
Initialized        false
Sealed             true			## seal 상태 확인
Total Shares       0
Threshold          0
Unseal Progress    0/0
Unseal Nonce       n/a
Version            1.12.1
Build Date         2023-03-23T12:51:35Z
Storage Type       raft
HA Enabled         true
command terminated with exit code 2

$ kubectl exec vault-2 -n vault -- vault status
Key                Value
---                -----
Seal Type          shamir
Initialized        false
Sealed             true			## seal 상태 확인
Total Shares       0
Threshold          0
Unseal Progress    0/0
Unseal Nonce       n/a
Version            1.12.1
Build Date         2023-03-23T12:51:35Z
Storage Type       raft
HA Enabled         true
command terminated with exit code 2

 

unseal을 위해 초기화를 진행하고, 초기화 때 나오는 unseal secret 키를 파일로 저장한다.

먼저 vault-0 pod를 leader로 선정하기 위해 vault-0 pod부터 진행한다.

$ kubectl exec -n vault vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json

$ cat cluster-keys.json
{
  "unseal_keys_b64": [
    "atmQ5qgSzQfdgdfv4345vsdfvD/8Zmxg="
  ],
  "unseal_keys_hex": [
    "6ad990e6a812cd0a02437c31c6fc1ba47390fff199b18"
  ],
  "unseal_shares": 1,
  "unseal_threshold": 1,
  "recovery_keys_b64": [],
  "recovery_keys_hex": [],
  "recovery_keys_shares": 0,
  "recovery_keys_threshold": 0,
  "root_token": "hvs.8YXfTgQnMZK4VdE1"
}

위에서 초기화 때 -key-shares=1 -key-threshold=1 옵션을 사용하는데

  • key-shares는 Vault 클러스터의 초기화에 사용되는 master key를 생성할 때 분할할 secret 조각 수의 총합이다.
  • key-threshold는 secret을 복원하는 데 필요한 최소 secret 조각 수이다. 
예시) 
key-shares=5, key-threshold=3이라고 가정하자. 이때 unseal을 위해 사용되는 5개의 unseal_key 중 3개 이상이 필요하다는 의미이다.

 key-shares=1, key-threshold=1는 secret 조각을 분할하지 않고 1개만 필요하다는 의미로, 보안에 취약할 수 있으니 테스트 환경에서만 사용한다.

 

초기화를 통해 추출한 unseal_keys_b64를 사용하여 unseal 상태가 되게 한다.

$ kubectl exec -n vault vault-0 -- vault operator unseal atmQ5qgSzQfdgdfv4345vsdfvD/8Zmxg=
Key                     Value
---                     -----
Seal Type               shamir
Initialized             true
Sealed                  false      	  ## true -> false 로 변경 확인
Total Shares            1
Threshold               1
Version                 1.12.1
Build Date              2023-03-23T12:51:35Z
Storage Type            raft
Cluster Name            vault-cluster-2523014a
Cluster ID              b485973a-61e7-c7cf-833d-dd97218b0fe4
HA Enabled              true
HA Cluster              https://vault-0.vault-internal:8201
HA Mode                 active
Active Since            2023-04-08T08:01:27.251867834Z
Raft Committed Index    36
Raft Applied Index      36

 

unseal이 됐으면 vault-0 pod만 READY 상태가 0/1 -> 1/1로 변경된 것을 확인할 수 있다.

kubectl get po -n vault
NAME                                    READY   STATUS    RESTARTS   AGE
vault-0                                 1/1     Running   0          43m  ## 1/1 확인
vault-1                                 0/1     Running   0          43m
vault-2                                 0/1     Running   0          43m
vault-agent-injector-7b797687f7-gjlss   1/1     Running   0          43m

 

Sealed 상태가 false 가 됐으면 Vault init때 저장한 cluster-keys.json 파일에서 root_token을 통해 로그인한다.

$ kubectl exec -n vault vault-0 -- vault login hvs.8YXfTgQnMZK4VdE1
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                hvs.8YXfTgQnMZK4VdE1
token_accessor       8mPHZDIUmjluDM2sI3koW1bj
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]

 

로그인을 성공하면 클러스터의 상태를 확인한다.

$ kubectl exec -n vault vault-0 -- vault operator raft list-peers
Node                                    Address                        State     Voter
----                                    -------                        -----     -----
1c35b340-d3dd-e923-7001-60fa7fcf17a6    vault-0.vault-internal:8201    leader    true

 

현재는 1개의 노드만 leader로 존재하는 것을 확인할 수 있다.

 

이제 두 번째인 vault-1 pod도 unseal을 진행해 보자. unseal을 진행하기 전 leader vault에 join 시켜야 한다.

## vault join
$ kubectl exec -n vault vault-1 -- vault operator raft join http://vault-0.vault-internal:8200
Key       Value
---       -----
Joined    true

## vault unseal
$ kubectl exec -n vault vault-1 -- vault operator unseal atmQ5qgSzQfdgdfv4345vsdfvD/8Zmxg=
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       1
Threshold          1
Unseal Progress    0/1
Unseal Nonce       n/a
Version            1.12.1
Build Date         2023-03-23T12:51:35Z
Storage Type       raft
HA Enabled         true

 

join일 잘 되었는지 leader vault에서 확인한다.

## vauilt-1 follower 상태 확인
$ kubectl exec -n vault vault-0 -- vault operator raft list-peers
Node                                    Address                        State       Voter
----                                    -------                        -----       -----
1c35b340-d3dd-e923-7001-60fa7fcf17a6    vault-0.vault-internal:8201    leader      true
7cb6b646-3f51-da3d-b21b-51a4db0287a9    vault-1.vault-internal:8201    follower    true

## vault-0, vault-1 READY 상태 확인
$ kubectl get po -n vault
NAME                                    READY   STATUS    RESTARTS   AGE
vault-0                                 1/1     Running   0          57m
vault-1                                 1/1     Running   0          57m
vault-2                                 0/1     Running   0          57m
vault-agent-injector-7b797687f7-gjlss   1/1     Running   0          57m

 

세 번째 vault-2 pod도 vault-1과 동일하게 진행한다.

## vault join
$ kubectl exec -n vault vault-2 -- vault operator raft join http://vault-0.vault-internal:8200
Key       Value
---       -----
Joined    true

## vault unseal
$ kubectl exec -n vault vault-2 -- vault operator unseal atmQ5qgSzQfdgdfv4345vsdfvD/8Zmxg=
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       1
Threshold          1
Unseal Progress    0/1
Unseal Nonce       n/a
Version            1.12.1
Build Date         2023-03-23T12:51:35Z
Storage Type       raft
HA Enabled         true

 

정상으로 클러스터가 구성이 되었는지 마지막으로 확인한다.

$ kubectl exec -n vault vault-0 -- vault operator raft list-peers
Node                                    Address                        State       Voter
----                                    -------                        -----       -----
1c35b340-d3dd-e923-7001-60fa7fcf17a6    vault-0.vault-internal:8201    leader      true
7cb6b646-3f51-da3d-b21b-51a4db0287a9    vault-1.vault-internal:8201    follower    true
bfaa548a-18a1-995e-7cd0-1c21a0da7327    vault-2.vault-internal:8201    follower    true

$ kubectl get po -n vault
NAME                                    READY   STATUS    RESTARTS   AGE
vault-0                                 1/1     Running   0          60m
vault-1                                 1/1     Running   0          60m
vault-2                                 1/1     Running   0          60m
vault-agent-injector-7b797687f7-gjlss   1/1     Running   0          60m

 

Vault Web Ui 대시보드에 접근한다.

eks의 vault이름의 service를 LoadBalancer로 변경 후 LoadBalancer:8200으로 접근한다.

$ kubectl patch service -n vault vault -p '{"spec": {"type": "LoadBalancer"}}'

 

로그인 token은 Vault init 때 추출한 cluster-keys.json 파일에서 root_token 값을 넣어주면 된다.

Vault 대시보드 로그인 화면

 

Token으로 로그인하면 아래와 같은 화면을 볼 수 있다.

Vault 대시보드

[참고]
Vault pod가 다시 생성되면(restart) unseal 과정을 다시 해줘야 한다.

 

마치며


이번 글에서는 HashiCorp Vault의 기본 개념과 기능을 간단히 살펴보았으며, 특히 EKS (Elastic Kubernetes Service) 환경에서 Helm Chart를 이용하여 Vault를 Raft HA 방식으로 구성하는 실습을 진행해보았다.

Raft HA 방식 외에도 다양한 구성 방식이 존재하므로, 각 환경과 요구에 맞게 구성 방식을 선택할 수 있다. 또한, 글에서 다뤘던 번거로운 Unseal 과정을 자동으로 처리해주는 Auto Unseal 기능도 Vault에서 제공하고 있다.

안전한 데이터 보관은 기업에게 불가피한 요구사항 중 하나로, Vault를 통해 안전한 환경을 구성하여 데이터 안정성을 강화해보자.

 

반응형

댓글