> For the complete documentation index, see [llms.txt](https://handbook.novice.solutions/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://handbook.novice.solutions/tools/security/hashicorp-vault.md).

# Hashicorp Vault

HashiCorp Vault เป็นเครื่องมือจัดการความปลอดภัยและการเข้าถึงข้อมูลสำคัญในระบบไอที มันถูกออกแบบมาเพื่อจัดเก็บ จัดการ และควบคุมการเข้าถึงข้อมูลลับต่าง ๆ เช่น รหัสผ่าน คีย์ API และข้อมูลที่เป็นความลับอื่น ๆ โดยมีคุณสมบัติที่สำคัญดังนี้

1. **การจัดเก็บข้อมูลลับ (Secrets Management)**: Vault ช่วยในการจัดเก็บข้อมูลลับต่าง ๆ ในที่เดียว และควบคุมการเข้าถึงอย่างเข้มงวด ผู้ใช้งานสามารถกำหนดสิทธิ์การเข้าถึงได้ตามบทบาทหรือการกำหนดนโยบายเฉพาะ
2. **Dynamic Secrets**: Vault สามารถสร้างข้อมูลลับแบบชั่วคราวสำหรับการเข้าถึงระบบภายนอก เช่น ฐานข้อมูลหรือบริการอื่น ๆ ซึ่งข้อมูลลับเหล่านี้จะถูกสร้างใหม่ในทุกครั้งที่มีการร้องขอ และจะหมดอายุเมื่อใช้งานเสร็จสิ้น
3. **Encryption as a Service**: Vault ให้บริการการเข้ารหัสข้อมูลผ่าน API เพื่อใช้ในการเข้ารหัสและถอดรหัสข้อมูลต่าง ๆ โดยที่แอปพลิเคชันหรือระบบต่าง ๆ ไม่จำเป็นต้องมีการจัดการคีย์เข้ารหัสเอง
4. **การควบคุมการเข้าถึงที่ปลอดภัย (Access Control)**: Vault มีระบบการควบคุมสิทธิ์การเข้าถึงที่ละเอียด ผู้ใช้งานจะสามารถเข้าถึงเฉพาะข้อมูลที่จำเป็นตามที่ได้รับอนุญาต ซึ่งลดความเสี่ยงจากการเปิดเผยข้อมูลที่ไม่จำเป็น
5. **Audit Logging**: Vault มีการบันทึกการใช้งานเพื่อให้สามารถตรวจสอบการเข้าถึงและใช้งานข้อมูลลับต่าง ๆ ทำให้มีความโปร่งใสและสามารถติดตามการดำเนินการย้อนหลังได้

## Consul คืออะไร

Consul เป็นเครื่องมือที่ให้บริการ **service discovery** และ **distributed key-value store** ที่ใช้สำหรับเก็บข้อมูลเช่น การกำหนดค่าและข้อมูลสภาวะการทำงานของระบบแบบกระจายตัว (distributed systems) โดย Consul มีคุณสมบัติหลัก ๆ ดังนี้

1. **High Availability**: สามารถทำงานในโหมดกระจายตัวที่มีหลายโหนด (nodes) เพื่อเพิ่มความทนทานต่อการล้มเหลว
2. **Replication**: Consul จะทำการ replicates ข้อมูลระหว่างโหนดหลายโหนด เพื่อความทนทานต่อการสูญเสียข้อมูล
3. **Service Discovery**: มีคุณสมบัติการค้นหาบริการและการติดตามสุขภาพ (health checking) ของบริการในระบบ

การใช้ **Consul** เป็น backend สำหรับ HashiCorp Vault เป็นการตั้งค่าที่ช่วยให้ Vault สามารถจัดเก็บข้อมูลที่สำคัญและมีความทนทานในการทำงาน โดย Consul ทำหน้าที่เป็น **Storage Backend** ที่สามารถจัดเก็บข้อมูลต่าง ๆ ที่ Vault ต้องการเก็บ เช่น Secret, Tokens, และข้อมูลการกำหนดค่าอื่น ๆ การตั้งค่า Consul เป็น backend มีประโยชน์ในด้านการจัดเก็บที่ปลอดภัยและการกระจายโหลดสำหรับการใช้งาน Vault ใน production environment

## การติดตั้ง Hashicorp Vault

### ติดตั้ง Consul

จากตัวอย่างนี้ จะติดตั้ง consul บน Kubernetes cluster ผ่าน Helm Chart ของ Hashicorp

#### Architecture

ตาม recommend ของ Hashicorp กำหนดว่า consul server ควรมีอย่างน้อย 5 node และกระจายกันอยู่ใน 3 AZ แต่โดยส่วนมากสำหรับ small production site ใช้ 3 node ก็เพียงพอ เช่นกัน

<figure><img src="/files/QMxQMr5aV105jFfYg33Z" alt=""><figcaption><p>consul for production</p></figcaption></figure>

#### Hardware Requirement

<table><thead><tr><th width="92">Size</th><th width="101">CPU</th><th width="105">Memory</th><th width="138">Disk Capacity</th><th width="147">Disk IO</th><th>Disk Throughput</th></tr></thead><tbody><tr><td>Small</td><td>2-4 core</td><td>8-16 GB</td><td>100+ GB</td><td>3000+ IOPS</td><td>75+ MB/s</td></tr><tr><td>Large</td><td>8-16 core</td><td>32-64 GB</td><td>200+ GB</td><td>7500+ IOPS</td><td>250+ MB/s</td></tr></tbody></table>

#### Network Latency Requirement

round trip time (RTT) ในการสื่อสารกันระหว่าง agent ต้องไม่เกิน ดังนี้

* RTT ของทุก traffic โดยเฉลี่ย ต้องไม่เกิน 50ms
* RTT ที่ percentile 99 ต้องไม่เกิน 100ms

#### Firewall rule

<table><thead><tr><th width="150">Name</th><th>Port / Protocol</th><th>Source</th><th>Destination</th><th>Description</th></tr></thead><tbody><tr><td>RPC</td><td>8300 / TCP</td><td>All agents (client &#x26; server)</td><td>Server agents</td><td>Used by servers to handle incoming requests from other agents.</td></tr><tr><td>Serf LAN</td><td>8301 / TCP &#x26; UDP</td><td>All agents (client &#x26; server)</td><td>All agents (client &#x26; server)</td><td>Used to handle gossip in the LAN. Required by all agents.</td></tr><tr><td>Serf WAN</td><td>8302 / TCP &#x26; UDP</td><td>Server agents</td><td>Server agents</td><td>Used by server agents to gossip over the WAN to other server agents. Only used in multi-cluster environments.</td></tr><tr><td>HTTP/HTTPS</td><td>8500 &#x26; 8501 TCP</td><td>Localhost of client or server agent</td><td>Localhost of client or server agent</td><td>Used by clients to talk to the HTTP API. HTTPS is disabled by default.</td></tr><tr><td>DNS</td><td>8600 TCP &#x26; UDP</td><td>Localhost of client or server agent</td><td>Localhost of client or server agent</td><td>Used to resolve DNS queries.</td></tr><tr><td>gRPC (Optional)</td><td>8502 TCP</td><td>Envoy proxy</td><td>Client agent or server agent that manages the sidecar proxies service registration</td><td>Used to expose the xDS API to Envoy proxies. Disabled by default.</td></tr><tr><td>Sidecar Proxy (Optional)</td><td>21000 - 21255 TCP</td><td>All agents (client &#x26; server)</td><td>Client agent or server agent that manages the sidecar proxies service registration</td><td>Port range used for automatically assigned sidecar service registrations.</td></tr></tbody></table>

#### ตัวอย่าง value file

สร้างไฟล์ `consul.values.yaml`

```yaml
global:
  name: consul
  datacenter: dc1
  gossipEncryption:
    autoGenerate: true
server:
  replicas: 3
  storage: 10Gi
  resources:
    requests:
      memory: '1Gi'
      cpu: '1'
    limits:
      memory: '1Gi'
      cpu: null # override existing cpu limit value
  topologySpreadConstraints: |
    - maxSkew: 1
      topologyKey: topology.kubernetes.io/zone
      whenUnsatisfiable: DoNotSchedule
      labelSelector:
        matchLabels:
          app: {{ template "consul.name" . }}
          release: "{{ .Release.Name }}"
          component: server
client:
  enabled: true
  resources:
    requests:
      memory: '512Mi'
      cpu: '500m'
    limits:
      memory: '512Mi'
      cpu: null # override existing cpu limit value
ui:
  enabled: true
  service:
    type: ClusterIP
```

ติดตั้งด้วยคำสั่งดังนี้

```bash
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
helm upgrade --install consul hashicorp/consul --values consul.values.yaml --create-namespace --namespace vault
```

***

### ติดตั้ง Vault

เตรียม YAML file ชื่อ `vault.values.yaml` ดังนี้

```yaml
server:
  ha:
    enabled: true
    replicas: 3
  auditStorage:
    enabled: true
    size: 10Gi
  resources:
    requests:
      memory: "1Gi"
      cpu: "250m"
    limits:
      memory: "1Gi"
  topologySpreadConstraints: |
    - maxSkew: 1
      topologyKey: topology.kubernetes.io/zone
      whenUnsatisfiable: DoNotSchedule
      labelSelector:
        matchLabels:
          app.kubernetes.io/name: {{ include "vault.name" . }}
          app.kubernetes.io/instance: {{ .Release.Name }}
          component: server
ui:
  enabled: true
```

ติดตั้งด้วยคำสั่งดังนี้

```bash
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
helm upgrade --install vault hashicorp/vault --values vault.values.yaml --create-namespace --namespace vault
```

หลังจากติดตั้งเสร็จ ตรวจสอบสถานะ vault

```bash
kubectl exec vault-0 -n vault -- vault status
```

จะขึ้นผลลัพธ์ว่าถูก seal ไว้อยู่

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

ใช้ command ดังนี้เพื่อ generate root key <mark style="color:orange;">**ใช้ในการ bootstrap cluster ครั้งแรกเท่านั้น**</mark>

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

{% hint style="warning" %}
จากตัวอย่างจากกำหนด key 1 ตัวเท่านั้น เพื่อความง่าย

ใน enterprise อาจจะไม่ควรใส่ `-key-shares=1 -key-threshold=1`
{% endhint %}

ทำการ unseal vault server

```bash
VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
kubectl exec vault-0 -n vault -- vault operator unseal $VAULT_UNSEAL_KEY
```

จะได้ผลลัพธ์ดังนี้

```
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         1.17.2
Build Date      2024-07-05T15:19:12Z
Storage Type    consul
Cluster Name    vault-cluster-7e64d0dc
Cluster ID      05f0b39c-2def-5ce6-5597-71863db4864e
HA Enabled      true
HA Cluster      https://vault-0.vault-internal:8201
HA Mode         active
Active Since    2024-10-11T10:15:00.540042962Z
```

ทำ port-forward เพื่อทดสอบใช้งาน Vault

```bash
kubectl port-forward svc/vault-ui -n vault 8200:8200
```

เข้า web browser ผ่าน <http://localhost:8200>

ทดสอบ login ผ่าน UI ด้วย token ของ root

{% hint style="info" %}
root token ได้มาจากตอน bootstrap cluster ด้วยคำสั่ง vault operator init

ดังนั้นสามารถหาได้จากคำสั่ง

```bash
cat cluster-keys.json |jq '.root_token'
```

{% endhint %}
