# DevSecOps: Amazon Prime Clone application

In this blog, we'll explore how to set up a DevSecOps pipeline that integrates GitOps principles, enhanced security scanning, and strong monitoring. This comprehensive project demonstrates deploying an Amazon Prime Clone application using Jenkins, Docker, SonarQube, Trivy, Docker Scout, Prometheus, Grafana, Amazon EKS, and ArgoCD.

## **Step-by-Step Breakdown**

![](https://miro.medium.com/v2/resize:fit:1250/1*G4eK70WAla3QRvXchKnLRA.png align="left")

## **Step 1: Setting Up the Foundation**

### **Initial Setup**

To get started, we prepared the environment by provisioning a Jenkins VM and installing essential tools. This included:

* Jenkins installation for continuous integration. Access it on `<vm_ip>:8080`
    

```bash
#!/bin/bash
sudo apt update -y
wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo tee /etc/apt/keyrings/adoptium.asc
echo "deb [signed-by=/etc/apt/keyrings/adoptium.asc] https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | sudo tee /etc/apt/sources.list.d/adoptium.list
sudo apt update -y
sudo apt install temurin-17-jdk -y
/usr/bin/java --version
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null
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 -y
sudo apt-get install jenkins -y
sudo systemctl start jenkins
sudo systemctl status jenkins
```

```bash
chmod +x jenkin.sh
```

![](https://miro.medium.com/v2/1*GeYABmI5H0muq_0b78ANFg.png align="left")

* Docker for containerization.
    

```bash
sudo apt install docker.io
sudo systemctl enable docker 
sudo systemctl start docker
sudo chmod 666 /var/run/docker.sock
```

* SonarQube for static code analysis. And access your dashboard at `<vm_ip>:9000`
    

```bash
docker run -d --name Sonar-Qube -p 9000:9000 sonarqube:lts-community
```

![](https://miro.medium.com/v2/resize:fit:875/1*jjq15sUaHd4GHtHEkaYO6g.png align="left")

* Trivy for vulnerability scanning.
    

```bash
sudo apt-get install wget apt-transport-https gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
```

```bash
chmod +x trivy.sh
./trivy.sh
```

![](https://miro.medium.com/v2/1*pHmsBNGJfVAFkCe4R1BfJw.png align="left")

* Installing Docker-scout.
    

```bash
docker login -u <username> -p <password>
curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- -b /usr/local/bin
```

Additional tools introduced in this project include:

* Docker Scout for software composition analysis (SCA) and generating SBOM (Software Bill of Materials).
    
* Eclipse Temurin Installer for managing JDK versions.
    
* Prometheus Metrics Plugin for monitoring Jenkins performance.
    
* Email Extension Plugin for automated notifications.
    

## **Jenkins Configuration**

1. **Installed plugins:**
    

![](https://miro.medium.com/v2/resize:fit:875/1*u15g0simoOPNb6YGxcLEEQ.png align="left")

![](https://miro.medium.com/v2/1*AJeMQoS_1pjrZyDoR6CouA.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*EWZeGSTyGjDtDLYif7uiHQ.png align="left")

**2\. Configured tools:**

* **JDK (Temurin JDK 17)** for Java-based **SonarQube** scanner.
    

![](https://miro.medium.com/v2/resize:fit:875/1*OTzqByOF_MJar72j_4giZQ.png align="left")

![](https://miro.medium.com/v2/1*7GPM7iM9XwIm1jmpZs07vg.png align="left")

* **Node.js** (version 16) for JavaScript dependencies.
    

![](https://miro.medium.com/v2/resize:fit:868/1*IXblPMknYVe6Ej1ObfV76w.png align="left")

* **Docker**: Configure installation for Docker.
    

![](https://miro.medium.com/v2/1*nf-KF2QV09ZXNiAM0r7QMA.png align="left")

**3\. Created credentials for GitHub (Personal Access Token), DockerHub, Email App Password and Sonarqube Token**.

* GitHub: Create a personal access token (`Settings > Developer Settings > Personal Access Tokens`) and add it in Jenkins.
    

![](https://miro.medium.com/v2/1*l1VbG2Qt_-tUXXv5NpXLaw.png align="left")

![](https://miro.medium.com/v2/1*ba_cK3CeTx0ORDyJGts3FA.png align="left")

![](https://miro.medium.com/v2/1*nHPxRnToo5yERTPakjFeFQ.png align="left")

* Go back to Jenkins and create new secret for storing it.
    

![](https://miro.medium.com/v2/1*jiqmCEnNUR-bp0frdhhYPQ.png align="left")

* **DockerHub**: Add your Docker Hub Username and password in Jenkins.
    

![](https://miro.medium.com/v2/1*ml4Mr2cdqwL0GGezcREOwA.png align="left")

* **SonarQube**: Generate a token in the SonarQube dashboard and add it in Jenkins.
    
* Go to `Administration > Security > Users > Administrator > Tokens` and generate new token and copy it.
    

![](https://miro.medium.com/v2/resize:fit:875/1*Ipt9haP4dixATyw6fZN3Rw.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*MbLo3Ho0gd5BsukSGjNU8w.png align="left")

* Create credentials named `sonar-token` and paste your token there.
    

![](https://miro.medium.com/v2/1*0lhvFws7OfWN6_FOHnqxrA.png align="left")

* **EMAIL CRED:** Go to your google account app password and create new password and copy it.
    
* Now come back to Jenkins credentials and create new cred.
    

![](https://miro.medium.com/v2/resize:fit:803/1*ZonK7eqd-T-84xh61j2LWw.png align="left")

**4\. Configured SonarQube URL and token in Jenkins system settings. Go to Dashboard &gt; Manage Jenkins &gt; System.**

![](https://miro.medium.com/v2/resize:fit:875/1*0zrXv6iUmsavg5bZJVQayQ.png align="left")

## **Email Notification Setup**

To send build notifications:

* Configured SMTP server settings in Jenkins.
    
* Enabled “Extended Email Notifications” in the pipeline for customizable HTML reports.
    

![](https://miro.medium.com/v2/resize:fit:875/1*onDPD1yCTYr03bDWIyCNZg.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*v--rsG5ZDMh01iSzX_I__g.png align="left")

## **Step 2: Implementing the Jenkins CI/CD Pipeline**

![](https://miro.medium.com/v2/resize:fit:875/1*Q0QgvkXm1DU_6K_BslEB0w.png align="left")

```bash
pipeline{
    
    agent any
    
    tools{
        jdk 'jdk17'
        nodejs 'nodejs16'
    }
    
    environment{
        SONAR_HOME = tool 'sonar-scanner'
    }
    
    stages{
    
        stage('Clean Workspace'){
            steps{
                cleanWs()
            }
        }
    
        stage('Git Checkout'){
            steps{
                git branch: 'main', credentialsId: 'git-credential', url: 'https://github.com/harsh2478/Prime-Video-Clone-Deployment.git'
            }
        }
        
        stage('Sonarqube Analysis'){
            steps{
                withSonarQubeEnv('sonar-scanner'){
                    sh '$SONAR_HOME/bin/sonar-scanner -Dsonar.projectKey=amazonprime -Dsonar.projectName=amazonprime'
                }
            }
        }
        
        stage("Quality Gate"){
            steps{
                script{
                    waitForQualityGate abortPipeline: false, credentialsId: 'sonar-token'
                }
            }
        }
        
        stage("Installing Dependecies"){
            steps{
                sh 'npm install'
            }
        }
        
        stage("Trivy scan"){
            steps{
                sh 'trivy fs . > trivy-output.txt'
            }
        }
        
        stage("Build Docker Image") {
            steps {
                script {
                    withDockerRegistry(credentialsId: 'docker-cred') {
                        sh 'docker build -t kanha05/amazon-prime:$BUILD_NUMBER .'
                    }
                }
            }
        }
        
        stage("Push Docker Image"){
            steps {
                script {
                    withDockerRegistry(credentialsId: 'docker-cred') {
                        sh 'docker push kanha05/amazon-prime:$BUILD_NUMBER'
                    }
                }
            }
        }
        
        stage("Docker-Scout Image"){
            steps{
                script{
                    withDockerRegistry(credentialsId: 'docker-cred'){
                        sh 'docker-scout quickview kanha05/amazon-prime:$BUILD_NUMBER'
                        sh 'docker-scout cves kanha05/amazon-prime:$BUILD_NUMBER'
                        sh 'docker-scout recommendations kanha05/amazon-prime:$BUILD_NUMBER'
                    }
                }
            }
        }
        
        stage("Testing Deploy to Docker Container"){
            steps{
                script{
                    withDockerRegistry(credentialsId: 'docker-cred'){
                        sh 'docker run -d --name prime-video -p 3001:3000  kanha05/amazon-prime:$BUILD_NUMBER'   
                    }
                }
            }
        }
        
        stage("Deployment to Production"){
            environment {
                GIT_REPO_NAME = "Prime-Video-Clone-Deployment"
                GIT_USER_NAME = "harsh2478"
            }
            steps {
                withCredentials([string(credentialsId: 'git-cred', variable: 'GITHUB_TOKEN')]){
                    sh '''
                        git config user.email "harsh.hg2005@gmail.com"
                        git config user.name "Harsh Gupta"
                        BUILD_NUMBER=${BUILD_NUMBER}
                        cp Kubernetes-development/* K8S-Production/
                        sed -i "s/replaceImageTag/${BUILD_NUMBER}/g" K8S-Production/Deployment.yaml
                        git add K8S-Production/
                        git commit -m "Update Deployment Manifest for Production"
                        git push @github.com/${GIT_USER_NAME}/${GIT_REPO_NAME">https://${GITHUB_TOKEN}@github.com/${GIT_USER_NAME}/${GIT_REPO_NAME} HEAD:main
                    '''
                }
            }
        }
    }
    post {
    always {
        emailext attachLog: true,
            subject: "'${currentBuild.result}'",
            body: """
                <html>
                <body>
                    <div style="background-color: #FFA07A; padding: 10px; margin-bottom: 10px;">
                        <p style="color: white; font-weight: bold;">Project: ${env.JOB_NAME}</p>
                    </div>
                    <div style="background-color: #90EE90; padding: 10px; margin-bottom: 10px;">
                        <p style="color: white; font-weight: bold;">Build Number: ${env.BUILD_NUMBER}</p>
                    </div>
                    <div style="background-color: #87CEEB; padding: 10px; margin-bottom: 10px;">
                        <p style="color: white; font-weight: bold;">URL: ${env.BUILD_URL}</p>
                    </div>
                </body>
                </html>
            """,
            to: 'harsh.hg2005@gmail.com',
            mimeType: 'text/html',
            attachmentsPattern: 'trivy-output.txt'
        }
    }
}
```

## **Pipeline Stages**

The following pipeline stages were implemented:

1. **Clean Workspace:**  
    Ensures that each build starts with a clean slate to avoid conflicts.
    

```bash
cleanWs()
```

2\. **Git Checkout:**  
Clones the repository’s main branch using GitHub credentials.

```bash
git branch: 'main', credentialsId: 'git-credential', url: 'https://github.com/harsh2478/Prime-Video-Clone-Deployment.git'
```

3\. **SonarQube Analysis**  
Scans the codebase for bugs, vulnerabilities, and code smells using SonarQube.

```bash
withSonarQubeEnv('sonar-scanner') {
    sh '$SONAR_HOME/bin/sonar-scanner -Dsonar.projectKey=amazonprime -Dsonar.projectName=amazonprime'
}
```

4\. **Quality Gate**  
Waits for SonarQube’s quality gate results to ensure the code meets security and quality standards.

```bash
script {
    waitForQualityGate abortPipeline: false, credentialsId: 'sonar-token'
}
```

Quality gates in SonarQube are a set of conditions that determine if a project’s code meets the required quality level. With this step, we need to done one more step, i.e, adding a webhook in sonarqube.

When using webhooks in SonarQube and Jenkins, a webhook is configured in SonarQube to call back into Jenkins. This allows the pipeline to either continue or fail based on the results of the analysis.

Go to `Administration > Configuration > Webhooks.`

![](https://miro.medium.com/v2/resize:fit:875/1*p8BLVqdVMxUOIXQ-Q50rAQ.png align="left")

![](https://miro.medium.com/v2/resize:fit:868/1*JjQy0yQ_rTIMnp9LKtCbzw.png align="left")

**URL** \-&gt; `<Jenkins-URL>/sonarqube-webhook` .

5\. **Installing Dependencies:**  
Installs all application dependencies.

```bash
sh 'npm install'
```

6\. **Trivy Scan:**  
Performs a file system scan for vulnerabilities and outputs results to a file.

```bash
sh 'trivy fs . > trivy-output.txt'
```

7\. **Build Docker Image:**  
Builds a container image for the application with a unique tag.

```bash
withDockerRegistry(credentialsId: 'docker-cred') {
    sh 'docker build -t kanha05/amazon-prime:$BUILD_NUMBER .'
}
```

8\. **Push Docker Image:**  
Pushes the built image to DockerHub.

```bash
withDockerRegistry(credentialsId: 'docker-cred') {
    sh 'docker push kanha05/amazon-prime:$BUILD_NUMBER'
}
```

9\. **Docker Scout Image Analysis:**  
Utilizes Docker Scout for supply chain security, checking for:

* Vulnerabilities (CVEs).
    
* Recommendations for better security practices.
    

```bash
withDockerRegistry(credentialsId: 'docker-cred') {
    sh 'docker-scout quickview kanha05/amazon-prime:$BUILD_NUMBER'
    sh 'docker-scout cves kanha05/amazon-prime:$BUILD_NUMBER'
    sh 'docker-scout recommendations kanha05/amazon-prime:$BUILD_NUMBER'
}
```

10\. **Testing Deploy to Docker Container:**  
Deploys the container locally for functional testing.

```bash
withDockerRegistry(credentialsId: 'docker-cred') {
    sh 'docker run -d --name prime-video -p 3001:3000 kanha05/amazon-prime:$BUILD_NUMBER'
}
```

11\. **Deployment to Production:**  
Updates Kubernetes manifests with the latest image tag, commits them to GitHub, and triggers ArgoCD for deployment.

```bash
sed -i "s/replaceImageTag/${BUILD_NUMBER}/g" K8S-Production/Deployment.yaml
git add K8S-Production/
git commit -m "Update Deployment Manifest for Production"
git push ...
```

12\. **Post-Build Email Notifications:**  
Sends build status reports via email with logs and Trivy scan results.

## **Step 4: Setting Up Amazon EKS and ArgoCD**

### **Amazon EKS**

Provisioned a Kubernetes cluster using eksctl:

```bash
# Create Cluster
eksctl create cluster --name=<name> \
                      --region=<region-code> \
                      --zones=ap-south-1a,ap-south-1b \
                      --without-nodegroup 


# Get List of clusters
eksctl get cluster



# To enable and use AWS IAM roles for Kubernetes service accounts on our EKS cluster, we must create & associate OIDC identity provider.
eksctl utils associate-iam-oidc-provider \
    --region region-code \
    --cluster <cluter-name> \
    --approve  



# Create Public Node Group   
eksctl create nodegroup --cluster=amcdemo \
                       --region=us-east-1 \
                       --name=amcdemo-ng-public1 \
                       --node-type=t3.medium \
                       --nodes=2 \
                       --nodes-min=2 \
                       --nodes-max=4 \
                       --node-volume-size=20 \
                       --ssh-access \
                       --ssh-public-key=<public-key-name> \
                       --managed \
                       --asg-access \
                       --external-dns-access \
                       --full-ecr-access \
                       --appmesh-access \
                       --alb-ingress-access               
```

* Replace `<name>, <region-code>, <cluster-name>, <public-key-name>` with their appropriate values.
    

![](https://miro.medium.com/v2/resize:fit:875/1*4B0zxtsGfQdfVwkYIYWybg.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*z3G0eJnJRvwTQEQjh7_0ag.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*WY_mPar3FM6czGAl9J5yEQ.png align="left")

## **ArgoCD Deployment**

1. **Installed ArgoCD in the EKS cluster.**
    

```bash
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
```

![](https://miro.medium.com/v2/resize:fit:681/1*-T60pES6wk3kxVAJ9MFEig.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*jdZDaqsumNtps20Yu7I8Bg.png align="left")

* Access Dashboard by port-forwarding. Copy password first.
    

![](https://miro.medium.com/v2/resize:fit:875/1*iSZ-88bfuioPeN9NGtU0vw.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*tDQeR-TxWpdl-Fd0RVMkqQ.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*MYkHH6BR3PBjMEhl74LENg.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*kqq76TApEy6bSjh4EtmcOQ.png align="left")

**2\. Created an ArgoCD application pointing to the** `K8S-Production/` **folder in the GitHub repo.**

```bash
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: amazon-prime
  namespace: argocd
spec:
  project: default
  destination:
    server: 'https://kubernetes.default.svc'
    namespace: default
  source:
    repoURL: 'https://github.com/harsh2478/Prime-Video-Clone-Deployment.git'
    path: K8S-Production
    targetRevision: HEAD
```

![](https://miro.medium.com/v2/resize:fit:875/1*jnKrAvPocwgNJdG2jRdW4g.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*mDdBRkcGrupLD08LVSWFVw.png align="left")

# **Step 5: Create Dockerfile & Kubernetes Manifest.**

Create `Dockerfile, Deployment.yaml, Service.yaml` and push them to github repository.

## **Dockerfile:**

```bash
FROM node:alpine

# Create working directory
WORKDIR /app

# Copy package files to working directory
COPY *.json /app/

# Install the dependencies
RUN npm install

# Copy all the files on working directory 
COPY . /app/

# Expose the app on 3000 port number
EXPOSE 3000

# command to start app
CMD ["npm", "start"]
```

## **Deployment:**

```bash
apiVersion: apps/v1
kind: Deployment
metadata:
  name: amazon-prime
  namespace: default
  labels:
    app: prime-app
spec:
  selector:
    matchLabels:
      app: prime-app
  replicas: 2
  template:
    metadata:
      name: amazon-prime
      labels:
        app: prime-app
    spec:
      containers:
      - name: prime-container
        image: kanha05/amazon-prime:replaceImageTag
        ports:
        - containerPort: 3000
```

## **Service:**

```bash
apiVersion: v1
kind: Service
metadata:
  name: prime-service
  labels:
    app: prime-service
spec:
  selector:
      app: prime-app
  ports:
    - port: 3000
      targetPort: 3000
  type: LoadBalancer
```

## **Start Pipeline:**

![](https://miro.medium.com/v2/resize:fit:875/1*L25lHPuUk0oCx844-7ZIsQ.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*tXc9lTHV42UujOMqalLATQ.png align="left")

* Copy the hostname and see your application.
    

![](https://miro.medium.com/v2/resize:fit:875/1*02b5KhPml9INwMCVbpepbQ.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*UNHi1Xhvm6Cq6HH5W8IU2w.png align="left")

# **Step 6: Observability with Prometheus and Grafana**

## **Prometheus Setup**

1. Installed Prometheus on a dedicated VM.
    

* First, create a dedicated Linux user for Prometheus and download Prometheus:
    

```bash
sudo useradd --system --no-create-home --shell /bin/false prometheus
wget https://github.com/prometheus/prometheus/releases/download/v2.47.1/prometheus-2.47.1.linux-amd64.tar.gz
```

* Extract Prometheus files, move them, and create directories:
    

```bash
tar -xvf prometheus-2.47.1.linux-amd64.tar.gz
cd prometheus-2.47.1.linux-amd64/
sudo mkdir -p /data /etc/prometheus
sudo mv prometheus promtool /usr/local/bin/
sudo mv consoles/ console_libraries/ /etc/prometheus/
sudo mv prometheus.yml /etc/prometheus/prometheus.yml
```

* Set ownership for directories:
    

```bash
sudo chown -R prometheus:prometheus /etc/prometheus/ /data/
```

* Create a systemd unit configuration file for Prometheus:
    

```bash
sudo vim /etc/systemd/system/prometheus.service
```

* Add the following content to the `prometheus.service` file:
    

```bash
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target

StartLimitIntervalSec=500
StartLimitBurst=5

[Service]
User=prometheus
Group=prometheus
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --storage.tsdb.path=/data \
  --web.console.templates=/etc/prometheus/consoles \
  --web.console.libraries=/etc/prometheus/console_libraries \
  --web.listen-address=0.0.0.0:9090 \
  --web.enable-lifecycle

[Install]
WantedBy=multi-user.target
```

Here’s a brief explanation of the key parts in this `prometheus.service` file:

* `User` and `Group` specify the Linux user and group under which Prometheus will run.
    
* `ExecStart` is where you specify the Prometheus binary path, the location of the configuration file (`prometheus.yml`), the storage directory, and other settings.
    
* `web.listen-address` configures Prometheus to listen on all network interfaces on port 9090.
    
* `web.enable-lifecycle` allows for management of Prometheus through API calls.
    

Enable and start Prometheus:

```bash
sudo systemctl enable prometheus
sudo systemctl start prometheus
```

* Verify Prometheus’s status:
    

```bash
sudo systemctl status prometheus
```

You can access Prometheus in a web browser using your server’s IP and port 9090:

`http://<your-server-ip>:9090`

![](https://miro.medium.com/v2/resize:fit:875/1*6ACHk-cSMo8WfB8N6L9SQA.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*MClwvOINYbV3gDeW0ZGRbw.png align="left")

## **Configured node exporter to extract system-level metrics.**

* Create a system user for Node Exporter and download Node Exporter:
    

```bash
sudo useradd --system --no-create-home --shell /bin/false node_exporter
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz
```

* Extract Node Exporter files, move the binary, and clean up:
    

```bash
tar -xvf node_exporter-1.6.1.linux-amd64.tar.gz
sudo mv node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/
rm -rf node_exporter*
```

* Create a systemd unit configuration file for Node Exporter:
    

```bash
sudo vim /etc/systemd/system/node_exporter.service
```

* Add the following content to the `node_exporter.service` file:
    

```bash
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target

StartLimitIntervalSec=500
StartLimitBurst=5

[Service]
User=node_exporter
Group=node_exporter
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/node_exporter --collector.logind

[Install]
WantedBy=multi-user.target
```

* Enable and start Node Exporter:
    

```bash
sudo systemctl enable node_exporter
sudo systemctl start node_exporter
```

* Verify the Node Exporter’s status:
    

```bash
sudo systemctl status node_exporter
```

You can access Node Exporter metrics in Prometheus at `<your-server-ip>:9100`

## **Added Prometheus scraping jobs in ‘/etc/prometheus.yml’ for:**

1. **Node Exporter:**
    

```bash
- job_name: 'node_exporter'
    static_configs:
      - targets: ['localhost:9100']
```

**2\. Jenkins:**

```bash
- job_name: 'jenkins'
  metrics_path: '/prometheus'
  static_configs:
  - targets: ['<jenkins-ip>:8080']
```

* The metrics path will be `/metrics` if not mentioned.(By-default)
    

![](https://miro.medium.com/v2/resize:fit:875/1*pBCyppMiYbxnEUIxBH0AaA.png align="left")

* Check the validity of the configuration file:
    

```bash
promtool check config /etc/prometheus/prometheus.yml
```

* Reload the Prometheus configuration without restarting:
    

```bash
curl -X POST http://localhost:9090/-/reload
```

![](https://miro.medium.com/v2/resize:fit:875/1*ftkNt1GHMDrrmScVA39xYQ.png align="left")

* You can access Prometheus targets at:
    

`http://<your-prometheus-ip>:9090/targets`

![](https://miro.medium.com/v2/resize:fit:875/1*z0wgjhKvbeRDkoupIynsig.png align="left")

# **Grafana Dashboard**

1. **Installed Grafana on the same VM as Prometheus.**
    

* First, ensure that all necessary dependencies are installed:
    

```bash
sudo apt-get update
sudo apt-get install -y apt-transport-https software-properties-common
```

* Add the GPG key for Grafana:
    

```bash
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
```

* Add the repository for Grafana stable releases:
    

```bash
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
```

* Install Grafana:
    

```bash
sudo apt-get -y install grafana
```

* To automatically start Grafana after a reboot, enable the service:
    

```bash
sudo systemctl enable grafana-server
```

* Then, start Grafana:
    

```bash
sudo systemctl start grafana-server
```

* Verify the status of the Grafana service to ensure it’s running correctly:
    

```bash
sudo systemctl status grafana-server
```

* Open a web browser and navigate to Grafana using your server’s IP address. The default port for Grafana is 3000.
    

`http://<your-server-ip>:3000`

![](https://miro.medium.com/v2/resize:fit:875/1*m4fvmu2lvR38kShA6N13Rg.png align="left")

**2\. Configured Prometheus as a data source.**

![](https://miro.medium.com/v2/resize:fit:875/1*emlOjHpF26TmbQVaZh6x7w.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*Vi2YS7wsmvGvA5NTRS9ZLA.png align="left")

* Add Your Prometheus Server URL.
    

![](https://miro.medium.com/v2/resize:fit:875/1*gwd2bgMAO2ARw6iPISKUWQ.png align="left")

* Click on `Save`
    

![](https://miro.medium.com/v2/resize:fit:875/1*JNtc7PH1OFFsOvo0Cm7MCA.png align="left")

**3\. Created dashboards for:**

* **Jenkins CI/CD performance:**
    

![](https://miro.medium.com/v2/resize:fit:875/1*2UjHt_YZk2L2cfzx_RGWAg.png align="left")

* Paste the Jenkins Dashboard ID `9964`
    

![](https://miro.medium.com/v2/resize:fit:875/1*aD86YlHa7hbLXiS2WRwLaA.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*kygCs1PVEI17GcO6MJNNyA.png align="left")

* Now you can view your dashboard.
    

![](https://miro.medium.com/v2/resize:fit:875/1*WW2n1R5h2Eop7h0TdWgg3g.png align="left")

# **Monitor Kubernetes with Prometheus**

Prometheus is a powerful monitoring and alerting toolkit, and you’ll use it to monitor your Kubernetes cluster. Additionally, you’ll install the node exporter using Helm to collect metrics from your cluster nodes.

## **Install Node Exporter using Helm**

To begin monitoring your Kubernetes cluster, you’ll install the Prometheus Node Exporter. This component allows you to collect system-level metrics from your cluster nodes. Here are the steps to install the Node Exporter using Helm:

1. Add the Prometheus Community Helm repository:
    

```bash
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
```

2\. Create a Kubernetes namespace for the Node Exporter:

```bash
kubectl create namespace prometheus-node-exporter
```

3\. Install the Node Exporter using Helm:

```bash
helm install prometheus-node-exporter prometheus-community/prometheus-node-exporter --namespace prometheus-node-exporter
```

![](https://miro.medium.com/v2/resize:fit:875/1*OFuPmDVpCtDbAFChQ4zBEQ.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*OJvGZWNQL_BDSfhR9gwsSQ.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*2Ln7dwrd4B7V9ldgwrEyKA.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*N1M3rHxQlZwAlp6aa05T6w.png align="left")

4\. Create a `node-exporter-svc.yml` to expose the `prometheus-node-exporter` service, so that Kubernetes node can be add as job in prometheus.

```bash
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/instance: amazon-prime
  name: node-exporter
  namespace: prometheus-node-exporter
spec:
  ports:
    - name: node-exporter
      port: 9100
      protocol: TCP
      targetPort: 9100
  selector:
    app: node-exporter
  type: NodePort
```

* Push it on the github repository in `K8S-Production` path, so that argocd automatically deploy the resource in cluster.
    

![](https://miro.medium.com/v2/resize:fit:875/1*7iCpd50qnR-tooOmj_eeTQ.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*IrpsrZFmoCndbncrkoKHeA.png align="left")

5\. Update your Prometheus configuration (prometheus.yml) to add a new job for scraping metrics from k8S-nodeip:9001/metrics. You can do this by adding the following configuration to your prometheus.yml file:

```bash
  - job_name: 'kubernetes'
    metrics_path: '/metrics'
    static_configs:
      - targets: ['K8S-node1Ip:9100']
```

* Copy the K8s Node IP :
    

![](https://miro.medium.com/v2/resize:fit:875/1*q2yVR8Jr790Q-vZEp_qGgQ.png align="left")

* Paste it inside `/etc/prometheus.yml` file.
    

![](https://miro.medium.com/v2/resize:fit:715/1*zL05Dq-NmJvr7hk8RDxVMQ.png align="left")

* Metrics path will remain default one, i.e, `/metrics`
    
* Don’t forget to reload or restart Prometheus to apply these changes to your configuration.
    

```bash
curl -X POST http://localhost:9090/-/reload
```

![](https://miro.medium.com/v2/resize:fit:875/1*7v_a5hLarP1jPNLbsYLLrA.png align="left")

![](https://miro.medium.com/v2/resize:fit:875/1*oKfJe35vbiBRiWDKQGrXqA.png align="left")

# **Enhancing Security with Docker Scout: Key Concepts of DevSecOps Learned**

When implementing Docker Scout, I gained an in-depth understanding of several crucial DevSecOps concepts. Here’s the detailed walkthrough of what I learned, step by step, as I integrated and utilized Docker Scout for securing the supply chain:

## **1\. Understanding Application Composition**

While building the Amazon Prime Clone application, I realized that:

* One portion of the application is the code manually written by developers. This is typically authored in an IDE (Integrated Development Environment) and continuously analyzed for syntax errors, bugs, and other quality issues.
    
* The other portion consists of external libraries, modules, or dependencies fetched from external sources (e.g., npm). These libraries bring added functionality but are potential security risks.
    

## **2\. Security of Manual Code: SAST (Static Application Security Testing)**

For the code that developers write themselves, security is enforced through SAST tools like SonarQube.

* **What SAST does**: Scans for vulnerabilities, logical flaws, or unsafe code patterns in the source code.
    
* **Integration into CI/CD**: By running SAST during the pipeline, we ensure early detection of issues before the code reaches the build or deployment phase.
    

## **3\. Security of External Libraries: SCA (Software Composition Analysis)**

The more significant challenge lies in the external libraries, as we have limited control over their code. This is where SCA tools, like Docker Scout, come into play.

**Why is SCA important?**

* Every application depends on third-party libraries.
    
* These libraries themselves depend on other libraries (transitive dependencies).
    
* Any of these dependencies may contain vulnerabilities or be exposed to newly discovered Common Vulnerabilities and Exposures (CVEs).
    

For example:  
If your application uses Library A, and Library A internally uses Library B, then a vulnerability in Library B could expose your entire application to risk.

## **4\. Continuous Monitoring of Dependencies: CVE Checks**

Docker Scout helps detect vulnerabilities in both direct and transitive dependencies by continuously monitoring for CVEs.

* Why continuous checks?
    
* CVEs can be discovered anytime, even after deployment.
    
* A dependency considered safe today may be flagged tomorrow due to newly reported vulnerabilities.
    
* **Integration with CI/CD:** By integrating tools like Docker Scout into Jenkins, we can ensure vulnerabilities are caught early during the build stage.
    

## **5\. Principle of “Fail Early, Fail Fast”**

In DevSecOps, it is critical to catch issues as soon as possible to avoid downstream problems.

* Docker Scout aligns with this principle by scanning container images immediately after they are built in the pipeline.
    
* If vulnerabilities are found, the pipeline fails, alerting the developer to address the issue before proceeding.
    

For instance:  
If the `npm install` stage introduces a vulnerable dependency, Docker Scout will flag it during the "Build Docker Image" or "Docker Scout Image Analysis" stages.

## **6\. Supply Chain Attestation**

During the build phase, the focus shifts to supply chain security, which ensures that no vulnerabilities are introduced at the dependency level.

* How Docker Scout fits here:
    
* By analyzing the entire container image (application code + all dependencies), Docker Scout provides insights into potential risks.
    
* It generates a Software Bill of Materials (SBOM), a comprehensive list of all components, their versions, and metadata.
    

**SBOM serves as a vital document for:**

* Identifying vulnerabilities.
    
* Meeting compliance requirements.
    
* Ensuring transparency in the supply chain
    

## **7\. Workflow of Docker Scout in the Pipeline**

1. **Build Stage:**
    

* After the container image is built, Docker Scout scans it.
    
* Command Used:
    

```bash
docker-scout quickview kanha05/amazon-prime:$BUILD_NUMBER
```

* Provides an overview of image health, vulnerabilities, and security recommendations.
    

**2\. Vulnerability Analysis:**

* The next step involves identifying CVEs using:
    

```bash
docker-scout cves kanha05/amazon-prime:$BUILD_NUMBER
```

* Outputs a detailed report of all vulnerabilities detected, along with their severity (Critical, High, Medium, Low).
    

**3\. Remediation Suggestions:**

* Lastly, Docker Scout suggests best practices to mitigate risks:
    

```bash
docker-scout recommendations kanha05/amazon-prime:$BUILD_NUMBER
```

* For example, upgrading a library version or using a different base image with fewer vulnerabilities.
    

## **8\. Post-Build Runtime Security: DAST (Dynamic Application Security Testing)**

After deploying the container for functional testing, another layer of security is applied: **DAST.**

* **Why DAST?**: Vulnerabilities may be exposed only during runtime due to misconfigurations, insecure APIs, or unpatched exploits.
    
* **Integration into CI/CD:** DAST tools can analyze the running application, test its endpoints, and ensure no runtime vulnerabilities exist.
    

## **9\. Continuous Improvement with SBOM**

The SBOM generated by Docker Scout serves as a blueprint for improving supply chain security:

* **Proactive Vulnerability Checks:**  
    Security teams can use SBOM to periodically scan for newly disclosed CVEs.
    
* **Transparency and Compliance:**  
    SBOM ensures compliance with regulations like the Executive Order on Improving the Nation’s Cybersecurity.
    

## **10\. Shifting Security Left**

Docker Scout reinforces the Shift Left Principle in security:

**What it means:**

* Security practices are integrated early in the software development lifecycle, specifically during development and build stages.
    

**Benefits**:

* Reduces the cost of fixing vulnerabilities.
    
* Minimizes the risk of vulnerabilities reaching production.
    

**By integrating Docker Scout in the pipeline, security checks occur during:**

* Dependency installation.
    
* Image building.
    
* Post-build runtime testing.
    

## **11\. Real-Time Runtime Analysis**

After deploying the image, runtime vulnerabilities may emerge due to:

* Insecure API endpoints.
    
* Misconfigurations in Docker or Kubernetes.
    
* Exposure to external threats.
    

Tools like Trivy and Docker Scout can scan the running container to identify potential runtime risks, completing the DAST process.

## **12\. Developer Remediation Workflow**

When Docker Scout flags vulnerabilities:

* Developers receive detailed feedback, including:
    
* Vulnerable library versions.
    
* Suggested fixes or alternatives.
    
* Steps to update the dependencies.
    

Remediation Example:  
If `Library A v1.2.3` has a known CVE, Docker Scout might suggest upgrading to `Library A v1.3.0`.

* Developers update the dependency in `package.json`:
    

```bash
"dependencies": {
    "LibraryA": "^1.3.0"
}
```

* Rerun the pipeline to verify the vulnerability has been resolved.
    

## **Conclusion:**

Implementing a strong DevSecOps framework requires careful attention at every stage of the software lifecycle, from development to deployment and runtime. With tools like Docker Scout, we learned to secure the supply chain by analyzing application dependencies, ensuring vulnerabilities are identified and addressed early in the pipeline.

This integration not only focused on Static Application Security Testing (SAST) for code written by developers but also included Software Composition Analysis (SCA) for external libraries, addressing risks related to supply chain vulnerabilities. The Software Bill of Materials (SBOM) provided a crucial inventory of dependencies, allowing for proactive monitoring of newly disclosed CVEs and ensuring compliance with industry standards.

This pipeline is a complete implementation of modern software practices.
