সেরা self-hosted secrets manager কোনটি?
একটি VPS-এর জন্য OpenBao, Infisical, SOPS, systemd credentials নাকি env ফাইল কোনটি সেরা? খরচ ও জটিলতা অনুযায়ী প্রতিটি পদ্ধতির বাস্তবসম্মত তুলনামূলক বিশ্লেষণ দেখুন এখানে।
একটি self-hosted secrets manager যা করে, তা একটি password manager করে না
একটি self-hosted secrets manager প্রসেসগুলোর কাছে credentials পৌঁছে দেয়। একটি password manager মানুষের কাছে credentials পৌঁছে দেয়। এই একটি পার্থক্যের ওপর ভিত্তি করেই বাকি সবকিছু নির্ধারিত হয়। একটি password manager আনলক করার জন্য একজন মানুষের উপস্থিতি এবং মনোযোগ প্রয়োজন। একটি secrets manager-কে রাত 03:00 টায় আপনার অ্যাপ্লিকেশনকে ডাটাবেস পাসওয়ার্ড দিতে হয়, যখন কেউ জেগে থাকে না।
এদের ব্যর্থতার ধরনগুলো গুরুত্বপূর্ণভাবে আলাদা। একটি locked password manager কেবল একটি অসুবিধা: আপনাকে আবার মাস্টার পাসওয়ার্ড টাইপ করতে হয়। একটি sealed secrets manager একটি বিভ্রাট: যে সার্ভিসটি seal থাকা অবস্থায় রিস্টার্ট হয়, সেটি credentials ছাড়াই চালু হয় এবং বন্ধই থেকে যায়। আপনার নিজের password manager হিসেবে Vaultwarden চালানো মানুষের সমস্যাটি ভালোভাবে সমাধান করে। এটি মেশিনের সমস্যা সমাধান করে না এবং এটি সেই উদ্দেশ্যে তৈরিও হয়নি।
একটি সার্ভারের জন্য বাস্তবসম্মত বিকল্পগুলোকে দুটি ভাগে ভাগ করা যায়। OpenBao এবং Infisical হলো সার্ভিস: একটি API, একটি ডাটাবেস, TLS (transport layer security), একটি লগইন ধাপ এবং একটি প্রসেস যা আপনাকে সচল রাখতে হবে। age-এর সাথে SOPS, systemd credentials এবং Docker secrets হলো ফাইল: এগুলো at rest অবস্থায় এনক্রিপ্ট করা থাকে, যা ইতিমধ্যে চলমান কোনো কিছু দ্বারা ডিক্রিপ্ট হয় এবং বাড়তি মনিটর করার মতো কিছু থাকে না।
এখানে সরাসরি সৎ উত্তরটি দেওয়া হলো। একজন বা দুইজন ব্যবহারকারী আছে এমন একটি সিঙ্গেল বক্সের জন্য, ফাইল-ভিত্তিক বিকল্পগুলো সাধারণত সঠিক। এমন একটি OpenBao যা কেউ সঠিকভাবে unseal করে না এবং কেউ rotate করে না, তা একটি mode 600 env file-এর চেয়েও খারাপ। কারণ এটি একটি বাড়তি চলমান অংশ এবং এমন একটি ব্যাকআপ যোগ করে যা আপনি ভুল করবেন, অথচ এটি আপনাকে এমন কোনো rotation সুবিধা দেয় না যা আপনি আগে থেকেই হাতে করছেন না।
600 মোডের env ফাইল কি যথেষ্ট?
অনেক ক্ষেত্রে, হ্যাঁ। এটি যে হুমকির বিরুদ্ধে সুরক্ষা দেয় তা হলো সার্ভারে থাকা অন্য কোনো ব্যবহারকারীর আপনার ডাটাবেজ পাসওয়ার্ড পড়ে ফেলা। ইউনিক্স ফাইল পারমিশন এই কাজটিই করে এবং নেটওয়ার্ক চালু হওয়ার আগেই এটি কার্যকর হয়।
sudo install -d -m 750 -o root -g myapp /etc/myapp
sudo install -m 640 -o root -g myapp /dev/null /etc/myapp/env
sudoedit /etc/myapp/envউভয় দিক থেকে এটি যাচাই করুন:
sudo -u myapp cat /etc/myapp/env
sudo -u nobody cat /etc/myapp/envপ্রথম কমান্ডটি ফাইলটি প্রিন্ট করে। দ্বিতীয়টি cat: /etc/myapp/env: Permission denied প্রিন্ট করে, কারণ nobody ব্যবহারকারী myapp গ্রুপে নেই এবং ফাইলে কোনো ওয়ার্ল্ড বিট সেট করা নেই। এটিই সম্পূর্ণ সিকিউরিটি মডেল এবং এটি কার্যকর।
তথ্য ফাঁসের ঘটনাটি ঘটে এর পরের ধাপে। EnvironmentFile= যুক্ত একটি systemd ইউনিট সেই মানগুলোকে প্রসেস এনভায়রনমেন্টে কপি করে এবং প্রসেস এনভায়রনমেন্টটি পড়া সম্ভব।
[Service]
User=myapp
EnvironmentFile=/etc/myapp/env
ExecStart=/usr/local/bin/myappsudo cat /proc/$(pgrep -n myapp)/environ | tr '\0' '\n'এটি আপনার গোপন তথ্যগুলো প্লেইনটেক্সটে প্রিন্ট করে, কারণ /proc/<pid>/environ ফাইলটি root এবং যে ব্যবহারকারীর অধীনে প্রসেসটি চলছে, উভয়ের জন্যই পাঠযোগ্য। কোনো ক্র্যাশ রিপোর্টার যদি রিপোর্টের সাথে এনভায়রনমেন্ট যুক্ত করে, তবে সেটিও একই তথ্য দেখতে পায়। একই অ্যাকাউন্টের অধীনে চলা যেকোনো টুলও এটি দেখতে পায়, আর এই কারণেই AI এজেন্ট থেকে গোপন তথ্য দূরে রাখা শুরু হয় এনভায়রনমেন্ট থেকে সেগুলোকে সরিয়ে ফেলার মাধ্যমে। ফাইলটির সাথে একটি ডেডিকেটেড লো-প্রিভিলেজ সার্ভিস ইউজার ব্যবহার করুন, যাতে "যে ব্যবহারকারীর অধীনে প্রসেসটি চলছে" সেটি যেন root না হয়।
age ব্যবহার করে SOPS: এমন গোপন তথ্য যা আপনি git-এ commit করতে পারেন
SOPS (secrets operations) একটি YAML বা JSON ফাইলের মানগুলোকে এনক্রিপ্ট করে এবং কী (keys)-গুলোকে প্লেইনটেক্সটে রাখে। age হলো একটি ছোট এনক্রিপশন টুল যা আপনাকে একটি কী পেয়ার (key pair) দেয় এবং এর জন্য কোনো কী সার্ভারের প্রয়োজন হয় না। এই দুটির সমন্বয়ে আপনি আপনার কোডের পাশে secrets.enc.yaml commit করতে পারেন এবং git diff ব্যবহার করে কোনো পাঠককে গোপন তথ্য না জানিয়েই বুঝতে পারেন যে কোন সেটিংটি পরিবর্তিত হয়েছে।
Ubuntu 24.04-এ age প্যাকেজ হিসেবে পাওয়া যায়। SOPS প্যাকেজ হিসেবে নেই, তাই রিলিজ পেজ থেকে .deb সংগ্রহ করুন। 2026 সালের আগস্ট মাস অনুযায়ী 3.13.3 সংস্করণটি বর্তমান ছিল।
sudo apt update && sudo apt install -y age
curl -LO https://github.com/getsops/sops/releases/download/v3.13.3/sops_3.13.3_amd64.deb
sudo apt install -y ./sops_3.13.3_amd64.deb
sops --versionএকটি কী পেয়ার তৈরি করুন। age-keygen প্রাইভেট কী-টিকে ফাইলে লেখে এবং পাবলিক কী-টিকে প্রিন্ট করে, তাই আপনি Public key: age1... দিয়ে শুরু হওয়া একটি লাইন দেখতে পাবেন।
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
chmod 600 ~/.config/sops/age/keys.txt
age-keygen -y ~/.config/sops/age/keys.txtপাবলিক কী-টিকে রিপোজিটরির রুট ডিরেক্টরিতে .sops.yaml ফাইলে রাখুন, যাতে আপনাকে কমান্ড লাইনে বারবার প্রাপকের নাম মনে রাখতে না হয়।
creation_rules:
- age: age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23csops encrypt secrets.yaml > secrets.enc.yaml
sops decrypt secrets.enc.yamlকোনো path_regex ছাড়া একটি রুল সবকিছুকেই ম্যাচ করে, যা শুরুতে আপনার প্রয়োজন। যদি আপনি পরবর্তীতে একটি রুল যোগ করেন, তবে সেটিকে এমনভাবে লিখুন যাতে তা sops-এ পাস করা ফাইলের সাথে ম্যাচ করে, কারণ রুলগুলো ইনপুট পাথের বিপরীতে চেক করা হয়, আউটপুট রিডাইরেক্ট করা ফাইলের বিপরীতে নয়।
রানটাইমে, মানগুলোকে একটি প্রসেসে পাঠান এবং অন্য কোথাও নয়:
sops exec-env secrets.enc.yaml './myapp'sops exec-env মেমরিতে ডিক্রিপ্ট করে এবং চাইল্ড প্রসেসের এনভায়রনমেন্টে মানগুলো সেট করে, তাই ডিস্কে কোনো প্লেইনটেক্সট লেখা হয় না। পূর্ববর্তী সেকশনের এনভায়রনমেন্ট সংক্রান্ত সতর্কতাটি এই চাইল্ড প্রসেসের ক্ষেত্রেও প্রযোজ্য।
এখানে দুটি বিষয় ব্যবহারকারীদের সমস্যায় ফেলে। systemd-এর অধীনে Failed to get the data key required to decrypt the SOPS file এররটির মানে প্রায় সবসময়ই এই যে, SOPS ভুল হোম ডিরেক্টরিতে খুঁজছে, কারণ একটি ইউনিট আপনার HOME ইনহেরিট করে না। ইউনিটে Environment=SOPS_AGE_KEY_FILE=/etc/sops/age.txt দিয়ে পাথটি স্পষ্টভাবে সেট করুন। এছাড়া, .sops.yaml এডিট করলে বিদ্যমান কোনো কিছু পুনরায় এনক্রিপ্ট হয় না: একজন সহকর্মীর পাবলিক কী যোগ করলে তা শুধুমাত্র নতুন ফাইলের ক্ষেত্রে কার্যকর হয়, তাই প্রতিটি বিদ্যমান ফাইলের ওপর sops updatekeys secrets.enc.yaml রান করুন। যদি আপনার কনফিগারেশন ইতিমধ্যে Ansible-এর মাধ্যমে চলে, তবে Ansible Vault দিয়ে একই মান এনক্রিপ্ট করা দ্বিতীয় কোনো টুল ছাড়াই একই ফলাফল দেয়।
systemd credentials: গোপন তথ্য যা কখনোই environment-এ পৌঁছায় না
Ubuntu 24.04-এ systemd 255 থাকে, তাই আলাদা করে কিছু ইনস্টল করার প্রয়োজন নেই। systemd-creds হোস্ট মেশিনে একটি গোপন তথ্য এনক্রিপ্ট করে এবং systemd সেটিকে একটি প্রাইভেট ডিরেক্টরিতে ডিক্রিপ্ট করে, যা শুধুমাত্র সংশ্লিষ্ট সার্ভিসটিই পড়তে পারে।
sudo systemd-creds setup
sudo install -d -m 700 /etc/myapp
echo -n 'hunter2' | sudo systemd-creds encrypt --name=db_password - /etc/myapp/db_password.cred[Service]
User=myapp
LoadCredentialEncrypted=db_password:/etc/myapp/db_password.cred
ExecStart=/usr/local/bin/myappসার্ভিসটি $CREDENTIALS_DIRECTORY দ্বারা নির্দেশিত ডিরেক্টরির ভেতর db_password নামক ফাইল থেকে মানটি পড়ে। এই মানটি environment-এ থাকে না, তাই /proc/<pid>/environ কোনো কার্যকর তথ্য দেখায় না এবং প্লেইনটেক্সট কখনোই রুট ফাইলসিস্টেমে জমা হয় না।
ইউনিট ফাইল নির্দেশ করার আগে ফাইলটি সঠিকভাবে ডিক্রিপ্ট হচ্ছে কি না তা যাচাই করুন:
sudo systemd-creds decrypt /etc/myapp/db_password.cred -কোন কি (key) দিয়ে এটি এনক্রিপ্ট করা হয়েছে তা জেনে রাখুন, কারণ ব্যাকআপটি কাজে আসবে কি না তা এর ওপরই নির্ভর করে। ডিফল্ট --with-key=auto টিপিএম2 (TPM2 - trusted platform module version 2) চিপ ব্যবহার করে যদি তা উপস্থিত ও ব্যবহারযোগ্য থাকে, অন্যথায় এটি হোস্ট কি ব্যবহার করে। বেশিরভাগ VPS ইনস্ট্যান্সে কোনো TPM2 থাকে না।
systemd-analyze has-tpm2no মানে হলো হোস্ট কি ব্যবহার করা হয়েছে এবং সেই কি-টি /var/lib/systemd/credential.secret-এ থাকে, যা শুধুমাত্র রুট ব্যবহারকারী পড়তে পারেন। নতুন কোনো VPS-এ db_password.cred রিস্টোর করার সময় যদি সেই ফাইলটি না থাকে, তবে কোনো কিছুই ডিক্রিপ্ট হবে না। একই ব্যাকআপে credential.secret কপি করে রাখুন অথবা প্লেইনটেক্সট এমন কোথাও রাখুন যেখানে আপনার অ্যাক্সেস আছে।
Docker secrets: /run/secrets এর অধীনে ফাইলসমূহ
Compose হোস্ট থেকে একটি ফাইল পড়ে এবং সেটিকে কন্টেইনারের মধ্যে /run/secrets/<name> পাথে মাউন্ট করে।
services:
app:
image: myapp:latest
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./db_password.txtdocker compose exec app cat /run/secrets/db_password
docker compose exec app env | grep -i passwordপ্রথম কমান্ডটি সিক্রেটটি প্রিন্ট করে। দ্বিতীয়টি শুধুমাত্র DB_PASSWORD_FILE=/run/secrets/db_password প্রিন্ট করে, আর এটাই মূল উদ্দেশ্য: ভ্যালুটি কখনোই কন্টেইনার এনভায়রনমেন্টে থাকে না, তাই এটি docker inspect আউটপুটে দেখা যায় না। অনেক অফিসিয়াল ইমেজ ইতিমধ্যেই এই ফরম্যাটটি প্রত্যাশা করে এবং Postgres ইমেজ ঠিক এভাবেই POSTGRES_PASSWORD_FILE পড়ে।
এটি কী তা পরিষ্কারভাবে বোঝা প্রয়োজন। Swarm মোডের বাইরে কোনো স্তরেই কোনো এনক্রিপশন থাকে না: ./db_password.txt হোস্টের একটি প্লেইনটেক্সট ফাইল এবং এর একমাত্র সুরক্ষা হলো এর মোড এবং মালিকানা। এগুলো আপনি নিজেই সেট করুন, কারণ Compose কোনো সতর্কতা ছাড়াই একটি সবার জন্য পাঠযোগ্য (world readable) ফাইল মাউন্ট করে দেবে। সাধারণ env_file শর্টকাটের বিপরীতে এর সুবিধা ও অসুবিধার বিস্তারিত Compose env ফাইল এবং সিক্রেট সংক্রান্ত নির্দেশিকা-তে রয়েছে।
OpenBao এবং Vault চালানোর প্রকৃত খরচ
OpenBao হলো HashiCorp Vault-এর একটি Linux Foundation fork, যা 2023 সালে HashiCorp তাদের Vault-কে Business Source License-এর অধীনে নিয়ে আসার পর তৈরি করা হয়। OpenBao এখনো MPL 2.0 (Mozilla Public License)-এর অধীনে রয়েছে। 2026 সালের আগস্ট মাস পর্যন্ত 2.6.2 রিলিজটি ছিল বর্তমান সংস্করণ। নিচে উল্লিখিত প্রায় সবকিছুই Vault-এর ক্ষেত্রেও প্রযোজ্য, কারণ এই fork-টি মূল কমান্ডের কাঠামো অপরিবর্তিত রেখেছে।
docker pull docker.io/openbao/openbaoআপনি যদি apt-এর মাধ্যমে আপডেট পরিচালনা করতে চান, তবে OpenBao ডাউনলোড পেজে Debian এবং Ubuntu প্যাকেজগুলো পাওয়া যাবে। সার্ভারের জন্য একটি কনফিগারেশন ফাইল প্রয়োজন, যাতে একটি listener এবং একটি storage backend থাকবে:
listener "tcp" {
address = "127.0.0.1:8200"
tls_cert_file = "/path/to/full-chain.pem"
tls_key_file = "/path/to/private-key.pem"
}
storage "raft" {
path = "/path/to/raft/data"
node_id = "raft_node_1"
}এরপর এটিকে একবার চালু করুন:
bao operator initডিফল্টভাবে এটি root key-কে 5টি অংশে বিভক্ত করে এবং unseal করার জন্য সেগুলোর মধ্যে 3টি প্রয়োজন হয়, যা -key-shares এবং -key-threshold ফ্ল্যাগ দ্বারা নিয়ন্ত্রিত হয়। এটি শেয়ারগুলো এবং প্রাথমিক root token একবারই প্রদর্শন করে, এরপর আর কখনোই দেখাবে না।
এখন সেই অংশটি, যা বেশিরভাগ তুলনামূলক আলোচনায় এড়িয়ে যাওয়া হয়। একটি রিস্টার্ট হওয়া সার্ভার মানেই একটি sealed সার্ভার। OpenBao শুধুমাত্র মেমরিতেই root key ধরে রাখে, তাই রিস্টার্টের পর এটি নিজস্ব স্টোরেজ ডিক্রিপ্ট করতে পারে না যতক্ষণ না কেউ প্রয়োজনীয় সংখ্যক শেয়ার সরবরাহ করে। ফলে কার্নেল আপডেট বা out of memory kill-এর কারণে সার্ভার sealed অবস্থায় চলে যায় এবং অ্যাপ্লিকেশনগুলো লগইন করতে পারে না।
একজন ব্যবহারকারীর VPS-এর ক্ষেত্রে Shamir split আসলে কোনো নিরাপত্তাই দেয় না, কারণ পাঁচটি শেয়ারই একই ব্যক্তির একই পাসওয়ার্ড ম্যানেজারে জমা থাকে। Auto unseal চাবিটিকে একটি বিশ্বস্ত ডিভাইস বা সার্ভিসে সরিয়ে নেয়। বড় ক্লাউড প্ল্যাটফর্মে এর অর্থ হলো একটি managed key service, কিন্তু আপনার VPS-এর ক্ষেত্রে এর অর্থ সাধারণত এমন একটি key file যা সেই ডেটার সাথেই একই ডিস্কে থাকে যাকে এটি রক্ষা করার কথা। এটি নিরাপত্তার একটি প্রকৃত অবনমন, যা সার্ভারকে রিবুটের পর স্বয়ংক্রিয়ভাবে চালু করার সুবিধার বিনিময়ে করা হয়। এই বিনিময়টি সচেতনভাবে করুন এবং আপনি কোন পদ্ধতিটি বেছে নিয়েছেন তা লিখে রাখুন।
Infisical: একটি UI, একটি ডাটাবেস এবং একটি মাস্টার কি যা আপনার কাছেই থাকে
Infisical হলো একটি সিক্রেটস প্ল্যাটফর্ম, যাতে ওয়েব ইন্টারফেস, প্রজেক্ট, এনভায়রনমেন্ট এবং ব্যবহারকারী-ভিত্তিক অ্যাক্সেস কন্ট্রোল রয়েছে। Compose ব্যবহার করে এটি সেলফ-হোস্ট করার প্রক্রিয়াটি সংক্ষিপ্ত:
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
curl -o .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
docker compose -f docker-compose.prod.yml up -dশেষ কমান্ডটি চালানোর আগে .env এডিট করুন। দুটি মান অবশ্যই আপনার নিজের হতে হবে এবং এর মধ্যে একটি পরবর্তীতে কখনোই পরিবর্তন করা যাবে না:
openssl rand -hex 16
openssl rand -base64 32প্রথমটি হলো ENCRYPTION_KEY, যা 16 বাইটের একটি হেক্স স্ট্রিং। এটি সেই কি (key) যা দিয়ে PostgreSQL-এর ভেতরে আপনার সিক্রেটগুলো এনক্রিপ্ট করা থাকে। তাই এটি হারিয়ে ফেললে আপনার ডাটাবেসের নিখুঁত ব্যাকআপও কেবল সাইফারটেক্সট বা অর্থহীন তথ্যে পরিণত হবে এবং চলমান ইনস্ট্যান্সে এটি পরিবর্তন করলে বিদ্যমান সিক্রেটগুলো আর ডিক্রিপ্ট করা যাবে না। দ্বিতীয়টি হলো AUTH_SECRET, যা সেশনের জন্য ব্যবহৃত 32 বাইটের একটি base64 স্ট্রিং। SITE_URL অবশ্যই সেই পূর্ণাঙ্গ URL হতে হবে যা আপনি বাস্তবে ব্যবহার করবেন (প্রোটোকলসহ), অন্যথায় লগইন রিডাইরেক্ট কাজ করবে না।
যখন আপনার মূলত মানুষের জন্য একটি প্ল্যাটফর্ম প্রয়োজন হয়, তখন OpenBao-এর চেয়ে Infisical বেশি কার্যকর। ছোট দলের জন্য ওয়েব ইন্টারফেস এবং বিভিন্ন এনভায়রনমেন্টের মধ্যে বিভাজন প্রয়োজন হলে এটি ভালো সমাধান, বিশেষ করে যখন আপনার এমন ডাটাবেস ক্রেডেনশিয়াল প্রয়োজন নেই যা নিজে থেকেই এক্সপায়ার হয়ে যায়। এর জন্য আপনার PostgreSQL, Redis এবং একটি TLS সার্টিফিকেট প্রয়োজন, যার সবগুলোর প্যাচ এবং ব্যাকআপ এখন আপনাকেই রক্ষণাবেক্ষণ করতে হবে।
secrets service ডাউন থাকলে এবং আপনার অ্যাপ রিস্টার্ট হলে কী ঘটে
এই প্রশ্নটি নির্ধারণ করে যে একটি secrets service একটি একক বক্সে থাকা উচিত কি না। নেটওয়ার্ক চালু হওয়ার আগেই ফাইল পড়া যায়, কিন্তু একটি সার্ভিস চালু করা যায় না।
বক্সটি রিবুট করলে আপনার অ্যাপ্লিকেশন এবং OpenBao একই সময়ে চালু হতে শুরু করে। অ্যাপ্লিকেশনটি তার ডাটাবেস পাসওয়ার্ডের জন্য অনুরোধ করে, কিন্তু OpenBao তখনো sealed অবস্থায় থাকে। ফলে অনুরোধটি ব্যর্থ হয় এবং systemd অ্যাপ্লিকেশনটিকে লুপে রিস্টার্ট করতে থাকে যতক্ষণ না কোনো ব্যবহারকারী ম্যানুয়ালি unseal shares প্রদান করেন। এতে কোনো কিছু ভেঙে যায় না, তবে কোনো কিছুই সচল থাকে না।
এটি সামলানোর দুটি সঠিক উপায় রয়েছে। ইউনিটগুলোকে ক্রমানুসারে সাজান এবং অ্যাপ্লিকেশনটিকে পুনরায় চেষ্টা করতে দিন: After= secrets service-এর উপর নির্ভরতা তৈরি করুন, সাথে Restart=on-failure এবং একটি RestartSec= ব্যবহার করুন যা যথেষ্ট দীর্ঘ যাতে আপনি API-তে অতিরিক্ত চাপ (hammering) না দেন। অথবা, বুট টাইমের পরিবর্তে ডেপ্লয়মেন্টের সময় সিক্রেট সংগ্রহ করুন: সিক্রেটটিকে একটি mode 600 ফাইলে বা systemd credential-এ রেন্ডার করুন, যাতে চলমান সিস্টেমটি API-এর পরিবর্তে একটি ফাইলের উপর নির্ভর করে।
Token expiry-এর সমস্যাটিও একই, তবে এটি ধীর গতিতে ঘটে। OpenBao token এবং lease-এর একটি নির্দিষ্ট সময়সীমা (time to live) থাকে, তাই দীর্ঘ সময় ধরে চলা কোনো প্রসেস যা কখনোই রিনিউ হয় না, সেটি এমন এক সময়ে অ্যাক্সেস হারিয়ে ফেলে যা কোনো ডেপ্লয়মেন্টের সাথে সম্পর্কিত নয়। এই ব্যর্থতাটি বিভ্রান্তিকর কারণ সেই নির্দিষ্ট দিনে কোনো কিছুই পরিবর্তন করা হয়নি।
স্টোরটির ব্যাকআপ নেওয়া
এখানে প্রতিটি অপশনের একটি কি (key) আছে এবং সেই কি ছাড়া ব্যাকআপটি মূল্যহীন। আপনার কি কোথায় থাকে তা লিখে রাখুন।
একটি env ফাইলের ক্ষেত্রে, ফাইলটিই হলো গোপন তথ্য, তাই ব্যাকআপটি অবশ্যই এনক্রিপ্ট করা থাকতে হবে। SOPS-এর ক্ষেত্রে, এনক্রিপ্ট করা ফাইলটি যেকোনো পাবলিক জায়গায় রাখা যায়, তবে ~/.config/sops/age/keys.txt-এ থাকা age private key-টি কোনোভাবেই হারানো যাবে না। systemd credentials-এর জন্য, .cred ফাইলগুলোর পাশাপাশি /var/lib/systemd/credential.secret-এর ব্যাকআপ রাখুন। Infisical-এর জন্য, একটি PostgreSQL ডাম্প নিন এবং ENCRYPTION_KEY-কে তার থেকে আলাদা কোথাও সংরক্ষণ করুন।
raft স্টোরেজ ব্যবহারকারী OpenBao নিজস্ব স্ন্যাপশট নেয়:
bao operator raft snapshot save backup.snap
bao operator raft snapshot restore backup.snapস্ন্যাপশটটিতে আপনার এনক্রিপ্ট করা স্টোরেজ থাকে, তাই এটিকে নতুন কোনো সার্ভারে রিস্টোর করতে হলে তখনও bao operator init থেকে প্রাপ্ত আনসিল শেয়ারগুলোর প্রয়োজন হবে। যদি শেয়ারগুলো কোথাও সংরক্ষণ না করে শুধুমাত্র স্ন্যাপশটগুলো অবজেক্ট স্টোরেজে কপি করার জন্য একটি nightly job চালানো হয়, তবে সেটি আসলে কোনো ব্যাকআপই নয়। কোনো কিছুর ওপর নির্ভর করার আগে একটি অস্থায়ী VPS-এ রিস্টোর প্রক্রিয়াটি পরীক্ষা করে দেখুন।
অডিট লগিং: কে কোন সিক্রেট পড়েছে
ফাইল আপনাকে কোনো অডিট ট্রেইল দেয় না। ফাইল মোড এবং মালিকানা থেকে কেবল বোঝা যায় কারা সিক্রেটটি পড়তে পারত, কিন্তু বাস্তবে কে পড়েছে তা কখনোই জানা যায় না। কোনো পাথের ওপর auditd ব্যবহার করা এর নিকটতম বিকল্প, তবে এটি কেবল জানায় যে ফাইলটি খোলা হয়েছে, কোনো নির্দিষ্ট ভ্যালু ব্যবহার করা হয়েছে কি না তা জানায় না।
OpenBao প্রতিটি অনুরোধ একটি অডিট ডিভাইসে লগ করে যা আপনাকে স্পষ্টভাবে সক্রিয় করতে হয়:
bao audit enable file file_path=/var/log/openbao_audit.logএই লগ সম্পর্কে দুটি তথ্য আপনার সার্ভার পরিচালনার পদ্ধতি বদলে দেয়। অনুরোধ এবং উত্তরের বেশিরভাগ স্ট্রিং HMAC-SHA256 এবং একটি সল্ট দিয়ে হ্যাশ করা থাকে, ফলে আপনি লগের ভেতরে প্লেইনটেক্সট না থাকা সত্ত্বেও আপনার জানা কোনো ভ্যালুর সাথে লগের মিল খুঁজে পেতে পারেন। তবে পূর্ণসংখ্যা (integers) এবং বুলিয়ান (booleans) সরাসরি প্লেইনটেক্সটে লেখা হয়, তাই সংখ্যাসূচক সিক্রেটগুলো এই হ্যাশিং থেকে কোনো সুরক্ষা পায় না।
এরপর একটি অপারেশনাল ফাঁদ রয়েছে: কোনো সক্রিয় অডিট ডিভাইস যদি অনুরোধ রেকর্ড করতে না পারে, তবে OpenBao কোনো অনুরোধের উত্তর দেয় না। কোনো ডিভাইস যদি ব্লক হয়ে যায়, তবে সমস্যা সমাধান না হওয়া পর্যন্ত অনুরোধগুলো ঝুলে থাকে। /var/log-এ ডিস্ক পূর্ণ হয়ে গেলে আপনার সিক্রেট API ডিজাইন অনুযায়ী অচল হয়ে যাবে। প্রথম দিন থেকেই অডিট লগের জন্য আলাদা জায়গা বরাদ্দ করুন এবং logrotate রুল সেট করুন, প্রথমবার সার্ভার অচল হওয়ার জন্য অপেক্ষা করবেন না।
কোন self-hosted secrets manager আপনার ব্যবহার করা উচিত?
প্রথমে মেশিন এবং ব্যবহারকারীর সংখ্যা গণনা করুন, তারপর সিদ্ধান্ত নিন।
- একটি মেশিন, একজন ব্যবহারকারী: root-এর মালিকানাধীন এবং service user-এর পড়ার উপযোগী mode 600-এর একটি env ফাইল ব্যবহার করুন। যখন process environment থেকে মানটি বের করার প্রয়োজন হয়, তখন systemd credentials যোগ করুন।
- একটি মেশিন, দুই থেকে পাঁচজন ব্যবহারকারী, কনফিগারেশন ইতিমধ্যে git-এ আছে: age-এর সাথে SOPS ব্যবহার করুন। প্রত্যেক ব্যক্তিকে একটি key pair দেওয়া হয় এবং
.sops.yamlফাইলে ডিক্রিপ্ট করার অনুমতিপ্রাপ্ত প্রতিটি public key তালিকাভুক্ত থাকে। - একাধিক মেশিন, একটি কনফিগারেশন রিপোজিটরি, এমন কোনো credentials-এর প্রয়োজন নেই যার মেয়াদ শেষ হয়ে যায়: এক্ষেত্রেও age-এর সাথে SOPS ব্যবহার করুন। প্রতিটি host-এর জন্য একটি করে recipient key রাখুন, যাতে একটি host key চুরি হলেও তা দিয়ে কেবল সেই নির্দিষ্ট host-এর ফাইলগুলোই ডিক্রিপ্ট করা যায়।
- একাধিক মেশিন এবং একাধিক টিম যাদের সত্যিকার অর্থেই নির্দিষ্ট মেয়াদের database credentials প্রয়োজন, এবং সাথে এমন একটি audit trail যা কেউ নিয়মিত পর্যবেক্ষণ করে: OpenBao ব্যবহার করুন। unsealing এবং restore ড্রিলের জন্য প্রতি মাসে অন্তত এক ঘণ্টা অপারেটর সময় বাজেট রাখুন।
এই চারটি পদ্ধতির মূল ভিত্তি একই। আপনার প্রয়োজন মেটাতে পারে এমন সবচেয়ে ছোট সমাধানটিই বেছে নিন, কারণ একটি secrets manager ডাউন থাকা এবং খালি থাকা—ব্যবহারকারীর কাছে একই রকম মনে হয়।
FAQ
একটি সিঙ্গেল VPS-এর জন্য কি self-hosted secrets manager ব্যবহার করা লাভজনক?
সাধারণত না, যদি আপনি OpenBao বা Infisical-এর মতো কোনো সার্ভিসের কথা বুঝিয়ে থাকেন। একটি সার্ভারে যদি এক বা দুইজন ব্যবহারকারী থাকেন, তবে mode 600 যুক্ত একটি env ফাইল বা systemd encrypted credential একই ধরনের নিরাপত্তা প্রদান করে। এতে কোনো unseal ধাপের প্রয়োজন হয় না এবং প্যাচ করার জন্য বাড়তি কোনো সার্ভিসের ঝামেলাও থাকে না। যখন আপনার একাধিক মেশিন এবং অনেক ব্যবহারকারী থাকে, অথবা এমন ক্রেডেনশিয়ালের প্রয়োজন হয় যা ম্যানুয়ালি পরিবর্তন না করেই মেয়াদোত্তীর্ণ হয়ে যায়, তখনই কেবল একটি secrets service ব্যবহার করা অর্থবহ হয়।
password manager এবং secrets manager-এর মধ্যে পার্থক্য কী?
একটি password manager এমন ক্রেডেনশিয়াল সংরক্ষণ করে যা একজন মানুষ টাইপ করে এবং তাদের উপস্থিতিতেই সেটি আনলক করা হয়। অন্যদিকে, একটি secrets manager প্রসেসগুলোকে ক্রেডেনশিয়াল প্রদান করে, তাই এটিকে রাত 3টার সময়ও কোনো মানুষের হস্তক্ষেপ ছাড়াই কাজ করতে হয়। এর ফলে একটি বড় পার্থক্য তৈরি হয়: একটি locked password manager আপনাকে মাস্টার পাসওয়ার্ড পুনরায় টাইপ করতে বলে, কিন্তু একটি sealed secrets manager সেই সমস্ত সার্ভিসকে থামিয়ে দেয় যা আনলক হওয়ার আগ পর্যন্ত রিস্টার্ট হতে চায়।
রিবুট হওয়ার পর OpenBao যদি sealed হয়ে যায়, তবে আমার অ্যাপগুলোর কী হবে?
সেগুলো তাদের সিক্রেটগুলো সংগ্রহ করতে পারে না, তাই সেগুলো চালু হতে ব্যর্থ হয়। যতক্ষণ না কেউ unseal threshold পূরণ করছে (ডিফল্টভাবে 5টির মধ্যে 3টি শেয়ার), ততক্ষণ systemd সেগুলোকে লুপে রিস্টার্ট করতে থাকে। OpenBao রুট কি (root key) শুধুমাত্র মেমরিতে রাখে, তাই প্রতিবার রিস্টার্টের পর এটি পুনরায় seal হয়ে যায়। হয় auto unseal চালু করুন (এটি মেনে নিয়ে যে একটি সিঙ্গেল VPS-এ unseal কি-টি ডেটার মতোই একই ডিস্কে থাকে), অথবা ডেপ্লয়মেন্টের সময় সিক্রেটগুলোকে একটি ফাইলে লিখে রাখুন যাতে বুট হওয়ার প্রক্রিয়াটি কোনো API-এর ওপর নির্ভরশীল না হয়।
আমি কি SOPS দিয়ে এনক্রিপ্ট করা ফাইল পাবলিক রিপোজিটরিতে কমিট করতে পারি?
ভ্যালুগুলো এনক্রিপ্ট করা থাকে, তাই age private key ছাড়া অন্য কারো পক্ষে সেগুলো পড়া সম্ভব নয়। তবে কি (keys) এনক্রিপ্ট করা থাকে না: যে কেউ দেখতে পাবে যে আপনার কাছে STRIPE_SECRET_KEY এবং SMTP_PASSWORD আছে এবং সেগুলো কত ঘনঘন পরিবর্তিত হচ্ছে। বেশিরভাগ প্রজেক্টের জন্য এই মেটাডেটা গ্রহণযোগ্য, তবে কিছু ক্ষেত্রে এটি গ্রহণযোগ্য নয়। age private key-কে রিপোজিটরির বাইরে রাখুন এবং যখনই কোনো নতুন recipient যোগ বা বাদ দেবেন, তখন প্রতিটি বিদ্যমান ফাইলে sops updatekeys কমান্ডটি চালান।