Việc lưu trữ secret (dữ liệu nhạy cảm) là một phần rất quan trọng đối với bất kì một phần mềm nào. Bởi vì nếu các secret như API keys, đường dẫn của các server, proxy bị lộ ra ngoài có thể dẫn đến các vấn đề về an ninh, bảo mật rất nghiêm trọng cho hệ thống của bạn. Do đó, trong bài viết hướng dẫn quản lý an toàn các Secrets bằng HashiCorp trên Ubuntu 20.04 này, Vietnix sẽ hướng dẫn cách để quản lí, lưu trữ và truy cập các secret một cách an toàn bằng Vault của HashiCorp.
Giới thiệu về Vault
Vault là một công cụ mã nguồn mở, giúp bạn lưu trữ và phân phối các secrets như API keys, access token và mật khẩu một cách an toàn, bảo mật và đáng tin cậy. Do đó, các phần mềm hay công cụ như Vault đóng một vai trò rất quan trong trong việc deploy các ứng dụng có sử dụng các secrets hoặc các dữ liệu nhạy cảm.
Và trong bài viết ngày hôm nay, bạn sẽ tìm hiểu về các điều sau:
- Cài đặt và cấu hình cho Vault.
- Khởi tạo vùng lưu trữ dữ liệu được mã hóa trên ổ đĩa.
- Lưu trữ và truy xuất dữ liệu nhạy cảm thông qua TLS.
Cùng với việc bổ sung thêm các policies, bạn sẽ có thể sử dụng Vault để quản lý dữ liệu nhạy cảm một cách an toàn cho ứng dụng của mình.
Yêu cầu tiên quyết để quản lý an toàn các Secrets bằng HashiCorp trên Ubuntu 20.04
Để theo dõi bài hướng dẫn này, bạn cần thỏa các yêu cầu sau:
- Máy chủ Ubuntu 20.04 có tài khoản user non-root được cấp quyền
sudo
và tường lửa được bật. - Chứng chỉ TLS sử dụng để bảo mật cho HTTP API của Vault. Bạn có thể sử dụng Certbot để nhận miễn phí.
Lưu ý: Vault sẽ tự động tạo một chứng chỉ tự cấp TLS vào lần đầu tiên được cài đặt. Nếu bạn không có sẵn một tên miền hoặc chứng chỉ TLS để sử dụng cho Vault, mà vẫn muốn theo dõi các bước thực hiện trong bài thì hãy bỏ qua phần xác thực TLS bằng cách thêm cờ -tls-skip-verify
vào các lệnh trong bài. Hoặc có một cách nữa là bạn định nghĩa một biến môi trường tên là VAULT_SKIP_VERIFY
. Tuy nhiên, việc bỏ qua xác thực này chỉ thích hợp để thử nghiệm Vault và không được khuyến khích ở môi trường production.
Các bước tiến hành
Bước 1: Cài đặt Vault
Vault có thể được xem như là một package của Debian/Ubuntu được cung cấp bởi HashiCorp, vì thế ở bước này, bạn sẽ tiến hành thêm repository của HashiCorp vào danh sách nguồn của các packages trên máy chủ của mình.
Để thực hiện, đầu tiên bạn cần phải thêm GPG key của HashiCorp vào trình quản lý package của hệ thống để nó nhận biết và tin tưởng repository đó.
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
Tiếp theo, bạn thêm repository vào danh sách nguồn của các packages, để HashiCorp được theo dõi và cập nhật thường xuyên:
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
Sau đó, bạn có thể cài đặt Vault bằng lệnh như dưới đây:
sudo apt install vault
Để xác nhận lại, bạn hãy dùng lệnh vault
để kiểm tra phiên bản hiện tại được cài đặt của Vault:
vault --version
Nếu đã cài đặt thành công, output của bạn sẽ tương tự như sau:
Output
Vault v1.8.5 (647eccfe0bd5817bdd8628f3c3171402dfc8a8fc)
Đến đây, file thực thi hay executable của Vault đã được cài đặt trên máy chủ của bạn, ở bước tiếp theo bạn sẽ cấu hình cho Vault để chạy với vai trò là một dịch vụ hệ thống.
Bước 2: Cấu hình Vault
Việc cài đặt Vault sẽ tự động tạo ra một vault user tên là vault
trên hệ thốngvà thiết lập một dịch vụ hệ thống để khởi chạy Vault ở background (chạy ẩn, không thể hiện trên màn hình). Ở bước này, bạn sẽ cần phải thay đổi một số cấu hình mặc định đó để có thể sử dụng chứng chỉ HTTPS được cung cấp bởi Let’s Ecrypt.
Lưu ý: Trong bài hướng dẫn này và theo mặc định, Vault sử dụng hệ thống file ở backend để lưu trữ các secrets trên hệ thống file cục bộ của máy /opt/vault
. Điều này là phù hợp cho việc deploy một máy chủ hoặc local server mà không cần được replicate. Còn đối với các hệ thống backends khác của Vault, như Consul chẳng hạn, các secrets sẽ được lưu trữ bên trong một hệ thống phân tán key/value.
Cấu hình mặc định của Vault được lưu trong /etc/vault.d/vault/hcl
. Đây là file mà bạn sẽ sử dụng để kiểm soát các tùy chọn, chẳng hạn như nơi để lưu trữ các secrets.
Hãy mở vault.hcl
bằng nano
hoặc bất kì text editor nào tùy thích:
sudo nano /etc/vault.d/vault.hcl
Đầu tiên, bạn hãy tìm mục listener "tcp"
nằm ở dưới dòng #HTTPS listener
. Nếu đang sử dụng nano
, bạn có thể nhấn CTRL+W
và sau đó nhập listener "tcp"
để tìm kiếm nhanh chóng.
...
#HTTPS listener
...
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/opt/vault/tls/tls.crt"
tls_key_file = "/opt/vault/tls/tls.key"
...
}
Khi đã tìm được, bạn hãy chỉnh sửa dòng tls_cert_file
và tls_key_file
để trỏ đến chứng chỉ Let’s Encrypt và file chứa key của mình như dưới đây. Và dĩ nhiên, bạn hãy nhớ thay đổi your_domain
thành tên miền máy chủ của mình.
listener "tcp" {
...
tls_cert_file = "/etc/letsencrypt/live/your_domain/fullchain.pem"
tls_key_file = "/etc/letsencrypt/live/your_domain/privkey.pem"
}
Lưu ý: Bạn cũng nên thay đổi giá trị từ address = "0.0.0.0:8200"
thành address = "127.0.0.1:8200"
để ngăn chặn các kết nối từ bên ngoài vào máy chủ của mình. Vì 127.0.0.1
là một địa chỉ được dùng cho local host hay còn gọi là địa chỉ private. Việc điều chỉnh như này sẽ giúp cho máy chủ của bạn an toàn, tách biệt với mạng lưới internet bên ngoài trước khi nó được bảo mật đúng cách. Đến đây, thì bạn đã có thể sử dụng lệnh vault
để kết nối trực tiếp đến máy chủ qua giao thức HTTPS.
Sau khi đã hoàn tất chỉnh sửa, bạn hãy lưu và đóng file lại, nếu sử dụng nano
bạn hãy nhấn CTRL + X
, sau đó là Y
và ENTER
.
Tiếp theo, người dùng trên hệ thống vault
cần phải được cấp quyền để đọc các file chứng chỉ và keys. Theo mặc định, chỉ có root
mới có quyền truy cập vào chúng. Do đó, để thực hiện cấp quyền cho người dùng, bạn sẽ tạo một nhóm đặc biệt gọi là pki
và thêm người dùng vào đó như sau:
sudo groupadd pki
Tiếp theo, bạn sẽ cập nhật quyền truy cập đến hai thư mục bên trong thư mục /etc/letsencrypt
để cho phép các thành viên trong nhóm pki
đọc nội dung của chúng:
sudo chgrp -R pki /etc/letsencrypt/archive
sudo chgrp -R pki /etc/letsencrypt/live
sudo chmod -R g+rx /etc/letsencrypt/archive
sudo chmod -R g+rx /etc/letsencrypt/live
Sau đó, bạn hãy thêm người dùng vault
vào nhóm pki
, để giúp vault
có thể truy cập đến các file chứng chỉ để phục vụ cho các giao thức HTTPS:
sudo usermod -a -G pki vault
Cuối cùng, để thuận tiện hơn, bạn hãy thêm một quy tắc trong /etc/hosts
để chuyển hướng các requests tới Vault tới localhost
. Thay thế your_domain
trong lệnh sau thành tên miền của mình đã được Let’s Encrypt cấp chứng chỉ cho.
echo 127.0.0.1 your_domain.com | sudo tee -a /etc/hosts
Lệnh trên giúp thêm dòng 127.0.0.1 your_domain.com
vào /etc/hosts
để bất kì các HTTP request nào được gửi từ máy chủ Vault đến your_domain.com
sẽ bỏ qua phần DNS và được gửi trực tiếp đến localhost
.
Ở bước tiếp theo bạn sẽ tiến hành khởi động Vault và khởi tạo nơi để lưu trữ các secret.
Bước 3: Khởi tạo Vault
Vào lần đầu tiên khởi động, phần backend lưu trữ các dữ liệu của Vault sẽ không được khởi tạo theo. Do đó, bạn hãy khởi động dịch vụ hệ thống Vault để khởi tạo phần backend và sau đó khởi chạy Vault như dưới đây:
sudo systemctl start vault.service
Bạn có thể dùng lệnh sau để kiểm tra các dịch vụ đã chạy thành công hay chưa:
sudo systemctl status vault.service
Nếu thành công, bạn sẽ nhận được output tương tự như sau:
Output
● vault.service - "HashiCorp Vault - A tool for managing secrets"
Loaded: loaded (/lib/systemd/system/vault.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2021-11-16 21:55:13 UTC; 22s ago
Docs: https://www.vaultproject.io/docs/
Main PID: 104207 (vault)
Tasks: 7 (limit: 1137)
Memory: 179.3M
CGroup: /system.slice/vault.service
└─104207 /usr/bin/vault server -config=/etc/vault.d/vault.hcl
Output trên chứa một số thông tin về các dịch vụ hiện đang chạy cũng như ID của tiến trình và tài nguyên sử dụng tương ứng. Bạn hãy đảm bảo rằng, dòng lệnh sau đây được hiển trị trên output:
Output
. . .
Active: active (running)
. . .
Nếu dịch vụ không hoạt động, bạn có thể kiểm tra lại lỗi bằng cách xem các dòng log ở cuối của output trên.
Tiếp theo, nếu đã chạy thành công, bạn hãy set một biến môi trường để giúp người dùng vault
biết cách kết nối đến máy chủ. Ở bước 1, bạn đã cấu hình cho Vault chỉ listen trên localhost, vì vậy hãy set biến môi trường VAULT_ADDR
thành endpoint như sau:
export VAULT_ADDR=https://your_domain:8200
Từ đây, vault
đã có thể giao tiếp với máy chủ của bạn. Lưu ý ở đây, bạn chỉ định tên miền một cách đầy đủ thay vì chỉ là localhost
hay 127.0.0.1
để có thể xác thực bằng chứng chỉ HTTPS.
Tiếp theo, xác nhận trạng thái của máy chủ Vault bằng lệnh sau:
vault status
Output của lệnh trên sẽ cho bạn biết rằng máy chủ hiện đã đang chạy nhưng chưa được khởi tạo Intialized false
.
Key Value
--- -----
Seal Type shamir
Initialized false
Sealed true
Total Shares 0
Threshold 0
Unseal Progress 0/0
Unseal Nonce n/a
Version 1.8.5
Storage Type file
HA Enabled false
Ở đây sẽ có hai thông tin mà Vault chỉ cho bạn biết ở thời điểm khởi tạo mà không ở bất kì một thời điểm nào khác:
- Intial root token: Tương ứng với các quyền của root vào quá trình deploy của Vault, cho phép quản lý các policies, mounts và dữ liệu trong Vault.
- Unseal keys: Các khóa này được dùng để mở Vault khi máy chủ khởi chạy, cho phép Vault giải mã các secrets được lưu ở backend.
Cụ thể hơn, quá trình unseal của Vault sẽ giải mã các dữ liệu được lưu ở backend bằng một key được tạo thành từ các key chia sẻ. Vào lần khởi tạo Vault đầu tiên, bạn sẽ chọn số lượng unseal key cần tạo và số lượng cần thiết để unseal. Để biết thêm thông tin chi tiết hơn, bạn có thể xem qua trong document chính thức của Vault.
Cấu hình thường thấy ở Vault là bạn sẽ sử dụng 3 key cho lúc tạo và 2 key cho lúc unseal. Điều này cho phép các key được lưu trữ riêng biệt ở các nơi khác nhau và tăng tính bảo mật khi một khóa sẽ là không đủ để unseal Vault. Hay nói cách khác, khi Vault khởi động, bạn sẽ cần ít nhất là 2 key để khởi chạy dịch vụ thành công. Khi chưa được unseal, các file lưu trữ các dữ liệu nhạy cảm sẽ vẫn bị mã hóa và không thể truy cập được.
Tiếp theo, bạn hãy khởi tạo 3 unseal keys bằng tùy chọn -key-shares=3
và yêu cầu ít nhất 2 key để unseal Vault với tùy chọn -key-threshold=2
như sau:
vault operator init -key-shares=3 -key-threshold=2
Bạn sẽ nhận được output tương tự như dưới đây:
Output
Unseal Key 1: eZcJeydRrqeSMZ1zTN+VVll9TFT2KvJy7VlnxUgtvuz5
Unseal Key 2: ntmqCKq8rgNnKT1YSLCjVmCCZBAA3NwUeqxIyRpYD4Wm
Unseal Key 3: 3FK1+Hsorh4p8/L9mki3VskaEU2eQhLqGOI/pJkTHMbx
Initial Root Token: s.hY0ieybfDqCadz7JpL88uO3x
Sau khi nhận được các key như trên, bạn hãy lưu lại chúng và lưu cả Intial Root Token bởi vì bạn sẽ không thể lấy lại các thông tin này nếu làm mất. Bạn có thể lưu mỗi key ở mỗi nơi khác nhau, một key ở trình quản lý mật khẩu, một key ở thiết bị USB và một key ở bên trong GPG-encrypted file.
Nếu chạy vault status
lại lần nữa, bạn sẽ thấy Intialized
đã được set thành true
, Total Shares
và Threshold
cũng phản ánh số lượng phân mảnh của key và số lượng key cần thiết để khởi chạy Vault.
vault status
Output
. . .
Initialized true
Sealed true
Total Shares 3
Threshold 2
Unseal Progress 0/2
. . .
Chú ý rằng Unseal Progress
hiện đang chỉ giá trị 0/2
, tức chưa có key nào được dùng để khởi chạy Vault cả. Để bắt đầu mở Vault, bạn sẽ sử dụng các unseal key vừa mới được tạo. Chạy lệnh vault operator unseal
và nhập vào bất kì key nào trong 3 key vừa tạo ở bước trên:
vault operator unseal
Sau đó bạn nhập key vào:
Output
Key (will be hidden):
Sau khi nhập, bạn sẽ thấy Unseal Progress 1/2
, chứng tỏ 1 key đã được dùng thành công, nhưng bạn vẫn cần thêm 1 key nữa để khởi chạy được Vault.
Output
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed true
Total Shares 3
Threshold 2
Unseal Progress 1/2
Unseal Nonce 0f3a328b-e0c6-6294-d6a2-56da49271dff
Version 1.8.5
Storage Type file
HA Enabled false
Tiếp tục, bạn hãy nhập key thứ 2 vào bằng lệnh unseal
một lần nữa:
vault operator unseal
Nhập một key khác với key trước đó:
Output
Key (will be hidden):
Nếu đã unseal thành công, output của bạn sẽ tương tự như sau:
Output
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 3
Threshold 2
Version 1.8.5
Storage Type file
Cluster Name vault-cluster-3042c7bc
Cluster ID c3e9d814-cf2a-2901-f0e4-ebc52d29e5cc
HA Enabled false
Đến đây, Vault đã được unseal và đã có thể sử dụng. Các bước unseal như trên sẽ cần phải được thực hiện mỗi khi Vault khởi động lại.
Ngoài ra, bạn nên kết hợp sử dụng Vault trên nền tảng máy chủ ảo VPS để bảo vệ và giảm thiểu tối đa rủi ro rò rỉ thông tin nhạy cảm. Với việc sử dụng VPS, bạn sẽ sở hữu một môi trường ảo hóa riêng tư, đáng in cậy để tăng cường bảo mật hệ thống của mình. Với toàn quyền quản trị, bạn cũng có thể tùy chỉnh các thiết lập bảo mật cho riêng mình để đáp ứng các yêu cầu cụ thể của công việc.
Để sở hữu một dịch vụ Cloud Server đáng tin cậy, bạn có thể tham khảo Vietnix, một trong những đơn vị cung cấp VPS hàng đầu tại Việt Nam hiện nay. Với đội ngũ kỹ thuật viên giàu kinh nghiệm và chuyên môn cao, Vietnix cam kết mang đến cho khách hàng những giải pháp lưu trữ VPS tốc độ, ổn định và bảo mật nhất. Hơn nữa, với các gói dịch vụ VPS Giá Rẻ, VPS SSD, VPS AMD, VPS NVMe và VPS GPU phù hợp với mọi nhu cầu và ngân sác, bạn hoàn toàn có thể tìm thấy một gói dịch vụ phù hợp với mình tại Vietnix.
Bước 4: Đọc và viết các Secrets
Ở bước này, bạn sẽ sử dụng kv
secret backend để lưu trữ các dữ liệu theo dạng key/value đơn giản trong Vault. Tuy nhiên, đây không phải là backend duy nhất sử dụng được với Vault.
Để thực hiện bạn sẽ cần bật kv
backend lên và sau đó tiến hành viết và đọc dữ liệu trong đó.
Đầu tiên, bạn hãy lưu Intial Root Token đã được tạo ra ở quá trình khởi tạo Vault vào một biến trong shell để sử dụng:
root_token=your_root_token_here
Tiếp theo, hãy bật kv
backend lên và xác thực cho token:
VAULT_TOKEN=$root_token vault secrets enable kv
Bạn sẽ nhận được output tương tự như sau nếu lệnh chạy thành công:
Output
Success! Enabled the kv secrets engine at: kv/
Sau đó, bạn có thể xác nhận lại kv
đã được thêm vào trong danh sách local của các backend lưu trữ secret bằng lệnh sau:
VAULT_TOKEN=$root_token vault secrets list
Bạn sẽ có được output tương tự như dưới đây:
Output
Path Type Accessor Description
---- ---- -------- -----------
cubbyhole/ cubbyhole cubbyhole_abc1631b per-token private secret storage
identity/ identity identity_631fe262 identity store
kv/ kv kv_4d5855c8 n/a
sys/ system system_79b13f2f system endpoints used for control, policy and debugging
Sau khi xác nhận kv
đã chạy thành công. Tiếp theo, bạn có thể lưu trữ dữ liệu vào trong phần backend này như sau:
VAULT_TOKEN=$root_token vault write kv/message value=mypassword
Trong lệnh trên, prefix kv/
chỉ định rằng bạn đang viết vào trong kv
backend được mở ở đường dẫn kv
và đang lưu trữ cho key value
ở đường dẫn message
có giá trị là mypassword
. Bạn cũng đang sử dụng quyền superuser để viết secret này.
Để kiểm tra lại secret đã lưu, bạn có thể dùng lệnh vault read
:
VAULT_TOKEN=$root_token vault read kv/message
Bạn sẽ nhận được output như dưới đây, với nội dung như đã tạo trước đó:
Output
Key Value
--- -----
refresh_interval 768h
value mypassword
Tuy nhiên, việc tạo, đọc và thực hiện các thao tác khác với Vault bằng Root Token không thực sự an toàn, khi cho phép chia sẻ quyền theo nhóm và không thể kiểm soát quyền truy cập vào các secrets. Ở bước tiếp theo, cũng là bước cuối cùng trong bài hôm nay, bạn sẽ tìm hiểu cách để định nghĩa các policies và tạo thêm các access token để hạn chế người dùng tương tác với Vault.
Bước 5: Tạo Authorization Policy
Trong các dự án thực tế, bạn có thể sẽ cần lưu các giá trị của API keys hay mật khẩu để các ứng dụng bên ngoài có thể sử dụng. Mặc dù trong các tình huống đó bạn có thể sử dụng root token để truy cập, nhưng sẽ là an toàn hơn nếu tạo ra một token có quyền truy cập hạn chế hơn như read-only chẳng hạn.
Trong bước cuối cùng này, bạn sẽ tạo một policy của Vault để chỉ cho phép thao tác read-only vào các secrets. Để tạo một policy, bạn hãy mở file policy.hcl
bằng nano
hoặc bất kì text editor nào tùy thích:
nano policy.hcl
Sau đó, bạn hãy chỉnh sửa policy trong Vault để chỉ cho phép các truy cập read-only vào secret kv/message
như sau:
path "kv/message" {
capabilities = ["read"]
}
Lưu và đóng file sau khi hoàn tất.
Tiếp theo bạn sẽ load file policy.hcl
vào trong Vault và tạo một policy tên là message-readonly
bằng lệnh sau:
VAULT_TOKEN=$root_token vault policy write message-readonly policy.hcl
Sau đó, bạn sẽ tạo một token để sử dụng cho truy cập read-only vào Vault. Bạn hãy thêm cờ -policy="message-readonly"
vào trong lệnh vault token create
để token sử dụng policy mà bạn mới tạo:
VAULT_TOKEN=$root_token vault token create -policy="message-readonly"
Output sẽ tương tự như sau:
Output
Key Value
--- -----
token your_token_value
token_accessor your_token_accessor
token_duration 768h0m0s
token_renewable true
token_policies ["default" "message-readonly"]
identity_policies []
policies ["default" "message-readonly"]
Bạn hãy lưu lại giá trị của your_token_value
vào một biến môi trường tên là app_token
:
app_token=your_token_value
Sau đó, bạn có thể sử dụng app_token
để truy cập đến dữ liệu được lưu ở kv/message
.
VAULT_TOKEN=$app_token vault read kv/message
Output
Key Value
--- -----
refresh_interval 768h0m0s
value mypassword
Lưu ý, vì bạn đã thiết lập cho policy trước đó chỉ có quyền read-only nên nếu sử dụng app_token
cho các truy cập khác như list
thì sẽ bị từ chối, ví dụ như dưới đây:
VAULT_TOKEN=$app_token vault list kv/
Output
Error reading kv/: Error making API request.
URL: GET https://your_domain:8200/v1/secret?list=true
Code: 403. Errors:
* 1 error occurred:
* permission denied
Việc thiết lập hay tạo ra các token hạn chế quyền truy cập sẽ đảm bảo ứng dụng được an toàn hơn và khiến các token không thể thực hiện các thao tác truy cập vào dữ liệu không được cho phép.
Lời kết
Trong bài hướng dẫn hôm nay về cách quản lý an toàn các Secrets bằng HashiCorp trên Ubuntu 20.04, bạn đã tiến hành cài đặt, cấu hình và deploy Vault trên Ubuntu 20.04. Bạn cũng đã tạo ra các phân mảnh của key và số lượng key cần thiết cho việc mở hay unseal Vault, cuối cùng là khởi tạo kv
backend và các policy để định nghĩa các token bị giới hạn quyền truy cập vào các secrets. Nếu còn bất cứ thắc mắc gì trong bài viết, hãy để lại bình luận ở bên dưới để được giải đáp nhanh chóng.