পাঠ ৫৪ · ৬০-এর মধ্যে · মডিউল ১১
Home / Courses / Cybersecurity & Ethical Hacking / DevSecOps ও CI/CD

DevSecOps ও সিকিউর CI/CD পাইপলাইন

DevSecOps & secure CI/CD pipelines
৮ মিনিট পড়া মধ্যবর্তী · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

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

  • "Shift left" সিকিউরিটির অর্থ কী এবং কেন আগে ধরা পড়া সমস্যা সস্তা হয়
  • চারটি সাধারণ স্বয়ংক্রিয় পাইপলাইন গেট — SAST, dependency scanning, secret scanning, DAST
  • কেন একটি সিকিউরিটি গেট বিল্ড ব্লক করা উচিত, শুধু ওয়ার্নিং লগ করা নয়
  • একটি টয় CI/CD পাইপলাইন গেট ফাংশন লেখা যা স্ক্যান রেজাল্ট থেকে PASSED/BLOCKED সিদ্ধান্ত নেয়

১ · Shift Left — সিকিউরিটিকে আগে নিয়ে আসা

DevSecOpsDevSecOpsDevelopment, Security, Operations-এর সংযুক্তি — সিকিউরিটি চেককে পুরো সফটওয়্যার ডেভেলপমেন্ট পাইপলাইনে ইন্টিগ্রেট করার অনুশীলন, শুধু শেষে একটি আলাদা ধাপ হিসেবে নয়। -এর মূল ধারণা হলো shift leftShift Leftসিকিউরিটি টেস্টিংকে ডেভেলপমেন্ট টাইমলাইনে যত সম্ভব আগে ("বাম দিকে") নিয়ে আসা — ডিপ্লয়মেন্টের পরে নয়, commit/build-এর সময়। — একটি দুর্বলতা যত পরে ধরা পড়ে, ঠিক করতে তত বেশি খরচ ও সময় লাগে। commit-সময়ে ধরা একটি বাগ কয়েক মিনিটে ঠিক করা যায়; প্রোডাকশনে ধরা পড়া একই বাগ ইনসিডেন্ট রেসপন্স (M10), গ্রাহক-প্রভাব ও জরুরি হটফিক্স ডিপ্লয়মেন্টের দিকে নিয়ে যেতে পারে।

২ · চারটি সাধারণ পাইপলাইন গেট

SAST
Static Application Security Testing — সোর্স কোড স্ক্যান করে known-insecure প্যাটার্ন খুঁজে বের করে, কোড আদৌ বিল্ড/রান হওয়ার আগেই।
Dependency Scanning
প্রতিটি বিল্ডে স্বয়ংক্রিয়ভাবে third-party লাইব্রেরির known CVE চেক করে (L24-এর সরাসরি স্বয়ংক্রিয় রূপ)।
Secret Scanning
একটি API key বা পাসওয়ার্ড দুর্ঘটনাক্রমে কমিট হওয়ার আগেই ধরে ফেলে — একবার পাবলিক/শেয়ার্ড রিপোজিটরিতে পৌঁছালে সেটিকে leaked হিসেবে ধরে নিতে হয় (L53-এর সিক্রেট-ইন-ইমেজ সমস্যার আরেকটি রূপ)।
DAST
Dynamic Application Security Testing — চলমান অ্যাপ্লিকেশনকে বাস্তবে টেস্ট করে (M5-এর OWASP Top 10-স্টাইল দুর্বলতার জন্য), SAST যা কোড পড়ে দেখতে পায় না তা ধরে ফেলতে পারে।

৩ · কেন "ব্লক করা" জরুরি, শুধু "ওয়ার্নিং" নয়

একটি স্ক্যান টুল যদি শুধু একটি ওয়ার্নিং লগ করে এবং বিল্ড চলতে দেয়, বাস্তবে সেই ওয়ার্নিং প্রায়ই উপেক্ষিত হয় — বিশেষ করে চাপের মধ্যে থাকা একটি টিমে। একটি কার্যকর পাইপলাইন গেট একটি নির্দিষ্ট severity threshold-এর বেশি কোনো ফাইন্ডিং পেলে বিল্ডকে ব্লক করে দেয় — ডিপ্লয়মেন্ট শারীরিকভাবে সম্ভব হয় না যতক্ষণ না সমস্যাটি ঠিক হয়। এটি সিকিউরিটি এনফোর্সমেন্টকে ঐচ্ছিক থেকে স্বয়ংক্রিয় করে তোলে।

SAST → dep-scan → secret-scan → DAST কোনো ক্রিটিক্যাল ফাইন্ডিং নেই = PASSED, ডিপ্লয় চলবে ≥ threshold ফাইন্ডিং = BLOCKED, বিল্ড আটকে যায়
চারটি স্ক্যান পাস করার পর একটি একক threshold-ভিত্তিক সিদ্ধান্ত — PASSED অথবা BLOCKED।

৪ · একটি পাইপলাইন গেট বাস্তবায়ন

নিচের toy উদাহরণে pipeline_gate() ফাংশনটি একটি বিল্ডের সব স্ক্যান রেজাল্ট নেয় এবং fail_on_severity-এর সমান বা তার বেশি severity-র কোনো ফাইন্ডিং থাকলে "BLOCKED" রিটার্ন করে, নাহলে "PASSED"।

Python
def pipeline_gate(scan_results, fail_on_severity="critical"):
    severity_rank = {"low": 1, "medium": 2, "high": 3, "critical": 4}
    threshold = severity_rank[fail_on_severity]
    blockers = [r for r in scan_results if severity_rank[r["severity"]] >= threshold]
    status = "BLOCKED" if blockers else "PASSED"
    return status, blockers

clean_build = [
    {"scan_type": "SAST", "severity": "low"},
    {"scan_type": "dependency-scan", "severity": "medium"},
    {"scan_type": "secret-scan", "severity": "low"},
]

risky_build = [
    {"scan_type": "SAST", "severity": "medium"},
    {"scan_type": "dependency-scan", "severity": "critical"},
    {"scan_type": "DAST", "severity": "high"},
]

for label, build in [("বিল্ড #101 (clean)", clean_build),
                      ("বিল্ড #102 (dependency-vuln)", risky_build)]:
    status, blockers = pipeline_gate(build, fail_on_severity="critical")
    print(f"{label}: {status}")
    for b in blockers:
        print(f"   -> ব্লকার: {b['scan_type']} ({b['severity']})")
    print()

    
লক্ষ্য করুন — risky_build-এর DAST ফাইন্ডিং ("high") threshold অতিক্রম করে না (থ্রেশহোল্ড "critical"), শুধু dependency-scan-এর "critical" ফাইন্ডিংটিই ব্লক করে। বাস্তব পাইপলাইনে fail_on_severity প্রায়ই টিম-ভেদে টিউন করা হয় — কিছু টিম "high"-তেই ব্লক করে, আবার কিছু টিম শুধু "critical"-এ, স্পিড বনাম সিকিউরিটির trade-off বিবেচনা করে (L16-এর প্যাচ ম্যানেজমেন্ট trade-off-এর মতো একই যুক্তি)।
মূল কথা · Key takeaway

DevSecOps এই পুরো মডিউলের (এবং কোর্সের) একটি সংশ্লেষণ — L24-এর dependency-vulnerability, L53-এর সিক্রেট-ম্যানেজমেন্ট, ও M5-এর OWASP দুর্বলতা সবই একই স্বয়ংক্রিয় পাইপলাইনে চেক হয়। মূল বার্তা: সিকিউরিটি একটি ম্যানুয়াল, শেষ-মুহূর্তের চেকলিস্ট না হয়ে, একটি স্বয়ংক্রিয়, প্রতিটি বিল্ডে প্রয়োগ হওয়া গেট হওয়া উচিত।

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

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

প্র ০১ একজন টিম লিড বলছেন, "স্ক্যান ব্লক করলে আমাদের রিলিজ ধীর হয়ে যাবে, শুধু ওয়ার্নিং লগ করাই ভালো।" এর ঝুঁকি কী?

একটি ওয়ার্নিং-শুধু পদ্ধতিতে সিকিউরিটি এনফোর্সমেন্ট নির্ভর করে প্রতিটি ডেভেলপার প্রতিটি লগ পড়বেন এবং সময়মতো পদক্ষেপ নেবেন — বাস্তবে চাপের মধ্যে এটি প্রায়ই ঘটে না, এবং ক্রিটিক্যাল দুর্বলতা প্রোডাকশনে পৌঁছে যায়। ব্লক করা রিলিজকে সাময়িকভাবে ধীর করলেও, একটি প্রোডাকশন ব্রিচ ঠিক করা (ইনসিডেন্ট রেসপন্স, গ্রাহক-বিশ্বাস, সম্ভাব্য আইনি প্রভাব সহ) এর চেয়ে বহুগুণ বেশি ব্যয়বহুল ও ধীর।

প্র ০২ SAST কোড স্ক্যান করে, DAST চলমান অ্যাপ্লিকেশন টেস্ট করে — কেন দুটোই প্রয়োজন, শুধু একটি নয়?

SAST অনেক ইস্যু আগেভাগে ধরতে পারে কিন্তু রানটাইম আচরণ (যেমন দুটি কম্পোনেন্ট একসাথে কীভাবে ইন্টারঅ্যাক্ট করে, বা প্রকৃত HTTP রেসপন্সে কী রেন্ডার হচ্ছে) দেখতে পারে না। DAST একটি সত্যিকারের চলমান অ্যাপ্লিকেশনের বিরুদ্ধে টেস্ট করে বলে এমন কিছু ধরতে পারে যা শুধু কোড পড়ে বোঝা যায় না — যেমন একটি রানটাইম কনফিগারেশন মিসটেক (L23)। দুটি ভিন্ন কোণ থেকে দেখে বলে একসাথে ব্যবহার করলে কভারেজ বেশি সম্পূর্ণ হয়।

প্র ০৩ secret scanning কেন একটি "shift left" উদাহরণ, এবং L53-এর ইমেজ-সিক্রেট সমস্যার সাথে এর সম্পর্ক কী?

Secret scanning কমিট/পুশ-সময়েই সিক্রেট ধরে ফেলে — অর্থাৎ পাইপলাইনের সবচেয়ে বামের ধাপে, ইমেজ বিল্ড হওয়ারও আগে। এটি L53-এর সমস্যার (ইমেজে বেক করা সিক্রেট) একটি earlier-stage প্রতিরোধ: যদি সিক্রেটটি কখনো রিপোজিটরিতে কমিটই না হয়, সেটি পরে কোনো ইমেজ লেয়ারেও পৌঁছাতে পারবে না। দুটি নিয়ন্ত্রণ একসাথে defense-in-depth তৈরি করে — একটি ব্যর্থ হলেও অন্যটি এখনো সুরক্ষা দেয়।

অনুশীলন

  1. চিন্তা করুন: উপরের কোড সেলে pipeline_gate()-কে fail_on_severity="high" দিয়ে কল করুন। risky_build-এর ফলাফল কী হবে তা আগে অনুমান করুন, তারপর যাচাই করুন।

    এখন থ্রেশহোল্ড "high" (rank ৩), তাই risky_build-এর DAST ফাইন্ডিং ("high", rank ৩) এবং dependency-scan ফাইন্ডিং ("critical", rank ৪) — দুটিই থ্রেশহোল্ড অতিক্রম করবে, তাই blockers লিস্টে দুটি এন্ট্রি থাকবে এবং status এখনও "BLOCKED" হবে, কিন্তু এবার দুটি কারণে।

  2. পরীক্ষা করুন: একটি নতুন clean_build_2 তৈরি করুন যার সব স্ক্যান রেজাল্ট "low" বা "medium" — নিশ্চিত করুন fail_on_severity="high" দিয়েও এটি PASSED দেখায়।

    যেহেতু "low" (rank ১) ও "medium" (rank ২) দুটোই "high" থ্রেশহোল্ডের (rank ৩) নিচে, কোনো ফাইন্ডিংই blockers-এ যোগ হবে না, ফলে status "PASSED" থাকবে — এটি নিশ্চিত করে যে গেটটি শুধু threshold-এর সমান বা তার উপরের severity-তেই প্রতিক্রিয়া দেখায়, তার নিচের যেকোনো কিছুতে নয়।

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

আগের পাঠ
কন্টেইনার ও Kubernetes সিকিউরিটি