VPS & Server Security Guidelines
These guidelines define the mandatory infrastructure security baseline for every VPS, server, CI/CD tool, and object-storage service operated by Sadeem Informatique. They complement the Application Security Guidelines — application code can be perfectly secure and still be compromised through an unhardened server, an unencrypted internal tool, or a public storage bucket.
Any item marked Mandatory blocks a server or service from going into production use if not satisfied. Exceptions require written sign-off from the System Information Chief.
1. SSH & Server Access
Mandatory:
- Root login over SSH is disabled (
PermitRootLogin no). - Password authentication over SSH is disabled — key-based authentication only.
- Each engineer uses their own named account/key. Shared root or shared credentials are not permitted; access must be individually attributable.
sudoaccess is granted per person, on a least-privilege basis, and revoked immediately when someone leaves the project or the company.- Install and configure
fail2ban(or equivalent) to block repeated failed authentication attempts. - Keep the OS and all installed packages patched; enable automatic security updates where feasible.
When someone leaves the team, their SSH keys and access must be revoked the same day — not at the next audit.
2. Firewall & Network Exposure
Mandatory:
- A firewall (UFW, iptables, cloud security group, etc.) is active on every server, default-deny inbound.
- Only the ports actually required are open: typically
80/443for web traffic, and22for SSH restricted to known IPs/VPN where possible. - Internal services (databases, caches, message queues, admin/metrics ports) are never exposed directly to the public internet — they must sit behind the firewall/VPC and be reachable only from application servers or a VPN.
- Disable or firewall off any port opened by default by installed software that isn't actually needed (e.g., unused database ports, default dashboards).
3. TLS/SSL Everywhere — Jenkins, Subdomains & Internal Tools (Mandatory)
- Every URL served by Sadeem Informatique infrastructure must be served over HTTPS with a valid certificate — including Jenkins, staging environments, admin panels, monitoring dashboards, and any other subdomain, not just customer-facing production sites.
- This explicitly includes:
- Jenkins UI and Jenkins webhooks (
jenkins.*, or equivalent). - Staging, QA, and preview subdomains.
- Internal tools (monitoring, log dashboards, admin/backoffice panels, API docs left open in non-prod).
- Jenkins UI and Jenkins webhooks (
- Use a reverse proxy (Nginx, Traefik, Caddy) to terminate TLS, redirect all HTTP traffic to HTTPS, and set HSTS.
- Certificates are issued and auto-renewed (Let's Encrypt or internal CA) — no server should be running on an expired or self-signed-and-ignored certificate.
- "It's just an internal tool" is not a justification for plain HTTP: internal tools frequently hold credentials, build logs, and deployment secrets that are just as sensitive as production data.
An internal Jenkins instance or admin panel reachable over unencrypted HTTP leaks session cookies, credentials, and build secrets to anyone positioned on the network path. Treat this the same as a production TLS gap.
4. Jenkins & CI/CD Server Hardening
Mandatory:
- Jenkins is served exclusively over HTTPS (see §3).
- Anonymous read/access is disabled; matrix-based or role-based authorization is configured so users only see and trigger jobs relevant to them.
- CSRF protection (crumb issuer) is enabled.
- Jenkins and all plugins are kept up to date; unused plugins are removed to reduce attack surface.
- Credentials (deploy keys, API tokens, FTP/SSH passwords) are stored exclusively in the Jenkins Credentials Store (masked in logs), never hardcoded in
Jenkinsfiles, job configs, or shell scripts. - Build logs are reviewed to ensure secrets aren't accidentally printed to console output.
- Access to trigger production deployment jobs is restricted to authorized engineers/DevOps only.
5. Object Storage (S3 / MinIO) (Mandatory)
- Buckets containing sensitive data — user documents, invoices, ID scans, private uploads, database backups — must be private. Public-read is never the default.
- Access to private objects is granted through short-lived, signed/presigned URLs generated by the backend, not permanent public links or bucket-wide public ACLs.
- Public buckets are allowed only for genuinely public static assets (site logos, public marketing images) and must be a deliberate, documented, reviewed choice — not an oversight from leaving default settings in place.
- Access keys/service accounts for object storage follow least privilege: scope IAM policies per service/bucket rather than issuing account-wide admin keys.
- Rotate access keys periodically and immediately after any suspected exposure.
- Backups stored in object storage are encrypted at rest and access-restricted the same as production data; test restores periodically.
A MinIO or S3 bucket left with public-read (by default config or a copy-pasted policy) is one of the most common real-world data leaks. Verify bucket ACLs explicitly as part of every deployment checklist — do not assume the default is safe.
6. Secrets on Servers
- Secrets (API keys, DB credentials, signing keys) live in environment variables, a secrets manager, or the CI/CD secure variable store — never in plaintext files committed to the server's home directory or a world-readable path.
- Deployment scripts that must reference secrets read them from a vault/secret manager or protected environment file (
chmod 600, correct ownership) — never embed them inline in scripts checked into any repository. .envfiles on servers are excluded from backups that leave the secured environment, or are encrypted if included.
7. Docker & Container Hosts
- The Docker daemon socket is never exposed over the network without authentication/TLS.
- Containers do not run in
--privilegedmode unless there is a specific, documented need. - Container images for étatique/government projects are pulled from the organization's self-hosted/offline registry, consistent with the Application Security Guidelines §7.
- Unused images, volumes, and networks are pruned regularly to reduce stale attack surface.
8. Monitoring & Logging
- Centralize system and application logs (auth attempts, sudo usage, firewall drops, service errors) to a log aggregator, not just local disk.
- Alert on repeated failed SSH/login attempts, unexpected new admin accounts, and unusual outbound traffic.
- Monitor certificate expiry for every HTTPS endpoint, including internal tools, so renewals never lapse silently.
9. DevOps Delivery Checklist
Use this checklist before any server, VPS, or CI/CD tool is considered production-ready, and re-verify it on every infrastructure change.
- SSH: root login disabled, password auth disabled, key-only access,
fail2banactive. - Firewall is default-deny inbound; only required ports are open; internal services are not internet-facing.
- Jenkins and every subdomain (staging, admin, monitoring, internal tools) is served over HTTPS with a valid, auto-renewing certificate; HTTP is redirected to HTTPS.
- Jenkins: anonymous access disabled, CSRF protection enabled, credentials stored in the Credentials Store, plugins up to date.
- S3/MinIO buckets holding sensitive data are private; access is via signed URLs; any public bucket is explicitly reviewed and justified.
- Object storage access keys are scoped per service (least privilege), not account-wide admin keys.
- Secrets on servers are stored via environment variables/secret manager with restricted file permissions — never plaintext in a shared/world-readable path.
- Docker daemon socket is not exposed unauthenticated; containers avoid
--privilegedunless justified. - Étatique/government project containers and packages come from the self-hosted/offline registry.
- System and application logs are centralized; alerts exist for failed logins and certificate expiry.
- OS and installed packages are patched; automatic security updates are enabled where feasible.
- Individual, attributable access accounts exist for every engineer — no shared root/shared credentials.
Conclusion
Application-layer controls are only as strong as the infrastructure underneath them. Treat every server, every subdomain, and every storage bucket as part of the security perimeter — encrypt every URL, isolate every internal tool, lock down every bucket, and keep access individually attributable and least-privilege by default.
