Hvordan vi skapte idiotsikker multitenant sikkerhet
Sikkerhet i multitenant SaaS-produkter kan være utfordrende. For verktøyet vårt Designmaskinen har vi utviklet en løsning som krever minimalt vedlikehold og som funker!
Sikkerhet i Designmaskinen
Sikkerhet er kanskje det viktigste aspektet i et multitenant SaaS-produkt. Multitentant handler om at flere kunder deler samme programvareinstans og infrastruktur, men har adskilte og sikre datasett.
Da vi utviklet Designmaskinen, en B2B-applikasjon som håndterer flere organisasjoner i samme system, var dataisolering vår høyeste prioritet. Vi ønsket å skape et robust system som lot oss utvikle raskt uten frykt for å introdusere sikkerhetshull uansett hvor kompleks applikasjonen ble.
I Designmaskinen er det avgjørende å holde kundedata adskilt. For å få det til bruker vi Clerk for identitetshåndtering og PostgreSQLs row-level security.
Tjenesten har vært i produksjon siden november 2023 – så hvorfor skriver vi om dette nå? Fordi vi nylig tok et steg tilbake og beundret det vi hadde oppnådd.
Sikkerhetsløsningen vi utviklet har stått urørt siden lansering. Den fungerer bare. Den gjør jobben sin. En skuddsikker svart boks som håndterer hvem som har tilgang til hva. Det synes vi fortjener et blogginnlegg.
Multitenancy: Sikkerhetsutfordringene med flere kunder i én applikasjon
For å forstå utfordringene knyttet til multitenancy, er det viktig å definere begrepet. Multitenancy innebærer at flere tenants, i vårt tilfelle ulike organisasjoner, bruker samme applikasjon, mens dataene holdes strengt atskilt. Det finnes flere måter å løse dette på:
Tilgangskontroll på API-nivå: En enkel løsning er å kontrollere tilgang ved hjelp av API-kall. Du sjekker hvem brukeren er, og returnerer dataene de skal ha tilgang til. Imidlertid kan denne tilnærmingen være risikabel, da tilgangslogikken kan bli spredt over hele kodebasen, noe som kan føre til feil etter hvert som applikasjonen vokser.
Egen instans for hver organisasjon: En annen tilnærming er å opprette en separat instans av applikasjonen for hver enkelt organisasjon. Selv om dette sikrer 100 % isolasjon, blir det raskt uholdbart og tungvint etter hvert som kundebasen vokser.
Løsningen vår: Slik sikrer vi data med row-level security (RLS)
Vi valgte å sikre dataene med row-level security (RLS) i PostgreSQL, som gir en robust, innebygd sikkerhetskontroll direkte i databasen. Med RLS, defineres tilgangsregler på radnivå i databasen, slik at kun de radene som en bruker har rettigheter til, kan leses eller endres.
Fordelene med å bruke RLS:
Sentralt administrert sikkerhet: RLS flytter sikkerhetslogikken til databasen, og reduserer risiko for feil.
Automatisk håndheving av regler: Sikkerhetsreglene er alltid aktivert, uansett tilgangsmetode.
Redusert kompleksitet: Mindre behov for komplisert kode i applikasjonen.
Skalérbarhet: Vi kan håndtere mange kunder i én enkelt database uten å kompromittere sikkerheten.
Hvorfor Clerk ble vår partner for sikker identitetshåndtering
Designmaskinen består av flere individuelle deler. Frontend-applikasjonen som er bygget med Next.js, og en API-server bygget med Express som igjen kommuniserer med en PostgreSQL-database. I tillegg snakker både frontend-applikasjonen og API-serveren med identitetsplattformen Clerk. I motsetning til løsninger som Auth0 (Okta), NextAuth.js/Auth.js eller Firebase, er Clerk spesifikt designet for multitenant-miljøer. Det tilbyr støtte for både brukere, organisasjoner og ulike roller rett ut av boksen – som gjør det til en perfekt match for vårt bruksmønster.
Opprinnelig vurderte vi å håndtere brukere selv, lagre all brukerinfo i vår egen database, og ha full kontroll. Men det ble raskt klart at det å vedlikeholde en egen autentiseringsløsning med et lite teknologiteam ville kreve mye tid og potensielt utgjøre en sikkerhetsrisiko på sikt. Derfor valgte vi å benytte en tredjepart, Clerk, som lot oss fokusere på å bygge kjernen i Designmaskinen, uten å gå på kompromiss på sikkerhet.
JWT: Nøkkelen til sikkerhet og dataautentisering
Nå som brukere og organisasjoner ikke lenger lever i vår database, men håndteres av en ekstern aktør, hvordan lager vi en solid kobling mellom brukere og organisasjoner i Clerk, og dataen deres i vår base?
Hver enkelt spørring mot API-serveren inneholder et JSON Web Token. Et JWT kan sammenlignes med en låst glassboks. Alle kan se hva som er i boksen, men kun de med nøkkelen kan åpne boksen og endre innholdet. Hvis du kan åpne boksen med din nøkkel, vet du også at den ble låst med din nøkkel.
Denne nøkkelen inneholder ikke-sensitiv informasjon om hvem brukeren er, i vårt tilfelle session-, bruker- og organisasjon-ID, samt hvilken rolle brukeren har i organisasjonen. Ved å validere nøkkelen kan vi garantere at informasjonen er utstedt av Clerk, og ikke har blitt tuklet med.
Fordelene med vår sikkerhetstilnærming: Fleksibilitet og skalering uten kompromiss
Gjennom et tynt Express-middleware åpner vi en ny kobling til databasen og kaller på en PostgreSQL-funksjon som midlertidig lagrer informasjon om hvem brukeren er. Deretter er det RLS-reglene vi har satt som bestemmer hvem som har tilgang til hva.
Med RLS er det også enkelt å utvide sikkerhetsreglene i fremtiden, skulle behovet oppstå. Vi kan legge til nye regler, nye roller, eller til og med endre hele måten tilgang kontrolleres på, uten å forstyrre eksisterende kodebase. Det gir oss trygghet i at løsningen vår er bygget for å skalere uten å gå på kompromiss med sikkerheten. Og i en applikasjon som Designmaskinen, hvor dataintegritet og -sikkerhet er alt, er det akkurat det vi trenger.
Oppsummert: Sikkerhet som styrke, ikke en byrde
Sikkerhet i et multitenant SaaS-produkt som Designmaskinen er ikke bare en teknisk utfordring, men en balansekunst. Vi måtte bygge noe som føles sømløst og intuitivt for brukerne, samtidig som det beskytter dataene deres med et system så robust at ingen noensinne trenger å tenke på det. Ved å kombinere JWT for autentisering og RLS i PostgreSQL for tilgangskontroll, har vi skapt en løsning som «bare funker». Usynlig, men uknuselig.
Denne tilnærmingen sikrer at data holdes logisk adskilt på radnivå i én fysisk database, mens all sikkerhetslogikk håndteres i backend.
Til syvende og sist handler vår tilnærming om å sikre at sikkerhet ikke blir en belastning, men en styrke, uten at utviklere, designere eller brukere trenger å tenke på det. At vi kan si at det har fungert perfekt siden dag én, gjør oss stolte. Dette betyr at vi kan fokusere på å bygge en fantastisk brukeropplevelse, vel vitende om at alt under panseret er like sikkert som et bankhvelv.
Hvis du står overfor lignende utfordringer med sikkerhet i ditt eget produkt, eller er nysgjerrig på hvordan vi implementerte dette, ta kontakt!
Vi elsker å dykke ned i sikkerhetsløsninger som både fungerer og skalerer.