2026-04-21·14 min read·

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:

  1. Entity type definition — which entities fall under the article
  2. Baseline incorporation — Art.21 measures apply in full
  3. Sector-specific additions — measures specific to the entity type's risk profile
  4. Implementing act delegation — the Commission publishes technical standards specifying minimum measures (by 17 October 2024 or later delegated dates)
  5. 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 TypeExampleNIS2 Classification
Authoritative DNS operatorsProviders running authoritative nameservers for customer domainsEssential if large-scale, Important if medium-scale
Recursive resolver operatorsISPs providing DNS resolution to end users, public DNS servicesEssential/Important by size
DNS management SaaS platformsPlatforms that manage zone files + provisioning for multiple domainsImportant (if meeting Annex II criteria)
CDN-integrated DNSCDNs providing DNS as part of content deliveryEssential/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 TypeRoleNIS2 Classification
TLD registryOperates the authoritative zone for a top-level domain (.de, .fr, .eu, .com)Essential (all sizes — systemic importance)
Domain name registration serviceProcesses domain registrations / transfers / deletions on behalf of registrantsImportant (if meeting Annex II size criteria)
RegistrarAccredited intermediary between registrants and registryImportant

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:

  1. Collect and verify registrant data — name, organisation, physical address, email, phone number
  2. Maintain data accuracy — implement procedures to validate and update registrant records
  3. Provide lawful access — make WHOIS data available to NCAs, CSIRTs, and parties with legitimate access requests
  4. 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 ModelExamplesNIS2 Classification
IaaSAWS EC2, Azure VMs, Hetzner CloudEssential (large scale), Important
PaaSAWS Elastic Beanstalk, Azure App Service, sota.ioEssential (large scale), Important
SaaSOffice 365, Salesforce, Google WorkspaceImportant (if meeting size criteria)
Cloud Management PlatformsMulti-cloud management, FinOps platformsImportant

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:

  1. Art.23 upstream reporting: Cloud providers must report significant incidents to their NCA (24h early warning → 72h notification → 30-day final report)
  2. 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:

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:

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:

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:

ArticleImplementing ActStatusENISA Guidance Available
Art.25 (DNS)Pending Commission DecisionExpected 2026Yes — ENISA DNS Security Guidelines
Art.26 (TLD/WHOIS)Partial — ICANN coordination2025–2026ENISA TLD Security Framework
Art.27 (Cloud)Commission Delegated Act plannedExpected 2026ENISA Cloud Security Guidelines v3
Art.28 (Data Centres)Pending Commission DecisionExpected 2026ENISA 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)

RequirementEssentialImportantAction
DNSSEC signing on authoritative zonesRequiredRecommendedSign all zones
MFA on zone management interfacesRequiredRequiredEnforce MFA + access logging
Multi-region anycast redundancyRequiredRecommendedDeploy geographically distributed nameservers
Query log retention ≥ 90 daysRequiredRequiredConfigure log retention policy
Abuse response SLA ≤ 24hRequiredRequiredImplement abuse handling workflow
Anomaly detection (tunnelling, amplification)RequiredRecommendedDeploy DNS monitoring tooling

TLD Registries and Registration Services (Art.26)

RequirementStatus
WHOIS accuracy verification proceduresMandatory
Abuse contact publicationMandatory
Data escrow with accredited escrow agentMandatory for TLD registries
DNSSEC signing of TLD zoneMandatory for TLD registries
Zone transfer access controlsMandatory
WHOIS data available for NCA/CSIRT requestsMandatory (with GDPR-compliant access procedures)

Cloud Computing Service Providers (Art.27)

RequirementEssentialImportant
Multi-tenant logical isolationRequiredRequired
Customer-managed keys (BYOK)RequiredRecommended
Data residency controlsRequiredRequired
Standard-format data exportRequiredRequired
Customer incident notification ≤ 72hRequiredRequired
Annual penetration testingRequiredRecommended
Transparency report publicationRequiredRecommended

Data Centre Service Providers (Art.28)

RequirementEssentialImportant
Power redundancy2NN+1
Cooling redundancy2NN+1
Physical access: badge + biometric + CCTVRequiredRecommended
Diverse network providers≥2≥2
Generator fuel supply≥72h≥48h
Physical access log retention≥90 days≥90 days
Visitor management systemRequiredRequired

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.