← Terug naar blog

Architecture Operating Model

Support

Architecture Operating Model 2025–2035

:root{ --bg:#f6f8fb; --panel:#fff; --ink:#0f172a; --muted:#475569; --blue:#1e40af; --blue-soft:#e0e7ff; --amber:#b45309; --teal:#0f766e; --grid:#e5e7eb; --chip:#eef2ff; --ok:#16a34a; --warn:#f59e0b; --danger:#dc2626; --code-bg:#0b1020; --code-ink:#e6edf3; } *{box-sizing:border-box} body{margin:0;font:15px/1.5 system-ui,Segoe UI,Roboto,Helvetica,Arial; color:var(--ink);background:linear-gradient(#eef2ff,#fff)} .wrap{max-width:1200px;margin:32px auto;padding:0 16px} .toolbar{display:flex;gap:8px;flex-wrap:wrap;align-items:center;justify-content:space-between;margin-bottom:16px} .btn{appearance:none;border:1px solid var(--grid);background:#fff;border-radius:8px;padding:8px 12px;cursor:pointer} .btn:active{transform:translateY(1px)} .field{width:420px;max-width:100%;height:70px;border:1px solid var(--grid);border-radius:8px;padding:8px} .canvas{background:var(--panel);border:1px solid var(--grid);border-radius:16px;padding:24px;box-shadow:0 12px 30px rgba(2,6,23,.06)} h1{color:var(--blue);text-align:center;margin:8px 0 4px} .subtitle{color:var(--muted);text-align:center;margin:0 0 16px} .grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;align-items:center} .card{background:var(--panel);border:1px solid var(--grid);border-radius:12px;padding:16px} .title-sm{font-weight:700;margin:0 0 6px} .muted{color:var(--muted)} .center{display:flex;justify-content:center;align-items:center} .orb{height:220px;width:220px;border-radius:999px;background:radial-gradient(ellipse at 30% 30%, #3b82f6, #1e3a8a); border:8px solid #fff;box-shadow:0 12px 30px rgba(2,6,23,.15);color:#fff;text-align:center;display:grid;place-items:center} .orb h2{margin:0 0 4px;font-size:18px} .list{margin:0;padding-left:18px} .list li{margin:4px 0} .pillars .card{border-top:4px solid var(--grid)} .pillars .card:nth-child(1){border-top-color:#3b82f6} .pillars .card:nth-child(2){border-top-color:#1e40af} .pillars .card:nth-child(3){border-top-color:#0d9488} .runway{display:flex;gap:16px} .stage{flex:1} .bar{height:8px;border-radius:999px;background:#e5e7eb;margin:6px 0;overflow:hidden} .bar>span{display:block;height:100%;background:#3b82f6} .okr{margin-top:8px} .chip{display:inline-block;font-size:12px;padding:2px 8px;border-radius:999px;background:var(--chip);color:#3730a3;margin:2px 6px 0 0} .metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:12px} .gauge{background:var(--blue-soft);border:1px solid var(--grid);border-radius:10px;padding:12px;text-align:center} .gauge h4{color:var(--blue);margin:4px 0} .gauge .val{color:var(--muted);font-size:13px} .tabs{margin-top:8px} .tab-head{display:flex;gap:6px;flex-wrap:wrap} .tab-head button{border:1px solid var(--grid);background:#fff;border-radius:8px;padding:6px 10px;font-size:13px;cursor:pointer} .tab-head button.active{background:#eef2ff;border-color:#c7d2fe} .badges{font-size:11px;margin-left:6px;color:#1e3a8a;background:#e0e7ff;border-radius:999px;padding:1px 6px} .tab-body{border:1px solid var(--grid);border-radius:10px;overflow:hidden;margin-top:6px} pre{margin:0;background:var(--code-bg);color:var(--code-ink);padding:12px;overflow:auto;font-size:12px} .flow{display:grid;grid-template-columns:1fr 40px 2fr 40px 1fr;gap:8px;align-items:center} .arrow{font-weight:700;text-align:center;color:#2563eb} .grid-variants{display:grid;grid-template-columns:repeat(4,1fr);gap:8px} .cap{border:1px solid var(--grid);border-radius:10px;padding:10px;font-size:13px} .cap.good{outline:2px solid rgba(22,163,74,.35)} .cap .state{padding:2px 6px;border-radius:999px;font-size:11px} .state.ok{background:#dcfce7;color:#166534} .state.partial{background:#f1f5f9;color:#64748b} .ruler{margin-top:16px;text-align:center;color:var(--muted);font-style:italic} .siem{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:16px} .input{width:100%;padding:8px;border:1px solid var(--grid);border-radius:8px;font-size:13px} @media (max-width:1000px){ .grid-3{grid-template-columns:1fr} .flow{grid-template-columns:1fr} .grid-variants{grid-template-columns:1fr 1fr} .metrics{grid-template-columns:1fr 1fr} .siem{grid-template-columns:1fr} }

Export PNG Export SVG

Canvas 4:3 A4 Portrait A4 Landscape

Apply JSON

Architecture Operating Model 2025–2035

Van documentatie naar een levend besturingssysteem

Drukfactoren

Architecture as Operating System

Policy as Code, Zero Trust, Telemetry

Uitkomsten

  1. Gefedereerde organisatie
  1. Geautomatiseerd control plane
  1. Waardestroom integratie

Dagen 1–30, Baseline en Telemetrie

DF baseline SaaS discovery

Dagen 31–60, MVA en PaC

5–7 guardrails in audit API linting

Dagen 61–90, Enforce en Quick wins

Tagging enforced SaaS rationalisatie

DF

35

Deployment Frequency LT

12

Lead Time CFR

8

Change Failure Rate MTTR

45

Mean Time to Restore

OPA Rego CI, CD Kyverno YAML CD, Runtime Infracost Policy CI API Linting (Spectral) CI SBOM Checks (CycloneDX) CI, Runtime Export Rego skeleton

package terraform.azure.finops

denied_skus := {"Standard_D16s_v3", "Standard_E32s_v3", "Standard_M64ms"}

deny[msg] { resource := input.resource_changes[_] resource.type == "azurerm_linux_virtual_machine" resource.change.after.tags.environment == "dev" denied_skus[resource.change.after.size] msg := sprintf("FinOps Policy Violation: disallow %v in dev.", [resource.change.after.size]) } apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: disallow-root-user spec: validationFailureAction: Enforce rules:

rules: no-http: error security-schemes-required: error require-oauth2-scopes: severity: error given: $.paths[][].security[].OAuth2[] then: function: truthy

cyclonedx-policy.toml, simple SBOM gating example

[policy] min_severity_block = "high" # block high and critical allow_licenses = ["MIT", "Apache-2.0", "BSD-3-Clause"]

[checks]

fail build if any component vulnerability severity >= high

vuln_threshold = { severity = ["high", "critical"], max = 0 }

require purl for traceability

require_purl = true

disallow components without version

no_unversioned = true

API Gateway as Policy Enforcement Point

ClientApp, Agent, Service →

API Gateway PEP

AuthN OIDC mTLS AuthZ OPA Rate limit Schema validate Threat detect

→ ServiceDomain API

Enforcement points: CI spec linting, CD policy checks, runtime gateway decisions.

Gateway Variants Vendor:

KongApigeeAzure APIMIstio

Indicatief. Integreer OPA via ext-auth waar geen native support is. Evidence logs naar SIEM via audit en decision logs.

Data residency ≠ legal sovereignty • EU-qualified provider required

SIEM Targets

Syslog OTLP gRPC OTLP HTTP Object Store Index Retention (days)

Evidence Sources

Export JSON Export YAML

// Defaults let metrics = { DF:35, LT:12, CFR:8, MTTR:45 };

// Apply JSON document.getElementById('applyJson').addEventListener('click', () => { try{ const v = JSON.parse(document.getElementById('json').value || '{}'); if(v.metrics){ metrics = Object.assign(metrics, v.metrics); renderMetrics(); } }catch{ alert('Invalid JSON'); } });

function renderMetrics(){ document.getElementById('mDF').textContent = String(metrics.DF); document.getElementById('mLT').textContent = String(metrics.LT); document.getElementById('mCFR').textContent = String(metrics.CFR); document.getElementById('mMTTR').textContent = String(metrics.MTTR); } renderMetrics();

// Tabs const head = document.getElementById('tabHead'); head.addEventListener('click', (e)=>{ const b = e.target.closest('button[data-tab]'); if(!b) return; [...head.querySelectorAll('button[data-tab]')].forEach(x=>x.classList.remove('active')); b.classList.add('active'); const key = b.dataset.tab; [...document.querySelectorAll('.tab-body pre')].forEach(p=>p.hidden=true); document.getElementById('tab-'+key).hidden = false; });

// Gateway variant matrix const support = { 'OIDC': { 'Kong':1, 'Apigee':1, 'Azure APIM':1, 'Istio':1 }, 'OPA/Ext auth':{ 'Kong':1, 'Apigee':0, 'Azure APIM':0, 'Istio':1 }, 'mTLS': { 'Kong':1, 'Apigee':1, 'Azure APIM':1, 'Istio':1 }, 'Rate limiting':{ 'Kong':1,'Apigee':1,'Azure APIM':1,'Istio':1 }, 'Schema validate':{ 'Kong':1,'Apigee':1,'Azure APIM':1,'Istio':1 }, 'WAF/Threat detect':{ 'Kong':1, 'Apigee':1, 'Azure APIM':1, 'Istio':1 }, 'Native Rego': { 'Kong':0, 'Apigee':0, 'Azure APIM':0, 'Istio':0 }, 'Ext Auth plugin':{ 'Kong':1,'Apigee':1,'Azure APIM':0,'Istio':1 } }; const vendorSel = document.getElementById('vendor'); const variants = document.getElementById('variants'); function renderVariants(){ const v = vendorSel.value; variants.innerHTML = ''; Object.keys(support).forEach(label=>{ const ok = support[label][v]===1; const el = document.createElement('div'); el.className = 'cap'+(ok?' good':''); el.innerHTML = ''+label+''+(ok?'Yes':'Partial/Ext')+''; variants.appendChild(el); }); } vendorSel.addEventListener('change', renderVariants); renderVariants();

// Evidence sources const sourceList = [ 'CI: SBOM scan', 'CI: Spectral OpenAPI lint', 'CD: OPA PaC gate', 'Runtime: Gateway decisions', 'Runtime: K8s Admission', 'CD: Infracost cap checks' ]; const sourcesDiv = document.getElementById('sources'); sourceList.forEach(s=>{ const lab = document.createElement('label'); lab.style.display='flex'; lab.style.alignItems='center'; lab.style.gap='6px'; const cb = document.createElement('input'); cb.type='checkbox'; cb.checked=true; cb.dataset.evidence=s; lab.appendChild(cb); lab.appendChild(document.createTextNode(s)); sourcesDiv.appendChild(lab); });

// Export Evidence Manifest function buildManifest(){ const pick = id => document.getElementById(id).value || ''; const checked = [...document.querySelectorAll('[data-evidence]')].filter(n=>n.checked).map(n=>n.dataset.evidence); return { version:'1.0', targets:{ syslog:pick('syslog'), otlp_grpc:pick('otlp'), otlp_http:pick('otlph'), object_store:pick('obj') }, index: pick('index') || 'aom-control-plane', retention_days: Number(pick('retention') || '365'), evidence_sources: checked }; } function download(name, mime, data){ const blob = new Blob([data], {type:mime}); const url=URL.createObjectURL(blob); const a=document.createElement('a'); a.href=url; a.download=name; a.click(); URL.revokeObjectURL(url); } function buildYaml(m){ const esc = v => typeof v==='string' ? v.replace(/"/g,'\"') : v; const bullets = (m.evidence_sources||[]).map(s=>' - '+s).join('\n'); return version: "$\{m.version\}" targets: syslog: "$\{esc(m.targets.syslog)\}" otlp_grpc: "$\{esc(m.targets.otlp_grpc)\}" otlp_http: "$\{esc(m.targets.otlp_http)\}" object_store: "$\{esc(m.targets.object_store)\}" index: "$\{esc(m.index)\}" retention_days: $\{m.retention_days\} evidence_sources: $\{bullets\}; } document.getElementById('expJson').onclick = ()=> download('aom-evidence-manifest.json','application/json', JSON.stringify(buildManifest(),null,2)); document.getElementById('expYaml').onclick = ()=> download('aom-evidence-manifest.yaml','text/yaml', buildYaml(buildManifest()));

// Export Rego skeleton const spectralSample = String.raw`extends: spectral:recommended

rules: no-http: error security-schemes-required: error require-oauth2-scopes: severity: error given: $.paths[][].security[].OAuth2[] then: function: truthy; document.getElementById('exportRego').onclick = ()=>\{ const rego = package api.pep

deny on HTTP-only schemes

deny["transport must be https"] { input.request.scheme == "http" }

deny when OAuth2 scopes missing

deny["missing oauth2 scopes"] { not input.auth.oauth2.scopes }

derived from Spectral rules

---

${spectralSample.replace(//g,'\\')}

`; download('gateway-pep.rego','text/plain',rego); };

// Simple PNG export using print as fallback document.getElementById('exportPng').onclick = ()=>{ // Fallback: open print dialog for quick export to PDF/PNG via system tools. window.print(); };

// Paper size hint (visual) document.getElementById('paper').addEventListener('change',(e)=>{ const m = e.target.value; const c = document.getElementById('canvas'); c.style.aspectRatio = m==='screen' ? '4 / 3' : (m==='a4p' ? '210 / 297' : '297 / 210'); });

// Self-checks console.assert(spectralSample.startsWith('extends: spectral:recommended'),'spectralSample header ontbreekt'); console.assert(/function:\s+truthy$/.test(spectralSample.trim()), 'spectralSample sluit niet correct af');

DjimIT Nieuwsbrief

AI updates, praktijkcases en tool reviews — tweewekelijks, direct in uw inbox.

Gerelateerde artikelen