Automating Compliance: A CTO’s Guide to CIS Benchmarks and GDPR in a Post-Schrems II World
It is July 2022. If your engineering team is still manually editing /etc/ssh/sshd_config on production servers, you are not just inefficient—you are a liability. In the wake of the Schrems II ruling and the aggressive stance taken by Datatilsynet (The Norwegian Data Protection Authority), the "security through obscurity" mindset is dead. You need audit trails. You need reproducible infrastructure. You need to prove that your data hasn't left the EEA.
As a CTO, my job isn't to chase the latest JavaScript framework. It's to ensure the company survives a ransomware attack or a compliance audit. We don't harden servers because it's fun. We do it to reduce the blast radius when—not if—something goes wrong. This guide covers how to automate this process using Infrastructure as Code (IaC) principles, specifically targeting the CIS (Center for Internet Security) Benchmarks on Ubuntu 22.04 LTS instances running on local Norwegian infrastructure.
The Myth of the "Secure" Default Image
No OS image is secure by default. Not even the minimal ones. When you spin up a VPS, regardless of the provider, it is optimized for compatibility, not security. Services you don't need are running. Ports are open. Legacy protocols are enabled. If you deploy a standard LAMP stack without hardening, automated bots will brute-force your SSH within minutes.
To fix this at scale, we stop treating servers like pets. We use Ansible. Below is the difference between a junior admin's approach and a senior architect's approach.
1. Base Hardening with Ansible
Instead of running shell scripts, we define the desired state. Here is a production-ready Ansible playbook snippet that enforces basic SSH hardening rules required by most compliance frameworks (PCI-DSS, SOC2).
---
- name: Harden SSH Configuration
hosts: web_servers
become: yes
tasks:
- name: Ensure SSH protocol 2 is set
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^Protocol'
line: 'Protocol 2'
state: present
- name: Disable Root Login
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
state: present
- name: Disable Password Authentication
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
line: 'PasswordAuthentication no'
state: present
- name: Ensure SSH MaxAuthTries is set to 3
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^MaxAuthTries'
line: 'MaxAuthTries 3'
state: present
notify: Restart SSH
handlers:
- name: Restart SSH
service:
name: sshd
state: restarted
This ensures that every time we deploy a new node on CoolVDS, it lands with root login disabled and keys enforced. Consistency is the bedrock of security.
Pro Tip: Always validate your configuration syntax before restarting the service. In your CI/CD pipeline, run sshd -t to prevent locking yourself out of a thousand servers simultaneously.
Network Stack Hardening
Beyond SSH, the kernel itself needs tuning. For high-performance web serving, we often tune sysctl for throughput, but for security, we tune to prevent spoofing and flooding. Specifically, disabling IP forwarding (unless you are a router) and ignoring ICMP broadcasts are mandatory for passing a CIS Level 1 audit.
Apply these settings via a file in /etc/sysctl.d/99-security.conf:
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.tcp_syncookies = 1
kernel.randomize_va_space = 2
To apply this immediately without rebooting, run:
sysctl -p /etc/sysctl.d/99-security.conf
Automated Auditing with OpenSCAP
You have hardened the server. Great. How do you prove it? Taking screenshots of config files is not a strategy. We use OpenSCAP (Security Content Automation Protocol) to scan our systems against standard profiles.
In 2022, the scap-security-guide package covers Ubuntu 20.04 and 22.04. Here is how you install the tooling:
apt-get install libopenscap8 scap-security-guide -y
Running a CIS Compliance Scan
The following bash script automates the scanning process. It identifies the correct profile for Ubuntu and generates an HTML report that you can hand directly to your auditor.
#!/bin/bash
# Define variables
PROFILE="xccdf_org.ssgproject.content_profile_cis_level1_server"
CONTENT="/usr/share/xml/scap/ssg/content/ssg-ubuntu2204-ds.xml"
REPORT_DIR="/var/www/html/security-reports"
DATE=$(date +%F)
HOSTNAME=$(hostname)
# Ensure report directory exists
mkdir -p $REPORT_DIR
# Run the evaluation
echo "Starting OpenSCAP scan for $HOSTNAME..."
oscap xccdf eval \
--profile $PROFILE \
--results $REPORT_DIR/$HOSTNAME-$DATE.xml \
--report $REPORT_DIR/$HOSTNAME-$DATE.html \
$CONTENT
# Check exit status
if [ $? -eq 0 ]; then
echo "Scan Compliant."
elif [ $? -eq 1 ]; then
echo "Scan Error."
else
echo "Scan Non-Compliant. Check report at $REPORT_DIR/$HOSTNAME-$DATE.html"
fi
When running this on CoolVDS NVMe instances, the I/O intense nature of scanning thousands of files completes rapidly. On legacy spinning rust VPS, this scan can cause iowait spikes that degrade application performance. High IOPS isn't just for databases; it's for maintenance tasks too.
The "Schrems II" Reality Check
Technical hardening is useless if you fail legal compliance. Since the Schrems II ruling in 2020, relying on the US-EU Privacy Shield is illegal. Transferring personal data to US-owned hyperscalers (AWS, Azure, GCP) creates a complex risk assessment requirement regarding the US CLOUD Act.
This is where infrastructure choice becomes a compliance tool. By utilizing CoolVDS, your data resides physically in Oslo, on hardware owned by a Norwegian entity. There is no murky data transfer. Your data sovereignty is absolute. This simplifies your GDPR Article 30 records immensely.
Continuous Monitoring with Auditd
Compliance is not a one-time event. It is a state. We use the Linux Audit daemon (auditd) to watch critical files for changes. If /etc/passwd changes at 3 AM on a Sunday, I want to know.
Here is a robust audit.rules configuration block to catch unauthorized file access:
# Delete all existing rules
-D
# Set buffer size
-b 8192
# Failure mode (1=printk, 2=panic). We choose printk.
-f 1
# Monitor /etc/passwd
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/security/opasswd -p wa -k identity
# Monitor system calls for file truncation or deletion
-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete
-a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete
# Make the configuration immutable (requires reboot to change)
-e 2
Load these rules with:
augenrules --load
Conclusion
Compliance automation reduces the TCO of your infrastructure. It moves security from a bottleneck to a standard feature of your deployment pipeline. By combining Ansible for consistency, OpenSCAP for verification, and local Norwegian hosting for data sovereignty, you build a fortress that is both performant and legal.
Do not wait for the audit letter to arrive. Start hardening today. If you need a sandbox to test these playbooks without risking production, spin up a high-performance CoolVDS instance. With our KVM virtualization, you get the kernel-level isolation needed for accurate security testing.