티스토리 뷰
⚠ Vault란?
HashiCorp Vault는 ID 기반 시크릿 및 암호화 관리 시스템입니다. 여기서 시크릿은 API 암호화 키, 비밀번호, 인증서 등 액세스를 엄격하게 제어하고자 하는 모든 것을 아우릅니다. Vault는 인증(authentication) 및 인가(authorization) 방법에 따라 게이트화된 암호화 서비스를 제공합니다. Vault의 UI, CLI 또는 HTTP API를 사용하여 기밀 및 기타 중요 데이터에 대한 액세스를 안전하게 저장 및 관리하고, 엄격하게 제어(restrict)하며, 감사(audit)할 수 있습니다.
🎮 초기화
$ go mod init vault-example
$ touch main.go
$ touch docker-compose.yml
$ go get github.com/hashicorp/vault/api
📂 디렉터리 구조
🐳 docker-compose.yml
version: '3.9'
services:
vault:
image: vault:1.13.3 # 사용할 이미지 이름과 태그 지정
container_name: vault # 컨테이너 이미지 지정
ports:
- 8200:8200 # 로컬호스트 포트:컨테이너 포트 바인딩
cap_add:
- IPC_LOCK # 저장된 시크릿이 디스크로 스왑되지 않도록 컨테이너에서 메모리를 잠금
environment:
VAULT_DEV_ROOT_TOKEN_ID: "root" # 루트 토큰 환경 변수 지정
🐭 main.go
package main
import (
"context"
"log"
vault "github.com/hashicorp/vault/api"
)
func main() {
config := vault.DefaultConfig()
config.Address = "http://127.0.0.1:8200"
client, err := vault.NewClient(config)
if err != nil {
log.Fatalf("Error creating vault client: %s", err)
}
client.SetToken("root")
secretData := map[string]interface{}{
"password": "Hashi123",
}
ctx := context.Background()
_, err = client.KVv2("secret").Put(ctx, "my-secret-password", secretData)
if err != nil {
log.Fatalf("unable to write secret: %v", err)
}
log.Println("Secret written successfully.")
secret, err := client.KVv2("secret").Get(ctx, "my-secret-password")
if err != nil {
log.Fatalf("unable to read secret: %v", err)
}
value, ok := secret.Data["password"].(string)
if !ok {
log.Fatalf("value type assertion failed: %T %#v", secret.Data["password"], secret.Data["password"])
}
if value != "Hashi123" {
log.Fatalf("unexpected password value %q retrieved from vault", value)
}
log.Println("Access granted!")
}
🔪 main 함수 분해
클라이언트 생성
config := vault.DefaultConfig() // 기본 설정값 불러오기
config.Address = "http://127.0.0.1:8200" // vault 서버의 주소 지정
client, err := vault.NewClient(config) // 설정값을 사용해 vault 클라이언트 생성
if err != nil {
log.Fatalf("Error creating vault client: %s", err)
}
client.SetToken("root") // 클라이언트의 토큰을 직접 지정
시크릿 쓰기
secretData := map[string]interface{}{
"password": "Hashi123",
}
ctx := context.Background()
// 경로를 "my-secret-password"로 지정하여 "secret" 경로에 마운트된 KV v2 시크릿 엔진에 시크릿 추가
// Put은 추가하려는 값이 이미 존재할 경우, 새로운 버전으로 값을 추가한다.
// 기존의 값은 GetVersion을 사용해 불러올 수 있다.
_, err = client.KVv2("secret").Put(ctx, "my-secret-password", secretData)
if err != nil {
log.Fatalf("unable to write secret: %v", err)
}
log.Println("Secret written successfully.")
시크릿 읽기
// "my-secret-password" 경로에 저장된 시크릿을 "secret" 경로에 마운트된 KV v2 엔진으로부터 읽기
// Get은 최신 버전의 시크릿을 읽어들인다.
// 만약 최신 버전이 삭제되었다면, 데이터 필드는 nil이 되고 삭제된 시간이 포함된다.
secret, err := client.KVv2("secret").Get(ctx, "my-secret-password")
if err != nil {
log.Fatalf("unable to read secret: %v", err)
}
value, ok := secret.Data["password"].(string)
if !ok {
log.Fatalf("value type assertion failed: %T %#v", secret.Data["password"], secret.Data["password"])
}
if value != "Hashi123" {
log.Fatalf("unexpected password value %q retrieved from vault", value)
}
log.Println("Access granted!")
🚄 실행
docker compose 실행
$ docker compose up -d
main.go 실행
$ go run main.go
2023/10/25 14:46:35 Secret written successfully.
2023/10/25 14:46:35 Access granted!
docker compose 종료
$ docker compose down
📖 참고자료
글에서 수정이 필요한 부분이나 설명이 부족한 부분이 있다면 댓글로 남겨주세요!
'Go > 문서 읽기' 카테고리의 다른 글
Go 1.22.0 업데이트 살펴보기 (0) | 2024.02.08 |
---|---|
[Go] 컨텍스트(Context) (1) | 2023.10.05 |
[Effective Go] Names (0) | 2023.03.29 |