Console Login

Automating Compliance: Surviving Schrems II with OpenSCAP and Ansible on Norwegian Soil

Automating Compliance: Surviving Schrems II with OpenSCAP and Ansible on Norwegian Soil

If you are a CTO or Lead Architect operating in Europe right now, you are probably tired of hearing about the CJEU's ruling on July 16. The invalidation of the Privacy Shield (Schrems II) didn't just move the goalposts; it dismantled the stadium. Suddenly, that "easy" deployment on a US-based hyperscaler isn't just a technical decision—it's a massive legal liability regarding third-party data access.

I’ve spent the last six weeks migrating three separate fintech workloads from Frankfurt-based US cloud regions back to strictly Norwegian infrastructure. Why? Because Datatilsynet (The Norwegian Data Protection Authority) isn't known for being lenient when it comes to transfer mechanisms that no longer exist.

But moving data to a local VPS provider creates a new challenge: You lose the lazy comfort of managed proprietary security tools. You have to build the fortress yourself. And if you build it manually, you will fail. Humans forget config flags. Scripts break. Entropy sets in.

Here is how we solve the compliance headache using Compliance as Code—specifically with OpenSCAP and Ansible—deployed on high-performance KVM instances (like the NVMe-backed ones at CoolVDS) to satisfy both the auditors and the performance metrics.

The "War Story": The Audit That Almost Failed

In early 2020, before the Schrems II ruling dropped, I was auditing a Kubernetes cluster for a health-tech client in Oslo. They claimed to be CIS (Center for Internet Security) compliant. They showed me their spreadsheets. They looked green.

I ran a simple automated scan using the SCAP Security Guide.

Result: 43% compliance score. Why? Because someone manually enabled SSH root login to debug a database issue three months prior and forgot to disable it. A firewall rule for port 8080 was left open for a "temporary" test service. The sysctl kernel parameters for ICMP redirects were default (insecure).

Paper compliance is worthless. If you can't verify your infrastructure's state via code, it's not secure.

Step 1: establishing the Baseline with OpenSCAP

Stop guessing. The National Institute of Standards and Technology (NIST) and CIS provide the checklists. OpenSCAP checks them for you.

On a standard Ubuntu 20.04 LTS node (which we use as the base image for most CoolVDS deployments), you don't need expensive proprietary scanners. Install the SSG (SCAP Security Guide):

apt-get install libopenscap8 ssg-base ssg-deb ssg-debian ssg-nonfree ssg-applications

To run a scan against the standard CIS benchmark, you use the oscap binary. This consumes CPU, so do not run this during peak traffic if you are on a noisy-neighbor shared host. (On CoolVDS dedicated core instances, this takes about 45 seconds and won't impact your neighbor).

oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis \
  --results scan-results.xml \
  --report report.html \
  /usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml

This generates an HTML report telling you exactly where you fail. It’s brutal, but necessary.

Step 2: Remediation with Ansible

Knowing you are vulnerable is half the battle. Fixing it across 50 servers is the other half. Do not write bash scripts for this. Bash scripts are not idempotent; they don't know state. Use Ansible.

Below is a snippet from a hardening role I deploy to every new node. It addresses common failures found in the scan above: SSH configuration and IP stack hardening.

---
- name: Harden SSH Configuration
  hosts: all
  become: yes
  tasks:
    - name: Ensure SSH Protocol 2 is used
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^Protocol'
        line: 'Protocol 2'
        state: present
      notify: restart sshd

    - 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: Set idle timeout interval
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^ClientAliveInterval'
        line: 'ClientAliveInterval 300'
        state: present

- name: Kernel Hardening
  sysctl:
    name: "{{ item.key }}"
    value: "{{ item.value }}"
    state: present
    reload: yes
  loop:
    - { key: 'net.ipv4.conf.all.accept_redirects', value: '0' }
    - { key: 'net.ipv4.conf.all.log_martians', value: '1' }
    - { key: 'net.ipv4.icmp_echo_ignore_broadcasts', value: '1' }
Pro Tip: When applying kernel hardening via sysctl, be careful with net.ipv4.tcp_tw_recycle. In modern kernels (Linux 4.12+), this option is removed or behaves differently. Stick to tcp_tw_reuse for reducing TIME_WAIT sockets on high-traffic Nginx load balancers.

The Hardware Reality: Why Virtualization Type Matters

Compliance isn't just software. It's isolation. In the context of GDPR and high-security processing, the