SSD Nodes Learn 🎉 VPS $5.50/মাস থেকে
নির্দেশিকা Matt Connorদ্বারা Matt Connor

Ansible Vault ব্যবহার করে Git-এ পাসওয়ার্ড এনক্রিপ্ট করুন

Ansible Vault ব্যবহার করে কীভাবে আপনার playbook-এর গোপন তথ্য এবং API টোকেন সুরক্ষিত রাখবেন তা জানুন। ফাইল বা নির্দিষ্ট ভেরিয়েবল এনক্রিপ্ট করা এবং rekey করার সঠিক নিয়ম দেখুন।

Ansible Vault কী সুরক্ষা দেয় এবং কী দেয় না

Ansible Vault আপনার playbook repository-এর ভেতরের গোপন তথ্যগুলোকে এনক্রিপ্ট করে রাখে, ফলে git-এ plaintext পাসওয়ার্ডের পরিবর্তে ciphertext জমা থাকে। ansible-vault কমান্ডটি আপনার বেছে নেওয়া একটি পাসওয়ার্ড থেকে তৈরি সিমেট্রিক কি (symmetric key) ব্যবহার করে পুরো ফাইল অথবা ফাইলের ভেতরের কোনো একটি মানকে এনক্রিপ্ট করে। প্লে (play) চলার সময় Ansible সেই কন্টেন্টকে মেমরিতে ডিক্রিপ্ট করে নেয়, ফলে ভেরিয়েবলটি অন্য যেকোনো সাধারণ ভেরিয়েবলের মতোই কাজ করে।

এই মডেলটির একটি স্পষ্ট সীমাবদ্ধতা রয়েছে। Vault শুধুমাত্র repository-তে সংরক্ষিত অবস্থায় (at rest) গোপন তথ্যকে সুরক্ষা দেয়, এর বাইরে নয়। একবার কোনো টাস্ক রান করলে, সেই মানটি মেমরিতে, রেন্ডার করা টেমপ্লেটে, মডিউল আর্গুমেন্টে এবং রান আউটপুটে plaintext হিসেবে থাকে, যদি না আপনি তা আটকান। যারা playbook রান করতে পারে, তাদের সবার কাছেই vault পাসওয়ার্ডটি থাকে। তাই vault আপনাকে টিমের বাইরের মানুষের কাছ থেকে গোপনীয়তা দেয়, কিন্তু টিমের ভেতরের সদস্যদের জন্য আলাদা কোনো access control প্রদান করে না।

আপনি যদি এখনো কোনো playbook না লিখে থাকেন, তবে একটি VPS-এর বিপরীতে প্রথম Ansible playbook দিয়ে শুরু করুন এবং যখন সেই playbook-এ পাসওয়ার্ডের প্রয়োজন হবে, তখন এখানে ফিরে আসুন।

পুরো ফাইল এনক্রিপ্ট করবেন, নাকি একটি মাত্র স্ট্রিং?

ansible-vault encrypt একটি ফাইলকে সাইফারটেক্সট দিয়ে প্রতিস্থাপন করে। ফাইলটি $ANSIBLE_VAULT দিয়ে শুরু হওয়া একটি হেডার লাইনের নিচে base64 টেক্সটের একটি ব্লকে পরিণত হয়। যখন ফাইলে গোপন তথ্য ছাড়া অন্য কিছু থাকে না, তখন এটি ব্যবহার করুন।

ansible-vault encrypt_string একটি ভ্যালু এনক্রিপ্ট করে এবং একটি YAML স্নিপেট প্রিন্ট করে, যা আপনি সাধারণ vars ফাইলে পেস্ট করতে পারেন। ভেরিয়েবলের নাম পাঠযোগ্য থাকে এবং শুধুমাত্র ভ্যালুটি সাইফারটেক্সট হয়। যখন গোপন তথ্যের পাশাপাশি প্লেইনটেক্সট সেটিংস থাকে, তখন এটি ব্যবহার করুন।

দৈনন্দিন কাজের ক্ষেত্রে মূল পার্থক্যটি হলো diff। একটি vault ফাইল প্রতিবার সেভ করার সময় নতুন র‍্যান্ডম সল্ট দিয়ে পুনরায় এনক্রিপ্ট করা হয়, তাই সাইফারটেক্সটের প্রতিটি বাইট পরিবর্তিত হয়। git diff তখন একটি অপাঠ্য ব্লকের জায়গায় অন্য একটি অপাঠ্য ব্লক দেখায়, যার ফলে একজন রিভিউয়ার বুঝতে পারেন না যে আপনি একটি পাসওয়ার্ড পরিবর্তন করেছেন নাকি পুরো ফাইলটি নতুন করে লিখেছেন। encrypt_string-এর ক্ষেত্রে, প্রতিটি গোপন তথ্য প্লেইনটেক্সট ফাইলের ভেতরে নিজস্ব ব্লক হিসেবে থাকে, তাই diff-এ স্পষ্টভাবে দেখা যায় কোন ভেরিয়েবলটি পরিবর্তিত হয়েছে এবং ফাইলের বাকি অংশ অপরিবর্তিত থাকে।

ইনলাইন ফর্মের একটি অসুবিধা আছে, যা রোটেশনের সময় বোঝা যায়: ansible-vault rekey ইনলাইন ব্লকগুলোকে স্পর্শ করে না। যখন গোপন তথ্যের তালিকা দীর্ঘ হয় এবং খুব কম পরিবর্তিত হয়, তখন ফাইল ফর্মটি বেছে নিন। যখন ফাইলে গোপন তথ্যের সাথে সাধারণ ভেরিয়েবল মিশ্রিত থাকে এবং আপনি কোড রিভিউকে অর্থবহ করতে চান, তখন ইনলাইন ফর্মটি বেছে নিন।

group_vars লেআউট যা দেখায় কী সুরক্ষিত

Ansible group_vars/<group>.yml লোড করে, এবং এটি group_vars/<group>/ ডিরেক্টরির ভেতরের প্রতিটি ফাইলও লোড করে। ডিরেক্টরি ফরম্যাটটি আপনার ব্যবহার করা উচিত, কারণ এটি একটি সিঙ্গেল গ্রুপকে পাশাপাশি একটি প্লেইনটেক্সট ফাইল এবং একটি এনক্রিপ্টেড ফাইল রাখার সুবিধা দেয়।

inventory/
  hosts.ini
group_vars/
  all/
    vars.yml
    vault.yml
  web/
    vars.yml
    vault.yml
host_vars/
  db01/
    vars.yml
    vault.yml
playbooks/
  site.yml

প্রতিটি vault.yml এনক্রিপ্ট করা থাকে। প্রতিটি vars.yml প্লেইনটেক্সট। কোনো ফাইল না খুলেই একজন পাঠক বুঝতে পারেন কোন ভ্যালুগুলো সুরক্ষিত, কারণ ফাইলের নামেই তা উল্লেখ থাকে।

এই প্যাটার্নের দ্বিতীয় অংশটি হলো ইনডাইরেকশন (indirection)। এনক্রিপ্ট করা ফাইলের ভেতরে, প্রতিটি ভেরিয়েবলের আগে vault_ প্রিফিক্স হিসেবে ব্যবহার করুন।

vault_db_password: "a real password"
vault_grafana_admin_token: "a real token"

এরপর পাশের প্লেইনটেক্সট ফাইল থেকে সেই নামগুলোকে রেফারেন্স করুন।

db_password: "{{ vault_db_password }}"
grafana_admin_token: "{{ vault_grafana_admin_token }}"

রোল এবং টেমপ্লেটগুলো db_password ব্যবহার করে এবং ভ্যালুটি কোথা থেকে এসেছে তা তারা জানতে পারে না, যা প্লেবুক এবং রোলের মধ্যকার বিভাজন পরিষ্কার রাখে। প্লেইনটেক্সট vars.yml একটি সার্চযোগ্য ইনডেক্স হিসেবেও কাজ করে: grep -r vault_ group_vars/ রিপোজিটরিতে প্রত্যাশিত প্রতিটি সিক্রেটের তালিকা দেখায়, কোনো কিছু ডিক্রিপ্ট না করেই। এর বিনিময়ে প্রতিটি সিক্রেটের জন্য একটি অতিরিক্ত নামের প্রয়োজন হয়, এবং vault_ নামে কোনো টাইপো থাকলে তা রান টাইমে সিনট্যাক্স এরর হিসেবে নয়, বরং আনডিফাইনড ভেরিয়েবল হিসেবে ধরা পড়ে।

encrypt_string দিয়ে একটি ভেরিয়েবল এনক্রিপ্ট করা

ansible-vault encrypt_string --vault-id prod@~/.ansible/vault-prod.txt \
  --stdin-name 'vault_db_password'

আপনার গোপন তথ্যটি টাইপ করুন, তারপর Ctrl-D চাপুন। --stdin-name স্ট্যান্ডার্ড ইনপুট থেকে মানটি পড়ে নেয়, যা এটিকে আপনার শেল হিস্ট্রি ফাইল থেকে দূরে রাখে। অন্য পদ্ধতিটিতে মানটি কমান্ড লাইনে দেওয়া হয়, যেখানে শেল এটিকে রেকর্ড করে রাখে:

ansible-vault encrypt_string --vault-id prod@~/.ansible/vault-prod.txt \
  'a real password' --name 'vault_db_password'

যেকোনো পদ্ধতিতেই কমান্ডটি একটি YAML ব্লক প্রিন্ট করবে। এটিকে হুবহু vars ফাইলে পেস্ট করুন, কারণ !vault ট্যাগের নিচের ইনডেন্টেশন বা স্পেসগুলো মানের অংশ।

vault_db_password: !vault |
          $ANSIBLE_VAULT;1.2;AES256;prod
          6638643965323633646262656665306333616466396630323136393465356136396436383331
          3131303163306665326539353837343663313762616561306534373963383531613664393332

!vault ট্যাগটি YAML লোডারকে জানায় যে এই স্কেলারটি সাধারণ টেক্সট নয়, বরং সাইফারটেক্সট। হেডারটিতে ফরম্যাট ভার্সন, সাইফার এবং যে ভল্ট আইডি লেবেলটি এটিকে এনক্রিপ্ট করেছে তা থাকে। কোনো ভল্ট আইডি ছাড়া এনক্রিপ্ট করা মানে একটি 1.1 হেডার থাকে যাতে কোনো লেবেল থাকে না; এটি কাজ করে, তবে পাসওয়ার্ডটি কোথা থেকে এসেছে সে সম্পর্কে কম তথ্য দেয়।

ভল্ট পাসওয়ার্ড কোথায় থাকে?

এটি রিপোজিটরির বাইরে থাকে। এটিই একমাত্র নিয়ম যার কোনো ব্যতিক্রম নেই।

--ask-vault-pass প্রতিবার চালানোর সময় একবার প্রম্পট করে এবং কিছুই সংরক্ষণ করে না। এটি ল্যাপটপের জন্য উপযুক্ত, তবে ক্রন জব (cron job) বা সিআই রানারের (CI runner) জন্য এটি উপযুক্ত নয়।

পাসওয়ার্ড ফাইল হলো একটি প্লেইন টেক্সট ফাইল যার প্রথম লাইনে পাসওয়ার্ডটি থাকে। কঠোর পারমিশনসহ একটি খালি ফাইল তৈরি করুন, তারপর এডিটরে সেটি পূরণ করুন, যাতে পাসওয়ার্ডটি কখনোই আপনার শেল হিস্ট্রিতে না পৌঁছায়:

mkdir -p ~/.ansible
install -m 600 /dev/null ~/.ansible/vault-prod.txt
$EDITOR ~/.ansible/vault-prod.txt

--vault-password-file ব্যবহার করে যেকোনো কমান্ডকে এই ফাইলের দিকে নির্দেশ করুন:

ansible-playbook -i inventory/hosts.ini playbooks/site.yml \
  --vault-password-file ~/.ansible/vault-prod.txt

প্রতিটি কমান্ডে এই ফ্ল্যাগটি বারবার ব্যবহার করা ভুলে যাওয়ার সম্ভাবনা থাকে, তাই রিপোজিটরির রুটে ansible.cfg-এ এটি একবার সেট করে নিন।

[defaults]
inventory = inventory/hosts.ini
vault_password_file = ~/.ansible/vault-prod.txt

একই সেটিং ANSIBLE_VAULT_PASSWORD_FILE এনভায়রনমেন্ট ভেরিয়েবল থেকেও রিড করা যায়, যা সিআই জবে সাধারণত ব্যবহার করা হয়। জবটি তার নিজস্ব ক্রেডেনশিয়াল স্টোর থেকে পাসওয়ার্ডটি একটি অস্থায়ী ডিরেক্টরির ফাইলে লেখে, ভেরিয়েবলটি এক্সপোর্ট করে এবং রান শেষ হলে ফাইলটি মুছে ফেলে। ফাইলের নামের প্যাটার্নটি .gitignore-এও যোগ করুন, কারণ ansible.cfg-এর পাথটি কমিট করা থাকে এবং কোনো না কোনো সময় কেউ চেকআউটের ভেতরেই আসল ফাইলটি তৈরি করে ফেলতে পারে।

যদি পাসওয়ার্ড ফাইলটি এক্সিকিউটেবল হয়, তবে Ansible ফাইলটিকে টেক্সট হিসেবে না পড়ে সেটিকে রান করে এবং এর স্ট্যান্ডার্ড আউটপুট থেকে পাসওয়ার্ডটি পড়ে। এভাবেই আপনি ডিস্কে কোনো কিছু না লিখে সিস্টেম কি-রিং (keyring) বা ক্লাউড সিক্রেট ম্যানেজার থেকে ভল্ট পাসওয়ার্ড সংগ্রহ করতে পারেন। --vault-id-এর মাধ্যমে ব্যবহৃত স্ক্রিপ্টের কিছু বাড়তি প্রয়োজনীয়তা রয়েছে: এর নাম অবশ্যই -client বা -client এবং একটি এক্সটেনশন দিয়ে শেষ হতে হবে, এটি অবশ্যই এক্সিকিউটেবল হতে হবে, এটিকে একটি --vault-id অপশন গ্রহণ করতে হবে এবং এটিকে অবশ্যই স্ট্যান্ডার্ড আউটপুটে পাসওয়ার্ডটি প্রিন্ট করতে হবে।

দুটি vault ID: staging এবং production

একটি vault ID হলো vault পাসওয়ার্ডের সাথে যুক্ত একটি লেবেল, যা label@source হিসেবে লেখা হয়। এর উৎস হলো prompt, যা একটি পাসওয়ার্ড ফাইলের পাথ অথবা একটি ক্লায়েন্ট স্ক্রিপ্টের পাথ। লেবেল ব্যবহারের ফলে একটি রিপোজিটরিতে একাধিক পাসওয়ার্ডের অধীনে গোপন তথ্য রাখা সম্ভব হয়, যাতে staging পাসওয়ার্ড দিয়ে production ফাইল খোলা না যায়।

ansible-vault encrypt --vault-id staging@~/.ansible/vault-staging.txt \
  group_vars/staging/vault.yml
ansible-vault encrypt --vault-id prod@~/.ansible/vault-prod.txt \
  group_vars/prod/vault.yml

একটি রান-এর জন্য প্রয়োজনীয় প্রতিটি ID প্রদান করুন:

ansible-playbook playbooks/site.yml \
  --vault-id staging@~/.ansible/vault-staging.txt \
  --vault-id prod@~/.ansible/vault-prod.txt

অথবা সেগুলোকে ansible.cfg-এ একবার তালিকাভুক্ত করুন:

[defaults]
vault_identity_list = staging@~/.ansible/vault-staging.txt, prod@~/.ansible/vault-prod.txt

একটি আচরণ ব্যবহারকারীদের অবাক করে। ডিফল্টভাবে, লেবেলটি একটি ইঙ্গিত মাত্র, কোনো লক নয়। Ansible বর্তমানে তার কাছে থাকা প্রতিটি সিক্রেট দিয়ে ফাইলটি খোলার চেষ্টা করে যতক্ষণ না একটি সফল হয়। তাই staging লেবেলযুক্ত একটি ফাইলও খুলে যেতে পারে যদি production পাসওয়ার্ডটি কাকতালীয়ভাবে সঠিক চাবি হয়। [defaults]-এর অধীনে vault_id_match = True সেট করুন, অথবা এনভায়রনমেন্ট ভেরিয়েবল ANSIBLE_VAULT_ID_MATCH ব্যবহার করুন; এতে Ansible শুধুমাত্র সেই সিক্রেটটিই ব্যবহার করবে যার লেবেল ফাইলের হেডারের সাথে মেলে। এই চেকের জন্য 1.2 হেডার প্রয়োজন, তাই এটি শুধুমাত্র সেই কন্টেন্টের ক্ষেত্রেই প্রযোজ্য যা শুরু থেকেই একটি vault ID দিয়ে এনক্রিপ্ট করা ছিল।

একাধিক ID লোড করা থাকলে, ansible-vault encrypt আর বুঝতে পারে না কোন পাসওয়ার্ড দিয়ে এনক্রিপ্ট করতে হবে। --encrypt-vault-id prod দিয়ে সেটির নাম উল্লেখ করুন, অথবা ansible.cfg-এ vault_encrypt_identity সেট করুন যাতে রিপোজিটরির একটি ডিফল্ট থাকে।

এর সুবিধা হলো ডিপ্লয়মেন্টের পরিধি নিয়ন্ত্রণ। একটি CI জব যা staging ডিপ্লয় করে, তাকে শুধুমাত্র staging পাসওয়ার্ড দেওয়া হয়। ফলে কোনো রানার compromised হলেও সেটি production-এর ক্রেডেনশিয়াল পড়তে পারে না। যখন আপনি একটি কন্ট্রোল মেশিন থেকে একগুচ্ছ Linux সার্ভারে প্লে (play) চালাচ্ছেন, তখন এই বিভাজনই একটি ছোট ঘটনা এবং একটি বড় বিপর্যয়ের মধ্যে পার্থক্য গড়ে দেয়।

কেউ চলে গেলে ভল্ট (vault) পুনরায় কি (rekey) করা

Rekey করার মাধ্যমে ভল্টের পাসওয়ার্ড পরিবর্তন হয় এবং নতুন পাসওয়ার্ড দিয়ে কন্টেন্টগুলো পুনরায় এনক্রিপ্ট করা হয়। এটি আগের কোনো কিছু মুছে ফেলে না। যার কাছে আগে পাসওয়ার্ড ছিল, সে যদি রিপোজিটরির কোনো কপি রেখে দিয়ে থাকে, তবে সে তা ডিক্রিপ্ট করতে পারবে; এমনকি সেই কপির প্রতিটি পুরনো কমিটও সে দেখতে পাবে। তাই কেউ চলে যাওয়ার সাথে সাথেই ভল্টের পাসওয়ার্ডকে অকার্যকর হিসেবে গণ্য করুন এবং নিচের ক্রমানুসারে রোটেশন সম্পন্ন করুন।

  1. সার্ভার এবং থার্ড-পার্টি সার্ভিসে থাকা আসল ক্রেডেনশিয়ালগুলো পরিবর্তন করুন। এই ধাপটিই মূলত অ্যাক্সেস বাতিল করে।
  2. ansible-vault edit ব্যবহার করে নতুন মানগুলো ভল্ট ফাইলে যুক্ত করুন।
  3. প্রতিটি এনক্রিপ্ট করা ফাইলকে নতুন ভল্ট পাসওয়ার্ড দিয়ে rekey করুন।
  4. নতুন ভল্ট পাসওয়ার্ডটি যাদের প্রয়োজন, তাদের কাছে রিপোজিটরির বাইরের কোনো চ্যানেলের মাধ্যমে পৌঁছে দিন।
ansible-vault rekey --vault-id prod@~/.ansible/vault-prod-old.txt \
  --new-vault-id prod@prompt \
  group_vars/prod/vault.yml host_vars/db01/vault.yml

rekey কমান্ডটি দিয়ে একসাথে একাধিক ফাইল প্রসেস করা যায় এবং --new-vault-id prod@prompt ব্যবহার করলে বারবার ডিস্ক থেকে পাসওয়ার্ড না পড়ে একবারই নতুন পাসওয়ার্ড চাওয়া হয়। লেবেল পরিবর্তন করার বিশেষ কোনো কারণ না থাকলে আগের লেবেলটিই রাখুন, কারণ কমান্ডটি যে ফাইলগুলো পুনরায় লেখে, সেগুলোর হেডারে এই লেবেলটি লেখা থাকে।

এখানেই ইনলাইন ফর্ম ব্যবহারের অসুবিধাটি স্পষ্ট হয়। ansible-vault rekey শুধুমাত্র সম্পূর্ণ এনক্রিপ্ট করা ফাইলের ওপর কাজ করে, তাই প্লেইনটেক্সট vars ফাইলের ভেতরে থাকা কোনো !vault ব্লক অপরিবর্তিত থেকে যায়। প্রথমে সেগুলো খুঁজে বের করুন, তারপর নতুন পাসওয়ার্ডের অধীনে encrypt_string ব্যবহার করে প্রতিটি পুনরায় জেনারেট করুন:

grep -rl '!vault' group_vars/ host_vars/

এটাই হলো পুরো প্রক্রিয়ার বিনিময়। ইনলাইন ব্লক ব্যবহারের ফলে আপনি রিডেবল ডিভ (diff) পান, কিন্তু রোটেশনের সময় আপনাকে ম্যানুয়ালি কাজ করতে হয়। অন্যদিকে, সম্পূর্ণ এনক্রিপ্ট করা ফাইলগুলো একটি কমান্ডেই রোটেট করা যায়, কিন্তু রিভিউ করার সময় সেগুলো থেকে কোনো কার্যকর তথ্য পাওয়া যায় না।

কেন আপনার আউটপুটে গোপন তথ্যটি এখনও দেখা যাচ্ছে

ভ্যালু ডিক্রিপ্ট হওয়ার সাথে সাথেই Vault-এর কাজ শেষ হয়ে যায়। Ansible একটি টাস্কের ফলাফল রিপোর্ট করে, এবং যে মডিউলটি তার আর্গুমেন্টগুলো ইকো (echo) করে, সেটি সেই ক্রেডেনশিয়ালটিকে রিপোর্টে নিয়ে আসে। একটি ভার্বোস রান, টেমপ্লেট টাস্কে --diff ব্যবহার, কোনো ব্যর্থ টাস্কের আর্গুমেন্ট ডাম্প করা, অথবা কোনো কলব্যাক প্লাগইন ফাইল আউটপুট লিখলে—এগুলোর প্রতিটিতেই প্লেইনটেক্সট থেকে যায়। ফাইল এনক্রিপ্ট করার ফলে এগুলোর কোনোটিতেই কোনো প্রভাব পড়ে না।

no_log: true হলো এর সমাধান। ক্রেডেনশিয়াল গ্রহণ করে এমন যেকোনো টাস্কে এটি সেট করুন।

- name: Write the application environment file
  ansible.builtin.template:
    src: app.env.j2
    dest: /etc/myapp/app.env
    owner: myapp
    group: myapp
    mode: "0600"
  no_log: true

Ansible তখন সেই টাস্কের ফলাফল আউটপুট থেকে সরিয়ে রাখে, ফলে লগ রেকর্ড করে যে টাস্কটি চলেছে, কিন্তু এটি কী হ্যান্ডেল করেছে তা রেকর্ড করে না। বিশেষ করে লুপের ক্ষেত্রে এটি সেট করুন, কারণ একটি লুপ প্রতিটি আইটেমের জন্য একটি ফলাফল রিপোর্ট করে, এবং একটি ক্রেডেনশিয়াল তালিকার ওপর লুপ চালালে পুরো তালিকাটিই রিপোর্ট হয়ে যায়।

আরও চারটি জায়গা আছে যেখানে ডিক্রিপ্ট করা গোপন তথ্য বেরিয়ে আসতে পারে, যার কোনোটিই no_log কভার করে না:

  • টেমপ্লেট থেকে রেন্ডার করা একটি ফাইল আপনার দেওয়া mode এবং owner উত্তরাধিকারসূত্রে পায়। ক্রেডেনশিয়াল ধারণকারী যেকোনো কিছুতে mode: "0600" এবং নির্দিষ্ট মালিকানা সেট করুন, অন্যথায় গোপন তথ্যটি টার্গেট হোস্টে সবার পড়ার যোগ্য হয়ে যাবে।
  • ansible.builtin.command বা ansible.builtin.shell-এ পাস করা কোনো গোপন তথ্য কমান্ড চলার সময় টার্গেট হোস্টের প্রসেস লিস্টে দেখা যায়, যেখানে যেকোনো লোকাল ইউজার তা পড়তে পারে। এর পরিবর্তে ফাইল বা এনভায়রনমেন্ট ভেরিয়েবলের মাধ্যমে এটি পাস করুন।
  • ফ্যাক্ট ক্যাশিং সংগৃহীত ফ্যাক্টগুলো কন্ট্রোল মেশিনের ডিস্কে লেখে, তাই গোপন তথ্য ধারণকারী একটি রেজিস্টার্ড ভেরিয়েবল এমন একটি ক্যাশ ফাইলে চলে যেতে পারে যা কেউ সংবেদনশীল বলে মনে করে না।
  • একই গোপন তথ্য সাধারণত দ্বিতীয় কোনো জায়গায় থাকে, যেমন কন্টেইনারের পড়া কোনো এনভায়রনমেন্ট ফাইল। সেখানে নিয়মগুলো আলাদা, এবং Compose env ফাইল থেকে ক্রেডেনশিয়াল দূরে রাখা বিষয়টি সেই দিকটি কভার করে।

no_log ডিবাগিংকে কঠিন করে তোলে, যা এর মূল উদ্দেশ্য। কোনো টাস্ক ঠিকমতো কাজ না করলে টেস্ট হোস্টে সাময়িকভাবে এটি সরিয়ে ফেলুন, এবং পরিবর্তন প্রোডাকশনে পাঠানোর আগে তা আবার ফিরিয়ে আনুন।

plaintext ফাইল না রেখে এনক্রিপ্ট করা ফাইল পড়া ও সম্পাদনা করা

ansible-vault view group_vars/prod/vault.yml ফাইল ডিক্রিপ্ট করে সরাসরি পেজারে দেখায় এবং ডিস্কে কোনো কিছু লেখে না। ansible-vault edit ফাইল ডিক্রিপ্ট করে একটি অস্থায়ী ফাইলে রাখে, আপনার $EDITOR খোলে এবং ফাইলটি বন্ধ করার সাথে সাথে পুনরায় এনক্রিপ্ট করে ফেলে। ansible-vault decrypt ব্যবহার না করে এই দুটি পদ্ধতি বেছে নিন, কারণ ansible-vault decrypt ব্যবহার করলে ওয়ার্কিং ট্রিতে একটি plaintext ফাইল থেকে যায়। ভুলবশত কোনো ডিক্রিপ্ট করা ভল্ট ফাইল স্টেজিং এরিয়াতে চলে যাওয়া হলো পাবলিক রিপোজিটরিতে গোপন তথ্য ফাঁস হওয়ার সবচেয়ে সাধারণ উপায়।

Git এনক্রিপ্ট করা ফাইলগুলো পড়ার সময় ডিক্রিপ্ট করে সেগুলোর একটি পাঠযোগ্য diff দেখাতে পারে:

git config --local diff.ansible-vault.textconv "ansible-vault view --vault-password-file ~/.ansible/vault-prod.txt"
printf '%s\n' 'group_vars/**/vault.yml diff=ansible-vault' >> .gitattributes

এটি সক্রিয় করার আগে এর কার্যপদ্ধতি বুঝে নিন। git diff এখন আপনার টার্মিনালে প্রোডাকশন সিক্রেটগুলো প্রিন্ট করবে, যা আপনার স্ক্রলব্যাক এবং স্ক্রিন শেয়ারে দেখা যেতে পারে। এটি শুধুমাত্র একটি মেশিনে একজন ব্যবহারকারীর জন্য স্থানীয় সুবিধা, তাই git config ফাইলটি লোকাল রাখুন। অন্য ব্যবহারকারীরা যদি একই কনফিগারেশন সেট না করেন, তবে তাদের চেকআউটে এই সুবিধা কাজ করবে না।

কখন Vault আর সঠিক টুল থাকে না

Vault হলো এমন একটি ফাইল ফরম্যাট যেখানে প্রতিটি লেবেলের বিপরীতে একটি করে পাসওয়ার্ড থাকে, আর এই কাঠামোর সীমাবদ্ধতাই নির্ধারণ করে এটি কখন আর কার্যকর থাকে না। নিচের যেকোনো একটি পরিস্থিতি তৈরি হলে একটি প্রকৃত secret store-এ স্থানান্তর করুন।

  • আপনার যদি ব্যক্তি-ভিত্তিক অ্যাক্সেসের প্রয়োজন হয়। যারা playbook চালান তাদের সবার কাছে একই পাসওয়ার্ড থাকে এবং vault ID শুধুমাত্র environment অনুযায়ী অ্যাক্সেস ভাগ করে, কোনো ব্যক্তির ভিত্তিতে নয়।
  • আপনার যদি audit trail-এর প্রয়োজন হয়। কে কখন কী ডিক্রিপ্ট করেছে, Vault তার কোনো রেকর্ড রাখে না।
  • আপনার যদি নির্দিষ্ট সময় পরপর credential পরিবর্তনের (rotation) প্রয়োজন হয়। Vault-এ কোনো expiry বা versioning নেই, তাই কোনো কিছুই আপনাকে জানাবে না যে একটি credential গত দুই বছরেও পরিবর্তন করা হয়নি।
  • অ্যাপ্লিকেশনটির যদি রান-টাইমে secret-এর প্রয়োজন হয়। একটি সার্ভিস যদি বুট করার সময় তার ডাটাবেস পাসওয়ার্ড পড়ে, তবে সেটি আপনার deployment repository থেকে পড়া উচিত নয়।

তখন এই প্যাটার্নটি উল্টে যায়। Ansible তখন আর secret জমা রাখে না, বরং রান-টাইমে একটি lookup plugin-এর মাধ্যমে HashiCorp Vault (এটি একটি ভিন্ন পণ্য যার নাম বিভ্রান্তিকরভাবে একই রকম), কোনো ক্লাউড প্রোভাইডারের secret manager, অথবা কন্ট্রোল মেশিনের keyring থেকে তা সংগ্রহ করে। রিপোজিটরিতে শুধু একটি পাথ থাকে, স্টোরে থাকে আসল ভ্যালু এবং স্টোরটিই অ্যাক্সেস লগ সংরক্ষণ করে। ছোট দলের জন্য, API সুবিধাসম্পন্ন একটি self-hosted পাসওয়ার্ড ম্যানেজার, যেমন একটি Vaultwarden সার্ভার, একই কাজ ছোট পরিসরে সম্পন্ন করতে পারে।

একটি credential এই সবকিছুর বাইরে থাকে। আপনার কন্ট্রোল মেশিন সার্ভারে পৌঁছানোর জন্য যে SSH key ব্যবহার করে, তা Vault-এর সমস্যা নয়, কারণ যেকোনো play শুরু হওয়ার আগেই Ansible-এর সেটি প্রয়োজন হয়। এটি একটি agent এবং passphrase ব্যবহার করে পরিচালনা করুন, যেমনটি SSH key ব্যবস্থাপনার মৌলিক বিষয়গুলোতে উল্লেখ করা হয়েছে।

FAQ

আমার কি পুরো vars ফাইলটি এনক্রিপ্ট করা উচিত নাকি শুধু সিক্রেট স্ট্রিংটি?

যখন ফাইলে শুধুমাত্র সিক্রেট থাকে তখন পুরো ফাইলটি এনক্রিপ্ট করুন, কারণ একটি কমান্ডেই সবকিছুর রোটেশন সম্পন্ন হয় এবং লেআউট সহজ থাকে। যখন সাধারণ ভেরিয়েবলের পাশাপাশি সিক্রেট থাকে তখন ansible-vault encrypt_string ব্যবহার করুন, কারণ এতে শুধুমাত্র এনক্রিপ্ট করা ভ্যালুটি পরিবর্তিত হয় এবং একজন রিভিউয়ার সহজেই বুঝতে পারেন কোন ভেরিয়েবলটি পরিবর্তন করা হয়েছে। এর বিনিময়ে রোটেশনের ক্ষেত্রে বাড়তি কাজ করতে হয়। ansible-vault rekey পুরো ফাইল নিয়ে কাজ করে কিন্তু ইনলাইন !vault ব্লকগুলোকে স্পর্শ করে না, তাই নতুন পাসওয়ার্ডের অধীনে সেগুলোকে ম্যানুয়ালি পুনরায় তৈরি করতে হয়।

Ansible Vault পাসওয়ার্ড ফাইলটি কোথায় রাখা উচিত?

রিপোজিটরির বাইরে, 0600 মোডে, যেমন ~/.ansible/vault-prod.txt পাথে এটি রাখুন। --vault-password-file দিয়ে সেটিকে নির্দেশ করুন, অথবা ansible.cfg-এর [defaults] সেকশনের অধীনে vault_password_file সেট করুন, কিংবা এনভায়রনমেন্টে ANSIBLE_VAULT_PASSWORD_FILE সেট করুন। CI-এর ক্ষেত্রে, জব চলাকালীন নিজস্ব ক্রেডেনশিয়াল স্টোর থেকে পাসওয়ার্ডটি একটি অস্থায়ী ফাইলে লিখুন, ভেরিয়েবলটি এক্সপোর্ট করুন এবং জব শেষ হলে ফাইলটি মুছে ফেলুন। ফাইলটি যদি এক্সিকিউটেবল হয়, তবে Ansible সেটি রান করে স্ট্যান্ডার্ড আউটপুট থেকে পাসওয়ার্ড পড়ে নেয়, যা আপনাকে ডিস্কে ফাইল না রেখে কি-রিং (keyring) থেকে পাসওয়ার্ড ব্যবহারের সুবিধা দেয়।

আমি কীভাবে স্টেজিং এবং প্রোডাকশনের জন্য আলাদা ভল্ট পাসওয়ার্ড ব্যবহার করব?

--vault-id staging@/path/to/file এবং --vault-id prod@/path/to/file ব্যবহার করে প্রতিটি পাসওয়ার্ডের জন্য একটি লেবেল দিন এবং প্রতিটি এনভায়রনমেন্টের ফাইলকে তার নিজস্ব লেবেলের অধীনে এনক্রিপ্ট করুন। রান টাইমে উভয় আইডি পাস করুন, অথবা [defaults]-এর অধীনে vault_identity_list-এ সেগুলোর তালিকা দিন। ডিফল্টভাবে Ansible তার কাছে থাকা প্রতিটি সিক্রেট দিয়ে ফাইলটি ডিক্রিপ্ট করার চেষ্টা করে যতক্ষণ না সফল হয়, তাই আপনি যদি শুধুমাত্র ফাইলের হেডারের সাথে মিল থাকা লেবেলের সিক্রেটটিই ব্যবহার করতে চান তবে vault_id_match = True সেট করুন। একাধিক আইডি লোড করা থাকলে, --encrypt-vault-id ব্যবহার করে এনক্রিপশনের জন্য নির্দিষ্ট আইডি বেছে নিন।

Ansible Vault কি রান আউটপুটে পাসওয়ার্ড দেখা যাওয়া বন্ধ করে?

না। ভল্ট শুধুমাত্র রিপোজিটরিতে থাকা সিক্রেটকে সুরক্ষিত রাখে। একবার কোনো টাস্ক রান করলে ভ্যালুটি প্লেইনটেক্সট হয়ে যায় এবং ভার্বোস রান বা ব্যর্থ টাস্কের ক্ষেত্রে তা লগে চলে আসতে পারে। ক্রেডেনশিয়াল হ্যান্ডেল করে এমন প্রতিটি টাস্কে no_log: true যোগ করুন, টেমপ্লেট করা যেকোনো ফাইলে কঠোর mode এবং owner সেট করুন এবং কমান্ড আর্গুমেন্ট হিসেবে সিক্রেট পাস করা এড়িয়ে চলুন, কারণ কমান্ড চলার সময় টার্গেট হোস্টে প্রসেস লিস্টে সেগুলো দৃশ্যমান থাকে।