개발/IaC

EKS에 HashiCorp Vault 설치

Jaeyeon Baek 2024. 10. 22. 23:17

HashiCorp Vault는 비밀 관리 도구로, 민감한 데이터를 안전하게 저장하고 관리할 수 있게 해 줍니다. 이번 글에서는 EKS에 HashiCorp Vault를 테라폼으로 생성하고 설치하고 접속해 보도록 하겠습니다. 정말 간단하니까 눈으로만 따라오셔도 충분합니다.

EKS에 HashiCorp Vault를 테라폼으로 아래와 같이 코드를 작성해서 설치할 수 있습니다.

 resource "helm_release" "vault" {
   name             = "vault"
   repository       = "https://helm.releases.hashicorp.com"
   chart            = "vault"
   namespace        = "vault"
   create_namespace = true
   version          = "0.28.1"
   values = [templatefile("../../manifests/hashicorp/vault.yaml", {})]
   provider = helm.eks_helm
 }

 

vault.yaml 파일에는 여기 경로에서 필요한 설정을 가져와서 쓰면 됩니다. 저는 테스트를 위해 아래와 같이 코드를 작성했습니다. 

server:
  # For HA configuration and because we need to manually init the vault,
  # we need to define custom readiness/liveness Probe settings
  readinessProbe:
    enabled: true
    path: "/v1/sys/health?standbyok=true&sealedcode=204&uninitcode=204"
  livenessProbe:
    enabled: true
    path: "/v1/sys/health?standbyok=true"
    initialDelaySeconds: 60
  
  # This configures the Vault Statefulset to create a PVC for data
  # storage when using the file or raft backend storage engines.
  # See https://developer.hashicorp.com/vault/docs/configuration/storage to know more
  dataStorage:
    enabled: true
    # Size of the PVC created
    size: 10Gi
    # Location where the PVC will be mounted.
    mountPath: "/vault/data"
    # Name of the storage class to use.  If null it will use the
    # configured default Storage Class.
    storageClass: null
    # Access Mode of the storage device being used for the PVC
    accessMode: ReadWriteOnce
    # Annotations to apply to the PVC
    annotations: {}
    # Labels to apply to the PVC
    labels: {}
  
  # This configures the Vault Statefulset to create a PVC for audit
  # logs.  Once Vault is deployed, initialized, and unsealed, Vault must
  # be configured to use this for audit logs.  This will be mounted to
  # /vault/audit
  # See https://developer.hashicorp.com/vault/docs/audit to know more
  auditStorage:
    enabled: false
    # Size of the PVC created
    size: 10Gi
    # Location where the PVC will be mounted.
    mountPath: "/vault/audit"
    # Name of the storage class to use.  If null it will use the
    # configured default Storage Class.
    storageClass: null
    # Access Mode of the storage device being used for the PVC
    accessMode: ReadWriteOnce
    # Annotations to apply to the PVC
    annotations: {}
    # Labels to apply to the PVC
    labels: {}
  standalone:
    enabled: false
    
  # Run Vault in "HA" mode. There are no storage requirements unless the audit log
  # persistence is required.  In HA mode Vault will configure itself to use Consul
  # for its storage backend.  The default configuration provided will work the Consul
  # Helm project by default.  It is possible to manually configure Vault to use a
  # different HA backend.
  ha:
    enabled: false
    replicas: 3
		 # Enables Vault's integrated Raft storage.  Unlike the typical HA modes where
    # Vault's persistence is external (such as Consul), enabling Raft mode will create
    # persistent volumes for Vault to store data according to the configuration under server.dataStorage.
    # The Vault cluster will coordinate leader elections and failovers internally.
    raft:

      # Enables Raft integrated storage
      enabled: true
      # Set the Node Raft ID to the name of the pod
      setNodeId: true

      # Note: Configuration files are stored in ConfigMaps so sensitive data
      # such as passwords should be either mounted through extraSecretEnvironmentVars
      # or through a Kube secret.  For more information see:
      # https://developer.hashicorp.com/vault/docs/platform/k8s/helm/run#protecting-sensitive-vault-configurations
      # Supported formats are HCL and JSON.
      config: |
        ui = true
        cluster_name = "vault-storage-test"
        listener "tcp" {
          address = "[::]:8200"
          cluster_address = "[::]:8201"
        }

        storage "raft" {
          path = "/vault/data"
        }

        service_registration "kubernetes" {}

 

이제 terraform apply를 실행하면 vault가 설치될 겁니다. 설치가 완료되면 아래와 같이 vault pod가 생성된 것을 확인할 수 있습니다. 위에서 replicas를 3으로 했기 때문에 vault-0~2까지 존재하는 겁니다.

jybaek:~/bin$ kubectl get pods
NAME                                    READY   STATUS    RESTARTS      AGE
vault-0                                 1/1     Running   4 (11m ago)   16m
vault-1                                 1/1     Running   1 (18m ago)   19m
vault-2                                 1/1     Running   1 (18m ago)   18m
vault-agent-injector-7bcc447788-k29jc   1/1     Running   0             163m

 

이제 vault를 초기화하고 unsealing 작업을 진행해야 합니다. 포트 포워딩으로 vault-x로 접속하시면 됩니다.

새로운 Raft cluster를 만듭시다

 

여기서 잠깐! 중요합니다. 아래 이미지에서 볼 수 있듯이, vault 상태를 확인하면 초기화되지 않은 상태임을 알 수 있습니다. 이제 vault를 초기화하고 unsealing 작업을 진행해야 합니다. 그런데 왜 때문인지 화면에서 Initialize를 진행하는 경우 sealing key와 root key가 나오지 않았습니다. 그래서 저는 터미널에서 vault operator init 명령어를 사용해서 초기화를 수행했습니다. 여기 이 화면은 그대로 두고 다음에 나오는 터미널 작업을 마친 후에 새로고침 해주세요.

여기서 Initialize를 클릭하면 안됩니다. 터미널에서 작업할거에요

 

위에서 포트 포워딩으로 접속한 vault의 터미널로 접속해 주세요. 그리고 vault의 상태를 체크해 줍니다.. Initialized 부분과 Sealed를 보시면 됩니다. 이 상태를 이제 각각 true와 false로 바꿔주는 겁니다.

/ $ vault status
Key                Value
---                -----
Seal Type          shamir
Initialized        false
Sealed             true
Total Shares       3
Threshold          2
Unseal Progress    0/2
Unseal Nonce       n/a
Version            1.17.2
Build Date         2024-07-05T15:19:12Z
Storage Type       raft
HA Enabled         true
/ $

 

vault operator init 명령어를 사용해 줍니다.

/ $ vault operator init -key-shares=3 -key-threshold=2


Unseal Key 1: VhL8QfwF87Yf0unrH
Unseal Key 2: /PKZTUKNpJZVuqKrT
Unseal Key 3: hI/iGsPt+uxQp5Zf1

Initial Root Token: hvs.hrKuPOoG69

Vault initialized with 3 key shares and a key threshold of 2. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 2 of these keys to unseal it
before it can start servicing requests.

Vault does not store the generated root key. Without at least 2 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.
/ $

 

여기서 사용된 key-shares는 총 생성할 키의 수를 나타냅니다. 이 경우 3개의 키가 생성됩니다. key-threshold는 Vault를 unsealing 하는 데 필요한 최소 키의 수를 의미합니다. 여기서는 2개의 키가 필요합니다. 이 설정은 보안과 가용성 사이의 균형을 맞추는 데 중요합니다. 여기까지 했으면 이제 Initialized는 true가 됐을 거고요, 다음은 화면에서 이어서 작업하도록 합니다.

앞에서 생성된 Unseal key 정보를 아래 화면에 넣어줍니다.

Unseal key 정보를 넣어주세요

 

자! 이제 Sealed도 false로 바뀌었을 겁니다. 이제 Vault에 로그인하여 사용할 수 있습니다. Vault는 다양한 시크릿 엔진을 제공하며, 이를 통해 데이터베이스 자격 증명, API 키, 암호화 키 등을 안전하게 관리할 수 있습니다. 또한 Vault의 정책 기능을 사용하여 세분화된 접근 제어를 구현할 수 있습니다.

환영합니다!

 

# 마치며

이번 글에서는 EKS에 HashiCorp Vault를 설치하고 초기화하는 과정을 살펴보았습니다. Vault는 강력한 보안 기능과 유연한 관리 옵션을 제공하여 클라우드 네이티브 환경에서 중요한 정보를 안전하게 관리할 수 있게 해 줍니다. 이를 통해 개발자와 운영팀은 보안을 강화하면서도 효율적인 시스템 관리를 할 수 있습니다.

인터넷을 찾아봤을 때 테라폼으로 쿠버네티스에 Vault를 설치하는 예제가 없어서 글을 써보고 싶었습니다. 누군가는 굳이 하지 않아도 되는 삽질을 먼저 해보고 싶었거든요. 도움이 되셨기를 바랍니다. :) 

이 글을 작성하는 시점에 본인은 vault 뉴비입니다. 혹시 글에 잘못된 점이 있다면 가감 없이 말씀해 주세요. 감사합니다.