Multi-node Kubernetes infrastructure with a fully automated DevSecOps CI/CD pipeline - IaC provisioning via Ansible, zero-CVE Trivy scanning, HashiCorp Vault dynamic secret injection, and Kubernetes self-healing.
- Infrastructure as Code - entire cluster provisioned with Ansible (idempotent, reproducible)
- CI/CD pipeline - GitHub Actions builds, scans, and deploys automatically on every push
- Zero-Trust security - no secrets stored in plaintext, dynamic injection via Vault at runtime
- Trivy scanning - image scanned before every build, 0 CVE enforced as a pipeline gate
- Self-healing - Kubernetes Liveness Probes auto-restart failed containers, cluster stays stable
| Layer | Technology |
|---|---|
| Provisioning | Ansible (IaC, idempotent playbooks) |
| Container runtime | Docker |
| Orchestration | Kubernetes v1.28 |
| CI/CD | GitHub Actions |
| Security scanning | Trivy |
| Secret management | HashiCorp Vault |
| OS | Ubuntu 24.04 LTS |
The entire cluster configuration (Master + 2 Workers) is managed by Ansible playbooks. No manual steps - infrastructure state is declared, not clicked.
The PLAY RECAP below confirms a clean deployment with perfect state synchronization across all three nodes.
The pipeline enforces a strict promotion model - each stage must pass before the next one starts. A vulnerability in the image blocks the entire pipeline before anything reaches production.
Before every build, the base image is scanned by Trivy. The pipeline only continues if the result is 0 CVE. Any vulnerability blocks deployment automatically.
The application is deployed via YAML manifests - desired state declared, Kubernetes enforces it:
During monitoring, CrashLoopBackOff events were detected - caused by VXLAN encapsulation overhead from the Flannel CNI plugin under load.
Rather than a failure, this validated the self-healing mechanism: Kubernetes Liveness Probes detected the unhealthy containers and restarted them automatically, keeping the service available throughout.
No credentials are stored in plaintext - not in the repo, not in environment variables, not in Kubernetes Secrets as base64.
The application authenticates to Vault using its Kubernetes ServiceAccount. Vault returns the secret at runtime only to authorized pods. The screenshot below was taken directly from inside the application container - confirming live retrieval of api_key and db_password:
- 0 CVE on every build - enforced by Trivy as a hard pipeline gate
- Full cluster provisioned from zero with a single Ansible command
- No plaintext secrets anywhere in the codebase or cluster
- Self-healing validated under real failure conditions (CrashLoopBackOff recovery)
- End-to-end pipeline: push to deploy in a fully automated, auditable chain
k8s-devsecops-project/ ├── .github/workflows/ # GitHub Actions CI/CD pipeline ├── Dockerfile # Application container definition ├── deployment.yaml # Kubernetes Deployment + Service manifests └── index.html # Application frontend
Author: Sidali - Cloud Infrastructure & DevSecOps - 2026





