Database Security Best Practices for Cloud Hosting Environments

Database Security in the Cloud Era
Cloud-hosted databases face a unique threat landscape. Unlike on-premise setups where physical access controls provide a layer of security, cloud databases are accessible over the network by default. A misconfigured database on a ServerRaja Cloud VPS can be discovered and exploited within hours of deployment by automated scanning bots.
This guide covers defense-in-depth security practices for MySQL and PostgreSQL, organized from the most critical controls to advanced hardening techniques.
Principle 1: Network Isolation
The first line of defense is ensuring your database is not accessible from the public internet.
Bind to Localhost
# MySQL: /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 127.0.0.1# PostgreSQL: /etc/postgresql/16/main/postgresql.conf listen_addresses = 'localhost' ```
If your application runs on the same VPS, this is sufficient. If you need remote access from application servers, use a private VLAN or SSH tunnel.
Firewall Rules
# Using UFW on Ubuntu
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow from 10.0.1.0/24 to any port 5432 # PostgreSQL from private subnet
sudo ufw allow from 10.0.1.0/24 to any port 3306 # MySQL from private subnet
sudo ufw enable# Verify rules sudo ufw status verbose ```
SSH Tunneling for Remote Access
# From application server, create an SSH tunnel
ssh -L 5432:localhost:5432 user@database-server-ip -N -f# Now connect to localhost:5432 on the application server psql -h localhost -U appuser -d mydb ```
Principle 2: Strong Authentication
MySQL Authentication Hardening
-- Remove anonymous users
DELETE FROM mysql.user WHERE User = '';-- Remove remote root access DELETE FROM mysql.user WHERE User = 'root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
-- Require strong passwords INSTALL COMPONENT 'file://component_validate_password'; SET GLOBAL validate_password.length = 16; SET GLOBAL validate_password.mixed_case_count = 1; SET GLOBAL validate_password.number_count = 1; SET GLOBAL validate_password.special_char_count = 1;
-- Create application user with minimal privileges CREATE USER 'appuser'@'10.0.1.%' IDENTIFIED BY 'V3ryStr0ng!AppP@ssw0rd'; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'appuser'@'10.0.1.%'; FLUSH PRIVILEGES; ```
PostgreSQL Authentication Hardening
# pg_hba.conf - Restrict authentication methods
# TYPE DATABASE USER ADDRESS METHOD
local all postgres peer
host mydb appuser 10.0.1.0/24 scram-sha-256
host all all 0.0.0.0/0 reject
-- Create application user with limited privileges
CREATE USER appuser WITH PASSWORD 'V3ryStr0ng!AppP@ssw0rd';
GRANT CONNECT ON DATABASE mydb TO appuser;
GRANT USAGE ON SCHEMA public TO appuser;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO appuser;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO appuser;-- Never use 'trust' authentication in production -- Use 'scram-sha-256' (PostgreSQL 10+) or 'md5' at minimum ```
Principle 3: Encryption in Transit
Enable TLS for MySQL
# Generate SSL certificates
sudo mysql_ssl_rsa_setup --uid=mysql# Verify SSL is active mysql -e "SHOW VARIABLES LIKE '%ssl%';" ```
# my.cnf
[mysqld]
require_secure_transport = ON
ssl-ca = /var/lib/mysql/ca.pem
ssl-cert = /var/lib/mysql/server-cert.pem
ssl-key = /var/lib/mysql/server-key.pem
Enable TLS for PostgreSQL
# Generate self-signed certificates (for production, use CA-signed)
cd /var/lib/postgresql/16/mainopenssl req -new -x509 -days 365 -nodes -text \ -out server.crt -keyout server.key \ -subj "/CN=db-server"
chmod 600 server.key chown postgres:postgres server.crt server.key ```
# postgresql.conf
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
ssl_min_protocol_version = 'TLSv1.2'
ssl_ciphers = 'HIGH:!aNULL:!MD5'
Principle 4: Encryption at Rest
Full Disk Encryption
ServerRaja Cloud VPS supports LUKS full-disk encryption during provisioning. This protects data if physical media is compromised.
Application-Level Encryption
For sensitive columns (PII, financial data), encrypt at the application layer:
from cryptography.fernet import Fernet
import base64
import hashlibdef encrypt_field(value, key): """Encrypt a database field value""" k = base64.urlsafe_b64encode(hashlib.sha256(key.encode()).digest()) f = Fernet(k) return f.encrypt(value.encode()).decode()
def decrypt_field(encrypted, key): k = base64.urlsafe_b64encode(hashlib.sha256(key.encode()).digest()) f = Fernet(k) return f.decrypt(encrypted.encode()).decode()
# Usage cipher_text = encrypt_field("1234-5678-9012-3456", SECRET_KEY) # Store cipher_text in the database ```
PostgreSQL also supports column-level encryption via `pgcrypto`:
CREATE EXTENSION pgcrypto;-- Encrypt sensitive data INSERT INTO customers (name, ssn) VALUES ('Rahul', pgp_sym_encrypt('123-45-6789', 'encryption_key'));
-- Decrypt when needed SELECT name, pgp_sym_decrypt(ssn::bytea, 'encryption_key') AS ssn FROM customers WHERE name = 'Rahul'; ```
Principle 5: Audit Logging
MySQL Audit Plugin
-- Enable audit logging (MySQL Enterprise or Percona Server)
INSTALL PLUGIN audit_log SONAME 'audit_log.so';
SET GLOBAL audit_log_policy = 'ALL';
For MySQL Community Edition, use the general query log for basic auditing:
# my.cnf
general_log = 1
general_log_file = /var/log/mysql/audit.log
PostgreSQL Audit Logging with pgAudit
sudo apt install postgresql-16-pgaudit
# postgresql.conf
shared_preload_libraries = 'pgaudit'
pgaudit.log = 'ddl, role, write'
pgaudit.log_catalog = on
pgaudit.log_parameter = on
-- Enable for specific users
ALTER USER appuser SET pgaudit.log = 'all';
Principle 6: Regular Security Updates
# Automate security updates on Ubuntu
sudo apt install unattended-upgrades
sudo dpkg-reconfigure unattended-upgrades# Manual database updates sudo apt update sudo apt upgrade mysql-server # MySQL sudo apt upgrade postgresql-16 # PostgreSQL ```
Always test updates on a staging environment before applying to production. Use ServerRaja snapshots to create quick rollback points before major upgrades.
Security Checklist Summary
1. **Network**: Bind to localhost, use firewall rules, prefer SSH tunnels or private VLANs 2. **Authentication**: Remove default/anonymous users, enforce strong passwords, use least-privilege principles 3. **Encryption in transit**: Enable TLS for all database connections 4. **Encryption at rest**: Use full-disk encryption for sensitive workloads 5. **Audit logging**: Enable pgAudit or MySQL audit plugin to track who accessed what 6. **Updates**: Apply security patches promptly, test first on staging 7. **Backups**: Encrypt backups, store off-site, test restores regularly 8. **Monitoring**: Set up alerts for failed login attempts, unusual query patterns, and privilege escalations
Conclusion
Database security is not a one-time setup but an ongoing practice. Implement these layers on your ServerRaja Cloud VPS starting with network isolation and authentication—these two alone prevent the vast majority of database breaches. Then add encryption, audit logging, and monitoring to build a comprehensive security posture that protects your most valuable asset: your data.