পাঠ ৪০ · ৫৭-এর মধ্যে · মডিউল ৯
Home / Courses / Cloud Computing & DevOps / সিক্রেট ম্যানেজমেন্ট

সিক্রেট ম্যানেজমেন্ট ইন DevOps

Secrets management in DevOps
৮ মিনিট পড়া মধ্যবর্তী · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • কেন সিক্রেট সোর্স কোড বা IaC ফাইলে হার্ডকোড করা একটি গুরুতর নিরাপত্তা ঝুঁকি
  • ডেডিকেটেড সিক্রেট ম্যানেজমেন্ট সার্ভিস কী সুবিধা দেয় — অ্যাক্সেস কন্ট্রোল ও রোটেশন
  • রানটাইমে অ্যাপ্লিকেশন কীভাবে সিক্রেট গ্রহণ করে, সোর্স কোড স্পর্শ না করেই
  • Python দিয়ে একটি অ্যাক্সেস-কন্ট্রোলড সিক্রেট স্টোর সিমুলেট করে অনুমোদিত ও অননুমোদিত অ্যাক্সেসের পার্থক্য দেখা

১ · সিক্রেট কী এবং কেন হার্ডকোড করা বিপজ্জনক

সিক্রেটSecretসংবেদনশীল তথ্য (API কী, ডেটাবেস পাসওয়ার্ড, TLS প্রাইভেট কী, ক্লাউড ক্রেডেনশিয়াল) যা প্রকাশ পেলে সিস্টেমে অননুমোদিত অ্যাক্সেসের সুযোগ তৈরি করে। — API কী, ডেটাবেস পাসওয়ার্ড, TLS প্রাইভেট কী, ক্লাউড ক্রেডেনশিয়াল — এসব কখনোই সোর্স কোডে সরাসরি লেখা বা Git-এ কমিট হওয়া কোনো IaC/কনফিগ ফাইলে রাখা উচিত নয়। একবার একটি সিক্রেট ভুলবশত কমিট হয়ে গেলে, পরে সেই লাইন "মুছে ফেললেও" তা Git-এর ইতিহাসে (পুরনো কমিটে) চিরস্থায়ীভাবে থেকে যায় — যে কেউ রিপোজিটরির ইতিহাস দেখতে পারলে সেই সিক্রেট পেয়ে যাবে (cybersecurity কোর্সের secrets-scanning DevSecOps ধারণার সরাসরি প্রয়োগ এখানে)।

একটি বাস্তব-জগতের সাধারণ ভুল — একজন ডেভেলপার টেস্টিং-এর সুবিধার জন্য একটি ডেটাবেস পাসওয়ার্ড সরাসরি কোডে লিখে রাখেন "পরে সরিয়ে ফেলব" ভেবে, কিন্তু ভুলে সেটি কমিট ও পুশ হয়ে যায় — এই একক ভুল একটি প্রোডাকশন ডেটাবেসের সম্পূর্ণ অ্যাক্সেস প্রকাশ করে দিতে পারে।

২ · ডেডিকেটেড সিক্রেট ম্যানেজমেন্ট সার্ভিস

সমস্যার সমাধান হলো একটি সিক্রেট ম্যানেজমেন্ট সার্ভিসSecrets Management Serviceএকটি ডেডিকেটেড সার্ভিস (Vault-স্টাইল, বা ক্লাউড-নেটিভ সিক্রেট ম্যানেজার) যা সিক্রেট এনক্রিপ্টেড রাখে, সূক্ষ্ম অ্যাক্সেস কন্ট্রোল দেয়, এবং স্বয়ংক্রিয় রোটেশন সমর্থন করে। ব্যবহার করা (উদাহরণ হিসেবে Vault-স্টাইল, বা যেকোনো ক্লাউড প্রোভাইডারের নেটিভ সিক্রেট ম্যানেজার — কনসেপ্ট প্রোভাইডার-নিরপেক্ষ)। এই সার্ভিসগুলো তিনটি মূল সুবিধা দেয় —

এনক্রিপশন
সিক্রেট সবসময় এনক্রিপ্টেড অবস্থায় সংরক্ষিত ও ট্রান্সমিট হয়, কখনো প্লেইন-টেক্সটে নয়।
অ্যাক্সেস কন্ট্রোল
ঠিক কোন সার্ভিস/ব্যক্তি কোন নির্দিষ্ট সিক্রেট পড়তে পারবে তা সূক্ষ্মভাবে নিয়ন্ত্রিত।
রোটেশন
ম্যানুয়াল সমন্বয় ছাড়াই নিয়মিতভাবে সিক্রেটের মান পরিবর্তন করা — ফাঁস হওয়া ক্রেডেনশিয়ালের বৈধতার সময় সীমিত করে।

৩ · রানটাইমে সিক্রেট ইনজেকশন

অ্যাপ্লিকেশন সিক্রেট পায় এনভায়রনমেন্ট ভেরিয়েবল বা Kubernetes Secret (L30-এর সরাসরি সম্প্রসারণ) হিসেবে, রানটাইমে ইনজেক্ট হওয়া — সোর্স কোড শুধু জানে কোন এনভায়রনমেন্ট ভেরিয়েবল থেকে সিক্রেট পড়তে হবে, কিন্তু কোডের মধ্যে কখনো প্রকৃত মান লেখা থাকে না। এর ফলে একই কোড dev/staging/production-এ ভিন্ন ভিন্ন সিক্রেট ব্যবহার করে চলতে পারে, কোনো কোড পরিবর্তন ছাড়াই।

Python
# একটি অ্যাক্সেস-কন্ট্রোলড সিক্রেট স্টোর সিমুলেশন (fake in-memory স্টোর)

secrets = {
    "db_password": {
        "value": "s3cr3t-db-p@ss",
        "allowed_services": ["order-service", "inventory-service"],
    },
    "payment_gateway_api_key": {
        "value": "pg-api-key-xyz789",
        "allowed_services": ["payment-service"],
    },
}

class AccessDeniedError(Exception):
    pass

def get_secret(name, requesting_service):
    secret = secrets.get(name)
    if secret is None:
        raise KeyError(f"সিক্রেট '{name}' খুঁজে পাওয়া যায়নি")
    if requesting_service not in secret["allowed_services"]:
        raise AccessDeniedError(
            f"'{requesting_service}' সার্ভিসের '{name}' সিক্রেট পড়ার অনুমতি নেই"
        )
    return secret["value"]

# অনুমোদিত অ্যাক্সেস — সফল
value = get_secret("db_password", "order-service")
print(f"order-service সফলভাবে db_password পড়ল: {value}")

# অননুমোদিত অ্যাক্সেস — প্রত্যাখ্যাত
try:
    get_secret("payment_gateway_api_key", "order-service")
except AccessDeniedError as e:
    print(f"অ্যাক্সেস প্রত্যাখ্যাত: {e}")

    
লক্ষ্য করুন order-service শুধুমাত্র তার নিজের allowed_services তালিকায় থাকা সিক্রেটগুলো পড়তে পারে — payment_gateway_api_key চাওয়ার চেষ্টা করলে অ্যাক্সেস প্রত্যাখ্যাত হয়, যদিও দুটোই একই সিক্রেট স্টোরের অংশ। এই ন্যূনতম প্রয়োজনীয় অ্যাক্সেস (least privilege) নীতি — L16-এর নেটওয়ার্ক সিকিউরিটি গ্রুপের একই মূলনীতি, এখন সিক্রেট-লেভেলে প্রয়োগ করা — নিশ্চিত করে একটি সার্ভিস কম্প্রোমাইজড হলেও আক্রমণকারী শুধু সেই সার্ভিসের অনুমোদিত সিক্রেটগুলোই পাবে, পুরো সিস্টেমের সব সিক্রেট নয়।
মূল কথা · Key takeaway

সিক্রেট ম্যানেজমেন্টের মূলনীতি সহজ — সিক্রেট কখনো সোর্স কোডে থাকবে না, সবসময় এনক্রিপ্টেড ও অ্যাক্সেস-কন্ট্রোলড একটি ডেডিকেটেড স্টোরে থাকবে, এবং নিয়মিত রোটেট হবে। M9-এর কনফিগারেশন ম্যানেজমেন্ট মডিউল এখানেই শেষ — L41 থেকে আমরা M10-এ প্রবেশ করব, যেখানে দেখব একবার সব সিস্টেম চালু হয়ে গেলে তার স্বাস্থ্য কীভাবে মনিটর করা হয়।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ একটি টিম যদি সিক্রেট Git-এ কমিট করার বদলে শুধু ".env ফাইল সার্ভারে ম্যানুয়ালি কপি করে রাখি" পদ্ধতি ব্যবহার করে (কোনো ডেডিকেটেড সিক্রেট ম্যানেজার ছাড়াই), তাহলে কী কী ঝুঁকি থেকে যায়?

এই পদ্ধতি Git-এ কমিট হওয়ার ঝুঁকি এড়ায়, কিন্তু অন্য সমস্যাগুলো থেকেই যায় — কোনো কেন্দ্রীয় অ্যাক্সেস কন্ট্রোল নেই (যে কেউ সার্ভারে অ্যাক্সেস পেলেই সব সিক্রেট দেখতে পারে), কোনো রোটেশন নেই (একবার সেট করা সিক্রেট বছরের পর বছর একই থাকতে পারে), এবং কোনো অডিট ট্রেইল নেই (কে কখন কোন সিক্রেট পড়েছে তার কোনো রেকর্ড থাকে না) — এই কারণেই একটি ডেডিকেটেড সিক্রেট ম্যানেজমেন্ট সার্ভিস শুধু ".env ফাইল লুকিয়ে রাখার" চেয়ে অনেক বেশি সুরক্ষা দেয়।

প্র ০২ স্বয়ংক্রিয় সিক্রেট রোটেশন বাস্তবায়ন করা কেন প্রযুক্তিগতভাবে চ্যালেঞ্জিং — শুধু একটি নতুন মান তৈরি করাই তো যথেষ্ট মনে হয়?

চ্যালেঞ্জটি নতুন মান তৈরি করায় নয়, বরং সমন্বয়ে — যে মুহূর্তে সিক্রেট পরিবর্তন হয়, সেই সিক্রেট ব্যবহারকারী প্রতিটি সার্ভিস/ইনস্ট্যান্সকে (সম্ভবত অনেকগুলো, বিভিন্ন সময়ে চালু হওয়া) নতুন মান জানতে হবে, নাহলে তারা পুরনো (এখন invalid) মান দিয়ে সংযোগের চেষ্টা করে ব্যর্থ হবে। তাই ভালো রোটেশন সিস্টেম প্রায়ই একটি সংক্ষিপ্ত সময়ের জন্য পুরনো ও নতুন — দুটো মানই বৈধ রাখে (গ্রেসফুল ট্রানজিশন), যতক্ষণ না সব সার্ভিস নতুন মানে সুইচ করে।

প্র ০৩ উপরের কোডে get_secret("db_password", "payment-service") কল করলে কী ঘটবে, এবং কেন?

একটি AccessDeniedError রেইজ হবে, কারণ db_password-এর allowed_services তালিকায় শুধু "order-service" ও "inventory-service" আছে — "payment-service" সেই তালিকায় নেই। এটিই দেখায় ফাংশনটি সঠিকভাবে least-privilege প্রয়োগ করছে — এমনকি payment-service, যার নিজস্ব সিক্রেট অ্যাক্সেস আছে (পেমেন্ট API কী), সেও অন্য কোনো সার্ভিসের জন্য নির্দিষ্ট সিক্রেট অ্যাক্সেস পাবে না।

অনুশীলন

  1. পরীক্ষা করুন: উপরের কোড সেলে secrets dict-এ একটি নতুন সিক্রেট "tls_private_key" যোগ করুন যা শুধুমাত্র "gateway-service"-এর জন্য অনুমোদিত, তারপর gateway-service ও order-service দুটোরই অ্যাক্সেস চেষ্টা করে ফলাফল দেখুন।

    get_secret("tls_private_key", "gateway-service") সফল হবে ও মান ফেরত দেবে, কিন্তু get_secret("tls_private_key", "order-service") কল করলে AccessDeniedError রেইজ হবে — কারণ order-service সেই নতুন সিক্রেটের allowed_services তালিকায় নেই। এটি নিশ্চিত করে ফাংশনটি নতুন যোগ করা যেকোনো সিক্রেটের জন্যও একইভাবে সঠিকভাবে কাজ করে।

  2. চিন্তা করুন: আপনার নিজের কোনো প্রজেক্টে (বা কল্পনা করা একটি প্রজেক্টে) এমন কোনো সিক্রেট আছে যা বর্তমানে সঠিকভাবে ম্যানেজ করা হচ্ছে না ভাবুন — কী পরিবর্তন করবেন?

    উদাহরণ: একটি সাইড-প্রজেক্টে API কী প্রায়ই সরাসরি একটি কনফিগ ফাইলে লেখা থাকে যা .gitignore-এ যোগ করা হয়েছে (Git-এ কমিট হয় না ঠিকই, কিন্তু কোনো অ্যাক্সেস কন্ট্রোল বা রোটেশন নেই) — একটি বাস্তবসম্মত উন্নতি হতে পারে একটি বিনামূল্যের/ছোট-স্কেল সিক্রেট ম্যানেজার সার্ভিস ব্যবহার শুরু করা, এমনকি একটি ছোট প্রজেক্টেও, যাতে ভবিষ্যতে প্রজেক্ট বড় হলে এই অভ্যাস ও অবকাঠামো ইতিমধ্যেই প্রস্তুত থাকে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

পূর্ববর্তী পাঠ
L39 · কনফিগারেশন ড্রিফট ও ইমিউটেবল ইনফ্রাস্ট্রাকচার