DevOps Security with Trivy (OWASP) and Argo CD - Part 1

DevOps Security with Trivy (OWASP) and Argo CD - Part 1

ยทPavan Kalyan Meda

Learn how to build a secure DevOps CI/CD pipeline on Google Cloud Platform using Jenkins, SonarQube, OWASP Dependency-Check, Trivy, Docker, Kubernetes (Kops), and Argo CD.

DevOps Security with Trivy (OWASP) and Argo CD - Part 1

Introduction

Building and deploying a secure Node.js application requires more than simply writing code. A modern DevOps workflow should incorporate version control, continuous integration, automated security scanning, containerization, orchestration, GitOps, and continuous monitoring to deliver reliable and secure applications.

In this guide, you'll build a complete DevOps pipeline using industry-standard tools such as Git, GitHub, Jenkins, SonarQube, OWASP Dependency-Check, Docker, Trivy, Docker Hub, Kubernetes (Kops), Argo CD, Helm, Prometheus, and Grafana on a Google Cloud Platform (GCP) Virtual Machine.

Throughout this series, you'll learn how to automate application delivery while integrating security at every stage of the software development lifecycle.

Prerequisites

Before getting started, ensure you have the following environment prepared:

  • Google Cloud Platform (GCP) account with access to Compute Engine
  • A GCP Virtual Machine running Ubuntu or Debian
  • Basic knowledge of Linux commands and shell scripting
  • A GitHub repository to manage application source code
  • Jenkins installed and configured on the VM
  • Docker installed and running
  • Kubernetes cluster created using Kops
  • Argo CD installed for GitOps deployments
  • Helm installed for Kubernetes package management
  • Prometheus and Grafana configured for monitoring
  • Trivy and SonarQube installed for security analysis

Tools Used in This Project

The following tools are used throughout the deployment pipeline.

ToolPurposeDefault Port
GitDistributed version control system for tracking source code changesโ€”
GitHubCloud-hosted Git repository for collaboration and source managementโ€”
JenkinsContinuous Integration and Continuous Deployment automation server8080
SonarQubeStatic code analysis and code quality inspection platform9000
Node.jsJavaScript runtime for building scalable backend applicationsโ€”
OWASP Dependency-CheckScans project dependencies for known vulnerabilitiesโ€”
DockerContainerization platform for packaging applicationsโ€”
TrivyContainer image and vulnerability scannerโ€”
Docker HubCloud container image registryโ€”
Kubernetes (Kops)Production-grade Kubernetes cluster managementโ€”
Argo CDGitOps Continuous Delivery for Kubernetes8080 / 443
HelmKubernetes package managerโ€”
PrometheusMetrics collection and monitoring system9090
GrafanaDashboarding and visualization platform3000

What is Trivy?

Trivy is an open-source security scanner developed by Aqua Security for cloud-native environments.

It helps developers, DevOps engineers, and security teams identify vulnerabilities and configuration issues across applications, containers, infrastructure, and source code before deployment.

Unlike traditional vulnerability scanners that focus on only one component, Trivy provides comprehensive security scanning across multiple layers of the application stack.


What Can Trivy Scan?

Container Images

Scans Docker and OCI container images for known operating system package and application dependency vulnerabilities.

Filesystems

Scans local project directories to identify:

  • Vulnerable dependencies
  • Security misconfigurations
  • Exposed secrets

Git Repositories

Analyzes source code repositories to detect:

  • Hardcoded secrets
  • API keys
  • Vulnerable libraries
  • Security risks before deployment

Infrastructure as Code (IaC)

Scans infrastructure configuration files including:

  • Terraform
  • Kubernetes YAML manifests
  • Dockerfiles
  • Helm Charts

to detect security misconfigurations before infrastructure is provisioned.


Why Use Trivy in DevOps Pipelines?

Integrating Trivy into a CI/CD pipeline provides several security benefits.

Shift-Left Security

Identify vulnerabilities early during development rather than after deployment.

Fast and Lightweight

Runs quickly, making it ideal for automated CI/CD workflows without significantly increasing build times.

OWASP Top 10 Support

Helps identify common security risks that align with the OWASP Top 10 recommendations.

GitOps Ready

Works seamlessly with GitOps workflows and can be integrated with tools like Argo CD to validate Kubernetes manifests before deployment.

Easy CI/CD Integration

Supports integration with popular automation platforms, including:

  • Jenkins
  • GitHub Actions
  • GitLab CI/CD
  • Azure DevOps
  • CircleCI
  • Bitbucket Pipelines

Step 1: Set Up a GCP Virtual Machine

The first step is to provision the Google Cloud infrastructure required for this project. In this guide, you'll create two Compute Engine virtual machines:

  • kops-cluster-poc โ€“ Used to create and manage the Kubernetes cluster using Kops.
  • pipeline-poc โ€“ Used to host the DevOps tools such as Jenkins, Docker, Trivy, SonarQube, Argo CD, Prometheus, and Grafana.

1.1 Create the Kubernetes Cluster VM

Navigate to Google Cloud Console โ†’ Compute Engine โ†’ VM instances.

Click Create Instance and configure the VM with the following settings:

SettingValue
Namekops-cluster-poc
Machine Typee2-medium (2 vCPUs, 4 GB RAM)
Boot DiskUbuntu 24.04 LTS
FirewallAllow HTTP, HTTPS, and SSH
Region & ZoneChoose your preferred location

Click Create to provision the virtual machine.


1.2 Install and Configure Kops

Install Kops

curl -Lo kops https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64

chmod +x ./kops

sudo mv ./kops /usr/local/bin/  

Install kubectl

curl -Lo kubectl https://dl.k8s.io/release/$(curl -s -L https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl

chmod +x ./kubectl

sudo mv ./kubectl /usr/local/bin/kubectl  

Configure the Kops State Store

export KOPS_STATE_STORE=gs://kubernetes-clusters-9863235

echo 'export KOPS_STATE_STORE=gs://kubernetes-clusters-9863235' >> ~/.bashrc

source ~/.bashrc  

Verify Google Cloud Authentication

gcloud auth list --filter=status:ACTIVE --format="value(account)"

gcloud config get-value project

gcloud compute instances describe $(hostname) --format="value(serviceAccounts[].scopes)"  

Create the Kubernetes Cluster

kops create cluster simple.k8s.local \  
--zones us-central1-a \  
--state ${KOPS_STATE_STORE} \  
--project=mineral-hangar-453509-r7  

Validate the Cluster

kops get cluster --state ${KOPS_STATE_STORE}

kops validate cluster --state=${KOPS_STATE_STORE}  

Export kubeconfig

kops export kubeconfig \  
--state=${KOPS_STATE_STORE} \  
--name=simple.k8s.local

export KUBECONFIG=~/.kube/config  

Verify the Cluster

kubectl cluster-info

kubectl get nodes  

Configure the kubectl Context (Optional)

kubectl config get-contexts

kubectl config use-context simple.k8s.local

kubectl get nodes  

Check Namespaces and Cluster Configuration

kubectl get ns

kubectl config view --minify  

Revalidate the Cluster

kops validate cluster --state=${KOPS_STATE_STORE}

kubectl get nodes  


1.3 Create the Pipeline Virtual Machine

Navigate to Google Cloud Console โ†’ Compute Engine โ†’ VM instances.

Click Create Instance and configure the VM using the following settings:

SettingValue
Namepipeline-poc
Machine Typee2-medium (2 vCPUs, 4 GB RAM)
Boot DiskUbuntu 24.04 LTS
FirewallAllow HTTP, HTTPS, and SSH
Region & ZoneChoose your preferred location

Click Create to provision the virtual machine.

Step 2: Update System Packages

Before installing the required DevOps tools, update the system packages to ensure you have the latest security patches and software updates.

Run the following command:

sudo apt update && sudo apt upgrade -y  

Step 3: Install Git

Git is used for source code management and integrates with platforms such as GitHub to enable version control throughout the CI/CD pipeline.

Install Git using:

sudo apt install git -y  

Verify the installation:

echo "Verifying Git installation..."

git --version  

Step 4: Install Docker

Docker is used to package applications and their dependencies into lightweight, portable containers that can run consistently across different environments.

Install the required packages:

sudo apt install -y ca-certificates curl gnupg  

Create the Docker keyring directory:

sudo install -m 0755 -d /etc/apt/keyrings  

Download the official Docker GPG key:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo tee /etc/apt/keyrings/docker.asc > /dev/null  

Set the correct permissions:

sudo chmod a+r /etc/apt/keyrings/docker.asc  

Add the Docker repository:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null  

Install Docker Engine and related components:

sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin  

Verify the installation:

docker --version  

Enable and start the Docker service:

sudo systemctl enable --now docker  

Allow the current user to run Docker commands without using sudo:

sudo usermod -aG docker $USER

newgrp docker  

Step 5: Install Jenkins

Jenkins is an open-source automation server used to build, test, and deploy applications as part of a Continuous Integration and Continuous Deployment (CI/CD) pipeline.

Install Java (required by Jenkins):

sudo apt install -y fontconfig openjdk-17-jre  

Add the Jenkins repository key:

curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null  

Add the Jenkins repository:

echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian binary/" | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null  

Install Jenkins:

sudo apt update && sudo apt install -y jenkins  

Enable and start the Jenkins service:

sudo systemctl enable --now jenkins  

Check the Jenkins service status:

sudo systemctl status jenkins  

Retrieve the initial administrator password:

sudo cat /var/lib/jenkins/secrets/initialAdminPassword  

Open your browser and access:

http://\<VM_PUBLIC_IP>:8080  

Use the retrieved administrator password to unlock Jenkins and complete the initial setup.


Step 6: Install and Configure SonarQube

SonarQube is a static code analysis platform that helps identify bugs, code smells, security vulnerabilities, and maintainability issues before applications are deployed.

In this guide, SonarQube is deployed using a Docker container.


6.1 Run the SonarQube Container

Start the SonarQube Community Edition container:

docker run -d \  
--name sonar \  
-p 9000:9000 \  
sonarqube:lts-community  

Command Explanation

  • -d โ€” Runs the container in detached mode.
  • --name sonar โ€” Assigns the container the name sonar.
  • -p 9000:9000 โ€” Maps port 9000 of the container to port 9000 on the host VM.
  • sonarqube:lts-community โ€” Pulls and runs the latest Long-Term Support (LTS) Community Edition image.

Open your browser and navigate to:

http://\<VM_PUBLIC_IP>:9000  

6.2 Log in to SonarQube

Use the default administrator credentials:

UsernamePassword
adminadmin

After logging in for the first time, SonarQube will prompt you to change the default administrator password.


6.3 Create a Project and Generate a Token

Create a project manually.

  1. Click Create Project.
  2. Select Locally as the project setup method.
  3. Generate a project token.
  4. Set the token expiration to 30 Days.
  5. Click Generate.
  6. Copy the generated token for later use.
  7. Select your operating system.
  8. Copy the Execute the Scanner command provided by SonarQube.

This token will be required when integrating SonarQube with Jenkins.


6.4 Create a Jenkins User in SonarQube

To allow Jenkins to authenticate with SonarQube, create a dedicated user.

Navigate to:

Administration โ†’ Security โ†’ Users โ†’ Create User

Provide the following details:

FieldExample
Loginjenkins
Emailabcs@gmail.com
PasswordChoose a secure password

Click Create.


6.5 Generate a Token for Jenkins

Log in using the newly created jenkins user.

Navigate to:

User Settings โ†’ Security โ†’ Generate Tokens

Configure the token:

SettingValue
Token NameJenkins-30Days-Token
Expiration30 Days

Click Generate and copy the generated token.


6.6 Store the Token in Jenkins

Open the Jenkins dashboard.

Navigate to:

Manage Jenkins โ†’ Credentials

Add a new credential with the following configuration:

FieldValue
KindSecret text
SecretPaste the generated SonarQube token
IDJenkins-30Days-Token

Save the credential.

Jenkins can now securely authenticate with SonarQube during pipeline execution.

Step 7: Install the Required Jenkins Plugins

Jenkins plugins extend the functionality of the Jenkins automation server, enabling integrations with tools such as Node.js, SonarQube, Docker, Trivy, and OWASP Dependency-Check.


7.1 Open the Plugin Manager

From the Jenkins Dashboard, navigate to:

Manage Jenkins โ†’ Manage Plugins


7.2 Install the Required Plugins

Open the Available Plugins tab.

Use the search box to locate and install the following plugins:

  • NodeJS Plugin
  • SonarQube Scanner
  • OWASP Dependency-Check
  • Docker Pipeline
  • Trivy Scanner

After selecting the required plugins, click Install without restart.

Wait until all plugins are successfully installed before proceeding.


Step 8: Configure Global Tools in Jenkins

After installing the required plugins, configure the development tools that Jenkins will use during pipeline execution.

Navigate to:

Dashboard โ†’ Manage Jenkins โ†’ Global Tool Configuration

Configure the following tools.


8.1 Configure JDK

Add a JDK installation.

SettingValue
Namejdk17
Versionjdk-17.0.8.1+1
Java Home/path/to/jdk

8.2 Configure Node.js

Add a Node.js installation.

SettingValue
Namenode16
Version16.2.0

Enable Install automatically if Node.js is not already installed.


8.3 Configure SonarQube Scanner

Add a SonarQube Scanner installation.

SettingValue
Namesonar-scanner
Version5.0.1.3006

Enable Install automatically if required.


8.4 Configure OWASP Dependency-Check

Add the Dependency-Check tool.

SettingValue
NameDP-Check
Version6.5.1

Install the tool automatically from GitHub if it is not already available.

After saving the configuration, Jenkins will be ready to use these tools within pipeline jobs.

Step 9: Create and Configure the Jenkins Pipeline

With Jenkins and the required tools configured, the next step is to create a Pipeline job that automates the complete CI/CD workflowโ€”from source code checkout and code quality analysis to security scanning, Docker image creation, and publishing to Docker Hub.


9.1 Create a New Pipeline Job

  1. Open the Jenkins Dashboard.
  2. Click New Item.
  3. Enter the job name as My Deployment.
  4. Select Pipeline.
  5. Click OK.
  6. Scroll to the Pipeline section.
  7. Select Pipeline script.
  8. Paste the Jenkins Pipeline script.
  9. Click Save.

9.2 Generate Docker Registry Pipeline Syntax

Jenkins provides a Pipeline Syntax Generator to simplify authentication with Docker Hub.

  1. Navigate to Pipeline Syntax.
  2. Select with Docker Registry from the dropdown.
  3. Choose your Docker Hub credentials.
  4. Click Generate Pipeline Script.
  5. Copy the generated syntax into your Jenkins pipeline.

9.3 Create the Dockerfile

Create a Dockerfile in the root directory of your Node.js project.

FROM node:16-slim

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]  

This Dockerfile installs the application dependencies, builds the project, exposes port 3000, and starts the Node.js application.


9.4 Configure the Jenkins Pipeline

Paste the following Jenkins Pipeline into the Pipeline section of the Jenkins job.

pipeline {  
    agent any

    tools {  
        jdk 'java'  
        nodejs 'nodejs'  
    }

    environment {  
        SCANNER_HOME = "/var/lib/jenkins/tools/hudson.plugins.sonar.SonarRunnerInstallation/mysonar"  
    }

    stages {

        stage("Clean Workspace") {  
            steps {  
                cleanWs()  
            }  
        }

        stage("Checkout Code") {  
            steps {  
                git branch: 'main', url: 'https://github.com/pavan5779/Zomato-Repo.git'  
            }  
        }

        stage("SonarQube Analysis") {  
            steps {  
                withSonarQubeEnv('mysonar') {  
                    sh '''$SCANNER_HOME/bin/sonar-scanner \  
                    -Dsonar.projectKey=zomato \  
                    -Dsonar.sources=. \  
                    -Dsonar.host.url=http://34.93.59.82:9000 \  
                    -Dsonar.login=squ_58d4d2054f6ee2b19117afdade6540fcb4dc52d7'''  
                }  
            }  
        }

        stage("Quality Gate Check") {  
            steps {  
                script {  
                    def qg = sh(returnStdout: true, script: """  
                        curl -u squ_58d4d2054f6ee2b19117afdade6540fcb4dc52d7: 'http://34.93.59.82:9000/api/qualitygates/project_status?projectKey=zomato'  
                    """).trim()  
                    echo "Quality Gate Status: ${qg}"  
                }  
            }  
        }

        stage("Install Dependencies") {  
            steps {  
                sh 'npm install'  
            }  
        }

        stage("OWASP Dependency Check") {  
            options {  
                retry(2)  
                timeout(time: 60, unit: 'MINUTES')  
            }  
            steps {  
                script {  
                    dependencyCheck additionalArguments: """  
                        --scan ./src \  
                        --disableYarnAudit \  
                        --disableNodeAudit \  
                        --failOnCVSS 9 \  
                        --format HTML  
                    """, odcInstallation: 'Dp-Check'

                    dependencyCheckPublisher pattern: '**/dependency-check-report.html'  
                }  
            }  
        }

        stage("Trivy Security Scan") {  
            steps {  
                sh "trivy fs . > trivyfs.txt"  
            }  
        }

        stage("Verify Docker Access") {  
            steps {  
                script {  
                    sh "id && groups && ls -l /var/run/docker.sock"  
                }  
            }  
        }

        stage("Build Docker Image") {  
            steps {  
                script {  
                    sh "newgrp docker && docker build -t image1 ."  
                }  
            }  
        }

        stage("Push Docker Image") {  
            steps {  
                script {  
                    withDockerRegistry(credentialsId: 'dockerhub') {  
                        sh """  
                            docker tag image1 pavan5779/kubernetesproject:CA  
                            docker push pavan5779/kubernetesproject:CA  
                        """  
                    }  
                }  
            }  
        }

        stage("Scan Docker Image") {  
            steps {  
                sh 'trivy image pavan5779/kubernetesproject:CA'  
            }  
        }  
    }  
}  

The pipeline performs the following tasks:

  • Cleans the Jenkins workspace.
  • Clones the application source code from GitHub.
  • Performs static code analysis with SonarQube.
  • Validates the SonarQube Quality Gate.
  • Installs project dependencies.
  • Runs OWASP Dependency-Check.
  • Performs filesystem security scanning with Trivy.
  • Verifies Docker access.
  • Builds the Docker image.
  • Pushes the Docker image to Docker Hub.
  • Performs a vulnerability scan on the published Docker image.

9.5 Validate the Pipeline Results

After the pipeline completes successfully, verify the following:

  • The OWASP Dependency-Check report is generated.
  • The SonarQube Quality Gate passes successfully.
  • The Docker image is built without errors.
  • The Docker image is successfully pushed to Docker Hub.


Step 10: Perform Code Quality and Security Analysis

The pipeline integrates SonarQube to analyze the application's source code.

A successful analysis should indicate:

  • Quality Gate Passed
  • No new bugs
  • No critical vulnerabilities
  • No security hotspots
  • Maintainability Rating: A
  • Reliability Rating: A
  • Security Rating: A


Step 11: Build and Publish the Docker Image

Once all quality and security checks pass, Jenkins builds the application container and publishes it to Docker Hub.

Docker image details:

PropertyValue
Repositorypavan5779/kubernetesproject
TagCA
Platformlinux/amd64
Compressed Size237.3 MB


Conclusion

In this first part of the series, you built the foundation of a secure DevOps pipeline by provisioning infrastructure on Google Cloud Platform, configuring Jenkins, integrating SonarQube, OWASP Dependency-Check, and Trivy for security scanning, containerizing the application with Docker, and publishing the image to Docker Hub.

In Part 2, you'll continue by deploying the application to a Kubernetes cluster using Argo CD and implementing observability with Prometheus and Grafana for monitoring and alerting.

Hi! I'm ERICA. Ask me anything!