
在这个现代时代,应用程序的开发非常庞大,当然,网络犯罪也变得越来越疯狂。我对学习一点SDLC自动化(通常称为 DevOps 文化)很感兴趣。不过,这一次,我尝试了几个额外的安全平台,以便它能够成为 DevSecOps。
一般来说,我会使用:
Jenkins作为 CI/CD 平台
使用Dependency Track作为 SCA
SonarQube作为 SAST
Trivy作为 Container Image Scanner
Defectdojo作为集中报告监控。
在基础设施方面,我使用:
Kubernetes 作为我在多个自托管平台进行实验的暂存容器
Harbor作为私有容器注册中心
ArgoCD作为持续部署平台
我使用的管道目标如下:
克隆存储库阶段
首先,我声明从 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 发送后的依赖报告。
同样地,如下图所示,Defectdojo 的产品网站上也已经开始了互动。
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 的样子。
这是 SonarQube 报告集成到 Defectdojo 之后的样子。
缺陷道场
构建映像阶段
然后下一步是创建一个用于使用 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 之后的示例。
推送图像阶段
之后,我们将镜像推送到 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上的显示。
港口
在 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作为图像标签,其中图像标签将遵循代码存储库中的最后一个提交编号。我这样做是为了更容易跟踪和回滚版本等。
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 集群的示例。
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。
后期阶段
此最后阶段负责清理环境并发送有关执行管道结果的警报,指示管道是成功、失败还是其他状态。通常,我以以下方式使用它:
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实战训练营火热开启!

2543

被折叠的 条评论
为什么被折叠?



