Scope

A technical self-assessment for entities in scope of the NIS2 Directive (Directive (EU) 2022/2555). Each item is a thing a sysadmin can verify on a host now — a command output, a config flag, a file’s contents, an external scan result — not a policy approval or a named role.

This is the box-level companion to nis2-infrastructure. That guide explains why each Article 21(2) measure matters and how to implement it; this checklist is the “is it actually configured?” layer.

NIS2 also requires governance, supply-chain, and reporting work that does not appear on the box — those obligations are not omitted, but they are kept to a short closing section (9) rather than padded into technical-looking checkboxes. Work top-to-bottom.

Compliance references map only where they actually apply. They are not legal advice; for formal classification and audit defence, use qualified counsel and your competent authority’s published guidance.

1. Hardening baseline (Article 21(2)(a), (e), (g))

The documented baseline applied to every host. Verify on a sample host or, better, in configuration management.

  • SSH password authentication off. sshd -T | grep -i passwordauthentication returns passwordauthentication no. See ssh-hardening. NIS2: 21(2)(e),(j); ISO 27001: A.8.5.
  • Root SSH login off. sshd -T | grep -i permitrootlogin returns permitrootlogin no. ISO 27001: A.8.2.
  • SSH key algorithms restricted to modern set. sshd -T | grep -E '^(kexalgorithms|ciphers|macs)' lists only ed25519 / curve25519-sha256 / aes*-gcm / hmac-sha2-*-etm variants. NIS2: 21(2)(h).
  • Firewall default-deny. ufw status verbose shows Default: deny (incoming) or firewall-cmd --get-default-zone returns drop / block. ISO 27001: A.8.20, A.8.22.
  • AppArmor / SELinux in enforcing mode. aa-status reports profiles in enforce mode, or getenforce returns Enforcing. ISO 27001: A.8.7.
  • Per-human sudoer accounts only. getent group sudo (Debian) or getent group wheel (RHEL) lists named humans, not service accounts. NIS2: 21(2)(i); ISO 27001: A.5.16, A.8.5.
  • No unrestricted NOPASSWD sudo entries. grep -r NOPASSWD /etc/sudoers /etc/sudoers.d/ returns only specifically documented automation entries. ISO 27001: A.8.5.
  • Unused listening services removed. ss -tlnp shows only services in the documented baseline; cups, bluetooth, avahi-daemon, postfix (if not sending) all absent. ISO 27001: A.8.9.

2. Patching and maintenance (Article 21(2)(e))

  • Automatic security updates enabled. Debian-family: apt-config dump APT::Periodic shows Update-Package-Lists "1", Unattended-Upgrade "1". RHEL-family: systemctl is-enabled dnf-automatic.timer returns enabled. NIS2: 21(2)(c); ISO 27001: A.8.8.
  • Reboot policy configured for kernel updates. /etc/apt/apt.conf.d/50unattended-upgrades includes Unattended-Upgrade::Automatic-Reboot "true" with a Reboot-Time, or equivalent on RHEL. ISO 27001: A.8.8.
  • Patch evidence on the box. tail -50 /var/log/unattended-upgrades/unattended-upgrades.log or dnf history shows recent automated runs. NIS2: 21(2)(f).
  • lynis run within the last 90 days. lynis show details LAST or the report file under /var/log/lynis* is dated within 90 days; hardening index recorded. NIS2: 21(2)(f); ISO 27001: A.5.35.
  • oscap baseline run within the last 90 days (RHEL family). Report file dated; failing rules tracked. NIS2: 21(2)(f).
  • Package sources pinned and authenticated. apt-key list / dnf repolist shows only intended repos with valid GPG; no [trusted=yes] overrides. NIS2: 21(2)(d); ISO 27001: A.8.30.

3. Cryptography (Article 21(2)(h))

  • Edge TLS protocols restricted. nginx -T 2>/dev/null | grep ssl_protocols returns TLSv1.2 TLSv1.3 only. See nginx-tls-2026. ISO 27001: A.8.24.
  • HSTS deployed with sane max-age. curl -sI https://host | grep -i strict-transport returns max-age31536000. ISO 27001: A.8.24.
  • OCSP stapling on. openssl s_client -connect host:443 -status </dev/null 2>/dev/null | grep -i 'OCSP Response Status' returns successful. ISO 27001: A.8.24.
  • External TLS scan grade A or A+ within the last 90 days. Qualys SSL Labs or testssl.sh report retained and dated. See tls-audit. NIS2: 21(2)(f).
  • PostgreSQL TLS enabled for non-local connections. psql -c 'SHOW ssl;' returns on; pg_hba.conf uses hostssl for every non-samehost entry. See postgresql-hardening. ISO 27001: A.8.24.
  • Redis plaintext port disabled. redis-cli -p 6379 PING from off-host fails; redis.conf has port 0 and tls-port 6379 (or equivalent). See redis-hardening. ISO 27001: A.8.24.
  • At-rest encryption on storage. lsblk -o NAME,FSTYPE shows crypto_LUKS on the data partition, or the cloud-provider console confirms volume encryption for the relevant disks. GDPR: Article 32; ISO 27001: A.8.24.
  • Backup repository encrypted. restic snapshots requires a passphrase; passphrase is stored outside the host being backed up. See encrypted-backups-restic. GDPR: Article 32.

4. Access control and identity (Article 21(2)(i), (j))

  • No shared interactive accounts. awk -F: '$3>=1000 && $3<60000 {print $1}' /etc/passwd lists only named humans; no developer, admin, or shared aliases. ISO 27001: A.5.16.
  • authorized_keys audit within the last 90 days. Every entry carries a dated # owner — added YYYY-MM-DD comment; no orphaned keys from former staff. ISO 27001: A.5.18, A.8.5.
  • PostgreSQL roles least-privilege. \du shows application roles without Superuser or Create role; replication on a dedicated replication role. ISO 27001: A.8.2.
  • Redis ACLs scoped. ACL LIST shows the default user with off nopass ~* &* -@all (or equivalent disabled) and per-purpose users with category limits. ISO 27001: A.8.2.
  • WordPress administrator accounts audited. wp user list --role=administrator --format=table returns only expected named accounts. ISO 27001: A.5.18.
  • Cloud provider IAM: no long-lived root keys in use. Provider console shows last-used dates on root credentials are Never (AWS) or equivalent on other providers. ISO 27001: A.5.16, A.8.5.
  • Asset inventory file present and current. A versioned file or system of record listing every host, its purpose, the data it processes, and the owner — last reviewed within 90 days. ISO 27001: A.5.9.

5. Logging and detection (Article 21(2)(b))

  • auditd enabled with a baseline ruleset. systemctl is-active auditd returns active; auditctl -l lists rules — not empty. ISO 27001: A.8.15, A.8.16.
  • Logs forwarded off-host. rsyslog/journal-upload/agent config present and reaching a remote target; remote ingest confirmed within last 24h. ISO 27001: A.8.15.
  • PostgreSQL audit-relevant logging on. SHOW log_connections; and SHOW log_disconnections; both return on; log_statement set per policy (ddl minimum). ISO 27001: A.8.15, A.8.16.
  • Nginx access logs retained per the documented policy. Logrotate config matches the policy; oldest log file aligns with retention. See log-minimisation-recipes. GDPR: Article 5(1)(c), 5(1)(e).
  • Failed-auth detection wired up. fail2ban-client status lists active jails for at least sshd and any other public-facing auth endpoint; or equivalent SIEM rules verified. ISO 27001: A.8.16.

6. Backups and recovery (Article 21(2)(c))

  • Encrypted backup job scheduled. systemctl list-timers --all | grep -i backup (or the cron equivalent) shows the schedule active and recently-run. ISO 27001: A.8.13.
  • restic check passes within the last 30 days. Output retained; failures alert on. ISO 27001: A.8.13.
  • Last successful restore test within the last 6 months. Restored-target evidence held (a database row count, a file hash, a screenshot of the recovered service responding). ISO 27001: A.5.30.
  • PostgreSQL WAL archiving on. SHOW archive_mode; returns on; SHOW archive_command; is non-empty and not 'true' or /bin/true. See postgres-backups. ISO 27001: A.8.13.
  • Backup retention enforced. restic forget --dry-run (or equivalent) returns the expected pruning plan against the documented retention policy. GDPR: Article 5(1)(e).

7. MFA on remote interfaces (Article 21(2)(j))

These checks happen in the relevant control panel or via API, not on the host — but they are verifiable, point-in-time checks.

  • Cloud provider portal: MFA enforced for every human user. Provider console shows zero users with MFA: not enabled. ISO 27001: A.8.5.
  • Code repository: org-level 2FA enforcement on. GitHub / GitLab org settings show Require two-factor authentication — enforcement, not just opt-in. ISO 27001: A.8.5.
  • CI/CD: short-lived tokens only. No long-lived personal access tokens in pipelines; OIDC or equivalent in use. ISO 27001: A.8.5.
  • WordPress: 2FA plugin active for administrator role. wp plugin list --status=active | grep -i -E 'two-factor|2fa' returns the configured plugin. ISO 27001: A.8.5.
  • Database admin tools (pgAdmin, RedisInsight, etc.) behind MFA or VPN. No public admin UIs reachable without an authenticated tunnel. ISO 27001: A.8.5, A.8.20.

8. External verification (Article 21(2)(f))

  • TLS scan dated within last 90 days. Qualys SSL Labs or testssl.sh output retained; grade A or A+. NIS2: 21(2)(f).
  • ssh-audit clean. ssh-audit host returns no FAIL or LEGACY findings on any public SSH endpoint. NIS2: 21(2)(f).
  • Public-facing vulnerability scan within last 90 days. Nessus, OpenVAS, or equivalent; report retained; findings tracked to closure or to an accepted-risk register. ISO 27001: A.5.35.
  • External pen test within the cadence the entity has committed to (typically annual for in-scope services). Report and remediation log retained. ISO 27001: A.8.29.

9. Governance, supply-chain, and reporting

The checks above cover the technical surface of Article 21(2). NIS2 also requires governance and reporting work that does not appear on a host — the minimum set is below, kept short. The reasoning for each is in nis2-infrastructure.

  • Information security policy approved by the management body, dated, with a defined review cadence. NIS2: 20(1), 21(2)(a).
  • Risk register exists, lists infrastructure-level risks, is reviewed at least annually. NIS2: 21(2)(a), (f).
  • Processor / supplier register exists with DPA references and security commitments per supplier. NIS2: 21(2)(d); GDPR: Article 28.
  • Incident-response playbook covers the Article 23 timeline: 24-hour early warning, 72-hour notification, one-month final report — starting from awareness, not containment. NIS2: 23.
  • Competent authority contact and reporting portal on file where the on-call can find them. NIS2: 23(1).
  • Out-of-band incident communications channel exists and has been used in a drill. NIS2: 21(2)(j).

This checklist is the technical “is it configured?” companion to nis2-infrastructure. When an item is unclear, the reasoning is in that guide. For formal classification and audit defence, work with qualified counsel and your competent authority’s published guidance.