
(क्लाउडबीज़ प्लगइन मार्गदर्शिका में टेम्पलेट प्लगइन की जानकारी से रूपांतरित)
विभिन्न Jenkins प्लगइन्स के लिए आवश्यक है कि उपयोगकर्ता कस्टम स्क्रिप्ट परिभाषित करें, जो प्रायः Groovy भाषा में होती हैं, ताकि Jenkins के व्यवहार को अनुकूलित किया जा सके। यदि इन स्क्रिप्ट्स को लिखने वाला हर व्यक्ति Jenkins व्यवस्थापक है—विशेष रूप से यदि उनके पास Overall/RunScripts अनुमति है, जिसका उपयोग उदाहरण के लिए Script Console लिंक द्वारा किया जाता है—तो वे अपनी पसंद की कोई भी स्क्रिप्ट लिख सकते हैं। ये स्क्रिप्ट प्लगइन्स को दिए गए उसी API का उपयोग करके सीधे आंतरिक Jenkins ऑब्जेक्ट्स को संदर्भित कर सकती हैं। ऐसे उपयोगकर्ताओं पर पूरी तरह भरोसा किया जाना चाहिए, क्योंकि वे Jenkins के साथ कुछ भी कर सकते हैं (यहाँ तक कि उसकी सुरक्षा सेटिंग्स बदल सकते हैं या सर्वर पर शेल कमांड चला सकते हैं)।
हालाँकि, यदि कुछ स्क्रिप्ट लेखक केवल अधिक सीमित अनुमतियों वाले "सामान्य उपयोगकर्ता" हैं, जैसे Job/Configure, तो उन्हें मनमानी स्क्रिप्ट चलाने देना अनुचित है। ऐसे भूमिका विभाजन का समर्थन करने के लिए, Script Security लाइब्रेरी प्लगइन को विभिन्न फीचर प्लगइन्स में एकीकृत किया जा सकता है। यह दो संबंधित प्रणालियों का समर्थन करता है: स्क्रिप्ट अनुमोदन (script approval) और Groovy सैंडबॉक्सिंग (Groovy sandboxing)।
पहली और सरल सुरक्षा प्रणाली यह है कि किसी भी प्रकार की स्क्रिप्ट को चलाने की अनुमति दी जाए, लेकिन केवल व्यवस्थापक की मंज़ूरी के साथ। अनुमोदित स्क्रिप्ट्स की एक वैश्विक रूप से बनाए रखी गई सूची होती है, जिन्हें कोई दुर्भावनापूर्ण कार्य नहीं करने वाला माना जाता है।
जब कोई व्यवस्थापक किसी प्रकार का कॉन्फ़िगरेशन सहेजता है (उदाहरण के लिए, एक जॉब), तो व्यवस्थापक द्वारा संपादित की गई वे स्क्रिप्ट स्वतः अनुमोदित हो जाती हैं और बिना किसी और हस्तक्षेप के चलने के लिए तैयार होती हैं। कम विशेषाधिकार वाले उपयोगकर्ताओं द्वारा प्रस्तुत की गई स्क्रिप्ट्स के लिए उचित चेतावनियाँ प्रदर्शित होंगी, जो यह संकेत देंगी कि अनुमोदन आवश्यक है। व्यवस्थापक स्क्रिप्ट अनुमोदन कॉन्फ़िगरेशन पृष्ठ का उपयोग करके या स्क्रिप्ट को संपादित करके सहेजकर उन स्क्रिप्ट्स को अनुमोदित कर सकते हैं। Script Security प्लगइन के पिछले संस्करणों में, व्यवस्थापक बिना विशेषाधिकार वाले उपयोगकर्ताओं द्वारा प्रस्तुत स्क्रिप्ट्स को बिना कोई बदलाव किए सहेजकर स्वतः अनुमोदित कर सकते थे, लेकिन सोशल इंजीनियरिंग-आधारित हमलों को रोकने के लिए यह कार्यक्षमता अक्षम कर दी गई थी। ("सहेजना" आमतौर पर वेब UI से होता है, लेकिन REST या CLI के माध्यम से नई XML कॉन्फ़िगरेशन अपलोड करना भी हो सकता है।)
जब कोई गैर-व्यवस्थापक टेम्पलेट कॉन्फ़िगरेशन सहेजता है, तो यह जाँच की जाती है कि क्या किसी भी शामिल स्क्रिप्ट को अनुमोदित पाठ से संपादित किया गया है। (अधिक सटीकता से, क्या अनुरोधित सामग्री को पहले कभी अनुमोदित किया गया है।) यदि इसे अनुमोदित नहीं किया गया है, तो इस स्क्रिप्ट के अनुमोदन का अनुरोध एक कतार में जोड़ दिया जाता है। (जब किसी स्क्रिप्ट का वर्तमान पाठ वर्तमान में अनुमोदित नहीं होता है, तो कॉन्फ़िगरेशन स्क्रीन UI में एक चेतावनी भी प्रदर्शित होती है।)
एक व्यवस्थापक अब Manage Jenkins » In-process Script Approval पर जा सकता है, जहाँ अनुमोदन की प्रतीक्षा कर रही स्क्रिप्ट्स की सूची दिखाई जाएगी। यह मानते हुए कि कुछ भी खतरनाक-दिखने वाला अनुरोधित नहीं है, बस Approve पर क्लिक करें ताकि स्क्रिप्ट को आगे से चलाया जा सके।
यदि आप कोई बिना-अनुमोदित स्क्रिप्ट चलाने का प्रयास करते हैं, तो वह बस विफल हो जाएगी, आमतौर पर एक संदेश के साथ जो बताता है कि वह अनुमोदन की प्रतीक्षा में है। स्क्रिप्ट के अनुमोदित हो जाने के बाद आप पुनः प्रयास कर सकते हैं। इस व्यवहार का विवरण इस लाइब्रेरी को एकीकृत करने वाले फीचर प्लगइन के अनुसार भिन्न हो सकता है।
किसी स्क्रिप्ट में हर बदलाव के लिए व्यवस्थापक की मंज़ूरी की प्रतीक्षा करना, चाहे वह कितना भी तुच्छ क्यों न लगे, विभिन्न टाइमज़ोन में फैली टीम के लिए या कड़ी समय-सीमाओं के दौरान अस्वीकार्य हो सकता है। एक वैकल्पिक विकल्प के रूप में, Script Security प्रणाली Groovy स्क्रिप्ट्स को बिना अनुमोदन के चलने देती है, बशर्ते वे स्वयं को उन्हीं कार्यों तक सीमित रखें जिन्हें स्वाभाविक रूप से सुरक्षित माना जाता है। इस सीमित निष्पादन वातावरण को सैंडबॉक्स कहा जाता है। (वर्तमान में अन्य भाषाओं के लिए कोई सैंडबॉक्स कार्यान्वयन उपलब्ध नहीं है, इसलिए गैर-व्यवस्थापकों द्वारा कॉन्फ़िगर की गई ऐसी सभी स्क्रिप्ट्स को अनुमोदित किया जाना चाहिए।)
इस मोड पर स्विच करने के लिए, बस Groovy स्क्रिप्ट के प्रविष्टि क्षेत्र के नीचे Use Groovy Sandbox बॉक्स को चेक करें। सैंडबॉक्स की गई स्क्रिप्ट्स को कोई भी तुरंत चला सकता है। (व्यवस्थापक भी, हालाँकि स्क्रिप्ट उन्हीं प्रतिबंधों के अधीन होती है, चाहे उसे किसी ने भी लिखा हो।) जब स्क्रिप्ट चलाई जाती है, तो हर मेथड कॉल, ऑब्जेक्ट निर्माण और फ़ील्ड एक्सेस की जाँच अनुमोदित कार्यों की व्हाइटलिस्ट के विरुद्ध की जाती है। यदि कोई बिना-अनुमोदित कार्य करने का प्रयास किया जाता है, तो स्क्रिप्ट समाप्त कर दी जाती है और संबंधित Jenkins सुविधा का अभी उपयोग नहीं किया जा सकता।
Script Security प्लगइन एक छोटी डिफ़ॉल्ट व्हाइटलिस्ट के साथ आता है, और एकीकृत प्लगइन्स उस सूची में कार्य जोड़ सकते हैं (आमतौर पर उस प्लगइन के लिए विशिष्ट मेथड्स)।
लेकिन आप डिफ़ॉल्ट व्हाइटलिस्ट तक सीमित नहीं हैं: हर बार जब कोई स्क्रिप्ट किसी ऐसे कार्य को चलाने से पहले विफल होती है जो अभी तक व्हाइटलिस्ट में नहीं है, तो वह कार्य स्वतः एक अन्य अनुमोदन कतार में जोड़ दिया जाता है। एक व्यवस्थापक पूरी स्क्रिप्ट्स के अनुमोदन के लिए ऊपर वर्णित उसी पृष्ठ पर जा सकता है और लंबित कार्य अनुमोदनों की सूची देख सकता है। यदि किसी कार्य के हस्ताक्षर के आगे Approve पर क्लिक किया जाता है, तो वह तुरंत व्हाइटलिस्ट में जोड़ दिया जाता है और सैंडबॉक्स की गई स्क्रिप्ट्स के लिए उपलब्ध हो जाता है।
अधिकांश हस्ताक्षर method class.Name methodName arg1Type arg2Type… रूप के होते हैं, जो एक विशिष्ट "रिसीवर" वर्ग (this), मेथड नाम, और तर्क (या पैरामीटर) प्रकारों की सूची के साथ एक Java मेथड कॉल का संकेत देते हैं। (किसी प्रयासित मेथड कॉल का सबसे सामान्य हस्ताक्षर अनुमोदन के लिए प्रस्तुत किया जाएगा, भले ही वास्तविक ऑब्जेक्ट जिस पर इसे कॉल किया जाना था, उस मेथड को ओवरराइड करने वाले अधिक विशिष्ट प्रकार का हो।) आप स्थैतिक (वर्ग) मेथड्स के लिए staticMethod, कंस्ट्रक्टरों के लिए new, और फ़ील्ड एक्सेस (get या set) के लिए field भी देख सकते हैं।
सुरक्षा-संवेदनशील वातावरणों में व्यवस्थापकों को सावधानीपूर्वक विचार करना चाहिए कि किन कार्यों को व्हाइटलिस्ट किया जाए। जो कार्य संग्रहीत ऑब्जेक्ट्स (जैसे Jenkins जॉब्स) की स्थिति बदलते हैं, उन्हें सामान्यतः अस्वीकार किया जाना चाहिए। अधिकांश getSomething मेथड्स हानिरहित हैं।
हालाँकि, ध्यान रखें कि कुछ "गेटर" मेथड्स भी विशिष्ट अनुमतियों की जाँच करने के लिए डिज़ाइन किए गए हैं (ACL: एक्सेस कंट्रोल सूची का उपयोग करके), जबकि स्क्रिप्ट्स अक्सर एक सिस्टम छद्म-उपयोगकर्ता द्वारा चलाई जाती हैं जिसे सभी अनुमतियाँ प्रदान की जाती हैं। तो उदाहरण के लिए method hudson.model.AbstractItem getParent (जो किसी जॉब वाले फ़ोल्डर या Jenkins रूट को प्राप्त करता है) अपने आप में हानिरहित है, लेकिन संभावित अनुवर्ती कॉल method hudson.model.ItemGroup getItems (जो किसी फ़ोल्डर के भीतर नाम से जॉब्स सूचीबद्ध करती है) Job/Read की जाँच करती है। यह दूसरा कॉल बिना शर्त व्हाइटलिस्ट करने के लिए खतरनाक होगा, क्योंकि इसका अर्थ होगा कि किसी फ़ोल्डर में Job/Create प्रदान किया गया उपयोगकर्ता उस फ़ोल्डर की किसी भी जॉब से कम से कम कुछ जानकारी पढ़ पाएगा, यहाँ तक कि उन जॉब्स से भी जिन्हें प्रोजेक्ट-आधारित प्राधिकरण रणनीति के अनुसार छिपाया जाना चाहिए; यह फ़ोल्डर में एक ऐसी जॉब बनाने के लिए पर्याप्त होगा जिसमें इस तरह की Groovy स्क्रिप्ट शामिल हो (विवरण एकीकृत प्लगइन के अनुसार भिन्न होंगे):
println("I sniffed ${thisjob.getParent().getItems()}!");
चलाए जाने पर, स्क्रिप्ट आउटपुट कथित रूप से गुप्त प्रोजेक्ट्स के कम से कम नाम प्रदर्शित करेगा। एक व्यवस्थापक इसके बजाय getItems के लिए अनुमति जाँच मानकर Approve पर क्लिक कर सकता है; यह कॉल को वास्तविक उपयोगकर्ता के रूप में चलाए जाने पर अनुमति देगा (यदि एकीकृत प्लगइन ऐसा कभी करता है), जबकि सिस्टम उपयोगकर्ता के रूप में चलाए जाने पर इसे प्रतिबंधित करेगा (जो अधिक सामान्य है)। इस मामले में, getItems वास्तव में केवल उन्हीं जॉब्स को लौटाने के लिए कार्यान्वित किया गया है जिन तक वर्तमान उपयोगकर्ता की पहुँच है, इसलिए यदि पूर्व मामले में (एक विशिष्ट उपयोगकर्ता के रूप में) चलाया जाता है, तो विवरण केवल उन्हीं जॉब्स को दिखाएगा जिन्हें वे वैसे भी देख सकते थे। यह अधिक उन्नत बटन केवल मेथड कॉल्स (और कंस्ट्रक्टरों) के लिए दिखाया जाता है, और इसका उपयोग केवल वहीं किया जाना चाहिए जहाँ आप जानते हैं कि Jenkins एक अनुमति जाँच कर रहा है।
एक सामान्य Groovy एकीकरण के लिए, जिसमें आप उपयोगकर्ता को स्क्रिप्ट अनुमोदन या सैंडबॉक्स में से किसी एक का उपयोग करने का विकल्प प्रदान करते हैं, अपने describable के String-मान वाले स्क्रिप्ट फ़ील्ड को SecureGroovyScript फ़ील्ड में बदलें। अपने कंस्ट्रक्टर में, मान संग्रहीत करने से पहले, configuringWithKeyItem कॉल करें (यदि प्रति टॉप-लेवल आइटम केवल एक ऐसी स्क्रिप्ट हो सकती है) या configuringWithNonKeyItem (यदि कई हो सकती हैं)। कॉन्फ़िगरेशन फ़ॉर्म को स्क्रिप्ट और सैंडबॉक्स कॉन्फ़िगरेशन प्राप्त करने के लिए <f:property field="…"/> का उपयोग करना चाहिए। जब आप स्क्रिप्ट चलाना चाहें, तो बस evaluate कॉल करें।
(पुराने डेटा के साथ संगतता के लिए, एक अलग फ़ील्ड नाम चुनें और मूल को पदावनत (deprecate) करें। फिर आप एक readResolve मेथड परिभाषित कर सकते हैं जो नए फ़ील्ड को सैंडबॉक्स बंद रखते हुए SecureGroovyScript पर सेट करता है, सिस्टम को यह सूचित करने के लिए उस पर configuring(ApprovalContext.create()) कॉल करता है कि एक बिना-अनुमोदित स्क्रिप्ट लोड की गई है, और पुराने फ़ील्ड को अनसेट करता है।)
इसका उपयोग तब करें जब आपको SecureGroovyScript द्वारा प्रदान की जाने वाली तुलना में अधिक नियंत्रण की आवश्यकता हो:
अपने कॉन्फ़िगरेशन में एक boolean sandbox फ़ील्ड शामिल करें।
जब यह सेट न हो, तो आपको @DataBoundConstructor में ScriptApproval.configuring कॉल करने की आवश्यकता है। ApprovalContext.withCurrentUser का उपयोग करें, और जहाँ लागू हो वहाँ withItemAsKey भी (जब प्रति जॉब केवल एक स्क्रिप्ट हो); अन्यथा कम से कम जहाँ लागू हो withItem, और/या withKey जब आप इस उपयोग को संदर्भ से विशिष्ट रूप से पहचान सकते हैं (StaplerRequest.findAncestorObject यहाँ सहायक है)। यह सिस्टम को यह बताता है कि एक (संभवतः नई) स्क्रिप्ट किसी विशेष व्यक्ति द्वारा कॉन्फ़िगर की गई है। आपको एक readResolve की भी आवश्यकता होगी जो सिस्टम को सूचित करने के लिए configuring को कॉल करता है जब स्क्रिप्ट के साथ एक configurable डिस्क से लोड किया गया हो (और इस प्रकार configurer अज्ञात हो)। स्क्रिप्ट चलाए जाने पर ScriptApproval.using कॉल करें, और यदि आवश्यक हो तो UnapprovedUsageException को पकड़ें। डिस्क्रिप्टर को स्क्रिप्ट फ़ील्ड पर फ़ॉर्म सत्यापन का उपयोग करना चाहिए और ScriptApproval.checking कॉल करना चाहिए (सामान्यतः आपके डिस्क्रिप्टर को पहले से ही इस फ़ील्ड पर कम से कम एक सिंटैक्स जाँच करनी चाहिए)।
जब sandbox फ़ील्ड सेट हो, तो आपको केवल GroovySandbox.createSecureCompilerConfiguration के साथ Groovy शेल सेट करने की आवश्यकता है और फिर GroovySandbox.run कॉल करें; RejectedAccessException को पकड़ने और ScriptApproval.accessRejected कॉल करने के लिए तैयार रहें।
कुछ विशेष मेथड कॉल्स को पूर्व-अनुमोदित करने के लिए, यदि वे आपके प्लगइन में हैं तो बस उन्हें @Whitelisted से एनोटेट करें; अन्यथा आप StaticWhitelist.from को डेलिगेट करने वाले ProxyWhitelist को पंजीकृत कर सकते हैं (@Extension के साथ) और व्हाइटलिस्ट किए गए मेथड्स की सूची वाली एक टेक्स्ट फ़ाइल लोड कर सकते हैं।
किसी स्क्रिप्ट का मूल्यांकन करने के लिए GroovyShell का निर्माण करते समय, या ecureGroovyScript.evaluate कॉल करते समय, आपको एक ClassLoader पास करना होगा जो स्क्रिप्ट के लिए प्रभावी क्लासपाथ का प्रतिनिधित्व करता है। आप Jenkins कोर का लोडर, या अपने प्लगइन का, या Jenkins.getInstance().getPluginManager().uberClassLoader का उपयोग कर सकते हैं।
आप जो भी चुनें, URLClassLoader बनाकर किसी बिना-विशेषाधिकार वाले उपयोगकर्ता को मनमानी क्लासपाथ प्रविष्टियाँ जोड़ने की अनुमति न दें! यह सैंडबॉक्स का उपयोग करते समय सभी सुरक्षा को दरकिनार करना तुच्छ बना देगा। (एक उपयोगकर्ता को केवल इस या किसी अन्य जॉब में एक JAR संग्रहीत करवाना होगा जिसमें @Whitelisted चिह्नित स्थैतिक मेथड वाला कोई क्लास हो और जो उन्हें जो चाहे करने दे, फिर उस मेथड को अपनी स्क्रिप्ट से कॉल करें।) पूरी-स्क्रिप्ट अनुमोदन का उपयोग करते समय अभी तक कोई हमला प्रदर्शित नहीं किया गया है—सामान्य पैरेंट-फर्स्ट डेलीगेशन वाला URLClassLoader समझौता किए गए संस्करणों द्वारा निर्दोष-दिखने वाले API के तुच्छ छद्मरण की अनुमति नहीं देगा—लेकिन यह संभावित है कि META-INF/services/org.codehaus.groovy.transform.ASTTransformation या इसी तरह का कोई चतुर उपयोग अन्यथा सुरक्षित स्क्रिप्ट को अप्रत्याशित और अनधिकृत तरीके से व्यवहार करने का कारण बन सकता है। JENKINS-22834 एक सुरक्षित मानक विकल्प सुझाता है।
जो प्लगइन्स Script Security प्लगइन का उपयोग करते हैं, उनके लिए परीक्षण लिखते समय आपको अपने परीक्षणों में कुछ त्रुटियों का सामना करना पड़ सकता है।
यदि आपके परीक्षण प्रत्यक्ष या अप्रत्यक्ष रूप से ScriptApproval.get() मेथड को कॉल करते हैं, तो आपके यूनिट परीक्षणों को JenkinsRule का उपयोग करना चाहिए ताकि Jenkins.getInstance() null न लौटाए। यह संभावना है कि जो परीक्षण काम कर रहे थे, वे अब विफल होने लगेंगे यदि आप सैंडबॉक्स का उपयोग नहीं कर रहे हैं। ऐसा इसलिए होता है क्योंकि उन्हें अनुमोदन के लिए कतार में डाला जा रहा है। ऐसे मामले में जहाँ आपको अनुमोदनों की परवाह किए बिना स्क्रिप्ट्स निष्पादित करने की आवश्यकता हो, ScriptApproval.get().preapprove(script, GroovyLanguage.get()) यह सुनिश्चित करेगा कि सभी कॉन्फ़िगर की गई स्क्रिप्ट्स अनुमोदित हैं। वैकल्पिक रूप से, आप अपने परीक्षणों को सैंडबॉक्स का उपयोग करके स्क्रिप्ट्स चला सकते हैं। इस मामले में आपको अपने परीक्षणों द्वारा उपयोग किए जाने वाले मेथड्स को व्हाइटलिस्ट करने की आवश्यकता हो सकती है — या तो सामान्य रूप से वास्तविक उपयोगकर्ताओं के लिए, या केवल परीक्षणों के लिए एक व्हाइटलिस्ट रखने हेतु @TestExtension का उपयोग करके।