NIS2 Art.25–28: Sector-Specific Security for DNS Providers, TLD Registries, Cloud Computing, and Data Centres — Developer Guide (2026)
Articles 22–24 established the operational compliance core: supply chain risk assessments, the three-phase incident reporting timeline, and entity registration. Articles 25–28 shift from universal entity obligations to sector-specific requirements — additional security measures that apply on top of Art.21's baseline, targeting four entity types whose infrastructure failure would cascade across the entire digital ecosystem.
These four entity types share a common characteristic: they are horizontal infrastructure providers. A DNS service provider failure affects every entity that depends on DNS. A TLD registry outage takes entire country-code zones offline. A cloud computing provider incident affects thousands of customer workloads simultaneously. A data centre power failure can cascade across co-located services regardless of their own security posture. NIS2 Art.25–28 recognises this multiplicative risk and imposes correspondingly higher obligations.
Structure of Sector-Specific Obligations
Art.25–28 follow a consistent pattern:
- Entity type definition — which entities fall under the article
- Baseline incorporation — Art.21 measures apply in full
- Sector-specific additions — measures specific to the entity type's risk profile
- Implementing act delegation — the Commission publishes technical standards specifying minimum measures (by 17 October 2024 or later delegated dates)
- NCA enforcement — national competent authorities supervise compliance using sector-specific supervisory criteria
The implementing acts are critical: they convert NIS2's principles into concrete technical requirements. ENISA's technical guidelines provide the pre-legislative baseline while formal implementing acts remain pending for some sectors.
Art.25: DNS Service Providers — Security Measures
Scope: Who Is a DNS Service Provider Under NIS2
NIS2 defines DNS service providers as entities that provide publicly available recursive or authoritative DNS resolution services. This includes:
| Entity Type | Example | NIS2 Classification |
|---|---|---|
| Authoritative DNS operators | Providers running authoritative nameservers for customer domains | Essential if large-scale, Important if medium-scale |
| Recursive resolver operators | ISPs providing DNS resolution to end users, public DNS services | Essential/Important by size |
| DNS management SaaS platforms | Platforms that manage zone files + provisioning for multiple domains | Important (if meeting Annex II criteria) |
| CDN-integrated DNS | CDNs providing DNS as part of content delivery | Essential/Important depending on scale |
Notably, internal enterprise DNS (resolution only within a private network, not offered as a service) falls outside Art.25's scope. The obligation applies to entities providing DNS as a service to external customers.
Art.25 Core Requirements
Art.25 requires DNS service providers to implement measures addressing:
1. Zone data integrity and availability
DNS zone data must be protected against unauthorised modification. Art.25 references DNSSEC as a mechanism for providing cryptographic assurance of zone data integrity. While Art.25 does not mandate DNSSEC deployment universally, ENISA's technical guidelines treat DNSSEC signing of authoritative zones as a baseline expectation for essential entities.
2. Access control to DNS management interfaces
Zone management interfaces — APIs used to create, modify, and delete DNS records — must implement access controls that prevent unauthorised modification. This connects directly to Art.21(2)(j)'s MFA requirement: MFA must be applied to any interface with write access to DNS zone data.
3. Logging and anomaly detection
DNS query logs must be retained and monitored for anomalies indicating abuse (DNS amplification, data exfiltration via DNS tunnelling, cache poisoning attempts). Retention periods align with Art.21's general logging requirements.
4. Redundancy and resilience
DNS service providers must ensure geographic and topological distribution of nameservers. A single anycast cluster or single-datacenter deployment does not meet the resilience standard for essential entities.
5. Abuse response
DNS service providers must implement procedures for responding to DNS abuse reports — including takedown requests for domains used in phishing, malware distribution, or SPAM operations. Response time SLAs are specified in implementing acts.
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional, List
from datetime import datetime, timedelta
class DNSSECStatus(Enum):
SIGNED = "dnssec_signed"
UNSIGNED = "unsigned"
PARTIAL = "partial_zones_signed"
CHAIN_BROKEN = "chain_of_trust_broken"
class DNSRedundancyTier(Enum):
INSUFFICIENT = "single_cluster" # Fails Art.25
MINIMAL = "multi_dc_single_region" # Borderline
ADEQUATE = "multi_region_anycast" # Meets Art.25 for important entities
RESILIENT = "multi_continent_anycast" # Meets Art.25 for essential entities
@dataclass
class DNSServiceProviderCompliance:
provider_id: str
dnssec_status: DNSSECStatus
redundancy_tier: DNSRedundancyTier
mfa_on_management_interfaces: bool
query_log_retention_days: int
abuse_response_sla_hours: int
zone_change_audit_log: bool
anomaly_detection_enabled: bool
entity_classification: str # "essential" or "important"
def art25_compliance_gaps(self) -> List[str]:
gaps = []
if self.entity_classification == "essential":
if self.dnssec_status not in (DNSSECStatus.SIGNED,):
gaps.append("DNSSEC signing required for essential entity DNS service providers")
if self.redundancy_tier not in (DNSRedundancyTier.ADEQUATE, DNSRedundancyTier.RESILIENT):
gaps.append("Multi-region anycast redundancy required for essential entities")
else:
if self.dnssec_status == DNSSECStatus.CHAIN_BROKEN:
gaps.append("Broken DNSSEC chain of trust must be repaired")
if self.redundancy_tier == DNSRedundancyTier.INSUFFICIENT:
gaps.append("Single-cluster DNS is insufficient under Art.25 for any NIS2 entity")
if not self.mfa_on_management_interfaces:
gaps.append("MFA required on zone management APIs (Art.21(2)(j) + Art.25)")
if self.query_log_retention_days < 90:
gaps.append(f"Query log retention {self.query_log_retention_days}d below 90-day minimum")
if self.abuse_response_sla_hours > 24:
gaps.append(f"Abuse response SLA {self.abuse_response_sla_hours}h exceeds 24h guideline")
if not self.zone_change_audit_log:
gaps.append("Zone change audit log required for traceability")
if not self.anomaly_detection_enabled:
gaps.append("DNS anomaly detection (amplification, tunnelling, cache poisoning) required")
return gaps
def is_art25_compliant(self) -> bool:
return len(self.art25_compliance_gaps()) == 0
DNS Amplification and the Art.25 Abuse Control Obligation
DNS amplification attacks use open recursive resolvers to flood targets with DNS responses. Art.25's abuse response obligation creates a direct requirement to configure recursive resolvers to prevent amplification abuse:
from dataclasses import dataclass
from typing import List
@dataclass
class RecursiveResolverAbuseControls:
resolver_ip_range: str
rate_limiting_enabled: bool
response_rate_limiting_rrl: bool # RFC 5358 / DNS RRL
qname_minimisation: bool # RFC 7816 — limits data exposure
open_resolver: bool # True = accessible to all internet IPs
access_control_list_configured: bool
def abuse_risk_assessment(self) -> dict:
risks = []
mitigations = []
if self.open_resolver:
risks.append("CRITICAL: Open recursive resolver — high amplification risk")
if not self.rate_limiting_enabled:
risks.append("HIGH: No rate limiting — vulnerable to abuse as reflector")
if not self.response_rate_limiting_rrl:
risks.append("MEDIUM: No DNS RRL — amplification responses unrestricted")
if not self.access_control_list_configured:
risks.append("HIGH: No ACL — resolver accessible without restriction")
if self.qname_minimisation:
mitigations.append("QNAME minimisation reduces upstream query exposure")
return {
"risks": risks,
"mitigations": mitigations,
"art25_compliant": not self.open_resolver and self.rate_limiting_enabled,
}
Art.26: Top-Level Domain Name Registries and Domain Name Registration Services
Scope: TLD Registries vs. Domain Name Registration Services
Art.26 applies to two distinct entity types that are frequently confused:
| Entity Type | Role | NIS2 Classification |
|---|---|---|
| TLD registry | Operates the authoritative zone for a top-level domain (.de, .fr, .eu, .com) | Essential (all sizes — systemic importance) |
| Domain name registration service | Processes domain registrations / transfers / deletions on behalf of registrants | Important (if meeting Annex II size criteria) |
| Registrar | Accredited intermediary between registrants and registry | Important |
DENIC (Germany .de), AFNIC (France .fr), and EURid (.eu) are TLD registries under Art.26. Their systemic importance means they are classified as essential entities regardless of employee count or turnover.
Art.26 Core Requirements: WHOIS Data Accuracy
Art.26's most operationally significant requirement is WHOIS database accuracy. NIS2 requires TLD registries and registration services to:
- Collect and verify registrant data — name, organisation, physical address, email, phone number
- Maintain data accuracy — implement procedures to validate and update registrant records
- Provide lawful access — make WHOIS data available to NCAs, CSIRTs, and parties with legitimate access requests
- Publish non-personal data — technical contacts, nameserver data, registration dates
Post-GDPR, WHOIS data was heavily restricted. Art.26 creates an explicit NIS2 legal basis for collecting and processing registrant data — this is the tension point between GDPR privacy principles and NIS2 security requirements. The EDPB's guidance on NIS2 WHOIS data processing provides the reconciliation framework.
from dataclasses import dataclass
from enum import Enum
from typing import Optional
from datetime import datetime
class WHOISDataVerificationStatus(Enum):
VERIFIED = "verified"
UNVERIFIED = "collected_not_verified"
SYNTHETIC = "fake_or_placeholder"
EXPIRED = "verification_expired"
@dataclass
class DomainRegistrantRecord:
domain_name: str
registrant_name: str
registrant_org: Optional[str]
registrant_email: str
registrant_phone: Optional[str]
registrant_address: Optional[str]
verification_status: WHOISDataVerificationStatus
last_verified: Optional[datetime]
nameservers: list
registration_date: datetime
expiry_date: datetime
def is_art26_compliant(self) -> bool:
if self.verification_status in (
WHOISDataVerificationStatus.SYNTHETIC,
WHOISDataVerificationStatus.EXPIRED,
):
return False
if not self.registrant_email:
return False
if not self.registrant_name or self.registrant_name in ("REDACTED", "Privacy Protected"):
# GDPR REDACTED is permitted for personal registrants but org fields must be present for business
return self.registrant_org is not None
return True
def whois_public_record(self) -> dict:
"""Returns non-personal data safe for public WHOIS publication."""
return {
"domain_name": self.domain_name,
"nameservers": self.nameservers,
"registration_date": self.registration_date.isoformat(),
"expiry_date": self.expiry_date.isoformat(),
# Registrant contact data omitted per GDPR — accessible via lawful access request
}
def abuse_contact_record(self) -> dict:
"""Returns data for NCA/CSIRT abuse contact requests."""
return {
"domain_name": self.domain_name,
"registrant_email": self.registrant_email,
"registrant_name": self.registrant_name,
"registrant_org": self.registrant_org,
"verification_status": self.verification_status.value,
}
@dataclass
class TLDRegistryCompliance:
tld: str # ".de", ".eu", etc.
whois_accuracy_verification_rate: float # 0.0–1.0
abuse_response_sla_hours: int
data_escrow_enabled: bool # Registry data backed up at ICANN-accredited escrow
dnssec_signed: bool
zone_transfer_restricted: bool
def art26_compliance_gaps(self) -> list:
gaps = []
if self.whois_accuracy_verification_rate < 0.95:
gaps.append(
f"WHOIS verification rate {self.whois_accuracy_verification_rate:.0%} below 95% threshold"
)
if self.abuse_response_sla_hours > 24:
gaps.append("Abuse response SLA exceeds 24h Art.26 requirement")
if not self.data_escrow_enabled:
gaps.append("Registry data escrow required under Art.26 for TLD continuity")
if not self.dnssec_signed:
gaps.append("TLD zone must be DNSSEC-signed (essential entity requirement)")
if not self.zone_transfer_restricted:
gaps.append("Zone transfers must be restricted to authorised secondary nameservers")
return gaps
The Abuse Contact Requirement
Art.26 requires registries and registration services to publish and maintain accurate abuse contacts and to implement procedures for handling abuse reports. This connects to broader NIS2 Art.23 reporting obligations: registries that become aware of domain-level incidents (mass phishing campaigns using their TLD, malware distribution) must assess whether these constitute reportable incidents.
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
class AbuseReportType(Enum):
PHISHING = "phishing"
MALWARE = "malware_distribution"
SPAM = "spam_operation"
CSAM = "child_sexual_abuse_material"
BOTNET_C2 = "botnet_command_and_control"
TRADEMARK_INFRINGEMENT = "trademark"
@dataclass
class AbuseReport:
report_id: str
domain: str
report_type: AbuseReportType
reported_at: datetime
resolved_at: datetime | None
action_taken: str | None # "suspended", "registrar_notified", "law_enforcement_referred"
@property
def resolution_hours(self) -> float | None:
if self.resolved_at:
return (self.resolved_at - self.reported_at).total_seconds() / 3600
return None
def is_within_sla(self, sla_hours: int = 24) -> bool | None:
h = self.resolution_hours
if h is None:
return None
return h <= sla_hours
Art.27: Cloud Computing Service Providers
Scope: What Is a Cloud Computing Service Provider Under NIS2
NIS2 uses ISO/IEC 17788 definitions for cloud service categories:
| Cloud Service Model | Examples | NIS2 Classification |
|---|---|---|
| IaaS | AWS EC2, Azure VMs, Hetzner Cloud | Essential (large scale), Important |
| PaaS | AWS Elastic Beanstalk, Azure App Service, sota.io | Essential (large scale), Important |
| SaaS | Office 365, Salesforce, Google Workspace | Important (if meeting size criteria) |
| Cloud Management Platforms | Multi-cloud management, FinOps platforms | Important |
The critical threshold for essential entity classification in cloud computing is serving more than 500,000 end users or infrastructure used by other essential entities. Most EU-focused cloud providers outside hyperscalers fall in the Important category.
Art.27 Core Requirements
Art.27 builds on Art.21's baseline with cloud-specific additions:
1. Multi-tenant isolation
Cloud providers must implement logical isolation between customer workloads. A vulnerability in one tenant's environment must not provide access to another tenant's data or compute resources. This goes beyond Art.21(2)(e)'s general network segmentation requirement to impose cloud-specific isolation standards.
2. Data residency and portability
Cloud providers must implement mechanisms enabling customers to ensure data remains within specified geographic boundaries and to export data in standard formats upon contract termination. This connects to GDPR Art.44's cross-border transfer restrictions and NIS2's EU regulatory context.
3. Cryptographic key management
Customer data must be encrypted at rest and in transit. For essential entity cloud providers, implementing acts require customer-managed encryption keys (BYOK — Bring Your Own Key) to be available, ensuring that even the cloud provider cannot access customer data without customer authorisation.
4. Availability and SLA transparency
Cloud providers must publish transparency reports on availability, incidents, and security measures. The transparency obligation is more extensive than Art.21's baseline and connects to Art.23's incident reporting — cloud providers must notify affected customers of incidents within the Art.23 reporting timeline.
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Optional
class CloudServiceModel(Enum):
IAAS = "infrastructure_as_a_service"
PAAS = "platform_as_a_service"
SAAS = "software_as_a_service"
class IsolationMechanism(Enum):
HYPERVISOR = "hypervisor_isolation"
CONTAINER_NAMESPACE = "container_namespace"
HARDWARE_ISOLATED = "hardware_isolated_tenant"
SHARED_PROCESS = "shared_process" # Insufficient for NIS2
@dataclass
class CloudProviderArt27Compliance:
provider_id: str
service_model: CloudServiceModel
entity_classification: str # "essential" or "important"
tenant_isolation_mechanism: IsolationMechanism
customer_managed_keys_available: bool # BYOK
data_residency_controls: bool
data_export_in_standard_formats: bool
availability_sla_percent: float
transparency_report_published: bool
incident_notification_to_customers_sla_hours: int
penetration_testing_frequency_months: int
def art27_compliance_gaps(self) -> List[str]:
gaps = []
if self.tenant_isolation_mechanism == IsolationMechanism.SHARED_PROCESS:
gaps.append("Shared-process tenant isolation is insufficient under Art.27")
if self.entity_classification == "essential":
if not self.customer_managed_keys_available:
gaps.append("BYOK (customer-managed encryption keys) required for essential cloud providers")
if self.penetration_testing_frequency_months > 12:
gaps.append("Annual penetration testing required for essential entity cloud providers")
if not self.transparency_report_published:
gaps.append("Transparency report publication required for essential entities")
if not self.data_residency_controls:
gaps.append("Data residency controls required — customers must be able to restrict data location")
if not self.data_export_in_standard_formats:
gaps.append("Standard-format data export required for portability compliance")
if self.incident_notification_to_customers_sla_hours > 72:
gaps.append(
f"Customer incident notification SLA {self.incident_notification_to_customers_sla_hours}h "
"exceeds 72h Art.23 downstream notification requirement"
)
return gaps
def is_art27_compliant(self) -> bool:
return len(self.art27_compliance_gaps()) == 0
@dataclass
class CloudTenantIsolationAssessment:
"""Assess isolation between tenants in a multi-tenant cloud environment."""
tenant_a_id: str
tenant_b_id: str
shared_hypervisor: bool
shared_kernel: bool
network_namespace_isolated: bool
storage_namespace_isolated: bool
cpu_pinning_available: bool # Prevents timing-based side-channel attacks
def isolation_risk_level(self) -> str:
if self.shared_kernel and not self.network_namespace_isolated:
return "CRITICAL — container escape may expose cross-tenant data"
if self.shared_hypervisor and not self.cpu_pinning_available:
return "HIGH — speculative execution side-channels (Spectre/Meltdown) risk"
if not self.storage_namespace_isolated:
return "HIGH — storage namespace not isolated"
if self.shared_hypervisor and self.network_namespace_isolated and self.storage_namespace_isolated:
return "MEDIUM — hypervisor isolation adequate but not hardware-isolated"
return "LOW — isolation meets Art.27 requirements"
Cloud Provider Incident Reporting: The Downstream Notification Chain
Cloud providers face a dual notification obligation under NIS2:
- Art.23 upstream reporting: Cloud providers must report significant incidents to their NCA (24h early warning → 72h notification → 30-day final report)
- Art.27 downstream notification: Cloud providers must notify affected customers of incidents affecting their services
This creates a notification chain:
Cloud Provider Incident
│
├──► NCA Report (Art.23: T+24h early warning, T+72h notification)
│
└──► Customer Notification (Art.27: within 72h of incident detection)
│
└──► Customer is itself an Essential/Important Entity?
│
├── YES: Customer must assess if this triggers THEIR Art.23 report
└── NO: Customer handles internally
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
class IncidentImpactScope(Enum):
SINGLE_TENANT = "single_tenant"
MULTIPLE_TENANTS = "multiple_tenants"
PLATFORM_WIDE = "platform_wide"
CROSS_REGION = "cross_region"
@dataclass
class CloudIncidentNotificationDecision:
incident_id: str
detected_at: datetime
impact_scope: IncidentImpactScope
affected_tenant_count: int
affected_essential_entity_tenants: int
data_breach_involved: bool
service_unavailability_minutes: int
def nca_report_required(self) -> bool:
return (
self.affected_essential_entity_tenants > 0
or self.impact_scope in (IncidentImpactScope.PLATFORM_WIDE, IncidentImpactScope.CROSS_REGION)
or self.data_breach_involved
or self.service_unavailability_minutes > 60
)
def customer_notification_deadline(self) -> datetime:
return datetime(
self.detected_at.year,
self.detected_at.month,
self.detected_at.day,
self.detected_at.hour,
self.detected_at.minute,
) + __import__("datetime").timedelta(hours=72)
Art.28: Data Centre Service Providers
Scope: What Is a Data Centre Service Provider
NIS2 defines data centre service providers as entities offering data centre services to customers — physical facilities providing power, cooling, physical security, and connectivity for customer equipment. This includes:
- Colocation providers: Customer equipment in provider's facility (Equinix, Interxion, DE-CIX)
- Managed hosting: Provider operates servers on behalf of customers
- Edge data centres: Distributed facilities for low-latency workloads
Hyperscale cloud providers that operate their own data centres are classified under Art.27 (cloud computing), not Art.28 — unless they separately offer colocation as a distinct service.
Art.28 Core Requirements
1. Physical security
Art.28 mandates layered physical access controls:
- Perimeter security (fencing, CCTV, motion detection)
- Access control to server halls (badge + biometric or multi-factor)
- Monitoring and audit logging of physical access
- Visitor management procedures
2. Power redundancy
Data centres must implement N+1 or 2N power redundancy. A single UPS failure must not cause customer-visible downtime. This typically requires:
- Redundant utility feeds
- UPS systems with automatic bypass
- Backup generators with automatic transfer switching (ATS)
- Fuel supply contracts ensuring generator runtime
3. Cooling redundancy
Cooling failures are a primary cause of data centre outages. Art.28's resilience requirement implies N+1 cooling — at minimum one cooling unit can fail without thermal breach.
4. Connectivity redundancy
Art.28's availability requirements extend to network connectivity: at least two physically diverse network paths from independent providers.
5. Incident reporting
Data centre providers are subject to Art.23 reporting for significant incidents affecting customer services. Physical security breaches (unauthorised access) that could compromise customer equipment are explicitly in scope.
from dataclasses import dataclass
from enum import Enum
from typing import List
class PowerRedundancyTier(Enum):
NONE = "no_redundancy" # Single UPS, single feed
N_PLUS_1 = "n_plus_1" # One additional unit — adequate for Important entities
TWO_N = "2n" # Full redundancy — required for Essential entities
TWO_N_PLUS_1 = "2n_plus_1" # Full redundancy with additional spare
class CoolingRedundancyTier(Enum):
NONE = "no_redundancy"
N_PLUS_1 = "n_plus_1"
TWO_N = "2n"
class PhysicalSecurityTier(Enum):
BASIC = "badge_only"
STANDARD = "badge_plus_cctv"
ENHANCED = "badge_biometric_cctv_motion"
HIGH_SECURITY = "mantrap_badge_biometric_cctv_24h_guard"
@dataclass
class DataCentreArt28Compliance:
facility_id: str
entity_classification: str # "essential" or "important"
power_redundancy: PowerRedundancyTier
cooling_redundancy: CoolingRedundancyTier
physical_security: PhysicalSecurityTier
diverse_network_providers: int # Number of independent connectivity providers
generator_fuel_hours_supply: int
physical_access_log_retention_days: int
visitor_management_system: bool
iso_27001_certified: bool # Proxy for physical security baseline
def art28_compliance_gaps(self) -> List[str]:
gaps = []
if self.entity_classification == "essential":
if self.power_redundancy not in (PowerRedundancyTier.TWO_N, PowerRedundancyTier.TWO_N_PLUS_1):
gaps.append("2N power redundancy required for essential entity data centres")
if self.cooling_redundancy not in (CoolingRedundancyTier.TWO_N,):
gaps.append("2N cooling redundancy required for essential entity data centres")
if self.physical_security not in (
PhysicalSecurityTier.ENHANCED,
PhysicalSecurityTier.HIGH_SECURITY,
):
gaps.append("Badge + biometric + CCTV minimum for essential entity data centres")
else:
if self.power_redundancy == PowerRedundancyTier.NONE:
gaps.append("N+1 minimum power redundancy required for all NIS2 data centres")
if self.cooling_redundancy == CoolingRedundancyTier.NONE:
gaps.append("N+1 minimum cooling redundancy required for all NIS2 data centres")
if self.diverse_network_providers < 2:
gaps.append("At least 2 diverse network providers required for connectivity redundancy")
if self.generator_fuel_hours_supply < 72:
gaps.append(
f"Generator fuel supply {self.generator_fuel_hours_supply}h below 72h minimum "
"for NIS2 crisis scenario coverage"
)
if self.physical_access_log_retention_days < 90:
gaps.append("Physical access logs must be retained for minimum 90 days")
if not self.visitor_management_system:
gaps.append("Visitor management system required for tracking physical access by third parties")
return gaps
def is_art28_compliant(self) -> bool:
return len(self.art28_compliance_gaps()) == 0
@dataclass
class DataCentrePhysicalSecurityIncident:
incident_id: str
incident_type: str # "unauthorised_access", "tailgating", "equipment_theft", "fire", "power_failure"
affected_customer_equipment: bool
detected_at: str
art23_report_required: bool # True if customer equipment affected
def assess_art23_reporting(self) -> dict:
triggers_art23 = (
self.affected_customer_equipment
or self.incident_type in ("equipment_theft", "fire")
)
return {
"art23_report_required": triggers_art23,
"rationale": (
"Physical security breach affecting customer equipment triggers Art.23 incident reporting"
if triggers_art23
else "Internal physical security incident — no customer equipment affected"
),
}
Cross-Article Compliance Architecture
The four sector-specific articles (25–28) layer on top of Art.21's baseline. A cloud provider that also operates its own data centres and provides DNS resolution (common for hyperscalers) must comply with Art.21 + Art.25 + Art.27 + Art.28 simultaneously:
Art.21 Baseline (All Entities)
├── Art.25 ADDITIONS (if DNS service provider)
│ ├── DNSSEC signing
│ ├── DNS abuse response procedures
│ └── Recursive resolver anti-abuse controls
├── Art.26 ADDITIONS (if TLD registry or domain name registration service)
│ ├── WHOIS accuracy verification
│ ├── Abuse contact publication
│ └── Data escrow with ICANN-accredited escrow agent
├── Art.27 ADDITIONS (if cloud computing service provider)
│ ├── Multi-tenant isolation
│ ├── Customer-managed encryption keys (BYOK)
│ ├── Data residency controls
│ └── Downstream customer incident notification
└── Art.28 ADDITIONS (if data centre service provider)
├── Physical security (badge + biometric + CCTV)
├── N+1 / 2N power and cooling redundancy
├── Diverse network providers
└── Generator fuel supply ≥ 72h
Implementing Acts Timeline
The Commission must publish implementing acts specifying technical measures for sector-specific entities. As of 2026:
| Article | Implementing Act | Status | ENISA Guidance Available |
|---|---|---|---|
| Art.25 (DNS) | Pending Commission Decision | Expected 2026 | Yes — ENISA DNS Security Guidelines |
| Art.26 (TLD/WHOIS) | Partial — ICANN coordination | 2025–2026 | ENISA TLD Security Framework |
| Art.27 (Cloud) | Commission Delegated Act planned | Expected 2026 | ENISA Cloud Security Guidelines v3 |
| Art.28 (Data Centres) | Pending Commission Decision | Expected 2026 | ENISA Data Centre Security Framework |
Until implementing acts are finalised, entities should use ENISA's technical guidelines as the compliance baseline. NCAs in Germany (BSI), France (ANSSI), and the Netherlands (NCSC-NL) have published national guidance documents that provide interim sector-specific requirements.
Art.25–28 Compliance Checklist
DNS Service Providers (Art.25)
| Requirement | Essential | Important | Action |
|---|---|---|---|
| DNSSEC signing on authoritative zones | Required | Recommended | Sign all zones |
| MFA on zone management interfaces | Required | Required | Enforce MFA + access logging |
| Multi-region anycast redundancy | Required | Recommended | Deploy geographically distributed nameservers |
| Query log retention ≥ 90 days | Required | Required | Configure log retention policy |
| Abuse response SLA ≤ 24h | Required | Required | Implement abuse handling workflow |
| Anomaly detection (tunnelling, amplification) | Required | Recommended | Deploy DNS monitoring tooling |
TLD Registries and Registration Services (Art.26)
| Requirement | Status |
|---|---|
| WHOIS accuracy verification procedures | Mandatory |
| Abuse contact publication | Mandatory |
| Data escrow with accredited escrow agent | Mandatory for TLD registries |
| DNSSEC signing of TLD zone | Mandatory for TLD registries |
| Zone transfer access controls | Mandatory |
| WHOIS data available for NCA/CSIRT requests | Mandatory (with GDPR-compliant access procedures) |
Cloud Computing Service Providers (Art.27)
| Requirement | Essential | Important |
|---|---|---|
| Multi-tenant logical isolation | Required | Required |
| Customer-managed keys (BYOK) | Required | Recommended |
| Data residency controls | Required | Required |
| Standard-format data export | Required | Required |
| Customer incident notification ≤ 72h | Required | Required |
| Annual penetration testing | Required | Recommended |
| Transparency report publication | Required | Recommended |
Data Centre Service Providers (Art.28)
| Requirement | Essential | Important |
|---|---|---|
| Power redundancy | 2N | N+1 |
| Cooling redundancy | 2N | N+1 |
| Physical access: badge + biometric + CCTV | Required | Recommended |
| Diverse network providers | ≥2 | ≥2 |
| Generator fuel supply | ≥72h | ≥48h |
| Physical access log retention | ≥90 days | ≥90 days |
| Visitor management system | Required | Required |
Summary
NIS2 Art.25–28 recognises that DNS providers, TLD registries, cloud computing providers, and data centres form horizontal infrastructure layers whose failures cascade across the entire digital ecosystem. Each article follows the same pattern: Art.21 baseline applies in full, sector-specific additions address the unique risk profile of the entity type, and implementing acts provide the technical specifics.
The critical implementation insight is layering: check which articles apply to your organisation (you may fall under multiple sector categories), implement Art.21 fully, then add the sector-specific measures for each applicable article. The Python compliance_gaps() methods in this guide provide a starting point for automated compliance assessment in your infrastructure code.
NIS2 Art.29–32 (next in the series) covers cybersecurity information sharing arrangements (Art.29–30), supervisory framework for essential entities (Art.31), and reactive supervision for important entities (Art.32) — including the CEO temporary management ban mechanism (Art.32(6)) that connects back to Art.17's liability framework.