DevSecOps:掌握端到端管道实施的关键概念!

750ea219953df45c6cb697da7462e594.png

image.png

在这个现代时代,应用程序的开发非常庞大,当然,网络犯罪也变得越来越疯狂。我对学习一点SDLC自动化(通常称为 DevOps 文化)很感兴趣。不过,这一次,我尝试了几个额外的安全平台,以便它能够成为 DevSecOps。
一般来说,我会使用:

  • Jenkins作为 CI/CD 平台

  • 使用Dependency Track作为 SCA

  • SonarQube作为 SAST

  • Trivy作为 Container Image Scanner

  • Defectdojo作为集中报告监控。

在基础设施方面,我使用:

  • Kubernetes 作为我在多个自托管平台进行实验的暂存容器

  • Harbor作为私有容器注册中心

  • ArgoCD作为持续部署平台

我使用的管道目标如下:
88c4b80a3f1c84c0c4dd5ae791042d4b.png

克隆存储库阶段

首先,我声明从 SCM 克隆代码,这里我使用 GitHub 托管我的示例 js 代码。此时我声明 Jenkinsfile 如下:

stage('Clone Repository') {
    steps {
        script {
            sourceCodeDir = sh(
                script: 'pwd',
                returnStdout: true
            ).trim()
            git branch: 'staging',
                url: 'https://github.com/gilangvperdana/react-code.git'
            env.CI_COMMIT_SHORT_SHA = sh(
                script: 'git log --pretty=format:\'%h\' -n 1',
                returnStdout: true
            ).trim()
        }
    }
}

生成 SBOM 阶段

其次,我将生成一个 BOM 文件,该文件将被发送到 Dependency Track 和 DefectDojo 进行分析。工具是cdxgen。在此阶段,我声明如下:

stage('Generate SBOM') {
      steps {
          dir(sourceCodeDir) {
            sh "cdxgen"
          }
      }
    }

在此阶段之后,我们的工作区应该生成两个名为“bom.json”和“bom.xml”的文件。

将 bom.xml 发送到 Dependency Track 和 Defectdojo 阶段

在这里,我使用 Dependency Track API,它通常在端口“8081”上运行,并且我利用第三方工具将[dd-import](https://github.com/MaibornWolff/dd-import)其发送到 DefectDojo。

stage('Send to Dependency Track & Defect Dojo') {
      steps {
        script {
          def projectVersion = "${env.BUILD_NUMBER}"
          dir(sourceCodeDir) {
            sh '''
            curl -X "POST" "$DEPTRACK_URL:8081/api/v1/bom" -H 'Content-Type: multipart/form-data' -H "X-Api-Key: $DEPTRACK_API_KEY" -F "autoCreate=true" -F "projectName=website" -F "projectVersion=''' + projectVersion + '''" -F "bom=@bom.xml"
            '''
            sh '''
            docker run --rm -e "DD_URL=$DD_URL" -e "DD_API_KEY=$DD_API_KEY" -e "DD_PRODUCT_TYPE_NAME=Research and Development" -e "DD_PRODUCT_NAME=website" -e "DD_ENGAGEMENT_NAME=Dependency Track" -e "DD_TEST_NAME=dependency-track" -e "DD_TEST_TYPE_NAME=Dependency Track Finding Packaging Format (FPF) Export" -e "DD_FILE_NAME=website/bom.json" -v "${WORKSPACE}:/usr/local/dd-import/website" maibornwolff/dd-import:latest dd-reimport-findings.sh
            '''
          }
        }
      }
    }

这是通过 API 发送后的依赖报告。
e7a1d21152fa43920e5b1b60487206f8.png
同样地,如下图所示,Defectdojo 的产品网站上也已经开始了互动。
d92a81df90284d33e8e3e496d6f35f97.png

Sonarqube SAST 阶段

现在是时候使用 SonarQube 或通常称为 SAST 的程序来扫描我们的源代码了。在这里,我使用 SonarScanner作为CLI。确保您已sonar-project.properties在代码存储库中创建了一个名为 的文件,其内容为sonar.projectKey=website。将其替换website为您将在 Sonarqube 中创建的项目的实际名称。

stage('SonarQube - SAST') {
      steps {
        withSonarQubeEnv('SonarQube') {
          dir(sourceCodeDir) {
            sh "sonar-scanner -Dsonar.projectKey=website -Dsonar.host.url=$SONAR_URL -Dsonar.login=${SONARQUBE_SECRET}"
          }
        }
        timeout(time: 2, unit: 'MINUTES') {
          script {
            waitForQualityGate abortPipeline: true
          }
        }
      }
    }

扫描后的脚本是 Quality Gate,它由 SonarQube 拥有,可以使用Jenkins 插件进行安装。之后,我们可以在 SonarQube 上设置一个 webhook,如下所示,这很有用,这样如果我们的分析结果与我们指定的规则不匹配,SonarQube 就可以与 Jenkins 进行通信。这最终将停止管道。

将 Sonarqube 发送到 DefectDojo 阶段

当然,SonarQube 的结果可以让我们更轻松地使用 dd-import 直接将其发送到 Defectdojo。但在此之前,我们需要从 SonarQube 获取 HTML 报告,以便使用sonar-report工具将其导入 DefectDojo 。

stage('Send Sonarqube to DefectDojo') {
      steps {
          sh '''
          sonar-report --sonarurl="$SONAR_URL" --sonartoken ${SONAR_TOKEN} --sonarcomponent="website" --sonarorganization="website" --project="website" --application="website" --release="1.0.0" --branch="main" --output="sonarreport.html"
          '''
          sh '''
          docker run --rm -e "DD_URL=$DD_URL" -e "DD_API_KEY=${DD_API_KEY}" -e "DD_PRODUCT_TYPE_NAME=Research and Development" -e "DD_PRODUCT_NAME=website" -e "DD_ENGAGEMENT_NAME=Sonar Qube" -e "DD_TEST_NAME=sonar-qube" -e "DD_TEST_TYPE_NAME=SonarQube Scan detailed" -e "DD_FILE_NAME=website/sonarreport.html" -v "${WORKSPACE}:/usr/local/dd-import/website" maibornwolff/dd-import:latest dd-reimport-findings.sh
          '''
        }
      }

这是报告成功分析时 SonarQube 的样子。
36cfecb57b08bf90a0dbca7cb9de4fb7.png
这是 SonarQube 报告集成到 Defectdojo 之后的样子。
970dfb85eabfc384b95f28fe3cdcf9d8.png
缺陷道场

构建映像阶段

然后下一步是创建一个用于使用 Trivy 进行扫描过程的 Docker 映像。

stage('Docker Build') {
    steps {
        sh '''
          docker build -t $HARBOR_URL/temp/research:${CI_COMMIT_SHORT_SHA} .
          '''
    }
}

Trivy 扫描图像阶段

在 Jenkins VM 中创建容器镜像后,下一步是使用 Trivy 扫描镜像,并将报告再次发送给 DefectDojo。

stage('Trivy Scan Image') {
    steps {
        sh 'trivy image --exit-code 0 --no-progress --severity HIGH,CRITICAL -f json -o trivy_report.json $HARBOR_URL/temp/research'
    }
}

此阶段完成后,它应该生成一个名为的文件trivy_report.json

将Trivy报告发送至 Defectdojo

我们会将报告结果发送给DefectDojo,以便于更好的观察。

stage('Send Trivy Report to Defectdojo') {
      steps {
          sh '''
          docker run --rm -e "DD_URL=$DD_URL" -e "DD_API_KEY=$DD_API_KEY" -e "DD_PRODUCT_TYPE_NAME=Research and Development" -e "DD_PRODUCT_NAME=website" -e "DD_ENGAGEMENT_NAME=Trivy" -e "DD_TEST_NAME=trivy" -e "DD_TEST_TYPE_NAME=Trivy Scan" -e "DD_FILE_NAME=website/trivy_report.json" -v "${WORKSPACE}:/usr/local/dd-import/website" maibornwolff/dd-import:latest dd-reimport-findings.sh
          '''
        }
      }

这是 Trivy 成功发送到 DefectDojo 之后的示例。
b189ae7e46e0f37186eac1056fdd3203.png

推送图像阶段

之后,我们将镜像推送到 Harbor 以在 Staging 环境中进行测试,并在 DefectDojo 中执行 Ops 分析。

stage('Push Image'){
        steps {
            sh 'docker push $HARBOR_URL/temp/research:${CI_COMMIT_SHORT_SHA}'
            sh 'docker rmi $HARBOR_URL/temp/research:${CI_COMMIT_SHORT_SHA}'
        }
    }

以下是镜像推送成功后Harbor上的显示。
ef748aa03bdee196ff2326f0286ad94c.png
港口

在 GitHub 上更改图像标签暂存

我使用的方法涉及更改 Git 存储库中的图像标签,其中包含暂存文件夹中的清单。然后,通过 ArgoCD 获取它以部署到 Kubernetes。我在 Jenkinsfile 中用于更改图像标签的命令如下:

stage('Change Image Tag on Github'){
    steps {
        script{
            env.GIT_URL = sh (
                script: 'echo @github.com/gilangvperdana/EXAMPLE.git'">https://oauth2:${access_token_PSW}@github.com/gilangvperdana/EXAMPLE.git',
                returnStdout: true
            ).trim()
        }
        dir('react-manifest-staging'){
            git branch: 'main',
                credentialsId: 'github_access_token',
                url: "$GIT_URL"
            sh 'git config user.email bot@email.com && git config user.name ci-bot'
            sh 'sed -i "s+$HARBOR_URL/temp/research:.*+$HARBOR_URL/temp/research:${CI_COMMIT_SHORT_SHA}+g" infra/staging/deployment.yaml'
            sh 'git add . && git commit -m "update staging research image tag to ${CI_COMMIT_SHORT_SHA}"'
            sh 'git push origin main'
        }
    }
}

我使用git log --pretty=format:\'%h\' -n 1作为图像标签,其中图像标签将遵循代码存储库中的最后一个提交编号。我这样做是为了更容易跟踪和回滚版本等。
7008fd2cb86fca609ca1436f30fabe66.png
Git SCM 工具

ArgoCD 同步STAG环境

我使用ArgoCD CLI尝试部署到 Kubernetes 暂存环境,结果类似于 Jenkinsfile 中显示的结果。我的 ArgoCD 配置遵循此参考。

stage('ArgoCD Sync Staging'){
        steps {
            withCredentials([string(credentialsId: "ARGOCD_TOKEN", variable: 'ARGOCD_TOKEN')]) {
                dir('react-manifest-staging'){
                    git branch: 'main',
                        credentialsId: 'github_access_token',
                        url: "https://github.com/gilangvperdana/EXAMPLE.git"
                    sh 'ARGOCD_SERVER=$ARGOCD_URL argocd --grpc-web app create research-service-staging --project default --repo https://github.com/gilangvperdana/EXAMPLE.git --path ./infra/staging/ --revision main --dest-namespace staging --dest-server https://kubernetes.default.svc --upsert'
                    sh 'argocd --grpc-web app sync research-service-staging --force'
                }
            }
        }
    }

这是一个使用 ArgoCD 成功部署到 Kubernetes 集群的示例。
09fa4577de38fd07efba69d76545f66e.png
ArgoCD 应用程序示例

发送批准部署到生产环境

在 IT 团队批准对 DefectDojo 和 Staging 应用程序的分析后,我通常会继续进行此阶段。在此阶段,IT 团队负责人将提供批准。此插件仅允许特定的 Jenkins 帐户授予批准。一旦获得批准,它将继续替换清单存储库生产文件夹中的 TAG 图像。随后,它将由生产命名空间中的 ArgoCD 获取。

stage('Send Approval Deploy to Prod'){
    steps{
        script{
            sh ("""
          curl -s -X POST https://api.telegram.org/bot$BOT_TOKEN/sendMessage -d chat_id=$TELEGRAM_CHATID -d parse_mode=markdown -d text="Dear team : \n*Approve* to Continue Deploy CICD Pipeline *${env.JOB_NAME}* \nfor *Release* Website \n\nPlease Approve at: ${env.RUN_DISPLAY_URL}"
          """)
            input(message: 'Approve to continue', submitter: "teamleader@email.com", submitterParameter: "teamleader@email.com")
        }
    }
}

更改 GitHub Stage 上的图像标签制作

获得批准后,将自动进行部署到生产阶段,从而立即替换生产存储库中的镜像标签。

stage('Change Image Tag on Github'){
    steps {
        script{
            env.GIT_URL = sh (
                script: 'echo @github.com/gilangvperdana/EXAMPLEPROD.git'">@github.com/gilangvperdana/EXAMPLEPROD.git'">https://oauth2:${access_token_PSW}@github.com/gilangvperdana/EXAMPLEPROD.git',
                returnStdout: true
            ).trim()
        }
        dir('react-manifest-production'){
            git branch: 'main',
                credentialsId: 'github_access_token',
                url: "$GIT_URL"
            sh 'git config user.email bot@email.com && git config user.name ci-bot'
            sh 'sed -i "s+$HARBOR_URL/temp/research:.*+$HARBOR_URL/temp/research:${CI_COMMIT_SHORT_SHA}+g" infra/production/deployment.yaml'
            sh 'git add . && git commit -m "update production research image tag to ${CI_COMMIT_SHORT_SHA}"'
            sh 'git push origin main'
        }
    }
}

ArgoCD 同步生产阶段

与 argosync staging 相同,唯一的区别在于 GitHub 存储库和部署命名空间。

stage('ArgoCD Sync Production'){
    steps {
        withCredentials([string(credentialsId: "ARGOCD_TOKEN", variable: 'ARGOCD_TOKEN')]) {
            dir('react-manifest-production'){
                git branch: 'main',
                    credentialsId: 'github_access_token',
                    url: "https://github.com/gilangvperdana/EXAMPLEPROD.git"
                sh 'ARGOCD_SERVER=$ARGOCD_URL argocd --grpc-web app create research-service-production --project default --repo https://github.com/gilangvperdana/EXAMPLEPROD.git --path ./infra/production/ --revision main --dest-namespace production --dest-server https://kubernetes.default.svc --upsert'
                sh 'argocd --grpc-web app sync research-service-production --force'
            }
        }
    }
}

当它成功部署到 ArgoCD 时,它的工作方式如下,然后它也会自动部署到 Kubernetes。
5a235ad98ca07158a8a83fe038575ab1.png

后期阶段

此最后阶段负责清理环境并发送有关执行管道结果的警报,指示管道是成功、失败还是其他状态。通常,我以以下方式使用它:

post {
        always {
            deleteDir()
            dir("${workspace}@tmp") {
                deleteDir()
            }
            dir("${workspace}@script") {
                deleteDir()
            }
        }
       success { 
          sh  ("""
              curl -s -X POST https://api.telegram.org/bot$BOT_TOKEN/sendMessage -d chat_id=$TELEGRAM_CHATID -d parse_mode=markdown -d text=" Dear team : \nCICD Pipeline *${env.JOB_NAME}* \nBranch : *${env.BRANCH_NAME}* \nStatus job : *Success* \nTotal Time : *${currentBuild.durationString}* \n\n*More info* at : ${env.RUN_DISPLAY_URL}"
          """)
       }
  
       aborted {
          sh  ("""
              curl -s -X POST https://api.telegram.org/bot$BOT_TOKEN/sendMessage -d chat_id=$TELEGRAM_CHATID -d parse_mode=markdown -d text=" Dear team : \nCICD Pipeline *${env.JOB_NAME}* \nBranch : *${env.BRANCH_NAME}* \nStatus job : *Aborted* \nTotal Time : *${currentBuild.durationString}* \n\n*More info* at : ${env.RUN_DISPLAY_URL}"
          """)
       }
       failure {
          sh  ("""
              curl -s -X POST https://api.telegram.org/bot$BOT_TOKEN/sendMessage -d chat_id=$TELEGRAM_CHATID -d parse_mode=markdown -d text=" Dear team : \nCICD Pipeline *${env.JOB_NAME}* \nBranch : *${env.BRANCH_NAME}* \nStatus job : *Failed* \nTotal Time : *${currentBuild.durationString}* \n\n*More info* at:  ${env.RUN_DISPLAY_URL}"
          """)
       }
    }

<图书推荐>

2024年原创发布的一本关于DevOps企业级持续集成与持续交付实战记录!

<训练营推荐>

2024-08-24 第⑨期 DevOps实战训练营火热开启!

977900d81f7521add15d9c22b3f3c4b6.jpeg

第⑨期 DevOps 训练营火热招生中:开启你的技术提升之旅!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值