diff --git a/.gitignore b/.gitignore index 549e00a2..660ed0da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -HELP.md +dockeHELP.md target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ @@ -31,3 +31,8 @@ build/ ### VS Code ### .vscode/ +terraform/.terraform.lock.hcl +terraform/bankapp-automate-key +terraform/.terraform/providers/registry.terraform.io/hashicorp/aws/6.13.0/windows_amd64/terraform-provider-aws_v6.13.0_x5.exe +terraform/terraform.tfstate +terraform/.terraform/providers/registry.terraform.io/hashicorp/aws/6.13.0/windows_amd64/LICENSE.txt diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..cc9d5b53 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# Stage 1 +FROM maven:3.8.3-openjdk-17 AS builder + +WORKDIR /src + +COPY . /src/ + +RUN mvn clean install -DskipTests=true + +# Stage 2 + +FROM openjdk:17-alpine + +COPY --from=builder /src/target/*.jar /src/target/bankapp.jar + +EXPOSE 8080 + +CMD ["java","-jar","/src/target/bankapp.jar"] \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..4b1c570b --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,39 @@ +pipeline{ + agent any; + + parameters { + string(name: 'IMAGE_VERSION', defaultValue: 'latest', description: 'Image tag') + } + stages{ + stage("Code Clone"){ + steps{ + git url: "https://github.com/himanshi1107/BankApp_DevSecOps_EKS.git", branch: "main" + } + } + stage("Trivy Scan"){ + steps{ + sh "trivy fs ." + } + } + stage("Build"){ + steps{ + sh "docker build -t bankapp-eks:${params.IMAGE_VERSION} ." + } + } + stage("Push"){ + steps{ + withCredentials([usernamePassword( + credentialsId: "dockerHub", + usernameVariable: "dockerHubUser", + passwordVariable: "dockerHubPass")]) { + sh ''' + docker login -u $dockerHubUser -p $dockerHubPass + docker image tag bankapp-eks:${IMAGE_VERSION} $dockerHubUser/bankapp-eks:${IMAGE_VERSION} + docker push $dockerHubUser/bankapp-eks:${IMAGE_VERSION} + ''' + } + + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 00000000..1989bf95 --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# 🏦 BankApp DevSecOps on AWS EKS using ArgoCD + +πŸš€ A **production-ready Bank Application** featuring **CI/CD, security, and observability** β€” deployed on **AWS EKS** using modern **DevSecOps practices**. + +--- + +## πŸ› οΈ Tech Stack + +- πŸ“‚ **GitHub** β†’ Code hosting & version control +- πŸ“¦ **Docker** β†’ Containerization +- πŸ”„ **Jenkins** β†’ Continuous Integration (CI) +- πŸ›‘οΈ **OWASP** β†’ Dependency vulnerability checks +- 🧹 **SonarQube** β†’ Code quality & static analysis +- πŸ” **Trivy** β†’ Filesystem & container image scanning +- πŸš€ **ArgoCD** β†’ Continuous Delivery (CD) +- ☸️ **AWS EKS** β†’ Kubernetes orchestration +- πŸ“œ **Helm** β†’ Manifest templating & deployment +- πŸ“Š **Grafana & Prometheus** β†’ Monitoring & visualization + +--- + +## πŸ“– Application Overview + +This project demonstrates **end-to-end automation** for deploying a **secure, scalable, and highly available Spring Boot–based banking application** on **AWS EKS**. + +βœ”οΈ Integrated quality checks +βœ”οΈ Vulnerability scanning +βœ”οΈ Monitored production environments +βœ”οΈ Security & compliance at every stage + +πŸ”— The architecture ensures **speed, reliability, and security** throughout the deployment lifecycle. + +--- + +## πŸ—οΈ Architecture + +Below is the high-level architecture of the project: + + Screenshot 2025-09-18 213408
+ +- **CI/CD**: Jenkins automates build, test, scan, and image push. +- **Security**: OWASP, SonarQube, and Trivy ensure code and container security. +- **CD**: ArgoCD automates deployment into AWS EKS. +- **Observability**: Prometheus collects metrics, Grafana provides dashboards. + +--- + +## ⚑ Requirements & Notes + +- 🌍 **Deployment Region** β†’ `us-east-1` (North Virginia) +- πŸ‘€ **AWS Access** β†’ Root account / IAM user with sufficient permissions +- πŸ”‘ **System Access** β†’ Requires `sudo` privileges +- πŸ”’ **Security Groups** β†’ Ensure ports are open as per reference screenshot +- πŸ–₯️ **Master Node** β†’ `t2.medium` (29GB storage) +- βš™οΈ **Pre-setup** β†’ AWS CLI, `kubectl`, and `eksctl` configured before cluster creation + +--- + +## πŸ“Έ Key Screenshots + +- πŸ’» **Application UI**

+ Screenshot 2025-09-17 143700 + +- ☸️ **AWS EKS Console**

+ Screenshot 2025-09-18 174939 + Screenshot 2025-09-18 174857 + +- πŸš€ **ArgoCD Dashboard**

+ Screenshot 2025-09-17 142928 + Screenshot 2025-09-18 174243 + Screenshot 2025-09-18 173731 + +- 🐳 **DockerHub Repository**

+ Screenshot 2025-09-18 174225 + +- βš™οΈ **Jenkins CI Pipeline**

+ Screenshot 2025-09-18 174058 + +- πŸ“Š **Grafana Monitoring**

+ Screenshot 2025-09-18 173310 + Screenshot 2025-09-18 173936 + Screenshot 2025-09-18 174022 + +--- + +✨ With this setup, you get a **bank-grade application** deployed with **modern DevSecOps practices** β€” combining **automation, security, and observability** on the cloud. + diff --git a/kubernetes/bankapp-deployment.yml b/kubernetes/bankapp-deployment.yml new file mode 100644 index 00000000..082a850b --- /dev/null +++ b/kubernetes/bankapp-deployment.yml @@ -0,0 +1,62 @@ +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: himanshi1107/bankapp-eks:v1 + 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" diff --git a/kubernetes/bankapp-hpa.yml b/kubernetes/bankapp-hpa.yml new file mode 100644 index 00000000..6c030161 --- /dev/null +++ b/kubernetes/bankapp-hpa.yml @@ -0,0 +1,19 @@ +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 diff --git a/kubernetes/bankapp-ingress.yml b/kubernetes/bankapp-ingress.yml new file mode 100644 index 00000000..528d9e07 --- /dev/null +++ b/kubernetes/bankapp-ingress.yml @@ -0,0 +1,28 @@ +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: + - himanshibankapp.duckdns.org + secretName: bankapp-tls-secret + rules: + - host: himanshibankapp.duckdns.org + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: bankapp-service + port: + number: 8080 diff --git a/kubernetes/bankapp-namespace.yml b/kubernetes/bankapp-namespace.yml new file mode 100644 index 00000000..d90656c1 --- /dev/null +++ b/kubernetes/bankapp-namespace.yml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: bankapp-namespace + labels: + name: bankapp-namespace \ No newline at end of file diff --git a/kubernetes/bankapp-service.yml b/kubernetes/bankapp-service.yml new file mode 100644 index 00000000..b09014a6 --- /dev/null +++ b/kubernetes/bankapp-service.yml @@ -0,0 +1,16 @@ + +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 + diff --git a/kubernetes/cert-issuer.yml b/kubernetes/cert-issuer.yml new file mode 100644 index 00000000..433992f0 --- /dev/null +++ b/kubernetes/cert-issuer.yml @@ -0,0 +1,16 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer + +metadata: + name: letsencrypt-prod + +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: himanshibobde@gmail.com + privateKeySecretRef: + name: letsencrypt-prod-key + solvers: + - http01: + ingress: + class: nginx diff --git a/kubernetes/configmap.yml b/kubernetes/configmap.yml new file mode 100644 index 00000000..67fd1ef4 --- /dev/null +++ b/kubernetes/configmap.yml @@ -0,0 +1,10 @@ + +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 diff --git a/kubernetes/mysql-deployment.yml b/kubernetes/mysql-deployment.yml new file mode 100644 index 00000000..8c0e3965 --- /dev/null +++ b/kubernetes/mysql-deployment.yml @@ -0,0 +1,41 @@ +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 \ No newline at end of file diff --git a/kubernetes/mysql-service.yml b/kubernetes/mysql-service.yml new file mode 100644 index 00000000..8a46c496 --- /dev/null +++ b/kubernetes/mysql-service.yml @@ -0,0 +1,14 @@ +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 \ No newline at end of file diff --git a/kubernetes/persistent-volume-claim.yml b/kubernetes/persistent-volume-claim.yml new file mode 100644 index 00000000..ec47c52f --- /dev/null +++ b/kubernetes/persistent-volume-claim.yml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mysql-pvc + namespace: bankapp-namespace +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: standard \ No newline at end of file diff --git a/kubernetes/persistent-volume.yml b/kubernetes/persistent-volume.yml new file mode 100644 index 00000000..6d56f7cf --- /dev/null +++ b/kubernetes/persistent-volume.yml @@ -0,0 +1,16 @@ +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 \ No newline at end of file diff --git a/kubernetes/secrets.yml b/kubernetes/secrets.yml new file mode 100644 index 00000000..a0642661 --- /dev/null +++ b/kubernetes/secrets.yml @@ -0,0 +1,10 @@ +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" + \ No newline at end of file diff --git a/terraform/Ec2.tf b/terraform/Ec2.tf new file mode 100644 index 00000000..72b321fa --- /dev/null +++ b/terraform/Ec2.tf @@ -0,0 +1,77 @@ +data "aws_ami" "os_image" { + owners = ["099720109477"] + most_recent = true + filter { + name = "state" + values = ["available"] + } + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd/*amd64*"] + } +} + +resource "aws_key_pair" "deployer" { + key_name = "bankapp-automate-key" + public_key = file("bankapp-automate-key.pub") +} + +resource "aws_default_vpc" "default" { + +} + +resource "aws_security_group" "allow_user_to_connect" { + name = "allow TLS" + description = "Allow user to connect" + vpc_id = aws_default_vpc.default.id + ingress { + description = "port 22 allow ssh" + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + description = " allow all outgoing traffic " + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + description = "port 80 allow http" + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + description = "port 443 allow https" + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = "bankapp_security" + } +} + +resource "aws_instance" "testinstance" { + ami = data.aws_ami.os_image.id + instance_type = var.my_enviroment == "prd" ? "t2.medium" : "t2.micro" + key_name = aws_key_pair.deployer.key_name + security_groups = [aws_security_group.allow_user_to_connect.name] + tags = { + Name = "BankApp_Automation_Server" + } + root_block_device { + volume_size = 30 + volume_type = "gp3" + } + +} \ No newline at end of file diff --git a/terraform/bankapp-automate-key.pub b/terraform/bankapp-automate-key.pub new file mode 100644 index 00000000..3a3d5466 --- /dev/null +++ b/terraform/bankapp-automate-key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDBFC8bY7ZvV+2qbosgZ7P4IDJnjLZmd4J4TdnKmitZ9 himan@Himanshi diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 00000000..e69de29b diff --git a/terraform/terraform.tf b/terraform/terraform.tf new file mode 100644 index 00000000..6c128499 --- /dev/null +++ b/terraform/terraform.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "6.13.0" + } + } +} + +provider "aws" { + # Configuration options + region = var.aws_region +} \ No newline at end of file diff --git a/terraform/utputs.tf b/terraform/utputs.tf new file mode 100644 index 00000000..e1b4e4fe --- /dev/null +++ b/terraform/utputs.tf @@ -0,0 +1,7 @@ +output "arn" { + value = aws_instance.testinstance.arn +} + +output "public_ip" { + value = aws_instance.testinstance.public_ip +} \ No newline at end of file diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 00000000..2c6bd730 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,19 @@ +variable "aws_region" { + description = "AWS region where resources will be provisioned" + default = "us-east-1" +} + +variable "ami_id" { + description = "AMI ID for the EC2 instance" + default = "ami-085f9c64a9b75eed5" +} + +variable "instance_type" { + description = "Instance type for the EC2 instance" + default = "t2.large" +} + +variable "my_enviroment" { + description = "Instance type for the EC2 instance" + default = "dev" +} \ No newline at end of file