[Vault] 설정 파일을 이용한 HA구성 및 TLS 설정(CentOS)

gweowe·2023년 11월 21일

Hashicorp의 Vault는 설정 파일을 사용하여 안전한 Raft 알고리즘 기반의 고가용성(High Availability) 구성을 쉽게 설정할 수 있습니다. 안전한 HA 구성과 함께 TLS 프로토콜을 이용한 통신을 구축하는 방법을 정리해 보았습니다.

사전 준비 사항

1. 환경 준비

Vault HA구성을 하기 위한 서버 3대가 필요합니다. 서버 3대는 자체 DNS 서버를 바라보고 있어야 합니다. 이 가이드에서는 CentOS 7 환경에서 구축하였습니다.

2. Vault 설치

해당 가이드를 참고하여 Vault를 설치합니다.

3. 자체 DNS 서버 구축

해당 가이드를 참고하여 인증서를 적용시킬 DNS 서버를 구축합니다.

4. 인증서 생성

인증서를 생성한 후, 각 서버에 인증서를 배치해줍니다. 해당 가이드를 참고하여 인증서를 생성합니다.

인증서를 생성할 때, DNS 작성 란에 *.gweowe.com와 같이 아스타리스크(*)를 이용해야 인증서 하나로 모든 서버에 적용할 수 있습니다.

생성한 인증서를 pem 형식의 파일로 변환시켜주어야 합니다.

openssl rsa -in [Key 명].key -text > [Key 명].pem
openssl x509 -inform PEM -in [Cert 명].crt > [Cert 명].pem

fullchain.pem을 생성해주어야 합니다.

cat [Subcert_Cert].pem [Root CA].pem >> fullchain.pem

5. 인증서 OS 등록

CentOS에서 인증서를 등록해주어야 합니다.

sudo cp [Root CA].pem /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extract

Vault 설정

1. Vault 폴더 생성

Vault 구축 작업을 진행할 폴더를 생성합니다.

mkdir vault

Vault가 구축될 때 생성되는 Data를 저장할 폴더를 생성합니다.

cd vault
mkdir data

2. Vault 설정 파일

서버마다 설정 파일을 생성합니다.

1번 서버 config.hcl
ui = true
disable_mlock = true

storage "raft" {
  path    = "/home/[유저명]/vault/data"
  node_id = "vault_server1"
  retry_join {
    leader_api_addr = "https://vault2.gweowe.com:8200"
		leader_ca_cert = "[인증서 경로]/fullchain.pem"
    leader_client_cert_file = "[인증서 경로]/cert.pem"
    leader_client_key_file = "[인증서 경로]/key.pem"
  }
  retry_join {  
    leader_api_addr = "https://vault3.gweowe.com:8200"
		leader_ca_cert = "[인증서 경로]/fullchain.pem"
    leader_client_cert_file = "[인증서 경로]/cert.pem"
    leader_client_key_file = "[인증서 경로]/key.pem"
  }
}

listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_disable = false
  tls_cert_file = "[인증서 경로]/cert.pem"
  tls_key_file = "[인증서 경로]/key.pem"
}

api_addr        = "https://vault1.gweowe.com:8200"
cluster_addr    = "https://vault1.gweowe.com:8201"
2번 서버 config.hcl
ui = true
disable_mlock = true

storage "raft" {
  path    = "/home/[유저명]/vault/data"
  node_id = "vault_server2"
  retry_join {
    leader_api_addr = "https://vault1.gweowe.com:8200"
		leader_ca_cert = "[인증서 경로]/fullchain.pem"
    leader_client_cert_file = "[인증서 경로]/cert.pem"
    leader_client_key_file = "[인증서 경로]/key.pem"
  }
  retry_join {  
    leader_api_addr = "https://vault3.gweowe.com:8200"
		leader_ca_cert = "[인증서 경로]/fullchain.pem"
    leader_client_cert_file = "[인증서 경로]/cert.pem"
    leader_client_key_file = "[인증서 경로]/key.pem"
  }
}

listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_disable = false
  tls_cert_file = "[인증서 경로]/cert.pem"
  tls_key_file = "[인증서 경로]/key.pem"
}

api_addr        = "https://vault2.gweowe.com:8200"
cluster_addr    = "https://vault2.gweowe.com:8201"
3번 서버 config.hcl
ui = true
disable_mlock = true

storage "raft" {
  path    = "/home/[유저명]/vault/data"
  node_id = "vault_server3"
  retry_join {
    leader_api_addr = "https://vault1.gweowe.com:8200"
		leader_ca_cert = "[인증서 경로]/fullchain.pem"
    leader_client_cert_file = "[인증서 경로]/cert.pem"
    leader_client_key_file = "[인증서 경로]/key.pem"
  }
  retry_join {  
    leader_api_addr = "https://vault2.gweowe.com:8200"
		leader_ca_cert = "[인증서 경로]/fullchain.pem"
    leader_client_cert_file = "[인증서 경로]/cert.pem"
    leader_client_key_file = "[인증서 경로]/key.pem"
  }
}

listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_disable = false
  tls_cert_file = "[인증서 경로]/cert.pem"
  tls_key_file = "[인증서 경로]/key.pem"
}

api_addr        = "https://vault3.gweowe.com:8200"
cluster_addr    = "https://vault3.gweowe.com:8201"

각 서버에 맞는 설정 파일을 생성합니다. 설정 값에 대한 설명은 다음과 같습니다.

  • ui : Vault 웹 사용자 인터페이스를 활성화합니다.
  • disable_mlock : 메모리 잠금을 설정합니다. 민감한 데이터를 메모리에서 스왑하지 않도록 하는 보안 기능입니다.
  • storage "raft" : Raft 스토리지 백엔드를 설정합니다. Raft는 분산 시스템에서 고가용성을 제공하는 알고리즘입니다.
    • path : Vault의 데이터를 저장할 경로를 지정합니다.
    • node_id : Vault 노드의 id를 설정합니다.
    • retry_join : 클러스터에 참가하기 위한 다른 Vault 노드의 정보를 설정합니다.
      • leader_api_addr : 다른 Vault 노드의 API 주소를 지정합니다.
      • leader_ca_cert : 인증서 chain 파일 경로를 설정합니다.
      • leader_client_cert_file : 대상 클라이언트의 인증서 파일 경로를 설정합니다.
      • leader_client_key_file : 대상 클라이언트의 개인 키 파일 경로를 설정합니다.
  • listener "tcp" : Vault가 수신하는 TCP 리스너를 설정합니다.
    • address : Vault가 바인딩할 IP 주소와 포트를 지정합니다.
    • tls_disable : TLS를 활성화 여부를 지정합니다.
    • tls_cert_file : TLS 인증서 파일의 경로를 설정합니다.
    • tls_key_file : TLS 개인 키 파일의 경로를 설정합니다.
  • api_addr : Vault API의 주소를 설정합니다.
  • cluster_addr : Vault 클러스터 간 통신을 위한 주소를 설정합니다.

3. 서비스 파일 생성

Vault를 실행하기 위한 서비스 파일을 생성합니다.

sudo vi /etc/systemd/system/vault.service
vault.service
[Unit]
Description="HashiCorp Vault - A tool for managing secrets"
Documentation=https://www.vaultproject.io/docs/
Requires=network-online.target
After=network-online.target
ConditionFileNotEmpty=/home/[유저명]/vault/config.hcl
StartLimitIntervalSec=60
StartLimitBurst=3

[Service]
User=[유저명]
Group=[유저명]
ProtectSystem=full
PrivateTmp=yes
PrivateDevices=yes
SecureBits=keep-caps
AmbientCapabilities=CAP_IPC_LOCK
Capabilities=CAP_IPC_LOCK+ep
CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK
NoNewPrivileges=yes
ExecStart=/usr/local/bin/vault server -config=/home/[유저명]/vault/config.hcl
ExecReload=/bin/kill --signal HUP $MAINPID
KillMode=process
KillSignal=SIGINT
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
StartLimitInterval=60
StartLimitIntervalSec=60
StartLimitBurst=3
LimitNOFILE=65536
LimitMEMLOCK=infinity

[Install]
WantedBy=multi-user.target

Vault를 실행하기 위한 모든 준비를 마쳤습니다.

Vault 실행

1. Vault 서비스 파일 실행

vault 서비스 파일을 실행합니다.

sudo systemctl start vault.service

성공적으로 서비스 파일이 실행되는지 확인합니다.

sudo systemctl status vault.service
Output :
● vault.service - "HashiCorp Vault - A tool for managing secrets"
   Loaded: loaded (/etc/systemd/system/vault.service; disabled; vendor preset: disabled)
   Active: active (running) since 화 2023-11-21 15:13:58 KST; 3s ago
     Docs: https://www.vaultproject.io/docs/
 Main PID: 16670 (vault)
   CGroup: /system.slice/vault.service
           └─16670 /usr/local/bin/vault server -config=/home/gweowe/vault/config.hcl

11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: | * Vault is sealed
11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: 2023-11-21T15:14:00.651+0900 [ERROR] core: failed to get raft challenge: leader_addr=https://vault2.gweowe.com:8200
11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: error=
11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: | error during raft bootstrap init call: Error making API request.
11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: |
11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: | URL: PUT https://vault2.gweowe.com:8200/v1/sys/storage/raft/bootstrap/challenge
11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: | Code: 503. Errors:
11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: |
11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: | * Vault is sealed
11월 21 15:14:00 c0178584D.static.as2116.net vault[16670]: 2023-11-21T15:14:00.651+0900 [ERROR] core: failed to retry join raft cluster: retry=2s err="failed to get raft challenge"

성공적으로 실행되었습니다. Vault가 sealed 상태이기 때문에 에러가 발생하고 있습니다. Unseal을 하기 위한 작업을 수행해야 합니다.

2. Vault 초기화

Vault 서버에 접속하기 위해 각 서버에서 환경변수를 등록합니다.

1번 서버
export VAULT_ADDR=https://vault1.gweowe.com:8200
2번 서버
export VAULT_ADDR=https://vault2.gweowe.com:8200
3번 서버
export VAULT_ADDR=https://vault3.gweowe.com:8200

Vault 상태를 확인합니다.

vault status
Output :
Key                Value
---                -----
Seal Type          shamir
Initialized        false
Sealed             true
Total Shares       0
Threshold          0
Unseal Progress    0/0
Unseal Nonce       n/a
Version            1.14.1
Build Date         2023-07-21T10:15:14Z
Storage Type       raft
HA Enabled         true

아직 초기화를 진행하지 않아 Initialized가 false , Sealed가 true로 출력되는 것을 확인할 수 있습니다.

서로 연결되어 있는 Vault 서버에서 동시에 초기화하면 충돌이 발생하기 때문에, 하나의 서버에서만 진행해야 합니다. 저는 1번 서버에서 진행했습니다.

1번 서버
vault operator init
Output :
Unseal Key 1: 1ZJ+hNC4ZUW95MzsN/4+wHFRjv1HX6/fkOMML6d/6VU1
Unseal Key 2: cHf7NvqDtNQFQiuWM6Ia4tDoFnlYcKXW3O3UhoP22DTy
Unseal Key 3: jC2spXrIYMh3I5WQ2Zce2VngN8b865TmrmSfmlMLdG9o
Unseal Key 4: 8AMcTvMXYhuDm/fIUKC10PRE6ntZNNvtp0PhqZOPHy9y
Unseal Key 5: x2bL35kFV4gZcN1Jv1wiSJKqWYpVs5IhlVJUYylr0w2h

Initial Root Token: hvs.bI82W9eynAsbudYQ7P8Yqgnh

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 root key. Without at least 3 keys to
reconstruct the root 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.

성공적으로 초기화 작업이 수행되면서 Unseal KeyRoot Token이 발급되었습니다.

  • Unseal Key : Vault의 암호화된 보안 저장소를 해제하는 데 사용되는 키로, Vault 서버의 초기 설정 및 운영 중에 필요한 중요한 보안 요소입니다.
  • Root Token : Vault 서버의 최상위 권한을 가지는 토큰으로, 모든 작업과 정책 변경을 제어하는 주요 권한을 가지고 있습니다.

3. Vault Unseal

Vault를 사용하기 위해 Unseal 작업을 수행합니다. 초기화를 통해 발급된 5개의 Unseal Key중 3개의 Key를 입력해야 합니다. 1번 서버 먼저 진행합니다.

1번 서버
vault operator unseal [Unseal Key 1]
vault operator unseal [Unseal Key 2]
vault operator unseal [Unseal Key 3]

3회 모두 진행하면 다음과 같은 Output을 확인하실 수 있습니다.

Key                     Value
---                     -----
Seal Type               shamir
Initialized             true
Sealed                  false
Total Shares            5
Threshold               3
Version                 1.14.1
Build Date              2023-07-21T10:15:14Z
Storage Type            raft
Cluster Name            vault-cluster-bcbe82d6
Cluster ID              90f0facc-18c7-1d9b-ad45-9bd57ce03549
HA Enabled              true
HA Cluster              n/a
HA Mode                 standby
Active Node Address     <none>
Raft Committed Index    30
Raft Applied Index      30

초기화와 Unseal 작업 모두 진행되었기 때문에 Initialized가 true , Sealed가 false로 출력되는 것을 확인할 수 있습니다.

이제 다른 서버도 Unseal 작업을 3회 수행해야 합니다.

2번, 3번 서버
vault operator unseal [Unseal Key 1]
vault operator unseal [Unseal Key 2]
vault operator unseal [Unseal Key 3]

4. HA 구성 확인

Vault HA구성이 제대로 되었는지 확인하기 위해서는 Token 인증이 필요합니다. 초기화해서 발급받은 Root Token으로 인증합니다.

vault login

Token (will be hidden): [Root Token]
Output :
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.bI82W9eynAsbudYQ7P8Yqgnh
token_accessor       csHTjvoYEMa5JlqCfXeeTHLD
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]

성공적으로 인증했습니다. 마지막으로 Vault HA구성 상태를 확인합니다.

vault operator raft list-peers
Output :
Node             Address                   State       Voter
----             -------                   -----       -----
vault_server1    vault1.gweowe.com:8201    leader      true
vault_server3    vault3.gweowe.com:8201    follower    true
vault_server2    vault2.gweowe.com:8201    follower    true

먼저 Unseal한 1번 서버가 leader가 되었고 2번, 3번 서버가 follower인 것을 확인할 수 있습니다.

이로써 TLS가 적용된 Vault를 HA 구성을 성공적으로 완료하였습니다.

profile
정리하는 공간

0개의 댓글