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 ArchitectTeam 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) InitialPolicy draft — Drop key management for AWS KMS + Secrets Managerdocument

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 forin the Drop payment app,application. includingDrop generation,processes distribution,regulated storage,financial usage,data rotation,(fødselsnummer, revocation,bank andaccounts, destruction.

transaction

Regulatorydata, basis:

AML
    records)
  • requiring systematic key management per GDPR Art. 3232, — 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 encryption key management
  • Hvitvaskingsloven (LOV-2018-06-01-23) § 30 — KYC data protection at rest
IKT-forskriften.

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 employeecloud andinfrastructure contractor(AWS — EEA regions, Phase 2+)
  • All developer workstations handling Confidential or Restricted data
  • All third-party integrations where ALAI Holdingholds ASkeys holds(Sumsub, Neonomics, Swan, BankID)
  • JWT signing keys, database encryption keys, TLS certificate private keys, API authentication keys

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


2. Key InventoryTypes & Purposes

2.1 CompleteCurrent KeyMVP TaxonomyKeys

env
Key ID Type Algorithm Purpose DataClassification ClassificationProtected OwnerStorageLocation
drop-national-id-keyJWT-01 KEKJWT Signing Key AES-256-GCMHMAC-SHA-256 (HS256) FoedselsnummerSign fieldand encryptionverify JWT session tokens RestrictedAll (L4)user data SecurityJWT_SECRET team AWS KMS (eu-north-1)var
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 CloudflareHosting / Let's EncryptCloudflare managedprovider
SUMSUB-01Webhook HMAC KeyHMAC-SHA-256Verify Sumsub KYC webhooksKYC data integrityBankID-certSUMSUB_WEBHOOK_SECRET env var
SENTRY-01DSN 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-EXT TLS Certificate Key RSA-2048ECDSA P-256 BankIDExternal Norway JWT signature verificationHTTPS BankIDPlatform Norge AS CABankID managedteam
SUMSUB-API-KEYTLS-INT APITLS 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 HMAC Key HMAC-SHA-256 Sumsub webhook verificationKYC data integrityEngineering
NEONOMICS-01OAuth Client SecretHMAC-SHA-256PSD2 API authentication Confidential (L3) Security teamAWS Secrets ManagerEngineering
DEK-*SWAN-01 DataOAuth EncryptionClient KeysSecret AES-256-GCMHMAC-SHA-256 Per-recordSwan envelopebanking DEKsAPI Restricted (L4) ApplicationGenerated by AWS KMS GenerateDataKey

2.2 Secrets Inventory (AWS Secrets Manager)

Secret NamePurposeRotation
JWT_SECRETJWT token signingQuarterly
SUMSUB_SECRET_KEYSumsub KYC integrationAnnual or on compromise
BANKID_CLIENT_SECRETBankID OIDC client secretPer BankID schedule
DATABASE_URLPostgreSQL connection stringOn DB credential rotation
SENTRY_DSNSentry error monitoringAnnualEngineering

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

4.3.1 Lifecycle Overview

flowchartGeneration LR(CSPRNG GEN[Generation] -->|"AWS/ KMS CSPRNG"|/ DIST[Distribution]HSM)
    DIST
-->|"RuntimeDistribution API(encrypted call\nneverchannel inonly env files"|never STORE[Storage]plaintext)
    STORE
-->|"Storage (KMS / Secrets Manager\naccess controlled"| USE[Usage]
    USE -->|"Scheduled"| ROT[Rotation]
    ROT -->|"New key active\noverlap period"| USE
    ROT -->|"Old key retired"| ARCH[ArchiveManager / Revoke]env ARCHvar -->|"End ofnever life"|in DEST[Destruction]code)
    REVOKE[Emergency
Revocation]Usage -->|"Compromise(access detected"|controlled, DESTall USEoperations -->logged)
    REVOKE↓
Rotation (scheduled — see §3.6)
    ↓
Revocation (on compromise — immediate)
    ↓
Destruction (secure erase — verified)

4.3.2 Generation

Entropy requirements:

  • All keys MUST be generated using AWS KMS or a CSPRNGcryptographically secure random number generator (CSPRNG)
  • Minimum entropy: 256 bits for symmetric keys
  • NEVER useuse: timestamps, UUIDs, 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 or GenerateDataKeyAPI

Approved key generation methods:

Key Type Generation Method ToolNotes
SymmetricJWT secret (AES-256) KMS keysKMS CreateKey APIAWS KMS (FIPS 140-2 Level 3 HSMs)
Envelope DEKsKMS GenerateDataKey APIAWS KMS
JWT signing secretHS256) crypto.randomBytes(32).toString('hex') (Node.js OS CSPRNG) Node.js CSPRNG256-bit
TLSAES-256 certificatesDEK ACME protocolcrypto.randomBytes(32) Cloudflare / Let's Encrypt256-bit
BankIDECDSA certificatesP-256 BankIDopenssl Norgeecparam AS-name CAprime256v1 -genkey -noout ExternalTLS CAcerts
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 verification

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

Generation environment:environment rule:

    Keys
  • All KMS-managed keys forprotecting Restricted data:(L4) data (fødselsnummer) MUST be generated within AWS KMS HSMs  key material never leaves AWS
  • JWT_SECRET: generated using crypto.randomBytes(32) then stored in AWSapplication Secrets Manager
  • All key generation events logged in AWS CloudTrail
code.


4.3.3 Distribution

Principles:

  • NEVERNever transmit keys in plaintext over any channel
  • NEVERNever include keys in source code, .envconfig files committed to Git,version control, or log outputlogs
  • NEVERNever send keys via email, Slack, or any messaging platform
  • AlwaysNever fetchhardcode secretskeys at applicationfatal runtimeerror fromif AWSJWT_SECRET Secretsnot Managerset orin KMSproduction API(enforced in auth.ts)

Distribution methods:

/ never
Scenario Method Notes
ApplicationProduction runtime secrets (JWT_SECRET)keys AWS Secrets Manager API(Phase at2) startup Fatalenvironment errorvariables if JWT_SECRET missing
Envelope DEK generationAWS KMS GenerateDataKey per encryption operationKey material decrypted in memory only(MVP)
Developer accesssecrets AWS1Password IAM/ roleVaultwarden + MFA Leastin privilege.env committed to git
CI/CD pipeline secrets GitHub Actions encrypted secrets (scoped)scoped per environment)
Third-party API keys RotatedAWS perSecrets projectManager (Phase 2) / Vaultwarden for local dev
Emergency key recoveryDual approval process — see §7

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.


4.3.4 Storage

Storage hierarchy for(Phase Drop:2 target):

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

Level 2 — AWS Secrets Manager
  +--├── JWT_SECRET (or JWT private key for RS256)
  ├── Database password (PostgreSQL)
  ├── Sumsub webhook HMAC signingkey
  key)├── +--Neonomics SUMSUB_SECRET_KEYOAuth (APIclient key)secret
  +--├── BANKID_CLIENT_SECRETSwan (OIDCOAuth secret)client +--secret
  DATABASE_URL└── (connectionBankID string)client credentials

Level 3 — Application memory (ephemeral only)
  +--├── Decrypted DEKDEKs during active encryption/decryption
  +--└── JWT_SECRETDecrypted secrets during tokenrequest signing/verificationhandling
  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 Gitversion control (.env in git)
  • Application logs or Sentry error messages (Sentry, BetterStack)
  • UnencryptedBrowser databaselocalStorage columnsor sessionStorage
  • Email attachments or Slack messages
  • BrowserUnencrypted localStoragedatabase orcolumns sessionStorage
  • for
  • ContainerRestricted image layersdata

4.3.5 Usage

Access control principles:

Principle Implementation
Least privilege KMSJWT secret only accessible by auth service; each integration key policies:scoped encrypt-onlyto forits application, decrypt-only for compliance functionservice
Separation of duties key-adminKey cannotgeneration performseparate decryption;from applicationkey servicedeployment cannot create keysapproval
Key purpose binding drop-national-id-JWT signing key not used onlyfor data encryption; encryption keys not used for national ID encryptionsigning
Audit all access EveryAll AWS KMS operationoperations logged in AWSCloudTrail CloudTrail(Phase 2)
Time-boundNo accesssharing IAMEach roleenvironment assumption(dev/staging/prod) withhas time-boundseparate session tokenskeys

KMSCurrent enforcement: JWT_SECRET loaded at startup only, fatal if missing. No key policyever roles:returned in API responses. Session tokens stored as SHA-256 hashes only.

IAM RolePermissionsMFA Required
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)

4.3.6 Rotation Schedule

before
Key Type Rotation Period Method Owner Alert if Overdue
JWT signing key (drop-national-id-keyJWT_SECRET) AnnualQuarterly AWSRotation KMSwith automaticoverlap keyperiod rotation(old valid 24h) Security team Yes — 7 days overdue
drop-db-master-keyDatabase KEK (AES-256, Phase 2) 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 certificatecertificates (getdrop.no)external) 90 days Automated (CloudflareLet's Encrypt / Let's Encrypt)cert-manager) Platform Yes — 14 days before expiry
BankIDTLS certificatecertificates (internal, Phase 3) Per30 BankID scheduledays ManualAutomatedPlatformYesBankID7 renewaldays process Security teamCalendar reminderexpiry
SUMSUB_SECRET_KEYSumsub webhook key AnnualAnnually or on compromiseSumsub rotation 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

JWT_SECRETJWT rotation overlapoverlap: procedure:

  1. Generate newOld JWT_SECRET value
  2. remains
  3. Deployvalid for 24 hours after new secretkey activation to AWSallow Secrets Manager
  4. Rolling deploy of Drop app (picks up new secret)
  5. Wait for all existingin-flight sessions to expirecomplete. (max 24h — JWT expiry)
  6. All sessions issued with old secretUsers are nowNOT invalidlogged out userson re-authenticate
  7. Delete old secret version from Secrets Manager
rotation.

AWSRotation KMSmonitoring: automaticCalendar rotation:reminders for manual rotations. AWS KMS generatesrotation new key material annually while retaining all prior versionsalerts for decryptionautomated ofkeys existing(Phase ciphertext.2).


4.3.7 Revocation Procedures

Trigger conditions for immediate revocation:

  • Known or suspected key compromise (key material logged, unauthorized access)
  • Employee departure with(for keykeys managementin IAMpersonal role accessknowledge)
  • System compromise where key was in use
  • DetectionRegulatory ofrequirement unauthorizedor decryptionlaw inenforcement CloudTrailorder
  • logs
  • Vendor security breach (Sumsub, Neonomics, Swan notify Drop)

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 AWSproduction Secrets(zero-downtime: Managerold valid 5min overlap)
Step 3: RollingAll deployexisting Dropsessions applicationwill be invalidated (revoke all in-flightin sessions invalidatedtable)
Step 4: All usersUsers 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

4.3.8 Destruction

When destruction is required:

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

Destruction methods:

fails
Key Location Destruction Method Verification
AWS KMS key ScheduleKeyDeletionKMS scheduled key deletion (7-30day dayminimum waiting period) KMS + CloudTrail audit log
AWS Secrets Manager DeleteSecretDelete (7-30secret, dayverify waitingvia period)API Secrets Manager auditAudit log
EnvelopeEnvironment DEK in databasevariable DeleteRemove encryptedfrom DEKdeployment fieldconfig, redeploy VerifyDeployment decryptionverification
Application memoryLanguage runtime GC (explicit Buffer.fill(0) for sensitive buffers)Code review
Local .env fileshred -vzu .env on developer machineDeveloper responsibility

Crypto-shredding for GDPR erasure (Art. 17):Verification: WhenAfter destruction, confirm that decryption with destroyed key fails on a usertest requests account deletion:ciphertext.

    Destruction

  1. Thelog: envelopeDocument DEKevery forkey thatdestruction user'sin foedselsnummerlegal/internkontroll.md iswith: deletedkey 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 — SEPARATE from theKEK-01)
        database
  2. The└── ciphertextDEK-FNR-{ID}: Fødselsnummer field DEKs (foedselsnummer)quarterly becomesrotation) permanently unreadable
  3. └──
  4. Encrypts: users.fodselsnummer (national ID — L4 Restricted) │ ├── KEK-03: AML/KYC Records Master (annual rotation) │ └── DEK-AML-{ID}: AML retention:record transactionDEKs │ └── Encrypts: KYC documents, AML investigation records retained 5├── yearsBACKUP-KEK: perBackup HvitvaskingslovenEncryption §Master (annual 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 (eu-north-1EEA regionStockholm region) Backup KMS: AWS KMS (eu-west-1 Ireland Ireland)or foreu-central-1 drop-backup-keyFrankfurt)
  • only — separate region for disaster recovery
  • Secrets management:Manager: AWS Secrets Manager for application secrets
  • Secondary: AWS KMS cross-region replication for disaster recovery
  • HSM: AWS CloudHSM (eu-north-1)for KEK-02 fødselsnummer — L4 Restricted data)

KMS access control (Phase 2):

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:

approver coordination
Operation Required RolesApproval Approval Process
Create new KMS keyKEK drop-key-adminCISO + CISOsecond approval (Phase 2: AWS IAM +dual ticket
Rotate KMS key (manual)approval) drop-key-adminDocumented (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 reviewrequest + approval
Rotate JWT_SECRETKEK SecurityCISO Lead(proposer) + second approver SingleCalendar rotation with+ deploymentdocumentation
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 review

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


7. FoedselsnummerKey FieldEscrow Encryption& — Implementation PatternRecovery

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

Current MVP recovery:

  • drop-national-id-keyJWT_SECRET (AWSrecovery: KMS — separateRe-generate from databaseCSPRNG, masterredeploy. key)All Stored:users Onlyre-authenticate.
  • AES-256-GCM ciphertext — never plaintext foedselsnummer in database Source:
  • If src/drop-app/src/lib/encrypt.tsJWT_SECRET (is lost: Service restarts with new secret. All sessions invalidated. This is acceptable for MVP.

Phase 2 implementation)

// Envelope encryptionescrow for foedselsnummer
// Key: drop-national-id-keyKEKs (AWS KMS):

//
    Stored:
  • AWS base64(encryptedDEKKMS ||provides ivmulti-region || tag || ciphertext) async function encryptNationalId(fodselsnummer: string): Promise<string> { const iv = crypto.randomBytes(12); // 96-bit random IVredundancyneverno reusedseparate constescrow dekneeded =for awaitKMS-only kmsClient.generateDataKey({keys
  • KeyId:
  • AWS process.env.NATIONAL_ID_KEY_ARN,KMS KeySpec:deletion 'AES_256'has });minimum const7-day cipherwaiting =period crypto.createCipheriv('aes-256-gcm',(protection dek.Plaintext,against iv);accidental constdeletion)
  • ciphertext
  • AWS =KMS Buffer.concat([cipher.update(fodselsnummer,CloudTrail 'utf8'),provides cipher.final()]);full constaudit tagtrail
  • =
cipher.getAuthTag();

Phase dek.Plaintext.fill(0);2 //escrow Zerofor DEKBackup plaintextencryption key (offline):

  1. Key material exported encrypted from memoryAWS afterKMS use(if //exportable) Return:OR
  2. base64(encryptedDEK
  3. Backup ||KMS ivkey ||replication tagto ||second ciphertext)region return(recommended Buffer.concat([dek.CiphertextBlob,for iv,KMS-native tag,keys)
  4. ciphertext]).toString('base64');
  5. Physical }escrow:
Encrypted key file stored in fireproof safe + separate secure off-site copy
  • Access: Requires CISO + one designated board member
  • Verification: Quarterly — confirm escrow holders can access
  • AccessRecovery restriction:procedure (Phase 2):

    Only
      the
    1. CISO Complianceopens functionemergency haskey IAMrecovery accessrequest (documented)
    2. Escrow holder(s) convene
    3. Key material combined and imported to drop-compliance-decryptKMS
    4. role.
    5. All Applicationkey coderecovery cannotevents decryptlogged foedselsnummerand exceptpost-mortem duringrequired explicitwithin compliance48 workflows.

      hours

    8. Audit Logging for Key Operations

    All key operations loggedmust inbe AWS CloudTrail, including:logged:

    • Key creationgeneration: (actor, key ID, key type, timestamp)timestamp
    • Encryption/decryptiondecryption: (actor, key ID, context,operation, timestamp)timestamp (not data content)
    • Key rotationrotation: (actor, old key version,ID, new key version,ID, timestamp)timestamp
    • Key disablingrevocation: / deletion scheduling (actor, key ID, reason, timestamp)timestamp
    • Key destruction: actor, key ID, verification, timestamp
    • Access grant/revoke: actor, grantee, key ID, permissions, timestamp
    • Failed access attemptsattempts: (actor, key ID, reason, timestamp)timestamp

    Log destination:destination (Phase 2): AWS CloudTrail → S3SIEM (immutable, append-only)only +Current BetterStackMVP: aggregationManual log in legal/internkontroll.md for all key operations

    Log retention: 5 years (AMLHvitvaskingsloven compliance§30)Hvitvaskingslovenkey §operation 30)logs are AML-relevant

    Alert on:

    • DecryptOff-hours operationsaccess byto unexpected IAM roleKEKs
    • Failed KMS access attempts > 3 in 5 minutes
    • Off-hoursKey accessdeletion to drop-national-id-key or drop-kyc-keyscheduled
    • AnyKey ScheduleKeyDeletionrotation event (immediate alert)overdue

    9. ExceptionCompliance ProcessMapping

    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:

    +migration privateDBaccess
    SystemRequirement ExceptionStandard ExpiryCompensating ControlsControl
    JWTEncryption signingkey (HS256 shared secret)management Shared-secretGDPR JWTArt. instead of asymmetric RS256/EdDSA32 PhaseThis 2policy migration JWT_SECRETKMS in AWS Secrets Manager; 24h session expiry; server-side revocation tableimplementation
    SQLiteCryptographic MVPkey (no column-level TDE)protection FilesystemDORA encryptionArt. only9(4)(d) AWS KMS (Phase 22)
    Key custodian documentation FullIKT-forskriften disk§ encryption;5 Key network;inventory notable public(§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)

    10. Emergency Procedures — Key Compromise

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

    □ Alert CISO immediately: [email protected] / +47 40 47 42 51ActivateCreate incident responsechannel: — notify: Security Lead + CISO + CTO#incident-key-compromise-{DATE}
    □ Identify scope:which Whichkey was compromised (JWT, database, API key)
    □ Identify what data was accessible with compromised key?keyAWS KMS: Disable compromisedRevoke key immediately (see For JWT_SECRET compromise: rotate immediately (all sessions invalidated)§3.7)
    □ Generate replacement key
    □ Re-encryptDeploy new 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 affected data protected by compromised key (Restricted data first)
    □ Audit CloudTrail:logs: What wasoperations decryptedused usingthe compromised key in lastpast 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:priority (if database key compromised):

    1. Foedselsnummer (drop-national-id-key) — Restricted (L4),: highestFødselsnummer, priorityAML records — IMMEDIATE
    2. Confidential (L3): Transaction data, KYC documents (drop-kyc-key)recordsRestrictedwithin (L4)4 hours
    3. Database backup filesInternal (drop-backup-key)L2): Logs, session dataRestrictedwithin (L4)24 hours

    Estimated impact of JWT compromise:

    • All active user sessions must be invalidated
    • DatabaseAll masterusers (drop-db-master-key)must — Phase 2re-authenticate
    • Expected customer impact: temporary app disruption
    • Communication: In-app notification + email explaining security measures taken

    Approval

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