DevSecOps CICD Pipelines with EKS deployment using ArgoCD


1. Application Layer
Frontend → Built with React.js
Backend → Built with Node.js
Database → Uses MongoDB
Repository → Code is stored and version-controlled in GitHub
This is the actual application stack that the DevSecOps pipeline will deploy.
2. Master Machine (Provisioning & Infrastructure as Code)
Uses Terraform to set up cloud resources.
IAM, Key Pairs, Security Groups → Handle authentication, authorization, and secure access.
Master Machine (EC2 t2.large) → The main control node for provisioning infrastructure.
3. Kubernetes Cluster (EKS on AWS)
Terraform provisions an EKS (Elastic Kubernetes Service) cluster.
Takes ~20 minutes to set up.
Node 1 & Node 2 → Worker nodes where the application containers will actually run.
Kubernetes (K8s) manages scaling, deployments, and networking.
4. DevSecOps Pipeline
Jenkins → CI/CD pipeline automation.
Trivy → Container vulnerability scanning.
OWASP Dependency-Check → Scans code dependencies for security issues.
SonarQube → Code quality and bug detection.
Docker → Builds application images.
Mail Notification → Alerts developers about pipeline results.
This ensures secure, automated builds and deployments.
5. GitOps Workflow
Developers push code to GitHub Repo.
ArgoCD continuously syncs GitHub with the Kubernetes cluster (GitOps model).
This ensures deployments are automated and version-controlled.
6. Monitoring & Observability
Prometheus → Metrics collection (CPU, memory, latency, etc.)
Grafana → Dashboards and visualizations.
Helm → Package manager for Kubernetes, used to install Prometheus/Grafana.
This ensures the system is observable, reliable, and secure.
🔑 Abstract Summary
This architecture represents a DevSecOps-driven CI/CD pipeline for deploying a cloud-native application on AWS EKS:
Infrastructure automated by Terraform.
Security integrated with Trivy, OWASP, SonarQube.
Delivery automated using Jenkins + GitOps (ArgoCD).
Monitoring enabled with Prometheus & Grafana.
It combines DevOps + Security (Sec) + Cloud (AWS + K8s) + GitOps into a mega project pipeline.
GitHub link: https://github.com/bhagya-patel/DevOps-SPRINGBOOT-BANKAPP.git
step-01:- start with terraform
step- a:- install aws CLI
for this fist create a new user

Then attach the policies and grant administrative access.


click on user
Go to the Security Credentials section

then go to the access keys

create new branch in github

then go on vs code


create a new folder


now go to the terraform
Now, go there and create one.
Link
https://registry.terraform.io/providers/hashicorp/aws/latest/docs

here use provider

Now, create a variables.tf file to specify the region.

We are now using this variable, so we can apply it for this purpose.

Now we want a public key in the Terraform folder because it is used in EC2.tf.
so, we use ssh-keygen

If you want to make any changes, such as volume or tags, you can change them yourself.
If your Terraform version is old, go to the link below and download the latest version.
link:- https://developer.hashicorp.com/terraform/install

After downloading, extract it. To do this, double-click on the folder where you saved Terraform.

Then, you will see another folder. Go inside that folder

copy terraform


and paste it on your folder where you want to use terraform

Then write correct path of you terraform where you store it

then terraform init


then write terrraform plan


now create output.tf
inside this


now do terraform apply

step-02:- start with Docker
install Docker Extension

now find an image in DockerHub
Link:- https://hub.docker.com/search?q=maven+image

now create a docker file
✅ What is Maven?
Maven is a build automation tool used primarily for Java projects.
🔧 Its Main Purposes:
✅ Dependency Management:
Automatically downloads and manages the libraries (JAR files) your project depends on.✅ Build Automation:
Compile code, run tests, package applications, generate reports, and deploy artifacts.✅ Project Structure Standardization:
Encourages a standard project directory layout (likesrc/main/java,src/test/java, etc.).
✅ What is a JAR file?
🔹 JAR = Java ARchive
👉 The JAR file is the final product of the Maven build process.
It contains:
Your compiled code
All resources needed at runtime

Here, for the OS image, search on Google and download it
To run it, get the installation command from Google or the Maven installation site.

but here test cases are empty

so we have to write below

also give name of this stage


in this asked maven stored compiled java classes into “target” folder
We should copy only the generated JAR file from the target directory into the Docker image, so it can be run by the container.


now lets buid a docker file
first give correct path

before run please open Docker Desktop . if you do not open Docker desktop then it is not working

Here first we login Docker
now go on Docker Hub for login

go on account setting

inside this create a personal access token




HERE we also show this


now here we add terraform private key,lock file,terraform tfstate,terraform provider,licence in .gitignore
for this go into source code

double click on file





Now, to work on your EC2 instanc
open a gitbash

i found some error so i recreate the keys



successfully logined


now we do a docker ps

but it shows error


now it is successfully run

this code commit above where write mega-project has recent pushes. clicked on this compare & pull request
clone code





here i did a mistake i have to write Dockerfile instead of DockerFile


step-03:- start with EKS

Step:- 1 Create a Cluster
step a:- for this first install a CLIv2
Link:- https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

download for Liniux



step b:- for this first install a EKSctl
Link:- https://eksctl.io/installation/


copy this and create below for pate





Now open aws and search EKS


step c:- create a controler manager
before it note down that if you stop EC2 instance than take a new IPv4 . old ipv4 not worked


for checkout EKS latest version
so we take 1.33 version


it shows an error because we have not install kubectl. so we install kubectl
what is kubectl
kubectl is the command-line tool used to interact with a Kubernetes cluster. Think of it as the "remote control" for managing Kubernetes resources (pods, deployments, services, etc.).
link:- https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/


now working
now go on

here shows we had not add any node. so we add node but before add node we add IAM OIDC provider
🔑 What is an IAM OIDC Provider?
OIDC = OpenID Connect, an identity layer built on top of OAuth 2.0.
In AWS, an IAM OIDC identity provider allows you to federate identities from an OIDC-compatible IdP (like Kubernetes, Okta, Google, GitHub, etc.) to AWS.
Instead of managing IAM users/keys, you let external identities authenticate and assume IAM roles.
🚀 Why is it used?
EKS (Kubernetes on AWS)
In EKS, workloads (pods) need to access AWS services (like S3, DynamoDB, Secrets Manager).
Instead of storing AWS credentials inside pods, you configure an IAM OIDC provider for your cluster.
Then you create IAM roles for service accounts (IRSA) → Pods can assume those roles securely.
Federated Login
- You can allow users from an external IdP (Okta, Azure AD, Google, etc.) to assume AWS roles via OIDC.

here you show identity providers

now we create it


now we create a node group

it is not working again try


successfull

here we will not show control plan because in EKS it is managed by AWS



click on this and checkout


can you see two cluster


click on eksctl-bankapp-cluster-cluster


click on control panel security group id

click on this id

here you manage inbound rule and outbound rule
When you create a Kubernetes cluster through EKS, a personal VPC is also created automatically.


click on this id


ou have not created this template. For this, you can use tools such as the Serverless Framework.


if you want to create infrastructure on AWS lambda then use serverless
if you wan to create infrastructure on EKS then use eksctl
Step:- 2 Create a namespace,pod,deployment,service,ingress

Here, the BankApp also uses a database in the backend, so we created mysql-deployment.yml and mysql-service.yml

We also need to create secrets.yml, persistent-volume.yml, persistent-volume-claim.yml, configmap.yml, vpa.yml, and hpa.yml

now for this first install extension for kubernetes

let’s first create a backapp-namespace.yml
kind: Namespace
apiVersion: v1
metadata:
name: bankapp-namespace
labels:
app: bankapp-namespace

Now, let's create bankapp-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: bankapp-deploy
name: bankapp-deploy
namespace: bankapp-namespace
spec:
replicas: 2 # Keep replicas >= 2 for high availability
selector:
matchLabels:
app: bankapp-deploy
template:
metadata:
labels:
app: bankapp-deploy
spec:
containers:
- name: bankapp
image: bhagyapatel123/bankapp-eks:v2
ports:
- containerPort: 8080
env:
- name: SPRING_DATASOURCE_URL
valueFrom:
configMapKeyRef:
name: bankapp-config
key: SPRING_DATASOURCE_URL
- name: SPRING_DATASOURCE_USERNAME
valueFrom:
configMapKeyRef:
name: bankapp-config
key: SPRING_DATASOURCE_USERNAME
- name: MYSQL_DATABASE
valueFrom:
configMapKeyRef:
name: bankapp-config
key: MYSQL_DATABASE
- name: SPRING_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: SPRING_DATASOURCE_PASSWORD
# readinessProbe:
# httpGet:
# path: /actuator/health # Update this based on your app's health endpoint
# port: 8080
# initialDelaySeconds: 10
# periodSeconds: 5
# livenessProbe:
# httpGet:
# path: /actuator/health # Update this based on your app's health endpoint
# port: 8080
# initialDelaySeconds: 30
# periodSeconds: 10
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"

but before we have not publish docker images so, now we have publish a docker images

Here, we need to publish the Docker image, which means we have to push it to Docker Hub. However, it cannot be pushed directly.

now push it in docker hub


now bakapp-service.yml
apiVersion: v1
kind: Service
metadata:
name: bankapp-service
namespace: bankapp-namespace
labels:
app: bankapp
spec:
selector:
app: bankapp-deploy
ports:
- protocol: TCP
port: 8080
targetPort: 8080

now bankapp-ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bankapp-ingress
namespace: bankapp-namespace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/ssl-redirect: "true" # Force HTTPS
cert-manager.io/cluster-issuer: letsencrypt-prod # Use Let's Encrypt
spec:
ingressClassName: nginx
tls:
- hosts:
- megaproject.trainwithshubham.com
secretName: bankapp-tls-secret # Cert-Manager will manage this
rules:
- host: megaproject.trainwithshubham.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bankapp-service
port:
number: 8080

now mysql-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: bankapp-namespace
labels:
app: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0 # Use a specific, stable version for production
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_ROOT_PASSWORD
- name: MYSQL_DATABASE
valueFrom:
configMapKeyRef:
name: bankapp-config
key: MYSQL_DATABASE
volumeMounts:
- name: mysql-pv-storage
mountPath: /var/lib/mysql
subPath: mysql-data # Optional: Ensure a subdirectory is used for better volume organization
volumes:
- name: mysql-pv-storage
persistentVolumeClaim:
claimName: mysql-pvc

now mysql-service.yml
apiVersion: v1
kind: Service
metadata:
name: mysql-svc
namespace: bankapp-namespace
labels:
app: mysql
spec:
selector:
app: mysql
ports:
- protocol: TCP
port: 3306
targetPort: 3306

now secrets.yml
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
namespace: bankapp-namespace
type: Opaque
data:
MYSQL_ROOT_PASSWORD: VGVzdEAxMjM= # Base64 for "Test@123"
SPRING_DATASOURCE_PASSWORD: VGVzdEAxMjM= # Base64 for "Test@123"

now persistent-volume.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
namespace: bankapp-namespace
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain # Keeps the PV after the PVC is deleted
storageClassName: standard # Make sure this matches your cluster's default storage class
hostPath:
path: /mnt/data/mysql
type: DirectoryOrCreate

now persistent-volume-claim.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
namespace: bankapp-namespace
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard

now configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: bankapp-config
namespace: bankapp-namespace
data:
MYSQL_DATABASE: BankDB
SPRING_DATASOURCE_URL: jdbc:mysql://mysql-svc.bankapp-namespace.svc.cluster.local:3306/BankDB?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
SPRING_DATASOURCE_USERNAME: root

now hpa.yml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: bankapp-hpa
namespace: bankapp-namespace
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: bankapp-deploy
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 40

now do git commit










step-04:- start with ArgoCD
start it in cluster

now we have to download official arogocd manifest file



but please try below command


step -01:- now Download ArgoCDCLI
Link:- https://argo-cd.readthedocs.io/en/stable/cli_installation/



here we show argocd server is running on port 80
now we give address of argocd-server
which service type is which allows you to expose a port number ?
ans: NodePort (Here N and P both are capital letter)
so,

now you can see it becomes a NodePort

also you show new port number 30571. in this port your argocd server is running

Now, you have to edit the inbound rules for one worker node to allow port 30571. Since all nodes are connected to each other, any change made on one should also be applied to the others.


go in second one



now take a this worker node public IPV4 address


now we take is as http


also you see this
now go in advanced

now click on proceed

now it is working correctly
now for username and password
use username as “admin”
and password shows after below command


now it is successfully open

now in this go on Accounts


now go on user info

click on update password

now login





but in this it has a default cluster. i want to add my EKS cluster
for this first find a URL


this is my cluster URL. i want add this

now check it on GUI

successfully i created
now go to the repository

connect repo



now connect it

now create new application

click on new app

SYNS means automatically deploy when we change on github , prune resources means when new code comes old is deleted, self heal ,Auto-create namespace means if i forget to create namespace then it will automatically create it

revision means branch
path means where are kubernetes menifest file.
now this source manifest file in which cluster deploy for these we used a destination

now create it

click on these

it shows error. now check logs

i understand my problem here i take v2 and in docker image i take v1


successful





now in security group also add 32418 port

in this if you want than also add a range like 30000-32767



check this our bankapp correctly working
step-01:- register for domain


register domain





after that it will be created.
i don’t want so i don’t create this
but if you use domain then also change in ingress
in host we take a domain
step -2: kubernetes service.yml manifest file
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bankapp-ingress
namespace: bankapp-namespace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/ssl-redirect: "true" # Force HTTPS
cert-manager.io/cluster-issuer: letsencrypt-prod # Use Let's Encrypt
spec:
ingressClassName: nginx
tls:
- hosts:
- megaproject.trainwithshubham.com
secretName: bankapp-tls-secret # Cert-Manager will manage this
rules:
- host: megaproject.bhagyapatel.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bankapp-service
port:
number: 8080
but we have not domain then start manually

But to run these, you also need an Ingress controller. Here, we are using NGINX as the Ingress controller.


But before this, we need to add the controller. So first, install the NGINX controller.

now install nginx controler through helm
Link:- https://helm.sh/docs/intro/install/
first helm install
helm is package manager. through helm you deploy in cluster

now add it for this search command

Link:- https://artifacthub.io/packages/helm/ingress-nginx/ingress-nginx


now install ingress-nginx


successful


these is the ip of these


here you completely show nginx. it is not error. it shows nginx
now we will apply ingress


here we have not domain so we take svc URL. because it is free

so take these
so change inside these





successful
but here we show mot secure

now we convert it to https
means we do here SSL
step -03:- now we do cert manager
Cert-Manager is an open-source Kubernetes add-on that automates the management and issuance of TLS/SSL certificates.
🔑 What it does:
Automatically requests certificates from certificate authorities (CAs) like Let’s Encrypt, HashiCorp Vault, or custom CAs.
Renews certificates before they expire (so no downtime due to expired certs).
Stores certificates securely in Kubernetes secrets.
Makes it easy to enable HTTPS for your applications in Kubernetes.
LInk:- https://github.com/cert-manager/cert-manager

for downloads
Link:- https://cert-manager.io/docs/installation/


now i have to create cert-issuer


in github you shows name inside metadata
acme server means which server help issue these certificate
means server gives you certificate


inside these


we add these

it takes some time . it shows certificate detail

in this it shows these

now i check it


please copy all two file code ingress and certificate code
and change in github


but here i have not any Domain so TLB not working.
for TLB Domain name required
👉 Reason: Let’s Encrypt only issues certificates for valid domain names you control.
It will not issue for AWS ELB hostnames (they belong to Amazon, not you). That’s why your cert is stuck in False.

here i requested but it is not issued


now it shows these error so go back






now correctly working
step-05:- start with Jenkins
LINK:- https://www.jenkins.io/doc/book/installing/linux/

first inatallation java


then take these

Jenkins by default running on 8080 port number.
and also our bank app is running on same port numer.
so ,



change these port number 8080 to 8081



here also shows admin password

here we install jenkins into t2.large server

so add inside rule in t2.large


take public ip
using these jenkins server you build a Docker
through Argocd upload manifest






now create job

click on pipeline



before writing full pipeline add credential for docker hub . it is help when we try to push


now go on setting

then go to the credential

now click on global

add credential


click bankapp-ci
and go in configure
pipeline {
agent any
stages {
stage("Code Clone") {
steps {
git url: 'https://github.com/bhagya-patel/DevOps-SPRINGBOOT-BANKAPP.git', branch: 'mega-project'
}
}
stage("Build") {
steps {
sh 'docker build -t bankapp-eks:v1 .'
}
}
stage("Push") {
steps {
withCredentials([usernamePassword(
credentialsId: 'dockerHub',
usernameVariable: 'dockerHubUser',
passwordVariable: 'dockerHubPassword'
)]) {
sh 'docker login -u $dockerHubUser -p $dockerHubPassword'
sh 'docker image tag bankapp-eks:v1 $dockerHubUser/bankapp-eks:v1'
sh 'docker push $dockerHubUser/bankapp-eks:v1'
}
}
}
}
}


save and apply


click on run button

it is failed checked in console output

but i take dockerfile code in main branch so i used main branch then it shows correct
pipeline {
agent any
stages {
stage("Code Clone") {
steps {
git url: 'https://github.com/bhagya-patel/DevOps-SPRINGBOOT-BANKAPP.git', branch: 'main'
}
}
stage("Build") {
steps {
sh 'docker build -t bankapp-eks:v1 .'
}
}
stage("Push") {
steps {
withCredentials([usernamePassword(
credentialsId: 'dockerHub',
usernameVariable: 'dockerHubUser',
passwordVariable: 'dockerHubPassword'
)]) {
sh 'docker login -u $dockerHubUser -p $dockerHubPassword'
sh 'docker image tag bankapp-eks:v1 $dockerHubUser/bankapp-eks:v1'
sh 'docker push $dockerHubUser/bankapp-eks:v1'
}
}
}
}
}


done
step-06:- start with SonarQube


now we add sonarqube in t2.large inbound rules



now it is working
in this initially password is admin and user is also admin


go in administration

i want to sonar qube communate with jenkins. for these

click on user

now update tokens for communate with jenkins
write name and click on generate. then it is generate

now go in jenkins credential


clicked on global of Stores scoped to Jenkins

add credentials


first install sonar plugging


install it

now integret with jenkins for these

click on system

here add sonar qube server

take like these sonar URL

save then
Now we have to install sonarqube version

now go into the tools

step-06:- start with trivy




add this into jenkins pipeline

save it
when jenkins pipeline running then also sonarqube running . for these webHook requiered

click on webHooks

click on create
take jenkins URL. bul last add sonarqube-webhook.


secret is not required


sonar qube is not working correctly so i take only Trive

step-07:- start with observability






and now open it in t2.medium which is used before please open these



using these command you show password
and username is admin

successfully logined

here you show prometheus
go to your dashboard


if i want to monitor my pods then click on these


choose namespace as a bankapp-namespace


now delete cluster




successfully created these project