2026-04-16·16 min read·

NIS2 Art.21 Cybersecurity Risk Management: 10 Mandatory Measures — Developer Implementation Guide (2026)

NIS2 (Directive 2022/2555/EU) is in force across all EU Member States. For the approximately 160,000 essential and important entities in 18 critical sectors, Article 21 defines the legal floor for cybersecurity: ten minimum risk management measures that every covered organisation must implement — regardless of size, regardless of prior practice.

Unlike a voluntary framework, Art.21 is binding law. ENISA's 2024 implementation guidance and the NIS Cooperation Group's sector guidelines translate these ten measures into concrete technical requirements. Failure to implement them exposes organisations to fines of up to €10 million or 2% of global annual turnover for essential entities (Art.32), and €7 million or 1.4% for important entities (Art.33).

This guide covers all ten Art.21(2) measures, the management accountability obligation under Art.17, the proportionality principle under Art.21(1), how each measure interacts with GDPR Art.32 and DORA, a Python NIS2SecurityAssessor implementation, and a 30-item checklist.


1. Scope: Who Must Implement Art.21 Measures

Art.21(1) applies to essential entities (Art.3(1)) and important entities (Art.3(2)) as classified under NIS2.

Essential entities include organisations in energy, transport, banking, financial market infrastructure, health, drinking water, wastewater, digital infrastructure (IXPs, DNS, TLD registries, data centres, CDNs, cloud services), public administration, and space. Cloud computing service providers are essential entities regardless of size (Art.2(2)).

Important entities include postal services, waste management, chemicals, food, manufacturing (medical devices, machinery, vehicles, electronics), and digital providers (online marketplaces, search engines, social networks).

Indirect scope via supply chain (Art.21(2)(d)): Even organisations not directly covered by NIS2 may need to demonstrate equivalent security practices to their NIS2-covered customers under Art.21(2)(d) supply chain security obligations. If you supply SaaS, PaaS, or managed services to an essential or important entity, expect contractual requirements flowing down from Art.21.


2. The Proportionality Principle (Art.21(1))

Art.21(1) introduces a critical qualification: measures must be appropriate and proportionate to the risk, taking into account:

Proportionality does not mean optional compliance. It means the implementation depth scales with risk and organisational capacity. A cloud provider running critical EU financial infrastructure faces far higher expectations under Art.21 than a mid-size manufacturing company. Both must implement all ten measures; the depth differs.

The 2026 audit risk: National competent authorities (NCAs) have begun proactive Art.32 supervision of essential entities. ENISA's 2024 NIS2 implementation survey found that 43% of covered organisations had not yet fully implemented all ten Art.21(2) measures. June 2026 marks the expected start of first-wave supervisory inspections in most Member States.


3. Management Accountability (Art.17)

Before detailing the ten measures, a structural obligation: Art.17 makes management bodies personally accountable for cybersecurity.

Art.17(1): Management bodies of essential and important entities must approve the cybersecurity risk management measures and oversee their implementation. They bear personal responsibility for compliance.

Art.17(2): Management body members must undergo regular cybersecurity training sufficient to identify risks and assess the impact of cybersecurity practices on the services the entity provides.

Art.17(3): Entities must ensure that the same training is offered to their employees on a regular basis.

Practical implication: Security cannot be purely a technical team function. Board-level sign-off on risk management documentation is legally required. In NCA inspections, auditors will request evidence of management approval (board resolutions, sign-off dates) for cybersecurity policies.


4. The Ten Art.21(2) Measures in Detail

4.1 Measure (a): Policies on Risk Analysis and Information System Security

"Policies on risk analysis and information system security"

This is the foundation measure. Art.21(2)(a) requires documented risk analysis covering:

The NIS Cooperation Group's sector-specific guidelines (available per sector at nis-cooperation.eu) define minimum risk analysis scope. For cloud providers under ENISA's cloud security guidelines, this includes multi-tenant isolation risks and shared-responsibility matrix documentation.

Developer implementation: Treat risk analysis as code. Version-controlled threat models (e.g., using OWASP Threat Dragon or Microsoft Threat Modeling Tool) with Git-tracked changes give NCAs auditable history of risk decisions. A RISK-REGISTER.md with structured fields (asset, threat, likelihood 1–5, impact 1–5, residual risk, owner, review date) is the minimum viable artefact.

4.2 Measure (b): Incident Handling

"Incident handling"

Art.21(2)(b) requires policies and procedures for incident handling. This measure overlaps directly with the Art.23 reporting obligation (see NIS2 Art.23 Incident Reporting guide).

Required elements:

Dual-reporting link: When incidents involve personal data, Art.21(2)(b) incident handling must integrate with GDPR Art.33 breach notification procedures (see NIS2 + GDPR Dual Reporting guide). The same incident triggers two notification tracks with different recipients and different content requirements.

Hosting jurisdiction note: Incident forensics require fast, unimpeded access to logs and evidence. If your infrastructure runs on US-incorporated providers (AWS, Azure, GCP, Railway, Vercel) operating under the CLOUD Act (18 U.S.C. § 2713), a US law enforcement production order can compel disclosure of your incident logs to US authorities — potentially before you complete your Art.23 NCA notification. EU-incorporated infrastructure removes this risk (see EU Region vs. EU Jurisdiction guide).

4.3 Measure (c): Business Continuity

"Business continuity, such as backup management and disaster recovery, and crisis management"

Art.21(2)(c) is the most operationally complex measure. It covers three linked domains:

Backup management:

Disaster recovery:

Crisis management:

DORA parallel: Financial entities covered by DORA (Regulation 2022/2554) must implement equivalent BCM requirements under DORA Art.12. For entities subject to both NIS2 and DORA, a unified BCM framework satisfies both (see NIS2 + DORA dual compliance guide).

4.4 Measure (d): Supply Chain Security

"Supply chain security, including security-related aspects concerning the relationships between each entity and its direct suppliers or service providers"

Art.21(2)(d) is one of the highest-risk measures for enforcement in 2026. The June 2026 audit cycle explicitly targets supply chain security after ENISA's 2023 Threat Landscape report identified supply chain attacks as the top threat vector for NIS2-covered sectors.

Required elements:

The CLOUD Act supply chain paradox: If your NIS2-critical services run on US-incorporated cloud infrastructure, your primary ICT supplier is subject to CLOUD Act compelled disclosure. This is a legally distinct supply chain risk. BSI (Germany) and ANSSI (France) have both issued guidance identifying US cloud providers as elevated NIS2 Art.21(2)(d) risk factors. See the NIS2 × CLOUD Act Supply Chain guide.

4.5 Measure (e): Security in Network and Information System Acquisition, Development, and Maintenance

"Security in network and information systems acquisition, development and maintenance, including vulnerability handling and disclosure"

Art.21(2)(e) extends security requirements across the full system lifecycle:

Acquisition: Procurement criteria must include security requirements. Vendors must demonstrate security practices (certifications, penetration test reports, SOC 2 reports, ISO 27001, or equivalent). This applies to hardware, software, and cloud services.

Development (secure SDLC):

Maintenance:

Vulnerability disclosure:

4.6 Measure (f): Assessment of Cybersecurity Risk Management Effectiveness

"Policies and procedures to assess the effectiveness of cybersecurity risk management measures"

Art.21(2)(f) closes the loop. Implementing measures is not sufficient — entities must prove their measures work.

Required practices:

The output of Art.21(2)(f) activities directly feeds the Art.21(2)(a) risk analysis update cycle. Ineffective controls identified in audits must trigger risk register updates and control improvements.

4.7 Measure (g): Basic Cyber Hygiene and Cybersecurity Training

"Basic cyber hygiene practices and cybersecurity training"

Art.21(2)(g) has two distinct components:

Basic cyber hygiene — the technical minimum:

Cybersecurity training — covering all staff:

4.8 Measure (h): Cryptography and Encryption

"Policies and procedures regarding the use of cryptography and, where appropriate, encryption"

Art.21(2)(h) requires a documented cryptography policy covering:

Encryption at rest:

Encryption in transit:

Key management lifecycle:

Algorithm standards: ENISA's Cryptographic Recommendations document (updated annually) defines approved algorithms. Post-quantum migration timelines are increasingly referenced in NCA guidance for essential entities with long-lived data.

4.9 Measure (i): Human Resources Security, Access Control, and Asset Management

"Human resources security, access control policies and asset management"

Art.21(2)(i) covers three linked domains:

Human resources security:

Access control:

Asset management:

4.10 Measure (j): Multi-Factor Authentication

"The use of multi-factor authentication or continuous authentication solutions, voice over IP, encrypted video and text communications and encrypted emergency communication systems"

Art.21(2)(j) is the most prescriptive measure in Art.21. It explicitly mandates:

Multi-factor authentication (MFA):

Continuous authentication:

Encrypted communications:


5. NIS2 Art.21 vs. GDPR Art.32: Overlap and Differences

NIS2 Art.21 and GDPR Art.32 both impose security requirements, but with different primary purposes:

DimensionNIS2 Art.21GDPR Art.32
Primary goalResilience of network and information systemsProtection of personal data
Who must complyEssential and important entities (NIS2 scope)All GDPR controllers and processors
Specificity10 named measures (Art.21(2)(a)–(j))Risk-appropriate measures (Recital 83)
Management accountabilityArt.17: explicit board responsibilityNo equivalent provision
Supply chainArt.21(2)(d): explicit supply chain obligationArt.28: processor requirements
MFAExplicit in Art.21(2)(j)Implied under "appropriate measures"
Enforcement bodyNational competent authority (NCA)Data protection authority (DPA)
Fine maximum€10M / 2% global turnover (EE)€20M / 4% global turnover

For organisations subject to both: NIS2 Art.21 implementation satisfies the technical security requirements of GDPR Art.32 when the measures address personal data systems. A unified security framework covering both regulatory requirements reduces audit burden. See the GDPR Art.32 Technical Security Measures guide for GDPR-specific implementation detail.


6. Python NIS2SecurityAssessor Implementation

from dataclasses import dataclass, field
from datetime import date, timedelta
from enum import Enum
from typing import Optional

class ComplianceStatus(Enum):
    COMPLIANT = "compliant"
    PARTIAL = "partial"
    NON_COMPLIANT = "non_compliant"
    NOT_ASSESSED = "not_assessed"

class EntityType(Enum):
    ESSENTIAL = "essential"
    IMPORTANT = "important"

@dataclass
class Art21Measure:
    """One of the 10 mandatory Art.21(2) measures."""
    code: str                         # e.g. "a", "b", ..., "j"
    name: str
    status: ComplianceStatus = ComplianceStatus.NOT_ASSESSED
    evidence: list[str] = field(default_factory=list)
    gaps: list[str] = field(default_factory=list)
    remediation_deadline: Optional[date] = None
    owner: str = ""
    last_assessed: Optional[date] = None

@dataclass
class NIS2SecurityAssessment:
    """Full Art.21 assessment for an NIS2-covered entity."""
    entity_name: str
    entity_type: EntityType
    sector: str                       # e.g. "cloud_computing", "energy", "health"
    assessment_date: date
    measures: dict[str, Art21Measure] = field(default_factory=dict)
    management_approved: bool = False  # Art.17(1) requirement
    management_training_done: bool = False  # Art.17(2) requirement

    def add_measure(self, measure: Art21Measure) -> None:
        self.measures[measure.code] = measure

    @property
    def compliant_count(self) -> int:
        return sum(
            1 for m in self.measures.values()
            if m.status == ComplianceStatus.COMPLIANT
        )

    @property
    def non_compliant_count(self) -> int:
        return sum(
            1 for m in self.measures.values()
            if m.status == ComplianceStatus.NON_COMPLIANT
        )

    @property
    def art17_compliant(self) -> bool:
        return self.management_approved and self.management_training_done

    @property
    def overall_status(self) -> ComplianceStatus:
        if not self.art17_compliant:
            return ComplianceStatus.NON_COMPLIANT
        if self.non_compliant_count > 0:
            return ComplianceStatus.NON_COMPLIANT
        partial = [m for m in self.measures.values()
                   if m.status == ComplianceStatus.PARTIAL]
        if partial:
            return ComplianceStatus.PARTIAL
        if self.compliant_count == 10:
            return ComplianceStatus.COMPLIANT
        return ComplianceStatus.NOT_ASSESSED

    def fine_exposure_eur(self) -> int:
        """Indicative maximum fine based on entity type."""
        if self.entity_type == EntityType.ESSENTIAL:
            return 10_000_000  # €10M or 2% global turnover, whichever higher
        return 7_000_000  # €7M or 1.4% global turnover

    def priority_gaps(self) -> list[tuple[str, list[str]]]:
        """Return non-compliant and partial measures with their gaps, sorted by measure code."""
        gaps = [
            (m.code, m.gaps)
            for m in self.measures.values()
            if m.status in (ComplianceStatus.NON_COMPLIANT, ComplianceStatus.PARTIAL)
            and m.gaps
        ]
        return sorted(gaps, key=lambda x: x[0])

    def generate_remediation_plan(self) -> list[dict]:
        """Generate time-bound remediation items for all gaps."""
        plan = []
        deadline_map = {
            ComplianceStatus.NON_COMPLIANT: date.today() + timedelta(days=30),
            ComplianceStatus.PARTIAL: date.today() + timedelta(days=90),
        }
        for m in self.measures.values():
            if m.status in deadline_map:
                for gap in m.gaps:
                    plan.append({
                        "measure": m.code,
                        "measure_name": m.name,
                        "gap": gap,
                        "owner": m.owner or "TBD",
                        "deadline": deadline_map[m.status].isoformat(),
                        "priority": "HIGH" if m.status == ComplianceStatus.NON_COMPLIANT else "MEDIUM",
                    })
        return plan


def build_example_assessment() -> NIS2SecurityAssessment:
    """Example: cloud PaaS provider (essential entity) self-assessment."""
    assessment = NIS2SecurityAssessment(
        entity_name="ExamplePaaS GmbH",
        entity_type=EntityType.ESSENTIAL,  # cloud providers are EE regardless of size
        sector="cloud_computing",
        assessment_date=date.today(),
        management_approved=True,      # Art.17(1): board approved security policies
        management_training_done=False,  # Art.17(2): training not yet completed — gap!
    )

    measures = [
        Art21Measure(
            code="a", name="Risk analysis and IS security policies",
            status=ComplianceStatus.COMPLIANT,
            evidence=["risk-register-v3.md", "board-approval-2026-03.pdf"],
            last_assessed=date(2026, 3, 15),
        ),
        Art21Measure(
            code="b", name="Incident handling",
            status=ComplianceStatus.PARTIAL,
            evidence=["incident-runbook-v2.md"],
            gaps=["Tabletop exercise not conducted in last 12 months",
                  "NIS2 Art.23 24h reporting runbook not tested"],
            owner="CISO",
            remediation_deadline=date(2026, 5, 1),
        ),
        Art21Measure(
            code="c", name="Business continuity and disaster recovery",
            status=ComplianceStatus.PARTIAL,
            evidence=["dr-plan.md", "backup-policy.md"],
            gaps=["Last DR test was 18 months ago — overdue",
                  "Backup restore test not documented"],
            owner="Infrastructure Lead",
            remediation_deadline=date(2026, 5, 15),
        ),
        Art21Measure(
            code="d", name="Supply chain security",
            status=ComplianceStatus.NON_COMPLIANT,
            gaps=["No formal supplier inventory", 
                  "No security questionnaires sent to critical ICT suppliers",
                  "Contracts with AWS/GCP lack NIS2 Art.21(2)(d) clauses",
                  "CLOUD Act risk not assessed in supplier risk register"],
            owner="Legal + Engineering",
            remediation_deadline=date(2026, 4, 30),
        ),
        Art21Measure(
            code="e", name="Secure SDLC, vulnerability handling and disclosure",
            status=ComplianceStatus.PARTIAL,
            evidence=["sast-results-q1-2026.pdf", "sca-report.json"],
            gaps=["No coordinated vulnerability disclosure (CVD) policy published",
                  "DAST not integrated in CI/CD"],
            owner="Engineering Lead",
        ),
        Art21Measure(
            code="f", name="Effectiveness assessment",
            status=ComplianceStatus.NON_COMPLIANT,
            gaps=["No penetration test in last 24 months",
                  "No security KPIs reported to management",
                  "No internal audit scheduled"],
            owner="CISO",
            remediation_deadline=date(2026, 5, 31),
        ),
        Art21Measure(
            code="g", name="Cyber hygiene and training",
            status=ComplianceStatus.COMPLIANT,
            evidence=["training-completion-2026-q1.csv",
                      "security-awareness-programme.md"],
            last_assessed=date(2026, 4, 1),
        ),
        Art21Measure(
            code="h", name="Cryptography and encryption",
            status=ComplianceStatus.COMPLIANT,
            evidence=["crypto-policy-v2.md", "tls-config-audit.pdf"],
            last_assessed=date(2026, 2, 1),
        ),
        Art21Measure(
            code="i", name="HR security, access control, asset management",
            status=ComplianceStatus.PARTIAL,
            evidence=["access-control-policy.md"],
            gaps=["No quarterly privileged access review documented",
                  "Asset inventory missing IoT/edge devices"],
            owner="IT Operations",
        ),
        Art21Measure(
            code="j", name="MFA and encrypted communications",
            status=ComplianceStatus.COMPLIANT,
            evidence=["mfa-policy.md", "yubikey-deployment.md"],
            last_assessed=date(2026, 3, 1),
        ),
    ]

    for m in measures:
        assessment.add_measure(m)

    return assessment


if __name__ == "__main__":
    assessment = build_example_assessment()

    print(f"Entity: {assessment.entity_name} ({assessment.entity_type.value})")
    print(f"Overall status: {assessment.overall_status.value}")
    print(f"Art.17 compliant: {assessment.art17_compliant}")
    print(f"Measures compliant: {assessment.compliant_count}/10")
    print(f"Fine exposure (indicative max): €{assessment.fine_exposure_eur():,}")
    print()
    print("Priority gaps:")
    for code, gaps in assessment.priority_gaps():
        m = assessment.measures[code]
        print(f"  [{code}] {m.name}: {m.status.value}")
        for gap in gaps:
            print(f"    - {gap}")
    print()
    print("Remediation plan:")
    for item in assessment.generate_remediation_plan():
        print(f"  [{item['priority']}] ({item['measure']}) {item['gap']}")
        print(f"    Owner: {item['owner']} | Deadline: {item['deadline']}")

7. NIS2 Art.21 Developer Checklist (30 Items)

Management and Governance (Art.17)

Measure (a): Risk Analysis

Measure (b): Incident Handling

Measure (c): Business Continuity

Measure (d): Supply Chain Security

Measure (e): Secure SDLC

Measure (f): Effectiveness Assessment

Measures (g)–(j): Technical Controls


8. Hosting and Art.21 Compliance

NIS2 Art.21 creates direct implications for hosting choices, particularly for essential entities:

Supply chain security (Art.21(2)(d)): Your cloud provider is a critical ICT supplier. If your provider is US-incorporated (AWS, Azure, GCP, Railway, Render, Vercel, Fly.io), they are subject to the CLOUD Act. Your NCA-facing Art.21(2)(d) supplier risk register must reflect this. BSI and ANSSI have both issued guidance treating US cloud providers as elevated supply chain risk factors.

Incident forensics (Art.21(2)(b)): US cloud providers can be compelled to hand over your incident logs to US law enforcement before your NCA notification is complete. EU-incorporated, EU-law-governed infrastructure removes this risk.

Cryptography and key management (Art.21(2)(h)): HSM solutions and key management must comply with export control regulations. EU-incorporated providers are not subject to US export control restrictions (EAR) that affect US-incorporated providers.

Backup and DR (Art.21(2)(c)): Data sovereignty requires that backups remain within EU jurisdiction. "EU region" on a US provider is not EU jurisdiction — see the EU Region vs. EU Jurisdiction guide.


See Also