An enterprise-grade DevSecOps repository showcasing security-hardened containerization and automated pipeline check gates for a modern React application using Gitleaks, Trivy, Nginx (Non-Root), and Cosign.
This project models secure "Shift-Left" software packaging by automatically scanning source code for secrets, auditing dependencies for vulnerabilities, verifying container image layers, and preparing cryptographic signatures before production release.
The diagram below details the automated verification stages executed on every commit to ensure no vulnerabilities or credentials bypass deployment gates:
graph TD
A[Developer Git Push] --> B(GitHub Actions Pipeline)
subgraph Parallel Scans
B --> C[Gitleaks: Secret Leak Scan]
B --> D[Trivy: Dependency SCA Scan]
end
C & D -->|All Passed| E[Docker Buildx: Compile Multi-Stage Image]
C & D -->|Any Failed| F[Block Build / Reject Commit]
E --> G[Trivy: Container OS Vulnerability Check]
G -->|Critical Vuln Found| F
G -->|0 Critical Vulns| H[Cosign: Cryptographic Image Signing]
H --> I[Safe to Deploy to Container Registry]
Running containers as root is one of the most common critical security findings in Kubernetes and cloud environments. If a hacker exploits a vulnerability in a root container, they can take over the host operating system.
This repository implements a fully hardened Nginx container with the following security features:
- The container runs under the default unprivileged
nginxuser (UID 101) instead ofroot. - Standard Nginx write paths are explicitly mapped and owned by the
nginxuser:RUN chown -R nginx:nginx /usr/share/nginx/html && \ chown -R nginx:nginx /var/cache/nginx && \ chown -R nginx:nginx /var/log/nginx && \ chown -R nginx:nginx /etc/nginx
- Unprivileged users cannot bind to ports below 1024. Nginx is configured to listen on port
8080rather than standard port80.
- Logs: System logs are redirected to standard output (
/dev/stdout) and standard error (/dev/stderr), aligning with cloud-native logging practices. - Tokens Disabled: Nginx is configured with
server_tokens offto disable outputting the Nginx version in HTTP headers, preventing hackers from searching for version-specific exploits. - Temp Write Path: Nginx's PID file is moved to
/tmp/nginx.pidso it can be written to without root credentials.
The Nginx configuration injects strict compliance headers:
X-Frame-Options: DENY(prevents clickjacking attacks).X-Content-Type-Options: nosniff(forces browsers to respect MIME types).X-XSS-Protection: 1; mode=block(mitigates cross-site scripting).- Content Security Policy (CSP): Restricts asset fetches strictly to the local origin and trusted fonts/styles.
Our GitHub Actions workflow (.github/workflows/devsecops-pipeline.yml) runs the following scanners on every push:
- Secret Scanning (Gitleaks): Scans git history to detect committed credentials, private keys, or API tokens.
- Software Composition Analysis (Trivy SCA): Audits npm packages in
package.jsonfor known vulnerabilities, alerting developers of high-risk libraries. - Container Image Scan (Trivy): Scans the layers of the compiled image for OS-level vulnerabilities (e.g. within Alpine base packages). If any
CRITICALvulnerability is found, the pipeline fails and blocks push. - Cosign Image Signing: Prepares keyless container signing (Sigstore/OIDC) to cryptographically prove image origin and integrity.
docker build -t devsecops-dashboard-app:latest .Run the container, binding port 8080 to your local machine:
docker run -d -p 8080:8080 --name secure-dashboard devsecops-dashboard-app:latestQuery the running container processes to prove it is executing under the unprivileged nginx user and not root:
docker exec secure-dashboard whoami
# Output should return: nginx
docker exec secure-dashboard id
# Output should return: uid=101(nginx) gid=101(nginx) groups=101(nginx)Open your browser and navigate to http://localhost:8080 to interact with the security audit dashboard.