diff --git a/Dockerfile b/Dockerfile index 8d376e8e..148a239d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,17 @@ -FROM maven:3.6-jdk-8 - +FROM maven:3.8.4-openjdk-17 AS build WORKDIR /app +COPY . . +RUN mvn package -DskipTests -COPY . . - -RUN mvn package -DskipTests && \ - mv target/demo-0.0.1-SNAPSHOT.jar /run/demo.jar - +FROM openjdk:18-alpine AS run +WORKDIR /run +COPY --from=build /app/target/demo-0.0.1-SNAPSHOT.jar demo.jar +ARG USER=devops +ENV HOME /home/$USER +RUN adduser -D $USER && chown $USER:$USER /run/demo.jar +RUN apk add --no-cache curl +HEALTHCHECK --interval=30s --timeout=10s --retries=2 --start-period=20s \ + CMD curl -f http://localhost:8080/ || exit 1 +USER $USER EXPOSE 8080 - -CMD java -jar /run/demo.jar +CMD java -jar /run/demo.jar diff --git a/Jenkinsfile b/Jenkinsfile index 2fc1e0d2..b138f7a4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,7 @@ pipeline { + environment { + ARGO_SERVER = '104.197.60.253:32100' + } agent { kubernetes { yamlFile 'build-agent.yaml' @@ -18,7 +21,7 @@ pipeline { } } } - stage('Test') { + stage('Static Analysis') { parallel { stage('Unit Tests') { steps { @@ -27,6 +30,60 @@ pipeline { } } } + stage('SCA') { + steps { + container('maven') { + catchError(buildResult: 'SUCCESS', stageResult:'FAILURE') { + sh 'mvn org.owasp:dependency-check-maven:check' + } + } + } + post { + always { + archiveArtifacts allowEmptyArchive: true,artifacts: 'target/dependency-check-report.html', fingerprint:true, onlyIfSuccessful: true + // dependencyCheckPublisher pattern: 'report.xml' + } + } + } + stage('OSS License Checker') { + steps { + container('licensefinder') { + sh 'ls -al' + sh '''#!/bin/bash --login + /bin/bash --login + rvm use default + gem install license_finder + license_finder + ''' + } + } + } + stage('Generate SBOM') { + steps { + container('maven') { + sh 'mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom' + } + } + post { + success { + //dependencyTrackPublisher projectName:'sample-spring-app', projectVersion: '0.0.1', artifact:'target/bom.xml', autoCreateProjects: true, synchronous: true + archiveArtifacts allowEmptyArchive: true,artifacts: 'target/bom.xml', fingerprint: true,onlyIfSuccessful: true + } + } + } + } + } + stage('SAST') { + steps { + container('slscan') { + sh 'scan --type java,depscan --build' + } + } + post { + success { + archiveArtifacts allowEmptyArchive: true, + artifacts: 'reports/*', fingerprint: true, onlyIfSuccessful:true + } } } stage('Package') { @@ -38,13 +95,44 @@ pipeline { } } } + stage('Build with Kaniko') { + steps { + container('kaniko') { + sh '/kaniko/executor -f `pwd`/Dockerfile -c `pwd` --insecure --skip-tls-verify --cache=true --destination=docker.io/vinycoolguy/dsodemo' + } } } + } + } + + stage('Image Analysis') { + parallel { + stage('Image Linting') { + steps { + container('docker-tools') { + sh 'dockle docker.io/vinycoolguy/dsodemo' + } + } + } + stage('Image Scan') { + steps { + container('docker-tools') { + sh 'trivy image vinycoolguy/dsodemo' + } + } + } + } + } stage('Deploy to Dev') { + environment { + AUTH_TOKEN = credentials('argocd-jenkins-deployer-token') + } steps { - // TODO - sh "echo done" + container('docker-tools') { + sh 'docker run -t schoolofdevops/argocd-cli argocd app sync dso-demo --insecure --server $ARGO_SERVER --auth-token $AUTH_TOKEN' + sh 'docker run -t schoolofdevops/argocd-cli argocd app wait dso-demo --health --timeout 300 --insecure --server $ARGO_SERVER --auth-token $AUTH_TOKEN' + } } } } diff --git a/build-agent.yaml b/build-agent.yaml index c9efebe3..88014de2 100644 --- a/build-agent.yaml +++ b/build-agent.yaml @@ -23,6 +23,22 @@ spec: name: docker-sock - mountPath: /tmp/trivycache/ name: trivycache + - name: slscan + image: shiftleft/sast-scan + imagePullPolicy: Always + command: + - cat + tty: true + - name: kaniko + image: gcr.io/kaniko-project/executor:v1.6.0-debug + imagePullPolicy: Always + command: + - sleep + args: + - 99d + volumeMounts: + - name: jenkins-docker-cfg + mountPath: /kaniko/.docker - name: trufflehog image: rmkanda/trufflehog command: @@ -43,3 +59,11 @@ spec: - name: trivycache hostPath: path: /tmp/trivycache/ + - name: jenkins-docker-cfg + projected: + sources: + - secret: + name: regcred + items: + - key: .dockerconfigjson + path: config.json diff --git a/deploy/dso-demo-deploy.yaml b/deploy/dso-demo-deploy.yaml new file mode 100644 index 00000000..76161e8b --- /dev/null +++ b/deploy/dso-demo-deploy.yaml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: dso-demo + name: dso-demo +spec: + replicas: 1 + selector: + matchLabels: + app: dso-demo + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: dso-demo + spec: + containers: + - image: vinycoolguy/dsodemo + name: dsodemo + ports: + - containerPort: 8080 + resources: {} +status: {} diff --git a/deploy/dso-demo-svc.yaml b/deploy/dso-demo-svc.yaml new file mode 100644 index 00000000..8931ce9f --- /dev/null +++ b/deploy/dso-demo-svc.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: null + labels: + app: dso-demo + name: dso-demo +spec: + ports: + - name: "8080" + nodePort: 30080 + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: dso-demo + type: NodePort +status: + loadBalancer: {} diff --git a/doc/dependency_decisions.yml b/doc/dependency_decisions.yml index cad03c45..e91d2688 100644 --- a/doc/dependency_decisions.yml +++ b/doc/dependency_decisions.yml @@ -40,14 +40,14 @@ - :who: :why: :versions: - - 1.2.3 + - 1.2.6 :when: 2020-05-31 15:28:30.302764000 Z - - :approve - logback-classic - :who: :why: :versions: - - 1.2.3 + - 1.2.6 :when: 2020-05-31 15:29:03.621478000 Z - - :approve - jakarta.xml.bind-api @@ -70,3 +70,9 @@ :versions: - 1.3.5 :when: 2020-05-31 15:29:53.045616000 Z +- - :permit + - New BSD + - :who: + :why: + :versions: [] + :when: 2020-09-29 diff --git a/pom.xml b/pom.xml index 9c2e8aad..4aec8086 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 2.4.3 + 2.5.5 com.demo @@ -16,6 +16,7 @@ 1.8 + 2.17.0 @@ -47,6 +48,9 @@ org.owasp dependency-check-maven 6.1.1 + + 8 + diff --git a/src/main/java/com/demo/demo/DemoApplication.java b/src/main/java/com/demo/demo/DemoApplication.java index b4943e0c..95b8bf7f 100644 --- a/src/main/java/com/demo/demo/DemoApplication.java +++ b/src/main/java/com/demo/demo/DemoApplication.java @@ -11,7 +11,7 @@ public class DemoApplication { @GetMapping("/") public String available() { - return "

DevSecOps Demo

"; + return "

DevSecOps Demo Updated

"; } public static void main(String[] args) {