Project 2 -Automated DevSecOps CI/CD Pipeline for Secure Node.js App Deployment

Hi! I'm a highly motivated Security and DevOps professional with 7+ years of combined experience. My expertise bridges penetration testing and DevOps engineering, allowing me to deliver a comprehensive security approach.
In this comprehensive guide, we will walk through the process of setting up a DevSecOps Jenkins CI/CD pipeline for a Node.js application. This pipeline will integrate various tools and practices to ensure high standards of code quality and security throughout the development lifecycle. The tools required for this project include GitHub, Docker, Jenkins, SonarQube, OWASP tools, and Trivy. Let's dive into the step-by-step process:
Prerequisites:
Powerful Machine: Utilize a robust machine for this project. In this guide, I recommend an AWS EC2 Instance (e.g., t2.large) for optimal performance.
Install Necessary Tools: Before proceeding, ensure the following tools are installed on your system:
JDK: Essential for running Jenkins.
Docker and Docker Compose: Required for containerizing the Node.js application.
SonarQube Server and SonarQube Scanner Plugin for Jenkins: Utilized for code quality analysis.
Trivy: Used for scanning Docker images for vulnerabilities.
OWASP Dependency Check: Essential for security testing.
Make sure these tools are installed on your system before proceeding with the project.
Setup Docker and Jenkins Services:
Install Jenkins:
Follow the official documentation provided by Jenkins to install it on your system. Refer to the Jenkins Installation Guide for Linux for detailed instructions. Here's a command that will install Jenkins:
sudo apt update sudo apt install fontconfig openjdk-17-jre sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \ https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \ https://pkg.jenkins.io/debian-stable binary/ | sudo tee \ /etc/apt/sources.list.d/jenkins.list > /dev/null sudo apt-get update sudo apt-get install jenkins
Install Docker and Docker-compose:
Refer to the official Docker documentation for installing Docker Engine on Ubuntu systems. Follow the instructions provided in the Docker Engine Installation Guide for Ubuntu. Here's a command that will install both Docker and Docker Compose: For Ubuntu/Debian-based systems:
sudo apt update && sudo apt install -y docker.io docker-compose
Install Trivy on your System
Follow the official documentation provided by Trivy to install it on your system. Refer to the Trivy Installation Guide for Linux for detailed instructions or you can use the script below
sudo apt update sudo apt install -y wget apt-transport-https gnupg lsb-release wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list sudo apt update sudo apt install -y trivy
Configure Docker and Jenkins Services:
After installation, ensure Docker and Jenkins services are set to start automatically upon system restart. Execute the following systemctl commands:
sudo systemctl enable docker sudo systemctl enable jenkinsGrant necessary permissions to users to interact with Docker. Add your user and the Jenkins user to the Docker group, then reboot the system:
sudo usermod -aG docker $USER sudo usermod -aG docker jenkins sudo reboot
Allow Inbound Traffic on Port 8000, 8080 and 9000:
- If you are utilizing an AWS EC2 instance, it's crucial to allow inbound traffic on port 8080, port 9000, and port 8000 to access the Jenkins dashboard, and SonarQube Server Dashboard and the application to serve requests.
Setting Up Jenkins: Once the installation is complete, you can access the Jenkins dashboard by navigating to http://<your_ec2_instance_public_ip>:8080 in your web browser. Now you have to configure Jenkins:
Configure Jenkins:
Configure Jenkins with a username and password and log in to Jenkins with these credentials and install suggested plugin.

Create a New Pipeline:
Create a new pipeline and configure it with a description and GitHub project details.

For this- Navigate to the Jenkins dashboard. Click on "Create a Job" and name the pipeline. Choose "Pipeline" and click "OK".
Configure Pipeline:
Add a description for the pipeline.

Select the GitHub project and provide the repository URL: https://github.com/neamulkabiremon/node-todo-cicd Enable the GitHub Hook trigger for GITScm Polling for Integrating GitHub and Jenkins for Automation and for now click on save.
Integrating OWASP Dependency Check into the Jenkins Pipeline
Adding an extra layer of security to your CI/CD pipeline is crucial. OWASP Dependency Check helps you identify potential vulnerabilities in your project's dependencies.

Begin by installing the OWASP Dependency Check plugin within Jenkins. Navigate to Manage Jenkins > Manage Plugins and locate the OWASP Dependency Check plugin. Install it and ensure to restart Jenkins post-installation.

Following installation, proceed to enable the Dependency Checker within Jenkins. Navigate to Jenkins > Dashboard > Manage Jenkins > Tools. Locate Dependency Check and select the option to Install automatically. Don't forget to save your changes afterwards. This step ensures that the Dependency Check tool is seamlessly integrated into your Jenkins environment, bolstering your pipeline's security posture.
Now Setting Up SonarQube:
Run SonarQube Server:
Launch the SonarQube server using Docker on your instance:
docker run -itd --name sonarqube-server -p 9000:9000 sonarqube:lts-community
Ensure that inbound traffic on port 9000 is permitted (if leveraging AWS EC2).
Configure SonarQube:
Access the SonarQube dashboard by navigating to http://<your_ec2_instance_public_ip>:9000. Upon accessing, you'll encounter a default login prompt; utilize the credentials admin/admin to log in and subsequently reset the password. Following login, you'll gain access to the dashboard.

- Navigate to Administration > Security > User Section and click on the ellipsis button to Generate a token for Jenkins authentication.

Safely copy the generated token and proceed to Jenkins for configuration. To integrate Jenkins with SonarQube, it's imperative to install the SonarQube scanner plugin within Jenkins.
Integrate SonarQube with Jenkins:
To establish connectivity between the SonarQube server and Jenkins, install the SonarQube scanner plugin in Jenkins via Jenkins > Manage Plugins > Available Plugin and install SonarQube Scanner.

Next, configure the SonarQube server using the generated token. For enhanced security, store the SonarQube secret within Jenkins Global Credentials. Navigate to Dashboard > Manage Jenkins > Credentials > System.

Click on Add credential, select secret text, and input the generated Secret token from SonarQube. Assign a Credential ID name, such as "Sonar."
Now, proceed to configure the SonarQube server plugin within Jenkins by navigating to Dashboard > Manage Jenkins > Tools and locating SonarQube Scanner.

Choice installs automatically and select the latest sonarqube scanner version and hit the save button.

Subsequently, configure the SonarQube scanner with the SonarQube Server. Navigate to Dashboard > Manage Jenkins > System and ad sonarqube server and define the Name and Server URL (http://<your_ec2_instance_public_ip>:9000/) while selecting the secret ID configured in Jenkins Credential. Save the configuration.
Configuring WebHooks:
SonarQube WebHook:
- Access your SonarQube dashboard (http://<your_instance_ip>:9000) and navigate to Configuration > Webhooks. Set up a webhook to establish communication with Jenkins.

Provide the name and URL of your Jenkins server, including the port and the specific endpoint for SonarQube integration. Typically, this involves appending http://your_instance_ip:8080>/sonarqube-webhook/your Jenkins IP or domain name, followed by the appropriate port number.
Save the webhook configuration.
Now Setting Up DockerHub Credentials on Jenkins:
To ensure secure management and seamless pushing of images to your Docker repository, it's essential to configure DockerHub credentials within Jenkins.
Navigate to Jenkins > Dashboard > Manage Jenkins > Credentials > System > Global credentials (unrestricted).
Click on "Add Credential" and select "Username and Password" as the credential kind, with the scope set to Global.

Provide your DockerHub credentials accordingly and assign a meaningful Credential ID name. For clarity, let's designate it as "DockerHubCreds" and hit the create batton.
Creating Jenkins Pipeline Script:
Write Pipeline Script:
Here's a sample pipeline script you can copy and paste into your Jenkins configuration for now. We'll delve deeper into script creation in the next article.
pipeline {
agent any
environment {
SONAR_HOME = tool "Sonar"
}
stages {
stage("Code") {
steps {
git url: "https://github.com/neamulkabiremon/node-todo-cicd.git", branch: "master"
echo "Code Cloned Successfully"
}
}
stage("SonarQube Analysis") {
steps {
withSonarQubeEnv("Sonar") {
sh "$SONAR_HOME/bin/sonar-scanner -Dsonar.projectName=nodetodo -Dsonar.projectKey=nodetodo -X"
}
}
}
stage("SonarQube Quality Gates") {
steps {
timeout(time: 1, unit: "MINUTES") {
waitForQualityGate abortPipeline: false
}
}
}
stage("OWASP") {
steps {
dependencyCheck additionalArguments: '--scan ./', odcInstallation: 'OWASP'
dependencyCheckPublisher pattern: '**/dependency-check-report.xml'
}
}
stage("Build & Test") {
steps {
sh 'docker build -t node-app-batch-6:latest .'
echo "Code Built Successfully"
}
}
stage("Trivy") {
steps {
sh "trivy image node-app-batch-6"
}
}
stage("Push to Private Docker Hub Repo") {
steps {
script {
withCredentials([usernamePassword(credentialsId: 'DockerHubCreds', usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
def dockerUsername = env.DOCKER_USERNAME
def dockerPassword = env.DOCKER_PASSWORD
sh "echo ${dockerPassword} | docker login -u ${dockerUsername} --password-stdin"
sh "docker tag node-app-batch-6:latest ${dockerUsername}/node-app-batch-6:latest"
sh "docker push ${dockerUsername}/node-app-batch-6:latest"
}
}
}
}
stage("Deploy") {
steps {
sh "docker-compose down && docker-compose up -d"
echo "App Deployed Successfully"
}
}
}
}
Define stages for the pipeline including code cloning, SonarQube analysis, OWASP checks, Docker image build, Trivy scanning, Docker image push, and deployment.
Adding the Script to Jenkins:
Go to your Jenkins server: http://your_instance_ip:8080
Navigate to Jenkins > Dashboard > DevSecOps CICD > Configuration.

In the pipeline configuration section, choose "Pipeline script from Definition and Paste the provided pipeline script into the designated code editor.
Save your pipeline configuration.
Executing the Pipeline:
Triggering the Build:
- Initiate the pipeline execution by clicking "Build Now" in Jenkins.

Monitoring Progress:

Once triggered, you can track the pipeline's progress in the Jenkins console. This console provides real-time logs and status updates for each stage within the DevSecOps pipeline. The process takes around 20-30 minutes depending on your system specifications.

- Upon successful completion of the pipeline, verify the application deployment. You can achieve this by accessing the application URL (http://[YOUR_IP_ADDRESS]:8000/) in your browser.

Success!

- Witnessing the application running at the designated port signifies a successful deployment via the Jenkins DevSecOps pipeline. This empowers you to leverage the deployed application, such as using the Node.js Todo app for your weekly planning.
Integrating GitHub and Jenkins for Seamless Automation:
DevOps thrives on automation to achieve efficiency and consistent development lifecycles. Integrating GitHub with Jenkins automates the build process whenever developers push code changes.
Configuring Jenkins for GitHub Webhooks:
Install the GitHub Plugin: Ensure the "GitHub plugin" is installed in Jenkins (if not already).
Pipeline Configuration: Navigate to Jenkins > Dashboard > DevSecOps CICD > Configuration. Select your pipeline and choose "Pipeline script from SCM."

Git Configuration:
Set SCM to "Git."
Provide your project repository URL : https://github.com/neamulkabiremon/node-todo-cicd.git
If your code is private, enter credentials (not required for public repositories).

Branch and Script Path:
- Under "Branches to build," specify
*/masterto build changes on the master branch.

In "Script path," enter the Jenkinsfile path within your GitHub repository (e.g., DevSecOps/Jenkinsfile).
Save Configurations: Save the pipeline configuration
Setting Up GitHub Webhooks:
Access Webhook Settings: Go to your GitHub repository settings and navigate to the "Webhooks" section.
Add a New Webhook: Click "Add webhook" and configure the following:

Payload URL: Set it to your Jenkins server URL followed by
/github-webhook/.Content type: set application/x-www-from-urlencoded
Events: Choose "Send me everything" or select specific events like push events and hit save webhook.
Voila! Seamless Integration: With these configurations, your GitHub repository and Jenkins are now seamlessly integrated. Any code changes pushed to the repository will automatically trigger builds in Jenkins.
Testing the Integration:
- Make a Code Change: In GitHub, modify your code and commit the changes (e.g., adding some text).

I just added some text to the code, then let's commit it and check Jenkins to see if the pipeline has started or not.

Boom The pipeline started automatically
Verify Jenkins Pipeline: Monitor Jenkins to see if the pipeline automatically starts upon committing the change.
DevSecOps Pipeline Checks and Feedback
Since this is a DevSecOps pipeline, security analysis results from SonarQube, OWASP Dependency Checker, and Trivy provide valuable insights for improving code quality and mitigating vulnerabilities. Let's review these results and provide actionable feedback to the developer:
OWASP Dependency Checker:
- Access the results in Jenkins under Dashboard > DevSecOps CICD > #7 > Dependency-Check.

Identified vulnerabilities: 4 Critical, 6 High, and 4 Medium severity.
Action: Collaborate with the developer to address these vulnerabilities as soon as possible.
SonarQube Quality and Security:
- Access the SonarQube dashboard at
your-IP-address:9000.

Findings:
0 Vulnerabilities (positive)
13 Bugs
130 Security Hotspots
Trivy Scan Results:
- Locate the Console Output within Jenkins for Trivy scan results.

Identified vulnerabilities: 2 Critical, 6 High, 14 Medium, and 4 Low severity.
Action: Report these vulnerabilities to the developer and work collaboratively to prioritize and fix them promptly.
Conclusion:
Congratulations! You have successfully set up a DevSecOps Jenkins CI/CD pipeline for a Node.js application. This pipeline integrates code quality analysis, security testing, and Docker image scanning, ensuring high standards of quality and security throughout the development process. By following this guide, you have gained valuable experience in CI/CD pipeline development, security integration in DevOps, and containerization, strengthening your skills in DevSecOps practices.




