Skip to main content

Key Management Policy

Key Management Policy

Project / Organization: ALAI Holding AS — Drop Payment App Policy Number: POL-SEC-KM-001 Version: 1.0 Date: 2026-02-23 Author: ALAI Security TeamArchitect Status: Draft Reviewers: CISO, CTO, DPO Next Review: 2027-02-23 (annual) or after Phase 2 AWS KMS integration Classification: Confidential — Restricted Distribution

Document History

Version Date Author Changes
0.1 2026-02-12Security Agent (ALAI)Initial standards from security audit
1.02026-02-23 Security Architect (ALAI) PolicyInitial documentdraft — Drop key management for AWS KMS + Secrets Manager

Sources: legal/ikt-sikkerhetspolicy.md §6.3, docs/SECURITY-COMPLIANCE/data-encryption-policy.md, security/security-hardening-implementation.md


1. Purpose & Scope

Purpose: This policy defines the lifecycle management requirements for all cryptographic keys and secrets used by ALAI Holding AS infor the Drop payment application.app, Dropincluding processesgeneration, regulateddistribution, financialstorage, datausage, (fødselsnummer,rotation, bankrevocation, accounts,and transactiondestruction.

data,

Regulatory AMLbasis:

records)
    requiring systematic key management per
  • GDPR Art. 32,32 — appropriate technical measures for personal data
  • Personopplysningsloven (LOV-2018-06-15-38) § 28
  • IKT-forskriften (FOR-2003-05-21-630) §§ 5-6
  • DORA (EU) 2022/2554 Art. 9(4)(d), and IKT-forskriften.

    encryption key management
  • Hvitvaskingsloven (LOV-2018-06-01-23) § 30 — KYC data protection at rest

Scope: All cryptographic keys and secrets in use across:

  • Production, staging, and development environments for Drop
  • AWS infrastructure (KMS, Secrets Manager, S3, App Runner)
  • All cloudemployee infrastructureand (AWS — EEA regions, Phase 2+)
  • All developercontractor workstations handling Confidential or Restricted data
  • All third-party integrations where ALAI Holding AS holds keys (Sumsub, Neonomics, Swan, BankID)
  • JWT signing keys, database encryption keys, TLS certificate private keys, API authentication keys

Policy Owner: Alem Bašić, CISO (alem@alai.security@getdrop.no) Operational Owner: ALAI Platform/Security team


2. Key Types & PurposesInventory

2.1 CurrentComplete MVPKey KeysTaxonomy

var
Key ID Type Algorithm Purpose Data Classification Protected LocationOwnerStorage
JWT-01drop-national-id-key JWT Signing KeyKEK HMAC-SHA-256 (HS256)AES-256-GCM SignFoedselsnummer andfield verify JWT session tokensencryption AllRestricted user data(L4) JWT_SECRETSecurity envteam AWS KMS (eu-north-1)
drop-db-master-keyKEK (Database)AES-256 XTSPostgreSQL TDE — Phase 2Restricted (L4)Security teamAWS KMS (eu-north-1)
drop-kyc-keyKEK (Object)AES-256-GCMKYC document encryption (S3 SSE-KMS)Restricted (L4)Security teamAWS KMS (eu-north-1)
drop-backup-keyKEK (Backup)AES-256Database backup encryptionRestricted (L4)Security teamAWS KMS (eu-west-1) — separate region
JWT_SECRETSigning secretHMAC-SHA-256JWT session token signing (HS256)Confidential (L3)Security teamAWS Secrets Manager
TLS-EXT TLS Certificate Key ECDSA P-256 External HTTPS (getdrop.no) All transit data HostingCloudflare provider/ Let's EncryptCloudflare managed
SUMSUB-01BankID-cert WebhookTLS HMAC KeyCertificate HMAC-SHA-256RSA-2048 VerifyBankID SumsubNorway KYCJWT webhookssignature verification KYC data integrity SUMSUB_WEBHOOK_SECRETBankID envNorge varAS CABankID managed
SENTRY-01SUMSUB-API-KEY DSN TokenBearer tokenSentry error reportingError dataSENTRY_DSN env var

2.2 Phase 2 Target Keys (AWS KMS)

Key IDTypeAlgorithmPurposeClassification ProtectedOwner
KEK-01Key Encryption KeyAES-256Master key for database DEKsRestrictedSecurity team
KEK-02Key Encryption KeyAES-256Fødselsnummer encryption masterRestricted (L4)Security team
DEK-PII-*Data Encryption KeyAES-256-GCMPer-record PII field encryptionConfidential/RestrictedApplication
DEK-FNR-*Data Encryption KeyAES-256-GCMFødselsnummer field encryptionRestrictedApplication
TLS-EXTTLS Certificate KeyECDSA P-256External HTTPSPlatform team
TLS-INTTLS Certificate KeyEd25519Internal mTLS (Phase 3)Platform team
JWT-02JWT Signing KeyRS256 (RSA-4096) or EdDSAAsymmetric JWT signingSecurity team
BACKUP-01Backup Encryption KeyAES-256-GCMDatabase backup encryptionRestrictedSecurity team
SUMSUB-01Webhook HMACAPI Key HMAC-SHA-256 Sumsub webhookKYC verificationAPI authentication KYCConfidential data integrity(L3) EngineeringSecurity teamAWS Secrets Manager
NEONOMICS-01DEK-* OAuthData ClientEncryption SecretKeys HMAC-SHA-256AES-256-GCM PSD2Per-record APIenvelope authenticationDEKs Restricted (L4) EngineeringApplicationGenerated by AWS KMS GenerateDataKey

2.2 Secrets Inventory (AWS Secrets Manager)

Secret NamePurposeRotation
JWT_SECRETJWT token signingQuarterly
SWAN-01SUMSUB_SECRET_KEY OAuthSumsub ClientKYC Secretintegration HMAC-SHA-256Annual or on compromise
BANKID_CLIENT_SECRET SwanBankID bankingOIDC APIclient secret Per BankID schedule
DATABASE_URL EngineeringPostgreSQL connection stringOn DB credential rotation
SENTRY_DSNSentry error monitoringAnnual

3. Key Hierarchy

AWS KMS Root of Trust (eu-north-1 primary — Stockholm)
    |
    +-- drop-national-id-key (AES-256-GCM — annual rotation)
    |       +-- DEK-{user_id}-{timestamp}: Per-record envelope DEKs
    |               +-- Encrypts: foedselsnummer field in users table
    |               +-- Stored: base64(encryptedDEK || iv || tag || ciphertext)
    |
    +-- drop-db-master-key (AES-256 XTS — annual rotation)
    |       +-- Encrypts: PostgreSQL database at rest (Phase 2 — AWS RDS)
    |
    +-- drop-kyc-key (AES-256-GCM — annual rotation)
    |       +-- Encrypts: KYC document objects in AWS S3 (SSE-KMS)
    |
    +-- AWS KMS Root of Trust (eu-west-1 — SEPARATE REGION)
            +-- drop-backup-key (AES-256 — annual rotation)
                    +-- Encrypts: All database backup files

AWS Secrets Manager (eu-north-1)
    +-- JWT_SECRET (HMAC-SHA-256 — quarterly rotation)
    |       +-- Signs: Drop JWT session tokens (HS256 via jose ^6.1.3)
    +-- SUMSUB_SECRET_KEY (API key — annual)
    +-- BANKID_CLIENT_SECRET (OIDC client secret)
    +-- DATABASE_URL (connection string)

Cloudflare / Let's Encrypt
    +-- TLS Certificate (ECDSA P-256 — 90-day automated rotation)
            +-- External HTTPS: getdrop.no

BankID Norge AS CA
    +-- BankID Certificate (RSA-2048 — per BankID renewal schedule)
            +-- Used for: BankID JWT signature verification (Phase 2)

4. Key Lifecycle

3.4.1 Lifecycle Overview

Generationflowchart (CSPRNGLR
    /GEN[Generation] -->|"AWS KMS /CSPRNG"| HSM)DIST[Distribution]
    DIST Distribution-->|"Runtime (encryptedAPI channelcall\nnever onlyin env neverfiles"| plaintext)STORE[Storage]
    STORE Storage (-->|"KMS / Secrets ManagerManager\naccess controlled"| USE[Usage]
    USE -->|"Scheduled"| ROT[Rotation]
    ROT -->|"New key active\noverlap period"| USE
    ROT -->|"Old key retired"| ARCH[Archive / envRevoke]
    varARCH -->|"End neverof inlife"| code)DEST[Destruction]

    REVOKE[Emergency UsageRevocation] (access-->|"Compromise controlled,detected"| allDEST
    operationsUSE logged)--> ↓
Rotation (scheduled — see §3.6)
    ↓
Revocation (on compromise — immediate)
    ↓
Destruction (secure erase — verified)REVOKE

3.4.2 Generation

Entropy requirements:

  • All keys MUST be generated using AWS KMS or a cryptographically secure random number generator (CSPRNG)
  • Minimum entropy: 256 bits for symmetric keysCSPRNG
  • NEVER use: timestamps, UUIDs,use user-supplied passphrases, timestamps, UUIDs, or predictable values as keys
  • NEVER generate Restricted (L4) keys in application code for Restricted data — use AWS KMS GenerateKey APIor GenerateDataKey

Approved key generation methods:

(
Key Type Generation Method NotesTool
Symmetric (AES-256) KMS keysKMS CreateKey APIAWS KMS (FIPS 140-2 Level 3 HSMs)
Envelope DEKsKMS GenerateDataKey APIAWS KMS
JWT signing secret (HS256) crypto.randomBytes(32).toString('hex') Node.js OS CSPRNG)256-bitCSPRNG
AES-256TLS DEKcertificates crypto.randomBytes(32)ACME protocol 256-bitCloudflare / Let's Encrypt
ECDSABankID P-256certificates opensslBankID ecparamNorge -nameAS prime256v1 -genkey -nooutCA TLSExternal certs
Ed25519openssl genpkey -algorithm ed25519JWT signing (Phase 2)
RSA-4096openssl genrsa -aes256 4096Legacy JWT (Phase 2)
AWS KMS-managedAWS KMS GenerateKey APIRestricted data keys
HMAC-SHA-256crypto.randomBytes(32) as key materialWebhook verificationCA

CurrentGeneration MVP:environment: JWT_SECRET is generated and set as environment variable by operator at deployment. Must be cryptographically random — minimum 32 bytes.

Generation

    environment
  • All rule:KMS-managed Keyskeys protectingfor Restricted (L4) data (fødselsnummer) MUST bedata: generated within AWS KMS HSMs  key material never leaves AWS
  • JWT_SECRET: generated using crypto.randomBytes(32) then stored in applicationAWS code.

    Secrets Manager
  • All key generation events logged in AWS CloudTrail

3.4.3 Distribution

Principles:

  • NeverNEVER transmit keys in plaintext over any channel
  • NeverNEVER include keys in source code, config.env files committed to version control,Git, or logslog output
  • NeverNEVER send keys via email, Slack, or any messaging platform
  • NeverAlways hardcodefetch keyssecrets at fatalapplication errorruntime iffrom JWT_SECRETAWS notSecrets setManager inor productionKMS (enforced in auth.ts)API

Distribution methods:

environment in
Scenario Method Notes
ProductionApplication runtime keyssecrets (JWT_SECRET) AWS Secrets Manager (PhaseAPI 2)at /startup Fatal variableserror (MVP)if JWT_SECRET missing
Envelope DEK generationAWS KMS GenerateDataKey per encryption operationKey material decrypted in memory only
Developer secretsaccess 1PasswordAWS /IAM Vaultwardenrole + neverMFA Least .env committed to gitprivilege
CI/CD pipeline secrets GitHub Actions encrypted secrets (scopedscoped)Rotated per environment)
Third-party API keysAWS Secrets Manager (Phase 2) / Vaultwarden for local dev
Emergency key recoveryDual approval process — see §7project

Current MVP protection: .env file excluded from git via .gitignore. JWT_SECRET fatal error if missing in production enforced in src/drop-app/src/lib/auth.ts.


3.4.4 Storage

Storage hierarchy (Phasefor 2 target):Drop:

Level 1 — AWS KMS HSMs (HSM-backed)FIPS ├──140-2 KEK-01:Level Master3)
  +-- drop-national-id-key for(foedselsnummer encryption)
  +-- drop-db-master-key (database PIITDE field— Phase 2)
  +-- drop-kyc-key (KYC document S3 encryption)
  +-- drop-backup-key (backup encryption ├── KEK-02: Master key for fødselsnummer encryption (separate key)
  └── Root of trust for all derived keyseu-west-1)

Level 2 — AWS Secrets Manager
  ├──+-- JWT_SECRET (orHMAC JWTsigning privatekey)
  key+-- for RS256)
  ├── Database passwordSUMSUB_SECRET_KEY (PostgreSQL)API ├──key)
  Sumsub+-- webhookBANKID_CLIENT_SECRET HMAC(OIDC keysecret)
  ├──+-- NeonomicsDATABASE_URL OAuth(connection client secret
  ├── Swan OAuth client secret
  └── BankID client credentialsstring)

Level 3 — Application memory (ephemeral only)
  ├──+-- DEKsDecrypted DEK during active encryption/decryption
  └──+-- Decrypted secretsJWT_SECRET during requesttoken handlingsigning/verification
  Note:NOTE: NEVER persist Level 3 to disk
or logs

Level 4 — CI/CD (GitHub Actions secrets)
  ├── Staging environment secrets
  └── Deployment credentials (scoped to specific environments)

Current MVP storage (pre-AWS):

  • JWT_SECRET: Environment variable — set at deployment by operator
  • Third-party API keys: Vaultwarden (vault.basicconsulting.no) for local dev, environment variables in deployment

Prohibited storage locations:

  • Source code or config files in version control (.env in git)Git
  • Application logs or Sentryerror errormessages (Sentry, BetterStack)
  • Unencrypted database columns
  • Email attachments or Slack messages
  • Browser localStorage or sessionStorage
  • EmailContainer attachmentsimage or Slack messages
  • Unencrypted database columns for Restricted datalayers

3.4.5 Usage

Access control principles:

Principle Implementation
Least privilege JWT secret only accessible by auth service; each integrationKMS key scopedpolicies: toencrypt-only itsfor serviceapplication, decrypt-only for compliance function
Separation of duties Keykey-admin generationcannot separateperform fromdecryption; keyapplication deploymentservice approvalcannot create keys
Key purpose binding JWT signing drop-national-id-key not used for data encryption; encryption keys not usedonly for signingnational ID encryption
Audit all access All AWSEvery KMS operationsoperation logged in AWS CloudTrail (Phase 2)
NoTime-bound sharingaccess EachIAM environmentrole (dev/staging/prod)assumption haswith separatetime-bound keyssession tokens

Current enforcement: JWT_SECRET loaded at startup only, fatal if missing. NoKMS key everpolicy returnedroles:

inAPIresponses.Sessionstoredashashesonly.

IAM tokensRole Permissions MFA SHA-256Required
drop-key-adminCreateKey, ScheduleKeyDeletion, RotateKey — NO DecryptYES
drop-app-encryptkms:Encrypt, kms:GenerateDataKeyNo (service account)
drop-compliance-decryptkms:Decrypt for drop-national-id-key onlyYES
drop-key-auditorkms:ListKeys, kms:DescribeKey, CloudTrail readYES
drop-app-runnerkms:GenerateDataKey, kms:Decrypt (scoped per key)No (IAM role)

3.4.6 Rotation Schedule

signing
Key Type Rotation Period Method Owner Alert if Overdue
JWTdrop-national-id-key AnnualAWS KMS automatic key (JWT_SECRET)QuarterlyRotation with overlap period (old valid 24h)rotation Security team Yes — 7 days overdue
Database KEK (AES-256, Phase 2)drop-db-master-key Annual AWS KMS automatic key rotation Security teamYes — 14 days overdue
Database DEKs (PII, Phase 2)QuarterlyAutomated via key rotation APIPlatform Yes — 7 days overdue
drop-kyc-keyAnnualAWS KMS automatic key rotationSecurity teamYes — 7 days overdue
drop-backup-keyAnnualManual + AWS KMS rotationSecurity teamYes — 7 days overdue
JWT_SECRETQuarterlyManual — generate new, deploy, rotateSecurity teamYes — 3 days overdue
TLS certificatescertificate (external)getdrop.no) 90 days Automated (Cloudflare / Let's Encrypt / cert-manager)Encrypt) Platform Yes — 14 days before expiry
TLSBankID certificates (internal, Phase 3)certificate 30Per daysBankID schedule AutomatedManual — BankID renewal process PlatformSecurity team YesCalendar — 7 days before expiryreminder
Sumsub webhook keySUMSUB_SECRET_KEY AnnuallyAnnual or on Sumsub rotationcompromise Manual via Sumsub dashboardEngineeringYes
Neonomics OAuth secretPer Neonomics policyVia Neonomics developer portalEngineeringYes
Swan OAuth secretPer Swan policyVia Swan developer portalEngineeringYes
Backup encryption key (Phase 2)AnnualManual + dual approval Security team Yes — 7 days overdue

JWTJWT_SECRET rotation overlap:overlap procedure:

Old
  1. Generate new JWT_SECRET remainsvalue
  2. valid
  3. Deploy new secret to AWS Secrets Manager
  4. Rolling deploy of Drop app (picks up new secret)
  5. Wait for 24all hoursexisting aftersessions to expire (max 24h — JWT expiry)
  6. All sessions issued with old secret are now invalid — users re-authenticate
  7. Delete old secret version from Secrets Manager

AWS KMS automatic rotation: AWS KMS generates new key activationmaterial toannually allowwhile in-flightretaining sessionsall toprior complete. Users are NOT logged out on rotation.

Rotation monitoring: Calendar remindersversions for manualdecryption rotations.of AWSexisting KMS rotation alerts for automated keys (Phase 2).ciphertext.


3.4.7 Revocation Procedures

Trigger conditions for immediate revocation:

  • Known or suspected key compromise (key material logged, unauthorized access)
  • Employee departure (forwith keyskey inmanagement personalIAM knowledge)role access
  • System compromise where key was in use
  • RegulatoryDetection requirementof orunauthorized lawdecryption enforcementin order
  • CloudTrail
  • Vendor security breach (Sumsub, Neonomics, Swan notify Drop)logs

Emergency JWT revocation procedure (target: < 1 hour):

Step 1: Alert Security Lead via #security-incident Slack channel
Step 2: Identify scope — which data was accessible with compromised key?
Step 3: AWS KMS: Disable compromised key (prevents new encrypt/decrypt)
Step 4: Generate replacement key via KMS CreateKey
Step 5: Re-encrypt all data protected by compromised key (Restricted first)
Step 6: Update KMS key references in application configuration
Step 7: Deploy updated configuration
Step 8: Verify all systems using new key
Step 9: Audit CloudTrail: What decrypt operations used compromised key in last 30 days?
Step 10: Assess breach notification requirement (data-breach-response-plan.md §5)
         -> GDPR Art. 33 / Personopplysningsloven § 32: 72h to Datatilsynet if personal data affected
         -> Finanstilsynet notification if payment data affected
Step 11: Document in incident log
Step 12: Post-mortem within 48 hours

JWT_SECRET emergency rotation (session compromise):

Step 1: Generate new JWT_SECRET immediately
Step 2: Deploy new secret to productionAWS (zero-downtime:Secrets old valid 5min overlap)Manager
Step 3: AllRolling existingdeploy Drop application — all in-flight sessions will be invalidated (revoke all in sessions table)
Step 4: UsersAll users must re-authenticate
(expected UX impact — communicate via status page)
Step 5: Audit all sessions active during compromise window
Step 6: Assess if breach notification required (see data-breach-response-plan.md)
Step 7: Document in incident log
Step 8: Post-mortem within 48 hours

Database key revocation (Phase 2):

  • Disable compromised key in AWS KMS
  • Re-encrypt all data protected by compromised key with new key
  • Priority: Restricted (L4) data first → Confidential → Internal

Certificate revocation:

  • Immediately upon compromise: Revoke via CA (Let's Encrypt ACME revoke)
  • Notify all certificate consumers
  • OCSP response updated within 1 hour

3.4.8 Destruction

When destruction is required:

  • Key has been rotated out and overlap period expired
  • Crypto-shredding: deleting user foedselsnummer by destroying envelope DEK (GDPR Art. 17)
  • System decommissioned
  • GDPR erasure via crypto-shredding (destroy key → all data encrypted with it is unreadable)

Destruction methods:

decryption
Key Location Destruction Method Verification
AWS KMS key KMS scheduled key deletionScheduleKeyDeletion (7-30 day minimum waiting period) KMS + CloudTrail audit log
AWS Secrets Manager DeleteDeleteSecret secret,(7-30 verifyday viawaiting APIperiod) AuditSecrets Manager audit log
EnvironmentEnvelope variableDEK in database RemoveDelete fromencrypted deploymentDEK config, redeployfield DeploymentVerify verification
Application memoryLanguage runtime GC (explicit Buffer.fill(0) for sensitive buffers)Code review
Local .env fileshred -vzu .env on developer machineDeveloper responsibilityfails

Verification:Crypto-shredding for GDPR erasure (Art. 17): AfterWhen destruction,a confirmuser requests account deletion:

  1. The envelope DEK for that decryptionuser's withfoedselsnummer destroyedis key fails on a test ciphertext.

    Destruction log: Document every key destruction in legal/internkontroll.md with: key ID, date, reason, verification method, actor.


    4. Key Hierarchy (Phase 2 Target)

    AWS KMS Root (HSM-backed — EEA region)
        │
        ├── KEK-01: General PII Encryption Master (annual rotation)
        │       └── DEK-PII-{ID}: Per-record PII field DEKs (quarterly rotation)
        │               └── Encrypts: name-as-stored, email, phone (if field-encrypted)
        │
        ├── KEK-02: Fødselsnummer Master Key (annual rotation — SEPARATEdeleted from KEK-01)the database
  2. └──
  3. The DEK-FNR-{ID}: Fødselsnummer field DEKsciphertext (quarterlyfoedselsnummer) rotation)becomes permanently └──unreadable
  4. Encrypts: users.fodselsnummer (national ID — L4 Restricted) │ ├── KEK-03: AML/KYC Records Master (annual rotation) │ └── DEK-AML-{ID}:
  5. AML recordretention: DEKs │ └── Encrypts: KYC documents, AML investigationtransaction records retained ├──5 BACKUP-KEK:years Backupper EncryptionHvitvaskingsloven Master§ (annual30
  6. rotation — different KMS region) │ └── Encrypts: All database backup snapshots │ ├── TLS Root CA (managed by cert-manager / Let's Encrypt) │ ├── External TLS Certificate (*.getdrop.no — 90 day rotation) │ └── Internal mTLS Certificates (30 day rotation — Phase 3) │ └── JWT Signing Keys (quarterly rotation) Current: JWT_SECRET (HS256 — symmetric) Phase 2: Private key (EdDSA or RSA-4096 — asymmetric)

5. Key Management System

MVP (Current):

  • JWT secret: environment variable with OS CSPRNG generation
  • Third-party secrets: Vaultwarden (vault.basicconsulting.no) for local dev
  • No formal KMS — acceptable for pre-production MVP

Phase 2 Target:

  • Primary KMS: AWS KMS (EEA regioneu-north-1Stockholm region) Backup KMS: AWS KMS (eu-west-1 Ireland orIreland) eu-central-1for Frankfurt)
  • drop-backup-key
  • only — separate region for disaster recovery Secrets Manager:management: AWS Secrets Manager for application secrets
  • Secondary: AWS KMS cross-region replication for disaster recovery
  • HSM: AWS CloudHSM (for KEK-02 fødselsnummer — L4 Restricted data)

KMS access control (Phase 2):eu-north-1)

RolePermissionsMFA Required
key-adminCreate, rotate, schedule deletion — NO decryptYES
key-encryptEncrypt only (specific key IDs)YES
key-decryptDecrypt only (specific key IDs)YES
key-auditorList, describe, view audit logs — no crypto opsYES
CI/CD pipelineEncrypt only (staging key IDs)N/A (service account)
Application serviceEncrypt + Decrypt (specific keys, VPC constraint)N/A (IAM role)

6. Access Controls for Key Operations

Separation of duties:

(Phase 2: deployment
Operation Required ApprovalRoles Approval Process
Create new KEKKMS key CISOdrop-key-admin + secondCISO approverapproval AWS IAM dual+ approval)ticket
Rotate KMS key (manual) Documenteddrop-key-admin request(proposer) + CISO (approver)Dual approval
Emergency key disableSecurity Lead (any one)Single — immediate incident ticket
Schedule key deletiondrop-key-admin + CISODual approval — minimum 7-day waiting period
Grant new service accessSecurity Lead + system ownerIAM PR review + approval
Rotate KEKJWT_SECRET CISOSecurity (proposer) + second approverLead CalendarSingle rotation +with documentation
Emergency revocationCISO alone (time-critical)Immediate + incident ticket within 1 hour
Destroy keyCISO + Legal (if litigation hold)Written approval before KMS deletion
Grant service access to keyCISO + system ownerIAM policy reviewcoordination

Current MVP: Alem Bašić (CEO/CISO) is sole key custodian. Dual approval to be implemented when team is hired (Phase 2).


7. KeyFoedselsnummer EscrowField &Encryption Recovery— Implementation Pattern

Escrow policy:Key: JWT signing drop-national-id-key and backup encryption keys must have recovery path.

Current MVP recovery:

  • JWT_SECRET recovery:(AWS Re-generateKMS — separate from CSPRNG,database redeploy.master Allkey) usersStored: re-authenticate.
  • Only
  • IfAES-256-GCM ciphertext — never plaintext foedselsnummer in database Source: JWT_SECRETsrc/drop-app/src/lib/encrypt.ts is lost: Service restarts with new secret. All sessions invalidated. This is acceptable for MVP.

(Phase 2 escrowimplementation)

// Envelope encryption for KEKsfoedselsnummer
// Key: drop-national-id-key (AWS KMS)
// Stored: base64(encryptedDEK || iv || tag || ciphertext)

async function encryptNationalId(fodselsnummer: string):

    Promise<string>
  • AWS{ KMSconst providesiv multi-region= redundancycrypto.randomBytes(12); // 96-bit random IVnonever separatereused escrowconst neededdek for= KMS-onlyawait keys
  • kmsClient.generateDataKey({
  • AWSKeyId: KMSprocess.env.NATIONAL_ID_KEY_ARN, deletionKeySpec: 'AES_256' }); const cipher = crypto.createCipheriv('aes-256-gcm', dek.Plaintext, iv); const ciphertext = Buffer.concat([cipher.update(fodselsnummer, 'utf8'), cipher.final()]); const tag = cipher.getAuthTag(); dek.Plaintext.fill(0); // Zero DEK plaintext from memory after use // Return: base64(encryptedDEK || iv || tag || ciphertext) return Buffer.concat([dek.CiphertextBlob, iv, tag, ciphertext]).toString('base64'); }

Access restriction: Only the Compliance function has minimumIAM 7-day waiting period (protection against accidental deletion)

  • AWS KMS CloudTrail provides full audit trail
  • Phase 2 escrow for Backup encryption key (offline):

    1. Key material exported encrypted from AWS KMS (if exportable) OR
    2. Backup KMS key replicationaccess to seconddrop-compliance-decrypt regionrole. (recommendedApplication forcode KMS-nativecannot keys)
    3. decrypt
    4. Physicalfoedselsnummer escrow:except Encryptedduring keyexplicit filecompliance stored in fireproof safe + separate secure off-site copy
    5. Access: Requires CISO + one designated board member
    6. Verification: Quarterly — confirm escrow holders can access

    Recovery procedure (Phase 2):workflows.

    1. CISO opens emergency key recovery request (documented)
    2. Escrow holder(s) convene
    3. Key material combined and imported to KMS
    4. All key recovery events logged and post-mortem required within 48 hours

    8. Audit Logging for Key Operations

    All key operations mustlogged bein logged:AWS CloudTrail, including:

    • Key generation:creation (actor, key ID, key type, timestamptimestamp)
    • Encryption/decryption:decryption (actor, key ID, operation,context, timestamp (not data content)timestamp)
    • Key rotation:rotation (actor, old key ID,version, new key ID,version, timestamptimestamp)
    • Key revocation:disabling / deletion scheduling (actor, key ID, reason, timestamp
    • Key destruction: actor, key ID, verification, timestamp
    • Access grant/revoke: actor, grantee, key ID, permissions, timestamptimestamp)
    • Failed access attempts:attempts (actor, key ID, reason, timestamptimestamp)

    Log destination (Phase 2):destination: AWS CloudTrail → SIEMS3 (immutable, append-onlyonly) Current+ MVP:BetterStack Manualaggregation log in legal/internkontroll.md for all key operations

    Log retention: 5 years (AML compliance — Hvitvaskingsloven § 30) — key operation logs are AML-relevant

    Alert on:

    • Off-hoursDecrypt accessoperations toby KEKsunexpected IAM role
    • Failed KMS access attempts > 3 in 5 minutes
    • KeyOff-hours deletionaccess scheduledto drop-national-id-key or drop-kyc-key
    • KeyAny rotationScheduleKeyDeletion overdueevent (immediate alert)

    9. ComplianceException MappingProcess

    Exceptions not permitted for: Restricted (L4) data (foedselsnummer, KYC documents) — no exceptions to field-level encryption.

    Exception request process:

    1. Submit request to: [email protected]
    2. Required: system, data classification, key being excepted, business justification, risk assessment, compensating controls, duration (max 12 months)
    3. Approval: CISO
    4. Logged in: compliance register
    5. Review: Quarterly — exceptions > 12 months require board-level approval

    Active exceptions:

    KMS2 encryption;publicDB
    RequirementSystem StandardException ControlExpiryCompensating Controls
    EncryptionJWT keysigning management(HS256 shared secret) GDPRShared-secret Art.JWT 32instead of asymmetric RS256/EdDSA ThisPhase policy2 +migration JWT_SECRET implementationin AWS Secrets Manager; 24h session expiry; server-side revocation table
    CryptographicSQLite keyMVP protection(no column-level TDE) DORAFilesystem Art.encryption 9(4)(d)only AWS KMS (Phase 2)
    Key custodian documentationmigration IKT-forskriftenFull §disk 5 Keyprivate inventorynetwork; tableno (§2)
    Key rotationIKT-sikkerhetspolicy §6.3Rotation schedule (§3.6)
    Key destructionIKT-forskriften § 5Destruction procedures (§3.8)
    Access controlsDORA Art. 9(4)Access controls (§6)
    Crypto-shredding for GDPR erasureGDPR Art. 17Key destruction triggers data erasure
    5-year AML record retentionHvitvaskingsloven §30Key retention aligned with data retention
    Audit trailDORA Art. 10Logging (§8)access

    10. Emergency Procedures — Key Compromise

    Immediate response checklist (execute within 1 hour of suspected compromise):

    AlertActivate incident response — notify: Security Lead + CISO immediately:+ [email protected] / +47 40 47 42 51
    □ Create incident channel: #incident-key-compromise-{DATE}CTO
    □ Identify whichscope: key was compromised (JWT, database, API key)
    □ Identify whatWhich data was accessible with compromised keykey?RevokeAWS KMS: Disable compromised key immediately
    □ For JWT_SECRET compromise: rotate immediately (seeall §3.7)sessions invalidated)
    □ Generate replacement key
    □ DeployRe-encrypt newall data protected by compromised key to all systems (zero-downtime rotation if possible)
    □ For JWT: Revoke ALL active sessions (UPDATE sessions SET revoked=1)
    □ For database key: Begin re-encryption of affectedRestricted data (Restricted first)
    □ Audit logs:CloudTrail: What operationswas useddecrypted theusing compromised key in pastlast 30 days?
    □ Assess breach notification requirement (see data-breach-response-plan.md §5)
       -> GDPR Art. 33 / Personopplysningsloven § 32: 72h to Datatilsynet
       -> Finanstilsynet notification if payment data affected
    □ Document everything in incident log
    □ Post-mortem within 48 hours
    

    Re-encryption priority (if database key compromised):priority:

    1. Foedselsnummer (drop-national-id-key) — Restricted (L4):, Fødselsnummer,highest AMLpriority
    2. records
    3. KYC documents (drop-kyc-key)IMMEDIATERestricted (L4)
    4. ConfidentialDatabase backup files (L3): Transaction data, KYC recordsdrop-backup-key)withinRestricted 4 hours(L4)
    5. InternalDatabase master (L2): Logs, session datadrop-db-master-key)withinPhase 24 hours2

    Estimated impact of JWT compromise:

    • All active user sessions must be invalidated
    • All users must re-authenticate
    • Expected customer impact: temporary app disruption
    • Communication: In-app notification + email explaining security measures taken

    Approval

    Role Name Date Signature
    Author ALAI Security TeamArchitect 2026-02-23
    CISO Alem Bašić
    CTO Alem Bašić
    DPO (complianceGDPR relevance) TBD — appointment required
    Management Alem Bašić