Home / Documentation / Security & Compliance / Security Hardening Guide

Security Hardening Guide

14 min read
Updated Jun 28, 2025

Security Hardening Guide

Comprehensive guide for hardening systems, applications, and infrastructure components against security threats.

Hardening Overview

Security hardening reduces the attack surface by eliminating unnecessary services, applying security configurations, and implementing defense mechanisms.

Hardening Objectives

  • Minimize Attack Surface: Remove unnecessary components
  • Apply Security Defaults: Secure configurations out of the box
  • Enable Security Features: Activate built-in protections
  • Continuous Compliance: Maintain security posture over time

Operating System Hardening

Linux Hardening

Initial System Setup:

#!/bin/bash
# Linux hardening script

# Update system
apt update && apt upgrade -y

# Install essential security tools
apt install -y fail2ban ufw aide auditd rsyslog apparmor-utils

# Configure automatic updates
cat > /etc/apt/apt.conf.d/50unattended-upgrades << EOF
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}ESMApps:${distro_codename}-apps-security";
    "${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
EOF

# Enable unattended upgrades
echo 'APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";' > /etc/apt/apt.conf.d/20auto-upgrades

User Account Hardening:

# Password policies (/etc/pam.d/common-password)
password requisite pam_pwquality.so retry=3 minlen=14 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1

# Account lockout (/etc/pam.d/common-auth)
auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900

# Secure shell limits (/etc/security/limits.conf)
* hard core 0
* hard maxlogins 3
* hard maxsyslogins 3

# Disable unused accounts
usermod -L -e 1 unused_account

# Set password aging
chage -M 90 -m 7 -W 14 username

Windows Hardening

PowerShell Hardening Script:

# Windows Server hardening
# Run as Administrator

# Enable Windows Defender
Set-MpPreference -DisableRealtimeMonitoring $false
Set-MpPreference -DisableBehaviorMonitoring $false
Set-MpPreference -DisableIOAVProtection $false
Set-MpPreference -DisablePrivacyMode $false

# Configure Windows Firewall
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
Set-NetFirewallProfile -DefaultInboundAction Block -DefaultOutboundAction Allow

# Disable unnecessary services
$services = @('Spooler', 'RemoteRegistry', 'Fax', 'CscService')
foreach ($service in $services) {
    Stop-Service -Name $service -Force -ErrorAction SilentlyContinue
    Set-Service -Name $service -StartupType Disabled
}

# Enable audit policies
auditpol /set /category:"Account Logon" /success:enable /failure:enable
auditpol /set /category:"Account Management" /success:enable /failure:enable
auditpol /set /category:"Logon/Logoff" /success:enable /failure:enable

Network Service Hardening

SSH Hardening

# /etc/ssh/sshd_config
Port 2222
Protocol 2
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key

# Authentication
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes

# Security restrictions
MaxAuthTries 3
MaxSessions 2
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 30
X11Forwarding no
AllowUsers [email protected]/8

# Crypto settings
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected]
KexAlgorithms curve25519-sha256,[email protected]

Web Server Hardening

Nginx Hardening:

# nginx.conf security settings
user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    # Hide version
    server_tokens off;
    
    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
    # SSL configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    
    # Limits
    client_body_buffer_size 1K;
    client_header_buffer_size 1k;
    client_max_body_size 1k;
    large_client_header_buffers 2 1k;
    
    # Timeouts
    client_body_timeout 10;
    client_header_timeout 10;
    keepalive_timeout 5 5;
    send_timeout 10;
    
    # Limit connections
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    limit_conn addr 10;
}

Database Hardening

PostgreSQL Hardening

# postgresql.conf
# Connection settings
listen_addresses = 'localhost,10.0.0.5'
port = 5432
max_connections = 100

# Authentication
password_encryption = scram-sha-256

# SSL
ssl = on
ssl_cert_file = '/etc/postgresql/server.crt'
ssl_key_file = '/etc/postgresql/server.key'
ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'
ssl_prefer_server_ciphers = on
ssl_min_protocol_version = 'TLSv1.2'

# Logging
log_connections = on
log_disconnections = on
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_statement = 'ddl'
log_min_duration_statement = 1000

# pg_hba.conf
# TYPE  DATABASE  USER  ADDRESS         METHOD
local   all       all                   scram-sha-256
hostssl all       all   10.0.0.0/24     scram-sha-256
host    all       all   127.0.0.1/32    reject

MySQL Hardening

# Run mysql_secure_installation first, then:

# my.cnf
[mysqld]
# Network
bind-address = 127.0.0.1
skip-networking = 0
port = 3306

# Security
local_infile = 0
skip-symbolic-links = 1
sql_mode = TRADITIONAL
secure_file_priv = /var/lib/mysql-files/

# SSL/TLS
require_secure_transport = ON
ssl-ca = /etc/mysql/ca.pem
ssl-cert = /etc/mysql/server-cert.pem
ssl-key = /etc/mysql/server-key.pem

# Logging
general_log = 0
log_error = /var/log/mysql/error.log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

# Remove anonymous users and test database
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.db WHERE Db='test' OR Db='test_%';
FLUSH PRIVILEGES;

Container Hardening

Docker Security

# Docker daemon configuration (/etc/docker/daemon.json)
{
  "icc": false,
  "log-driver": "syslog",
  "log-opts": {
    "syslog-address": "tcp://127.0.0.1:514"
  },
  "userland-proxy": false,
  "no-new-privileges": true,
  "selinux-enabled": true,
  "userns-remap": "default",
  "live-restore": true,
  "seccomp-profile": "/etc/docker/seccomp/default.json"
}

# Dockerfile best practices
FROM alpine:3.15
RUN apk add --no-cache python3 py3-pip
RUN adduser -D -s /bin/ash appuser
USER appuser
WORKDIR /app
COPY --chown=appuser:appuser . .
RUN pip3 install --user -r requirements.txt
EXPOSE 8080
ENTRYPOINT ["python3", "app.py"]

Kubernetes Hardening

# Pod Security Policy
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted
spec:
  privileged: false
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
    - ALL
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
    - 'persistentVolumeClaim'
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    rule: 'MustRunAsNonRoot'
  seLinux:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'
  readOnlyRootFilesystem: true

Application Hardening

Runtime Application Self-Protection (RASP)

  • Input validation at runtime
  • SQL injection prevention
  • XSS protection
  • Behavior monitoring

Secure Coding Configuration

# Example security.yml for Spring Boot
security:
  headers:
    frame-options: DENY
    xss-protection: "1; mode=block"
    content-type-options: nosniff
    referrer-policy: strict-origin-when-cross-origin
    content-security-policy: "default-src 'self'"
  
  csrf:
    enabled: true
    
  sessions:
    timeout: 900
    concurrent-sessions: 1
    
  password:
    encoder: bcrypt
    strength: 12

Compliance Scanning

CIS Benchmark Implementation

# Install and run CIS-CAT
wget https://cisecurity.org/cis-cat-lite
chmod +x cis-cat-lite
./cis-cat-lite -b benchmarks/CIS_Ubuntu_20.04_Benchmark_v1.0.0.xml

# OpenSCAP for continuous compliance
apt install openscap-scanner
oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis \
  --results results.xml \
  --report report.html \
  /usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml

Automated Hardening Tools

Tool Platform Purpose
Lynis Linux/Unix Security auditing and hardening
Bastille Linux Automated hardening
HardeningKitty Windows Windows hardening automation
DevSec Hardening Multi-platform Ansible/Chef/Puppet roles

Monitoring Hardened Systems

Security Monitoring

  • File integrity monitoring (FIM)
  • Configuration drift detection
  • Compliance status dashboards
  • Security event correlation

Audit Configuration

# auditd rules (/etc/audit/rules.d/hardening.rules)
# Monitor authentication
-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/group -p wa -k group_changes
-w /etc/sudoers -p wa -k sudoers_changes

# Monitor system calls
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -k perm_mod
-a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>=1000 -k owner_mod

# Monitor network connections
-a always,exit -F arch=b64 -S socket,connect,accept,bind -k network_conn

Hardening Verification

Verification Checklist

  • □ All default passwords changed
  • □ Unnecessary services disabled
  • □ Security patches applied
  • □ Firewall rules configured
  • □ Audit logging enabled
  • □ File permissions restricted
  • □ Network services minimized
  • □ Security tools installed

Penetration Testing

  • Run vulnerability scans
  • Attempt privilege escalation
  • Test network segmentation
  • Verify security controls

Best Practices

  • Automate: Use configuration management for consistency
  • Document: Keep hardening procedures updated
  • Test: Verify hardening doesn't break functionality
  • Monitor: Continuous compliance monitoring
  • Update: Regular reviews and updates
Note: This documentation is provided for reference purposes only. It reflects general best practices and industry-aligned guidelines, and any examples, claims, or recommendations are intended as illustrative—not definitive or binding.