Kai Ole Hartwig
20 min read
Low
By

Grundschutz++ against my own documentation

For anyone who maintains an ISMS and wonders whether it holds up against the new BSI Grundschutz. I checked mine against the state-of-the-art library. I answered every requirement against the running system, not against the page that claims it. And I show how the machine-readable catalogue can be compared directly with Infrastructure as Code and GitOps.

This post opens the series “Grundschutz++ as code”. The overview of all parts is further down.

01 — Where it started

My ISMS follows ISO 27001. There is a Statement of Applicability, registers for risks, assets and suppliers, and evidence for every control. Everything is versioned as Markdown in a repository. The setup is small: one business, one platform, a few customers.

With Grundschutz++ the BSI rebuilds its IT-Grundschutz. The requirements are published machine-readable in the Stand-der-Technik-Bibliothek. The question was simple. Does my ISMS hold up, and where does it not?

02 — Bringing Grundschutz++ and ISO 27001 together

Grundschutz++ no longer orders requirements by modules the way IT-Grundschutz used to. They are grouped by practices, for example DET for detection, KONF for configuration or NOT for contingency. Every requirement has an ID, a text and a level. The level is normal or elevated and follows the protection need.

The biggest change is the format. The BSI publishes the requirements in OSCAL, an open standard format, in the Stand-der-Technik-Bibliothek (state-of-the-art library). No custom parser is needed any more. A script can read the whole list, and no requirement gets lost in transfer.

The bridge to ISO 27001

An ISO 27001 ISMS already has a Statement of Applicability. Clause 6.1.3 d requires it. It lists the 93 controls of Annex A in the 2022 edition, each with the reason why it applies or not. The library contains a mapping from these controls to Grundschutz++.

That mapping produces the checklist. Every applied Annex A control brings its mapped Grundschutz++ requirements. In my case that was 280. Anyone running an ISO 27001 ISMS does not start from zero. The Statement of Applicability defines what to check.

03 — Normal and elevated: where the technical difference lies

The normal level is the baseline for any operation. The elevated level applies where the protection-need assessment shows a high need. The library states the level of each requirement. Whether it applies to your operation depends on your own protection need. The mapping to ISO 27001 does not make that decision for you.

The difference by example

The pairs below show how far apart the levels are. They are paraphrased summaries, not the BSI wording.

How I treated the elevated level

I answered all requirements at the normal level. At the elevated level there were three classes:

The third class matters most. An open requirement with a reason is a decision. An open requirement without one is a gap. In ISO 27001 that decision belongs in the risk treatment plan, approved by the risk owner.

04 — The method: configuration, not documents

The most important rule of the check: a requirement counts as met when the system shows it. A page claiming it is not enough.

Three kinds of evidence

The kind of evidence and the date of measurement sit on every line. That sounds pedantic. It is the difference between a check and comparing two texts. Whoever lays documents against documents checks whether the documentation agrees with itself. It almost always does.

Clear rating rules

One rule turned out to be especially important: a control that only exists on paper counts as not met, not as partly. Otherwise the middle of the scale becomes a hiding place.

05 — The catalogue as a data model: comparing it with IaC and GitOps

Grundschutz++ is the first BSI framework published in OSCAL, a NIST standard format for compliance data. It can therefore be processed without a custom parser. Every requirement is a JSON object with fixed fields. If you run your infrastructure as code, you now have two datasets that can be compared. That is what makes the check reproducible.

Anatomy of a requirement

A requirement is not free text with room for interpretation. It is a sentence with a fixed grammar, and the library splits it into fields. Shortened, it looks like this:

 

{
  "id": "KONF.3.2",
  "title": "Speicherverschlüsselung",
  "props": [
    { "name": "sec_level",       "value": "normal-SdT" },
    { "name": "effort_level",    "value": "3" },
    { "name": "confidentiality", "value": "2" },
    { "name": "threats",         "value": "G 0.19, G 0.14" }
  ],
  "parts": [{
    "name": "statement",
    "props": [
      { "name": "target_object_categories", "value": "IT-Systeme" },
      { "name": "documentation", "value": "Konfigurationshistorie" },
      { "name": "result",        "value": "integrierte Festspeichermedien" },
      { "name": "action_word",   "value": "verschlüsseln" },
      { "name": "modal_verb",    "value": "SOLLTE" }
    ],
    "prose": "Konfiguration für IT-Systeme SOLLTE integrierte Festspeichermedien verschlüsseln."
  }]
}

 

Source: BSI, Stand-der-Technik-Bibliothek, CC BY-SA 4.0, shortened. The catalogue is in German: the requirement says IT systems SHOULD encrypt built-in storage.

Five fields matter for a technical check:

On top come the level, an effort rating, the security objectives affected and references to the BSI's elementary threats. You can filter on all of that before reading a single line of text.

The action word decides the evidence

The action word is the most useful field. It separates the requirements you can check in a repository from those that need a record or an appointment. For my 280 requirements that gave four groups:

So almost 40 percent of the checklist can be answered directly against code. Another sixth against pipeline and monitoring data that exists anyway. Only the rest needs manual work on documents.

From target object to repository path

The target object tells you which part of the code to search. I defined the mapping once and used it for every requirement:

The configuration history is Git

The most common documentation type in the whole catalogue is the configuration history. It appears on 183 of 1,000 requirements. If you work with GitOps, you already have it. Every change is a commit, every commit belongs to a merge request, every approval to a pipeline. Nothing needs to be written down after the fact. You only have to point at the right commit.

That is why every line of the check names a repository and a commit. A statement like “encryption is on” is a claim without a commit. With a commit it can be verified, even a year later.

Desired, actual and claimed

IaC describes the desired state. That is not enough, because the running system can drift. For every configuration requirement I therefore compared three sources:

A requirement only counts as met when desired and actual agree. The interesting findings are where the claim disagrees with both. That happens more often than expected, and in both directions.

Making it reproducible

The library is republished continuously. A check against “the current version” cannot be repeated. Three rules solved that:

Whatever can be measured then becomes a check in the pipeline itself. A nightly job verifies, for example, that all release tags are protected. A daily tofu plan reports drift. A requirement that is met stays met, or someone finds out.

The tool

I have published the script as grundschutz-worksheets on GitHub, under the MIT licence. It is a Node program with no dependencies and nothing to install. It loads catalogue and mapping at a fixed commit directly from the library. It resolves nested requirements, fills in parameters and groups by practice. The output is one line per requirement with ID, level, modal verb, action word, target object, documentation type and the Annex A controls that lead to it. As a Markdown checklist or as CSV for a spreadsheet.

 

git clone github.com/ohartwig/grundschutz-worksheets
cd grundschutz-worksheets

C=367d775010abee641b258926bb482fcd05270059   # commit of the BSI library
CAT=control_layer/Grundschutz++/Grundschutz++-resolved_catalog.json
MAP=control_layer/Mappings/ISO-27001-zu-GSpp/ISO27001-AnnexA-to-GS++-mapping_collection.json

# Worksheet for your own Annex A controls, as CSV
node worksheet.mjs $CAT --mapping $MAP --sources @applicable-controls.txt \
  --format csv --commit $C > worksheet.csv

# Where is the work? Counts by practice, level, modal verb and action word
node worksheet.mjs $CAT --mapping $MAP --summary --commit $C

 

It does not answer anything for you. It only makes sure no requirement is missing. It does not copy the BSI texts into your own documentation either. That holds only IDs and your own assessment, partly because of the licence.

Second level: from the running system back to the code

An ISO 27001 auditor I showed the approach to named the weak spot right away. So far the comparison runs in one direction, from code to system. It checks whether what the repository says is actually running. It does not find what is running although it is written down nowhere. A server that should have been gone long ago. An open port nobody planned. A resource someone created by hand.

A drift check only helps halfway. tofu plan only compares the resources the code knows about. Whatever was created without code does not show up. The second level reverses the direction and asks the running system what exists:

A requirement is only met when both directions agree. The code describes the right thing, and the system contains nothing beyond it.

Limits of the approach

My setup is small and almost entirely described as code. That made the approach easy. In a grown environment I would start the same way, with a small area that already exists as code. There you quickly see whether the comparison holds. Bigger and more complex is always possible afterwards. Some things have to be checked several times and from different directions anyway.

06 — The figures

Of the 280 requirements, at the end of the check (26 September 2026):

The large middle is typical for an ISMS that is technically in good shape. The control runs, but one link of the chain is missing. Typical examples are an alert that fires but reaches nobody, or a test that checks an older setup. Only someone who measures the whole chain sees such gaps.

The 29 gaps are unevenly spread. Technical requirements, on logging, backups or configuration, could often be closed the same day. What stayed open were mostly organisational requirements. Those need appointments, not merge requests.

07 — The actual finding

I expected missing controls. What I mostly found was documentation that no longer matched. In both directions.

Patterns that repeated

In small organisations this is almost inevitable. The documentation is written once, carefully and completely. Then the system moves on and the documentation does not. Nobody lies. Nobody checks.

08 — What I am changing

The changes start where ISO 27001 already asks for something. They make the requirement checkable.

09 — What this means for an ISO 27001 audit

An auditor does not check whether the documentation looks nice. They check whether the documented controls are effective. They sample: show me this setting, this alert, this restore test.

That is exactly where outdated documentation surfaces. A control that only exists on paper is a nonconformity. If the pattern repeats, a minor nonconformity quickly becomes a major one, because control of documented information under 7.5 is then in question as a whole.

What the check does beforehand

Grundschutz++ does not replace a certification. It is, however, a very precise yardstick for what the state of the art is. Whoever checks their Statement of Applicability against it goes into the audit better prepared.

10 — My assessment of Grundschutz++

After one full pass my verdict is mixed. Overall it is clearly positive.

What convinces

What takes work

My conclusion: Grundschutz++ works as a yardstick for an ISO 27001 ISMS, especially in small businesses. It pays off most for those who treat the check as a measurement, not as a form.

11 — The series at a glance

So far the check only reads OSCAL. The catalogue arrives as data, but the answers are still prose in the handbook. The series turns that around step by step: the operation describes itself in OSCAL, generated from what the repositories already hold.

  1. Grundschutz++ against my own documentation: the method, the catalogue as a data model, the comparison with IaC and GitOps. This post.
  2. Applicability as data: your own selection from Grundschutz++ as an OSCAL profile, generated from the Statement of Applicability.
  3. Containers that say which requirements they meet: a signed component definition attached to every image the pipeline builds.
  4. Measurement as evidence: nightly checks write their results as OSCAL. Plus the second level, which finds in the running system what no repository knows about.
  5. The ISMS as a build product: a security plan that is assembled rather than written, with an honest account of the effort.

A part appears only once the step it describes is running and measured. The code for it lands in grundschutz-worksheets first. The titles are linked here as soon as each post is online.

Frequently asked questions

How often should you check?+

At least once a year as part of the internal audit under ISO 27001 clause 9.2, and after larger changes. Findings go into the improvement register as corrective actions.

Is this worth it for small businesses?+

Yes, if you use the requirements as a checklist and not as a specification. The machine-readable library makes matching much easier than the old Grundschutz with its modules. The biggest effort is measuring, not reading.

What do normal and elevated mean?+

It is the level of a requirement, derived from the protection need. The normal level is the baseline. The elevated level applies where an outage or a data leak weighs particularly heavily. It pays to take the easily reachable elevated requirements along right away.

How do you get from Annex A to the Grundschutz++ requirements?+

Through the mapping in the state-of-the-art library. It assigns the matching Grundschutz++ requirements to the Annex A controls. The starting point is your own Statement of Applicability: every applied control brings its requirements.

Does Grundschutz++ replace an ISO 27001 certification?+

No. Grundschutz++ is a catalogue of requirements, not a certification. It describes very precisely what the state of the art is. Checking your ISO 27001 Statement of Applicability against it finds the places an auditor would sample.

Conclusion

The check against Grundschutz++ found fewer missing controls than expected. Above all it showed where the documentation no longer fits the system. That is the part that costs most in an ISO 27001 audit. The Statement of Applicability provides the checklist, the library's mapping provides the requirements. Because every requirement is a record with a target object and an action word, a large part can be answered directly against IaC and GitOps repositories. The rest follows from one simple rule: only count what the system shows, and date every statement.

Next up: part 2, applicability as data.

I check your ISMS against Grundschutz++. Measured on the running system, not on the documentation.

Matching your Statement of Applicability against the state-of-the-art library, rating every requirement against configuration and measurement, and a clear list of gaps with effort and order.

Platform operations instead of paper consulting: on request I close the technical gaps myself and deliver the evidence for your ISO 27001 audit.

Book a call →

About the author

Photo of Kai Ole Hartwig.

Kai Ole Hartwig

Freelance DevSecOps consultant · OnlyOle Consulting

Programming since 2002 – self-taught, set up my own business with KO-Web in 2012. Over 100 projects, with a focus on security, performance, automation and quality. Today freelance: DevSecOps consulting, training and software development.