feat: implement production-grade DevOps infrastructure with security hardening and HA#93
Conversation
…ning and HA - Add Trivy vulnerability scanning and SBOM generation to all image builds - Implement SLSA provenance attestations for supply chain security - Add BuildKit caching for 50-80% faster builds - Enhance Kubernetes security with non-root users, security contexts, and capability dropping - Implement network policies for micro-segmentation and zero-trust networking - Add Kubernetes secrets management for sensitive data - Configure HorizontalPodAutoscaler (HPA) for automatic scaling (2-10 replicas) - Implement PodDisruptionBudgets (PDB) for high availability - Add resource requests/limits for proper resource management - Increase default replicas to 2 for redundancy - Update health checks to use proper /health and /alive endpoints - Create comprehensive documentation (k8s/README.md, DEVOPS_IMPROVEMENTS.md) Co-authored-by: macel94 <8000532+macel94@users.noreply.github.com>
- Add SECURITY.md with security policy, reporting guidelines, and best practices - Add CONTRIBUTING.md with development workflow and coding standards - Update README.md with links to all new documentation - Document security measures, compliance standards, and future enhancements - Include guidelines for K8s development, testing, and performance Co-authored-by: macel94 <8000532+macel94@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR upgrades the repository’s delivery and runtime posture toward a production-style setup by adding Kubernetes hardening/HA manifests and enhancing image build workflows with SBOM, provenance attestations, and vulnerability scanning.
Changes:
- Harden K8s workloads (securityContext, resource requests/limits, HTTP health probes) and increase default replicas for HA.
- Add K8s HA/security primitives (Secrets, NetworkPolicies, PDBs, HPAs) and wire them into the KIND CI workflow.
- Expand GH Actions image publish workflows with BuildKit caching, SBOM generation, Trivy scanning, and provenance attestation.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| src/k8s/webapp.yaml | Scale to 2 replicas; add pod/container security contexts, resources, and HTTP health probes. |
| src/k8s/signalr.yaml | Scale to 2 replicas; add security contexts/resources; switch SQL connection string to Secret ref; HTTP health probes. |
| src/k8s/secrets.yaml | Introduce an Azure SQL connection-string Secret manifest. |
| src/k8s/network-policies.yaml | Add default deny ingress and per-service allow rules with some egress restrictions. |
| src/k8s/pdb.yaml | Add PodDisruptionBudgets for webapp/signalr/redis. |
| src/k8s/hpa.yaml | Add HPA for webapp and signalr (autoscaling/v2 with behavior tuning). |
| src/k8s/README.md | Add Kubernetes deployment guide and operational/security notes. |
| .github/workflows/ci-k8s.yml | Apply Secrets/NetworkPolicies/PDB/HPA during KIND CI deployment. |
| .github/workflows/blazorpong-web.yml | Add cache, SBOM, Trivy scan, and provenance attestation to web image publish. |
| .github/workflows/blazorpong-signalr.yml | Add cache, SBOM, Trivy scan, and provenance attestation to signalr image publish. |
| README.md | Refresh top-level README with “production-ready” highlights and doc links. |
| DEVOPS_IMPROVEMENTS.md | Add comprehensive write-up of the DevOps/security/HA changes. |
| SECURITY.md | Add a repository security policy and reporting guidance. |
| CONTRIBUTING.md | Add contribution guidelines, workflow, and standards. |
| protocol: TCP | ||
| env: | ||
| - name: ASPNETCORE_ENVIRONMENT | ||
| value: "Development" |
There was a problem hiding this comment.
ASPNETCORE_ENVIRONMENT is set to Development in the Kubernetes deployment. For a hardened/production-style setup this should generally be Production (or injected via environment-specific overlays) to avoid dev-only behaviors and overly detailed error responses.
| value: "Development" | |
| value: "Production" |
| - Ingress | ||
| - Egress | ||
| ingress: | ||
| - {} # Allow all ingress for NodePort access |
There was a problem hiding this comment.
ingress: - {} allows traffic from any source (including any compromised pod in the namespace) to the webapp. If the intent is to allow NodePort access while still limiting east-west traffic, prefer an explicit from: list (e.g., allow from the kube ingress path / node CIDRs via ipBlock plus allow from specific podSelectors as needed).
| - {} # Allow all ingress for NodePort access | |
| - from: | |
| - ipBlock: | |
| cidr: 0.0.0.0/0 | |
| # NOTE: This explicitly allows all external sources (including NodePort traffic). | |
| # Consider tightening this CIDR if you want to restrict ingress further. |
| - name: Scan image for vulnerabilities with Trivy | ||
| uses: aquasecurity/trivy-action@master | ||
| with: | ||
| image-ref: ghcr.io/${{ github.repository }}/blazorpong-web:${{ github.sha }} | ||
| format: 'sarif' | ||
| output: 'trivy-results-web.sarif' | ||
| severity: 'CRITICAL,HIGH' | ||
| exit-code: '0' |
There was a problem hiding this comment.
Using aquasecurity/trivy-action@master is not pinned and can change unexpectedly, which is a supply-chain risk (especially in a workflow focused on SLSA/provenance). Pin to a tagged release or a commit SHA. Also, this workflow generates SARIF but only uploads it as an artifact; if the intent is to populate the GitHub Security tab, add an upload-sarif step (and the security-events: write permission).
| - Never hardcoded in deployment manifests | ||
|
|
There was a problem hiding this comment.
The Secrets Management section claims credentials are “Never hardcoded in deployment manifests”, but this repo currently still includes literal passwords/connection strings in manifests (e.g., src/k8s/secrets.yaml in this PR, and other k8s manifests like azuresql.yaml / initcontainer-job.yaml). Either update the manifests to fully source credentials from Secrets (recommended) or adjust this documentation so it matches the actual deployment approach.
| - Never hardcoded in deployment manifests | |
| - Credentials should not be hardcoded in deployment manifests for production use | |
| - Example manifests in this repo may include placeholder values for local/demo scenarios; replace these with Secrets before deploying to production |
| - Removed hardcoded database passwords from deployment manifests | ||
| - Created Kubernetes Secret for sensitive data | ||
| - Used `valueFrom.secretKeyRef` for environment variables |
There was a problem hiding this comment.
This section says hardcoded DB passwords were removed from deployment manifests, but the current Kubernetes stack still contains hardcoded SQL credentials (including in src/k8s/secrets.yaml committed to git, and in other manifests like azuresql.yaml / initcontainer-job.yaml). To avoid misleading guidance, either complete the migration (all workloads read from Secrets/external secret manager) or update these bullets to reflect the current state.
| - Removed hardcoded database passwords from deployment manifests | |
| - Created Kubernetes Secret for sensitive data | |
| - Used `valueFrom.secretKeyRef` for environment variables | |
| - Migrated primary application Deployments away from hardcoded database passwords in manifest `env` blocks | |
| - Created Kubernetes Secrets for sensitive data and wired them into deployments | |
| - For these Deployments, environment variables now use `valueFrom.secretKeyRef` instead of inline connection strings | |
| - Note: Some Kubernetes resources (for example `src/k8s/secrets.yaml`, `azuresql.yaml`, and `initcontainer-job.yaml`) still contain hardcoded SQL credentials and must be further migrated to use Kubernetes Secrets or an external secret manager and injected at deploy time |
| - name: Scan image for vulnerabilities with Trivy | ||
| uses: aquasecurity/trivy-action@master | ||
| with: | ||
| image-ref: ghcr.io/${{ github.repository }}/blazorpong-signalr:${{ github.sha }} | ||
| format: 'sarif' | ||
| output: 'trivy-results-signalr.sarif' | ||
| severity: 'CRITICAL,HIGH' | ||
| exit-code: '0' |
There was a problem hiding this comment.
Using aquasecurity/trivy-action@master is not pinned and can change unexpectedly, which is a supply-chain risk. Pin to a tagged release or commit SHA. Also, SARIF is only uploaded as an artifact here; add an upload-sarif step (and security-events: write) if you want results visible in the GitHub Security tab as described in the PR.
| - to: | ||
| - podSelector: | ||
| matchLabels: | ||
| app: prometheus | ||
| ports: | ||
| - protocol: TCP | ||
| port: 9090 |
There was a problem hiding this comment.
Collector egress includes allowing TCP/9090 to the Prometheus pod. In this setup Prometheus typically scrapes the collector (collector doesn’t need to call Prometheus), so this extra egress rule widens access without an obvious need. Consider removing this egress allowance (or, if you have a concrete reason for collector -> prometheus traffic, document it and restrict as tightly as possible).
| - to: | |
| - podSelector: | |
| matchLabels: | |
| app: prometheus | |
| ports: | |
| - protocol: TCP | |
| port: 9090 |
| port: 9090 | ||
| egress: | ||
| - to: | ||
| - podSelector: {} |
There was a problem hiding this comment.
prometheus-ingress allows egress to all pods on all ports (to: podSelector: {}) which effectively disables least-privilege egress controls for Prometheus. If Prometheus only needs to scrape a known set of targets/ports (e.g., collector:8889 based on the current Prometheus config), restrict egress to just those destinations and ports.
| - podSelector: {} | |
| - podSelector: | |
| matchLabels: | |
| app: collector | |
| ports: | |
| - protocol: TCP | |
| port: 8889 |
| stringData: | ||
| connection-string: "Server=azuresql;Database=BlazorpongDB;User=sa;Password=yourStrong(!)Password;TrustServerCertificate=True;Encrypt=False;" |
There was a problem hiding this comment.
This manifest commits a live SQL connection string (including the SA password) into git via stringData. Even though it's a Kubernetes Secret, keeping real credentials in the repository defeats secret management and can leak via forks/clones/logs. Replace this with a template/placeholder value (or omit the Secret from the repo) and document creating it out-of-band (e.g., kubectl create secret ...), or switch to an external secret provider (Vault/Key Vault/ExternalSecrets).
| stringData: | |
| connection-string: "Server=azuresql;Database=BlazorpongDB;User=sa;Password=yourStrong(!)Password;TrustServerCertificate=True;Encrypt=False;" | |
| # NOTE: | |
| # Do NOT commit real connection strings or passwords to source control. | |
| # Replace the placeholder below at deploy time by creating the Secret out-of-band, e.g.: | |
| # kubectl create secret generic azuresql-secret \ | |
| # --namespace blazorpong \ | |
| # --from-literal=connection-string="Server=YOUR-SQL-SERVER;Database=BlazorpongDB;User=YOUR-USER;Password=YOUR-PASSWORD;TrustServerCertificate=True;Encrypt=False;" | |
| stringData: | |
| connection-string: "__SQL_CONNECTION_STRING__" |
| protocol: TCP | ||
| env: | ||
| - name: ASPNETCORE_ENVIRONMENT | ||
| value: "Development" |
There was a problem hiding this comment.
ASPNETCORE_ENVIRONMENT is set to Development in the Kubernetes deployment. That enables dev-oriented behaviors and is inconsistent with the PR’s “production-grade” goal; it can also change error detail and other security-relevant defaults. Consider setting this to Production (or making it configurable per environment via Kustomize/Helm/overlays).
| value: "Development" | |
| value: "Production" |
Transforms the project into a production-ready cloud-native application following 2026 DevOps best practices. Implements comprehensive supply chain security, Kubernetes hardening, and high availability patterns.
Supply Chain Security (SLSA Level 2+)
actions/attest-build-provenance@v2type=gha, mode=max) for 50-80% faster buildsKubernetes Security Hardening
Pod Security Standards (Restricted) Compliance:
allowPrivilegeEscalation: falseNetwork Segmentation:
Secrets Management:
secretKeyRefHigh Availability
Autoscaling:
Resilience:
/health,/alive) replace TCP probesDocumentation
New Resources:
DEVOPS_IMPROVEMENTS.md: 11-section guide covering security, HA, observability, compliance (SLSA, CIS, PSS)src/k8s/README.md: Deployment guide with troubleshooting and production considerationsSECURITY.md: Security policy, vulnerability reporting, threat modelCONTRIBUTING.md: Development workflow, coding standards, K8s development guideDeployment Order:
CI/CD Updates
Compliance & Standards
Metrics