Udvalgt arbejde / Projekt

Java 21 Spring Boot Certificate Control Plane API til IoT-enheder

Forfatter: Thomas Bonderup Udgivet: Fokusområde: Certificate lifecycle control plane

Java 21 Spring Boot API til IoT certificate lifecycle management med tenant-aware REST API'er, Keycloak JWT-sikkerhed, PostgreSQL/Flyway, Kafka outbox-events, OpenAPI/Postman-dokumentation og 88 tests.

Hvorfor projektet er relevant

Kontekst frem for abstraktion

Projekterne viser det tekniske miljø, leverancepresset og systemconstraints omkring arbejdet.

Beslutninger skal kunne spores

Den nyttige del er at forstå hvilke arkitektur- eller implementeringsvalg der betød noget, og hvorfor de blev taget.

Bevis skal kunne genbruges

Et stærkt projektforløb efterlader kode, mønstre og læring, som en anden ingeniør hurtigt kan vurdere.

Certificate lifecycle control plane Java Spring Boot IoT Sikkerhed
Java 21 Spring Boot API til IoT certificate lifecycle management med tenant-aware REST API'er, Keycloak JWT-sikkerhed, PostgreSQL/Flyway, Kafka outbox-events, OpenAPI/Postman-dokumentation og 88 tests.

Projektoversigt

Udfordring

Embedded IoT-enheder har brug for et sikkert, tenant-aware control plane til certifikatinventar, asset-relationer, udløbsrisiko, renewal workflow-state, audit-evidens og operator-facing API'er uden at blande lifecycle management ind i selve audit execution engine.

Rammebetingelser

  • Hold certificate lifecycle, asset-relationer, tenant-grænser og renewal workflow-state i et control plane frem for i audit execution engine.
  • Gør sikkerhed og drift reviewable gennem JWT scope checks, admin guards, Flyway/PostgreSQL schema ownership, Kafka-integration, OpenAPI, Postman og tests.

Tiltag

  • Byggede Java 21 Spring Boot API'er til certifikater, assets, bindings, summary views, expiry risk, attention-needed views og renewal history.
  • Implementerede tenant-aware sikkerhed, PostgreSQL/Flyway persistence, Kafka evidence- og renewal-events, outbox-backed renewal publication, OpenAPI/Swagger, Postman-workflows og automatiseret testdækning.

Resultater

  • Projektet giver den bredere audit-platform en konkret Java/Spring control-plane slice med tydelige grænser omkring Scala/ZIO execution engine.
  • Repository'et demonstrerer sikker API-design, schema-managed persistence, Kafka/outbox-integration, review-venlig dokumentation og 88 rapporterede tests på tværs af web, service, persistence, security og event-adfærd.

Kontekst

Dette projekt er Java 21 + Spring Boot control-plane-siden af den bredere migrering af en IoT audit-platform, som jeg beskriver i Migrering af en IoT Audit Engine fra Scala (ZIO) til Java 21 + Spring Boot.

Det offentlige repository ligger på GitHub:

ThomasBonderup/certificate-control-plane-api

Problemet er operationelt mere end kryptografisk: når antallet af embedded IoT-enheder vokser, bliver certificate lifecycle hurtigt til mere end “gem et certifikat et sted”. Teams skal vide, hvilke certifikater der findes, hvilken tenant der ejer dem, hvilke assets der afhænger af dem, hvilke der nærmer sig udløb, hvem der ejer renewal, hvilken status renewal har, og hvilke workflow-ændringer der skal blive til holdbar audit-evidens.

Servicen er bevidst afgrænset som et control plane, ikke som certifikatparser eller audit execution engine. Den ejer platform-state omkring certifikater, assets, bindings, workflow-status, tenant-grænser, API-dokumentation og operationel integration. Teknisk probe execution, TLS-validering, findings-generering og rapportlogik ligger uden for denne service.

Den opdeling holder audit execution og platform workflow i hver sit plan og gør grænsen tydelig gennem API’er, schema migrations, tests og dokumentation.

Hvad API’et gør

Repository’et implementerer et Spring Boot API til certificate lifecycle management i embedded- og IoT-miljøer:

  1. Certifikatinventar med status, gyldighedsperiode, owner, noter, fingerprint, issuer, serial number og renewal workflow-felter.
  2. Asset-inventar med tenant, type, environment, hostname, location og audit-felter.
  3. Certificate-to-asset bindings modelleret som first-class records med binding type, endpoint, port og uniqueness constraints.
  4. Reverse lookup API’er fra asset til certificate bindings og bundne certifikater.
  5. Expiring-soon og attention-needed views for certifikater, der er udløbet, blokerede, tæt på udløb, uden owner eller ikke bevæger sig gennem renewal.
  6. Summary endpoints for tenant-scoped certificate posture.
  7. Renewal history API’er baseret på gemte status-change rækker.
  8. Evidence ingestion-fundamenter, der accepterer raw probe evidence og publicerer envelopes til Kafka.

Controllerne er dokumenteret med OpenAPI annotations og eksponeret gennem lokal Swagger UI. Den committede Postman collection dækker token acquisition, authorization failures, certificate/asset/binding flows og beskyttede actuator endpoints.

Spring Boot-arkitektur

Implementeringen bruger en konventionel, men produktionsorienteret Spring Boot-struktur:

  • controller-klasser ejer HTTP-routes, validation entry points, response codes, Location headers, pagination defaults og OpenAPI metadata.
  • api records definerer request- og response-DTO’er med validation annotations og Swagger schema examples.
  • services holder applikationslogik, transaktionsgrænser, tenant enforcement, renewal workflow-regler, outbox writing og event publication.
  • repositories bruger Spring Data JPA derived queries og JPQL til tenant-scoped filters, expiring-soon queries, attention-needed queries og summary counts.
  • model-klasser definerer JPA entities og enums for certifikater, assets, bindings, renewal history, evidence envelopes og outbox events.
  • common og config giver shared API errors, JSON security errors, tenant/user providers, pageable sanitization, OpenAPI setup, scheduling og Spring Security.

Det gør projektet nemt at reviewe, fordi de centrale ansvar er eksplicitte: request shape, sikkerhed, forretningsregel, persistencemodel, integrationspunkt og testdækning har alle synlige hjem.

Sikkerhed, tenancy og authorization

Sikkerhed er ikke kun beskrevet i README’en; den er implementeret og testet:

  • Servicen kører som stateless OAuth2 resource server.
  • Lokal udvikling bruger Keycloak med rendered realm template og JWTs, der indeholder et tenantId claim.
  • Spring Security mapper scopes til authorities og udtrækker Keycloak realm/client roles til ROLE_* authorities.
  • GET /api/** kræver controlplane.read; POST, PATCH og DELETE /api/** kræver controlplane.write.
  • Actuator health og info er public; metrics og Prometheus kræver controlplane.read.
  • @EnableMethodSecurity aktiverer method-level authorization.
  • Sletning af certifikater og assets er beskyttet med @PreAuthorize("hasRole('ADMIN')").
  • Tenant-aware services bruger det autentificerede tenantId claim som den reelle grænse.
  • Create requests med tenantId skal matche JWT-claimet.
  • Cross-tenant resource access skjules bevidst som not found.

Testpakken dækker de vigtigste failure modes: manglende token, forkert scope, write-token der forsøger read, read-token der forsøger write, non-admin delete attempts, cross-tenant lookup-adfærd og mismatched tenant input.

Persistence og schema evolution

Persistence-laget er bygget omkring PostgreSQL og Flyway frem for ad hoc schema creation:

  • certificates gemmer certificate metadata, tenant ownership, status, validity timestamps, owner, notes, audit fields, blocked reason og renewal update timestamp.
  • assets gemmer tenant-scoped operational assets med type, environment, hostname, location og audit fields.
  • certificate_bindings modellerer certificate-to-asset relationships med uniqueness constraint på tværs af certificate, asset, binding type, endpoint og port.
  • certificate_renewal_status_history gemmer workflow transitions til senere inspektion.
  • outbox_events gemmer pending event payloads som PostgreSQL jsonb med aggregate metadata, topic, key, status og publication timestamps.
  • Hibernate validerer schema ved startup med ddl-auto: validate, mens Flyway ejer schema changes.
  • Indexes understøtter tenant, status, expiry, asset, binding, history og outbox lookup paths.

Det betyder noget, fordi certificate lifecycle-platforme står og falder med kedelig korrekthed: schema ownership, tenant filters, forudsigelige queries og auditable state transitions.

Kafka, evidence og outbox

Eventing-implementeringen har tre nyttige dele:

  • Raw evidence ingestion accepterer probe evidence, mapper det til en EvidenceEnvelope og publicerer det til Kafka.
  • Renewal status changes repræsenteres som CertificateRenewalStatusChangedEvent records.
  • Renewal status updates skriver en outbox event som del af certificate update-flowet, og en OutboxPublisher publicerer pending rows til Kafka og markerer dem som published.

Outbox pattern bruges her for driftssikkerhed omkring renewal workflow-events.1 I stedet for kun at opdatere certificate-rækken og derefter forsøge at publicere direkte til Kafka som en separat best-effort sideeffekt, skriver servicen en pending event i databasen som del af update-flowet. En publisher kan derefter læse pending rows, publicere dem og markere dem som published. Det giver systemet et holdbart handoff point mellem database-state og asynkron event delivery.

Den vigtige nuance: dette er et outbox-backed flow for renewal status publication, ikke en påstand om at alle asynkrone stier i servicen er outbox-backed. Raw evidence ingestion publicerer stadig direkte til Kafka. Den distinktion holder implementeringsgrænsen ærlig og viser samtidig, hvor driftssikkerheden var vigtigst for lifecycle audit-events.

Dokumentation og lokal developer experience

Repository’et er sat op, så det kan reviewes, køres og afprøves manuelt:

  • README.md forklarer service scope, lokal setup, Keycloak token flows, tenant enforcement rules, OpenAPI, Swagger UI, Postman-brug, actuator endpoints og sikkerhedsforventninger.
  • specs/architecture.md dokumenterer control-plane/execution-plane split, domain model, layered structure, persistence model og den aktuelle API-overflade.
  • docker-compose.yml starter PostgreSQL, Kafka, Keycloak, API-containeren og optional Kafka UI med local-only port bindings.
  • .env.example og Postman environment templates er sanitized.
  • Swagger UI findes lokalt på /swagger-ui.html, bakket af /v3/api-docs.
  • Postman collection indeholder read/write/admin token flows, no-token demos, read/write failure demos, certificate/asset/binding requests og protected actuator checks.

Den type dokumentation er et leverancesignal: backenden er ikke kun implementeret; den er pakket, så en anden engineer hurtigt kan vurdere adfærden.

Testdækning

Den automatiserede testpakke er en af projektets stærkeste dele.

./gradlew test passerer, og den genererede JUnit XML rapporterer 88 tests på tværs af 13 testklasser. Dækningen handler ikke kun om happy-path CRUD:

  • MockMvc integration tests for certificates, assets, bindings, audit runs og authorization-adfærd.
  • Testcontainers PostgreSQL integration coverage for persistence-backed API-adfærd.
  • Spring Security test support for JWT scopes, tenant claims, roles og protected actuator endpoints.
  • Tests for pagination, sorting, malformed Swagger sort fallback, filters, summary counts, expiry windows, attention-needed rules, renewal workflow transitions og tenant isolation.
  • Service tests for renewal-status outbox writing.
  • Tests for Kafka producer configuration, renewal-status consumer persistence, outbox event writing og outbox publication ordering.

Jeg beskriver testpakken ud fra den adfærd, den beviser, ikke med en headline-procent, fordi repository’et ikke aktuelt publicerer en separat code coverage report.

Outcome

Resultatet er et offentligt backendprojekt, der demonstrerer:

  • Java 21 og Spring Boot platform delivery.
  • REST API-design med validation, response DTO’er, pageable/sortable endpoints og klare HTTP-semantikker.
  • Spring Security-fundamenter med JWT resource server configuration, Keycloak role extraction, scope checks, method-level authorization og JSON security errors.
  • Tenant-aware service-design med eksplicit claim enforcement og cross-tenant protections.
  • PostgreSQL/Flyway schema ownership med JPA/Hibernate validation.
  • Kafka-integration, evidence ingestion-fundamenter, renewal history og et outbox-backed event flow.
  • OpenAPI, Swagger UI, Postman, Docker Compose, Keycloak local setup, Actuator, Prometheus metrics og praktisk udviklerdokumentation.
  • En meningsfuld automatiseret testpakke, der beviser adfærd på tværs af web, service, persistence, security og integration boundaries.

For teknisk kontekst kan du læse den relaterede migrationsartikel eller inspicere repository’et direkte:

Læs Java-migrationsartiklen eller se det offentlige GitHub-repository.

Referencer

Footnotes

  1. Chris Richardson, Transactional outbox pattern, Microservices.io.

Thomas Bonderup

Thomas Bonderup

Software Engineer

Specialiserer sig i IoT-arkitektur, distribuerede systemer, driftssikkerhed og observability, edge-to-cloud levering.

Builder-noter og projektreferencer

Hvis denne portfolio-post minder om noget, du selv bygger, tager jeg gerne en snak om implementering, arkitektur og tradeoffs.

Portfolio-posterne bygger på konkret systemarbejde, tekniske analyser og tidligere projekter. Hvis problemstillingen, arkitekturen eller tradeoffs ligner noget, du selv står med, tager jeg gerne en snak om det næste tekniske skridt.

Teknisk scope: IoT-arkitektur, distribuerede systemer, driftssikkerhed og observability, edge-to-cloud levering.

Gå videre til relateret arbejde eller start en faglig samtale

Hvis projektet overlapper med de systemer, du arbejder med, så gå videre til relateret arbejde, CV'et eller kontaktsiden for rekruttering og teknisk opfølgning.

Relateret indhold

Lad os tale om lignende arbejde

Skriv, hvis du vil tale om en rolle, et samarbejde eller følge op fagligt på noget tilsvarende.

Du kan også ringe på +45 22 39 34 91 eller skriv til tb@tbcoding.dk.

Brug formularen til spørgsmål om roller, projekter eller faglig opfølgning.

Typisk svartid: 1-2 hverdage.