Vault - Signed SSH certificates를 이용한 서버 접근
HashiCorp Vault는 민감한 자격 증명, API 키, 암호화 키 등을 안전하게 저장하고 접근 제어를 제공하는 비밀 관리 시스템입니다. 그중에서도 SSH Secrets Engine은 SSH 접속을 보다 안전하게 제어할 수 있도록 지원하는 기능으로, OTP 방식 또는 SSH 인증서 서명 방식으로 서버 접근을 중앙에서 관리할 수 있습니다.
이번 포스팅에서는 Vault에 SSH Secrets Engine을 SSH 인증서 방식으로 서버에 접근하는 방법에 대한 내용을 다룹니다.
Vault 설치
- Vault Server, SSH Server, SSH Client 공통 - Vault 1.20.0(Latest) 설치
- Ubuntu 24.04 기준
wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install vault
Vault Server 설정
데이터 디렉토리 생성
mkdir -p /opt/vault/data
서버 환경 설정 파일 작성( /etc/vault.d/config.hcl )
- Vault 웹 UI 활성화(ui) 및 Vault를 외부에서 호출 가능한 API 주소(api_addr) 설정
- Storage는 Vault의 데이터 저장 방식이고, 여기에서는 /opt/vault/data 디렉토리에 저장
- listener는 TCP listener에서 사용하는 서비스 Port 및 Vault 서버가 어떤 IP 주소로 요청을 받을지 지정
tls-disable은 tls를 비화성화 하는 것이고, 실제 상용에서는 활성화해서 사용 필요.
ui = true
api_addr = "http://서비스IP:8200"
storage "file" {
path = "/opt/vault/data"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 1
}
Vault 서버 실행
- Vault 서버를 위에서 작성한 환경 설정을 통해서 서버 구동
- 본 포스팅에서는 백그라운드로 실행하는 것으로 진행.
sudo nohup vault server -config=/etc/vault.d/config.hcl > sudo /var/log/vault.log 2>&1 &
Vault 서버 초기화
- Vault 서버 최초 초기화(Initalize)
- Vault Unseal Key와 초기 Root Token(초기 관리자 접근을 위한 토큰) 생성
- Unseal Key와 관련하여, -key-shares, -key-threshold 옵션 사용 가능하며, 옵션은 내용은 다음과 같습니다.
- -key-shares : 생성하는 Unseal 키 수 (default 5)
- -key-threshold : 생성된 Unseal 키 중에서, Vault를 Unseal 하는 데 사용하는 키 수 (default 3)
export VAULT_ADDR="http://서비스IP:8200" # 실행 전 환경 변수 선언
#기본 실행
vault operator init
#옵션 사용 시
vault operator init -key-shares=5 -key-threshold=3
Vault 서버 잠금 해제
- Vault init 이후, sealed 상태로, Vault 사용을 위해서 unseal을 수행
- unseal은 -key-threshold에 선언된 만큼 진행해야 하면, unseal된 수량은 'Unseal Progress'에서 확인 가능
- 별도 옵션이 없을 경우, -key-threshold=3 으로 되어서, 3번의 unseal 수행
- unseal이 완료되면, 'Sealed'가 'true'에서 'false'로 변경 됨.
vault operator unseal
#실행 후, unseal key를 입력
Vault 서버 로그인
- Vault 사용을 위한 로그인 수행
- 별도 로그인 대신에, VAULT_TOKEN 환경 변수에 token 값을 선언해서 사용하는 것도 가능
vault login [root token]
-
secrets enable로 Secret Engine을 활성화합니다.
-
-path 옵션을 이용해서, 마운트 지점을 설정하는 데, 이는 SSH Secret Engine이 사용할 논리 경로
- -path 옵션을 사용해서, 서로 다른 설정을 여러 번 마운트 가능
예를 들어서, 이번 포스팅에서 다루는 SSH 인증서 방식과 다음 포스팅에서 다룰 OTP 인증서 방식을 각각 구성 가능
vault secrets enable -path=ssh-client-signer ssh
SSH Secret Engine의 CA 키 생성
- Vault가 내부적으로 사용할 SSH 인증서 서명용 키쌍 (private/public) 을 자동으로 생성
- 이 키는 Vault가 클라이언트의 공개 키를 받아 SSH 인증서 형식으로 서명할 때 사용
- Vault는 자체적으로 SSH CA 역할을 수행하게 되며,
이후 발급된 인증서는 대상 서버의 TrustedUserCAKeys에 등록된 공개 키와 비교되어 접근을 제어
vault write ssh-client-signer/config/ca generate_signing_key=true
SSH CA 공개 키를 조회하기 위한 정책 설정
- ssh-client-signer/config/ca 경로의 리소스(공개 키 포함)에 대해 읽기 권한만 허용
#policy.hcl
path "ssh-client-signer/config/ca" {
capabilities = ["read"]
}
vault policy write ssh-pubkey-read policy.hcl
- 앞서 만든 ssh-pubkey-read 정책을 받은 전용 토큰 생성
- 이 토큰을 사용해서, SSH Server가 Vault에서 서명된 CA 공개키를 읽을 수 있음
vault token create -policy=ssh-pubkey-read
- 클라이언트가 제출한 공개 키를 받아 인증서(서명된 키)로 발급해주는 기능을 제공
- 기본 계정을 zigi로 설정하고, 인증서에 대한 TTL을 5분으로 지정
vault write ssh-client-signer/roles/my-role -<<"EOH"
{
"algorithm_signer": "rsa-sha2-256",
"allow_user_certificates": true,
"allowed_users": "*",
"allowed_extensions": "permit-pty,permit-port-forwarding",
"default_extensions": [
{
"permit-pty": ""
}
],
"key_type": "ca",
"default_user": "zigi",
"ttl": "5m0s"
}
EOH
SSH 인증서 서명을 위한 정책 정의
- SSH Client가 앞서 생성한 역할(role)을 통해 인증서 서명을 요청하기 위한 sign 경로의 update 권한 정의
#sign-policy.hcl
path "ssh-client-signer/sign/my-role" {
capabilities = ["update"]
}
정책을 Vault에 등록용헌
vault policy write require-ssh-sign sign-policy.hcl
- 앞서 만든 require-ssh-sign 정책을 받은 전용 토큰 생성
- 이 토큰을 사용해서, SSH Client가 Vault에 인증서 서명 요청
vault token create -policy=require-ssh-sign
SSH Server 설정
Vault에서 서명한 SSH 인증서를 신뢰하기 위해서, Vault의 CA 공개키를 가져와서 등록
-
VAULT Token 값은 'SSH Public Key Read를 위한 Token 생성(SSH Server에서 사용)' 에서 확인한 Token 값 사용
export VAULT_ADDR=http://Vault_Serer_IP:8200
export VAULT_TOKEN="SSH Public Key Read Token"
설정 확인
env | grep VAULT
- Vault에서 Public Key를 SSH 서버로 가져와서, SSH 서버에 저장
vault read -field=public_key ssh-client-signer/config/ca | sudo tee /etc/ssh/trusted-user-ca-keys.pem > /dev/null
Public Key 경로를 SSH 구성 파일에 TrustedUserCAKeys 옵션으로 추가
- OpenSSH에서 서명된 인증서를 신뢰하기 위한 CA 공개키로 지정
# /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
SSH 서비스 재기동
- TrustedUserCAKeys 옵션 적용을 위해서 SSH 데몬 재기동
sudo systemctl restart ssh
SSH Client 설정
SSH 클라이언트는 자신의 공개키를 Vault에 제출하여 서명된 인증서를 발급받고, 이를 통해 SSH 서버에 안전하게 로그인합니다.
- VAULT Token 값은 ' 인증서 서명을 위한 Token 생성(SSH Client에서 사용) ' 단계에서 생성한 Token.
export VAULT_ADDR=http://Vault_Serer_IP:8200
export VAULT_TOKEN="require-ssh-sign Token"
설정 확인
env | grep VAULT
SSH Key 생성 (혹은 기존 Key 사용 가능)
- Vault에 제출할 Public Key 생성
ssh-keygen -t rsa
Vault에 Public Key Sign 요청
- 생성한 Public Key를 Vault에 제출하고, 기존에 생성한 역할(role) 기반으로 서명된 SSH 인증서 발급
vault write -field=signed_key ssh-client-signer/sign/my-role \
public_key=@./.ssh/id_rsa.pub > ./.ssh/id_rsa-cert.pub
SSH Server에 SSH 접속
- -i 옵션으로 앞서 생성한 Private Key를 지정해서, SSH Server에 접속
- OpenSSH가 같은 경로에 앞서 발급 받은 SSH 인증서를 함께 사용
- SSH Server에서는 TrustedUserCAKeys 값을 기준으로 서명된 인증서를 신뢰
ssh -i ~/.ssh/id_rsa username@SSH_Server_IP