Skip to main content

Key Management Policy

Key Management Policy

Project / Organization: {{ORG_NAME}}ALAI Holding AS — Drop Payment App Policy Number: POL-SEC-KM-{{NUMBER}}001 Version: {{VERSION}}1.0 Date: {{DATE}}2026-02-23 Author: {{AUTHOR}}Security Architect Status: Draft | In Review | Approved Reviewers: {{REVIEWERS}}CISO, CTO, DPO Next Review: {{REVIEW_DATE}}2027-02-23 Classification: Confidential — Restricted Distribution

Document History

Version Date Author Changes
0.1 {{DATE}}2026-02-23 {{AUTHOR}}Security Architect Initial draft — Drop key management for AWS KMS + Secrets Manager

1. Purpose & Scope

Purpose: This policy defines the lifecycle management requirements for all cryptographic keys and secrets used by {{ORG_NAME}},ALAI Holding AS for the Drop payment app, including generation, distribution, storage, usage, rotation, revocation, and destruction.

Regulatory basis:

  • GDPR Art. 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) — encryption key management
  • Hvitvaskingsloven (LOV-2018-06-01-23) § 30 — KYC data protection at rest

Scope: All cryptographic keys and secrets in use across:

  • All production,Production, staging, and development environments for Drop
  • All cloudAWS infrastructure and(KMS, on-premisesSecrets systemsManager, S3, App Runner)
  • All employee devicesand contractor workstations handling Confidential or Restricted data
  • All third-party integrations where {{ORG_NAME}}ALAI Holding AS holds keys

Policy Owner: {{CISO_NAME}}CISO ({{CISO_EMAIL}})[email protected]) Operational Owner: {{SECURITY_TEAM}}Security team


2. Key Types & PurposesInventory

2.1 Complete Key Taxonomy

Key KMS(eu-west-1)
Key ID Type Algorithm Purpose Data Classification Protected OwnerStorage
KEK-01drop-national-id-key KeyKEK Encryption(Data KeyEncryption) AES-256256-GCM MasterFødselsnummer key(national forID) encryptingfield DEKsencryption Restricted (L4) Security team AWS KMS (eu-north-1)
KEK-02drop-db-master-key KeyKEK Encryption(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-256 Database field-levelbackup encryption master Restricted (L4) Security team
AWS
DEK-* Data Encryptionseparate KeyAES-256-GCMRecord-level data encryptionConfidential/RestrictedApplicationregion
JWT_SECRETSigning secretHMAC-SHA-256JWT session token signingConfidential (L3)Security teamAWS Secrets Manager
TLS-EXT TLS Certificate Key ECDSA P-256 External HTTPS (getdrop.no) PlatformCloudflare team/ Let's EncryptCloudflare managed
TLS-INTBankID-cert TLS Certificate Key Ed25519RSA-2048 InternalBankID mTLSNorway integration JWT verification PlatformBankID teamNorge AS CABankID managed
SIG-01Signing KeyEd25519Code/artifact signingSecurity team
SIG-02Signing KeyHMAC-SHA-256Webhook signaturesEngineering
AUTH-01Auth Token KeyRSA-4096JWT signing (RS256)Security team
AUTH-02Auth Token KeyEd25519JWT signing (EdDSA)Security team
BACKUP-01Backup Encryption KeyAES-256-GCMDatabase backup encryptionRestrictedSecurity team
SUMSUB-API-*KEY API Key HMAC-SHA-256 CustomerSumsub KYC API authentication Confidential (L3) EngineeringSecurity teamAWS Secrets Manager
MFA-DEK-* SecretData KeyEncryption Keys TOTP (HMAC-SHA1/SHA256)AES-256-GCM UserPer-record MFAdata secretsencryption (envelope pattern) Restricted (L4) ApplicationGenerated by AWS KMS GenerateDataKey

2.2 Secrets Inventory (Non-KMS)

Secret NamePurposeStorageRotation
JWT_SECRETJWT token signingAWS Secrets ManagerQuarterly
SUMSUB_SECRET_KEYSumsub KYC integrationAWS Secrets ManagerAnnual or on compromise
BANKID_CLIENT_SECRETBankID OIDC client secretAWS Secrets ManagerPer BankID schedule
DATABASE_URLPostgreSQL connection stringAWS Secrets ManagerOn DB credential rotation
SENTRY_DSNSentry error monitoringAWS Secrets ManagerAnnual

3. Key Hierarchy

AWS KMS Root of Trust (eu-north-1 primary)
    │
    ├── drop-national-id-key (AES-256-GCM — annual rotation)
    │       └── DEK-{user_id}-{timestamp}: Per-record envelope DEKs
    │               └── Encrypts: fødselsnummer 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 for backups)
            └── drop-backup-key (AES-256 — annual rotation)
                    └── Encrypts: All database backup files

AWS Secrets Manager
    ├── JWT_SECRET (HMAC-SHA-256 — quarterly rotation)
    │       └── Signs: Drop JWT session tokens (HS256 via jose ^6.1.3)
    ├── SUMSUB_SECRET_KEY (API key — annual rotation)
    ├── BANKID_CLIENT_SECRET (OIDC client secret — BankID schedule)
    └── DATABASE_URL (connection string — on rotation)

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

4. Key Lifecycle

3.4.1 Lifecycle Overview

flowchart LR
    GEN[Generation] -->|"Secure,AWS random"KMS CSPRNG"| DIST[Distribution]
    DIST -->|"EncryptedRuntime channel"API call\nnever in env files"| STORE[Storage]
    STORE -->|"AccessKMS / Secrets Manager\naccess controlled"| USE[Usage]
    USE -->|"Scheduled"| ROT[Rotation]
    ROT -->|"New key active"active\noverlap period"| USE
    ROT -->|"Old key retired"| ARCH[Archive / Revoke]
    ARCH -->|"End of life"| DEST[Destruction]

    REVOKE[Emergency Revocation] -->|"Compromise detected"| DEST
    USE --> 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 keys, as specified for asymmetric
  • NEVER use:use user-supplied passphrases, timestamps, UUIDs, or predictable values as keys
  • NEVER generate keys in userspaceapplication withoutcode anfor establishedRestricted cryptodata library— use AWS KMS GenerateKey or GenerateDataKey

Approved key generation methods:

External
Key Type Generation Method Tool
Symmetric (AES-256) KMS keysKMS CreateKey APIAWS KMS (FIPS 140-2 Level 3 HSMs)
Envelope DEKsKMS GenerateDataKey APIAWS KMS
JWT signing secret crypto.randomBytes(32).toString('hex') (Node.js) / os.urandom(32) (Python) OSNode.js CSPRNG
AsymmetricTLS (Ed25519)certificates opensslACME genpkey -algorithm ed25519protocol OpenSSLCloudflare 1.1.1+/ Let's Encrypt
AsymmetricBankID (ECDSA P-256)certificates opensslBankID ecparamNorge -nameAS prime256v1 -genkeyCA OpenSSL
RSA-4096openssl genrsa -aes256 4096OpenSSL
KMS-managedKMS GenerateKey APICloud KMS
HSM-managedHSM key generation{{HSM_PROVIDER}}CA

Generation environment:

  • KeysAll KMS-managed keys for Restricted data: MUST be generated within AWS KMS or HSMHSMskey material never leaves AWS
  • JWT_SECRET: generated using crypto.randomBytes(32) then stored in applicationAWS code
  • Secrets
  • Keys for Confidential data: MAY be generated in application code using OS CSPRNGManager
  • All key generation events MUSTlogged bein loggedAWS CloudTrail

3.4.3 Distribution

Principles:

  • Never transmit keys in plaintext over any channel
  • Never include keys in source code, configuration.env files committed to Git, configuration files in VCS, or logslog output
  • Never send keys via email, Slack, or any messaging platform
  • Always usefetch encryptedsecrets channelsat withapplication mutualruntime authenticationfrom forAWS keySecrets distributionManager or KMS API

Distribution methods:

never
Scenario Method Notes
Application runtime keyssecrets (JWT_SECRET) Cloud KMS API /AWS Secrets Manager API at startup KeysFatal fetchederror atif runtimeJWT_SECRET missing
Envelope DEK generationAWS KMS GenerateDataKey per encryption operationKey material decrypted in environmentmemory filesonly
Developer access to secretsHashiCorp Vault / cloudnon-production secrets Role-basedAWS accessIAM withrole + MFALeast privilege
CI/CD pipeline secrets CIGitHub platformActions encrypted secrets (encryptedscoped atto rest)repo) Scoped to pipeline, rotatedRotated per project
Cross-systemBankID keyclient sharingsecret KMSAWS keySecrets policies (no key material exchange)Manager GrantFetched accessat to KMS key, not key itself
Emergency key recovery{{ESCROW_PROCESS}}Requires dual approval — see §8runtime

3.4.4 Storage

Storage hierarchy:hierarchy for Drop:

Level 1 — HSMAWS KMS HSMs (HardwareFIPS Security140-2 Module)Level 3)
  ├── Master keysdrop-national-id-key (KEKs)fødselsnummer forencryption)
  Restricted├── datadrop-db-master-key (database TDE — Phase 2)
  ├── drop-kyc-key (KYC document S3 encryption)
  └── Rootdrop-backup-key CA(backup privateencryption keys— eu-west-1)

Level 2 — Cloud KMS (AWS KMSSecrets / Azure Key Vault / GCP Cloud KMS)Manager
  ├── KeyJWT_SECRET Encryption(HMAC Keyssigning for Confidential datakey)
  ├── ServiceSUMSUB_SECRET_KEY signing(API keyskey)
  ├── BANKID_CLIENT_SECRET (OIDC secret)
  └── EncryptedDATABASE_URL DEK(connection storagestring)

Level 3 — Secrets Manager (HashiCorp Vault / AWS Secrets Manager)
  ├── Application secrets (DB passwords, API keys)
  ├── TLS certificate private keys
  └── Derived symmetric keys (encrypted by Level 2 keys)

Level 4 — Application memory (ephemeral only)
  ├── DEKsDecrypted DEK during active useencryption/decryption operation
  └── Decrypted secretsJWT_SECRET during operationtoken Note:signing/verification
  NOTE: NEVER persist Level 43 to disk

Prohibited storage locations:

  • Source code or config files in VCSGit (.env, config.ts, secrets.json)
  • Application logs or error messages (Sentry, BetterStack)
  • Unencrypted database columns (for Restricted data)
  • Email attachments or messagingSlack platforms
  • Shared drives or unencrypted file sharesmessages
  • Browser localStorage or sessionStorage
  • EnvironmentContainer variablesimage inlayers container(Dockerfile, images.dockerignore exclusions not sufficient)

3.4.5 Usage

Access control principles:

Principle Implementation
Least privilege KeysKMS scopedkey topolicies: minimumencrypt-only necessaryfor operations (encrypt-only,application, decrypt-only,only sign-only)for compliance function
Separation of duties Nokey-admin singlecannot personperform candecryption; generateapplication +service approvecannot +create deploy a keykeys
Key purpose binding Encryption keys NOTdrop-national-id-key used for signing; signing keys NOT usedonly for national ID encryption — not for other purposes
Audit all access Every KMS/HSMKMS operation logged within actorAWS identityCloudTrail — actor, key ID, operation, timestamp
Time-bound access TemporaryIAM accessrole assumption with time-bound session tokens for key operations — not persistent permissions

KeyKMS usagekey auditpolicy requirements:roles:

  • All
  • logged:actor,operation,keyID,
  • Logs
  • shippedtoSIEMwithinpatterns
    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 operationsonly YES
    drop-key-auditor kms:ListKeys, timestamp,kms:DescribeKey, sourceCloudTrail IPread YES
    drop-app-runner kms:GenerateDataKey, 1kms:Decrypt minute(scoped
  • Unusualper accesskey)
  • No alert(IAM withinrole, 5VPC minutesconstraint)

    3.4.6 Rotation Schedule

    encryptionDEKs
    Key Type Rotation Period Method Owner Alert if Overdue
    KEK (Master keys)drop-national-id-key Annual ManualAWS +KMS dualautomatic approvalkey rotation Security team Yes — 7 days overdue
    Databasedrop-db-master-key Annual AWS KMS automatic key rotationSecurity teamYes — 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_SECRET Quarterly AutomatedManual (key rotationgenerate API)new, deploy, rotate PlatformSecurity team Yes — 3 days overdue
    TLS certificatescertificate (external)getdrop.no) 90 days Automated (cert-managerCloudflare +/ ACME)Let's Encrypt) Platform Yes — 14 days overduebefore expiry
    TLSBankID certificates (internal)certificate 30Per daysBankID schedule AutomatedManual (cert-manager)— BankID renewal process PlatformSecurity teamCalendar reminder
    SUMSUB_SECRET_KEYAnnual or on compromiseManual via Sumsub dashboardSecurity team Yes — 7 days overdue
    JWT signing keysQuarterlyAutomated with overlap periodSecurityYes — 3 days overdue
    API signing keys (webhooks)QuarterlyAutomatedEngineeringYes — 3 days overdue
    Backup encryption keysAnnualManual + dual approvalSecurityYes — 7 days overdue
    Customer API keysOn customer request OR 2 yearsSelf-service portalCustomerNotify customer 30 days before
    MFA secretsOn user request or suspected compromiseSelf-serviceUserN/A

    RotationJWT_SECRET rotation overlap period:procedure:

    Old
      key
    1. Generate remainsnew validJWT_SECRET value
    2. Deploy new secret to AWS Secrets Manager
    3. Rolling deploy of Drop app (picks up new secret)
    4. Wait for {{OVERLAP_PERIOD}}all afterexisting sessions to expire (max 24h — JWT expiry)
    5. All sessions issued with old secret are now invalid (users re-authenticate)
    6. Delete old secret version from Secrets Manager

    AWS KMS automatic rotation: When enabled, AWS KMS generates new key activationmaterial toannually allowwhile in-flightretaining operationsall toprior complete.

    versions

    Keyfor rotationdecryption monitoringof dashboard:existing {{DASHBOARD_URL}}ciphertext. Re-encryption of existing data is required when performing cryptographic erasure (GDPR Art. 17).


    3.4.7 Revocation Procedures

    Trigger conditions for immediate revocation:

    • Known or suspected key compromise (e.g., key material logged, unauthorized access)
    • Employee departure (forwith keysaccess into personalkey custody)management IAM roles
    • System compromise where key was in use
    • Legal hold or regulatory requirement
    • CustomerDetection requestof (forunauthorized customerdecryption APIactivity keys)in CloudTrail logs

    Emergency revocation procedure (< 1 hour):

    Step 1: Alert Security Lead immediately via #security-incident Slack channel
    Step 2: Identify allscope systems usingwhich thedata was accessible with compromised key?
    Step 3: AWS KMS: Disable compromised key (prevents new encrypt/decrypt)
    Step 3:4: Generate replacement key (seevia §3.2)KMS CreateKey
    Step 4:5: KMS:Re-encrypt Disable/revokeall data protected by compromised key Step(priority: 5:Restricted Deploy new key to all systems (use zero-downtime rotation)first)
    Step 6: Update KMS key references in application configuration
    Step 7: Deploy updated application configuration
    Step 8: Verify all systems using new key
    Step 7:9: Audit forCloudTrail: unauthorizedWhat usagedecrypt ofoperations used the compromised key in last 30 days?
    Step 8:10: Assess breach notification requirement (see data-breach-response-plan.md §5)
    Step 11: Document in incident log
    Step 9:12: Post-mortem within 48 hours
    

    CertificateJWT_SECRET revocation:emergency rotation (session compromise):

      Step 
    • Immediately1: uponGenerate compromise:new RevokeJWT_SECRET viaimmediately CAStep and2: pushDeploy CRLto update
    • AWS
    • OCSPSecrets response:Manager MustStep reflect3: revocationRolling withindeploy {{OCSP_UPDATE_TIME}}
    • Drop
    • Notifyapplication — all certificatein-flight consumers
    • sessions
    invalidated Step 4: All users must re-authenticate (acceptable security impact) Step 5: Document in incident log

    3.4.8 Destruction

    When destruction is required:

    • Key has been rotated out and overlap period expired
    • System(KMS: decommissionedschedule deletion with 30-day waiting period)
    • Crypto-shreddingshredding: (deletedeleting encrypteduser data by destroying itsthe envelope DEK encrypted under drop-national-id-key (GDPR erasure)Art. 17 erasure mechanism)
    • System decommissioned

    Destruction methods:

    decryption
    Key Location Destruction Method Verification
    HSMAWS KMS key HSM secure erase commandHSM audit log
    Cloud KMSKMS scheduled key deletionScheduleKeyDeletion (min 7-30 day waiting period) KMS + CloudTrail audit log
    AWS Secrets Manager DeleteDeleteSecret secret(7-30 +day verifywaiting period) AuditSecrets Manager audit log
    Application memory (DEK) ExplicitlyGarbage zero memorycollection (memset/SecureZeroMemory)JavaScript — no explicit zeroing in V8 engine) CodeProcess reviewtermination
    LocalEnvelope fileDEK in database SecureDelete deleteencrypted (shredDEK -vzu / sdelete)field HashVerify verification
    Backup mediaPhysical destruction + certificateDestruction certificatefails

    Verification:Crypto-shredding for GDPR erasure (Art. 17): KeyWhen destructiona mustuser berequests verifiedaccount deletion:

    check
    1. The envelope DEK for that decryptionuser's withfødselsnummer destroyedis keydeleted fails.

      from

      Destructionthe log:database

    2. Every
    3. The key destruction event recorded in {{KEY_DESTRUCTION_LOG_LOCATION}}


      4. Key Hierarchy

      Root of Trust: HSM / Cloud KMS Root
          │
          ├── KEK-01: Database Encryption Master Keyciphertext (annualfødselsnummer) rotation)becomes permanently ├──unreadable
    4. DEK-DB-{ID}:
    5. AML Per-tableretention: encryptiontransaction keyrecords (quarterlyretained rotation)5 years but └──user's Encrypts:fødselsnummer Databaseis field-levelunrecoverable
    6. PII │ └── DEK-BACKUP-{ID}: Backup encryption key (annual rotation) │ └── Encrypts: Database backup files │ ├── KEK-02: Application Secrets Master Key (annual rotation) │ ├── DEK-MFA-{ID}: MFA secret encryption key │ │ └── Encrypts: User TOTP secrets in database │ └── DEK-APIKEY-{ID}: API key material encryption │ └── Encrypts: API key secrets in database │ ├── TLS Root CA (10-year validity) │ ├── Intermediate CA (2-year validity) │ │ ├── External TLS Certificates (90-day) │ │ └── Internal mTLS Certificates (30-day) │ └── Code Signing CA │ └── Release Signing Certificates (1-year) │ └── JWT Signing Keys (Ed25519, quarterly rotation) └── Signs: JWT access + refresh tokens

    5. Key Management System

    Primary KMS: {{KMS_TOOL}}AWS KMS (e.g.,eu-north-1 — Stockholm region) Backup KMS for backups: AWS KMS,KMS Azure(eu-west-1 Key Vault,Ireland) HashiCorpfor Vault)drop-backup-key only Secondary/BackupSecrets KMS:management: {{SECONDARY_KMS}}AWS Secrets Manager (separate region/provider) HSM: {{HSM_PROVIDER}} (for highest-classification keys)eu-north-1)

    Multi-region note: KMS accesskeys control:

    are single-regionbydefault.drop-backup-keyisinaseparate thatoutagedoesnotbackup
    Role Permissions MFAintentionally Required
    key-adminCreate, rotate, schedule deletion — NO decryptYES
    key-user-encryptEncrypt onlyYES
    key-user-decryptDecrypt onlyYES
    key-auditorList, describe, view audit logs — NO cryptographic opsYES
    CI/CD pipelineEncrypt onlyregion (specificeu-west-1) keyso IDs) N/Aa (serviceregional account)
    Applicationprevent service Encrypt + Decrypt (specific key IDs, specific operations)N/A (service account + VPC constraint)
    restoration.


    6. Access Controls for Key Operations

    Separation of duties requirements:

    Operation Required Roles Approval Process
    Create new KEKKMS key Security Leaddrop-key-admin + CISO approval Dual approval via KMSAWS IAM + ticket
    Rotate KEKKMS key (manual) Security Leaddrop-key-admin (proposer) + CISO (approver) Dual approval via IAM policy
    Emergency revocationkey disable Security Lead (any one of)one) Single with immediate incident ticket required
    DestroySchedule key deletion Security Leaddrop-key-admin + CISO + Legal (if litigation hold) TripleDual approval — minimum 7-day waiting period
    Grant new service access to key Security Lead + system owner PeerIAM PR review + approval
    Rotate JWT_SECRETSecurity LeadSingle — with deployment coordination

    7. Key Escrow & Recovery

    Escrow policy: KEKs and backup encryption keys must be escrowed.

    Escrow process:

    1. Key generated in KMS/HSM
    2. Key material exported (encrypted under escrow master key) — only where KMS allows export
    3. Exported material split into {{N}} shares using Shamir's Secret Sharing (requires {{K}} of {{N}} shares to reconstruct)
    4. Shares distributed to: {{SHARE_HOLDER_1}}, {{SHARE_HOLDER_2}}, {{SHARE_HOLDER_3}}
    5. Share holders store in secure location (safe deposit box or equivalent)
    6. Quarterly: Verify shares exist and holders still accessible

    Recovery procedure (requires {{K}} share holders):

    1. Incident Commander opens emergency key recovery ticket
    2. {{K}} share holders convene (in person or secure video call)
    3. Shares combined to reconstruct key material
    4. Key imported into KMS
    5. Full event logged and post-mortem required

    Note: For cloud KMS-only keys that cannot be exported: Rely on KMS redundancy (multi-region replication) — no separate escrow needed.


    8. Audit Logging for Key Operations

    All key operations logged,logged in AWS CloudTrail, including:

    • Key generationcreation (actor, key ID, key type, timestamp)
    • Key encryption/Encryption/decryption (actor, key ID, data context, timestamp)
    • Key rotation (actor, old key ID,version, new key ID,version, timestamp)
    • Key revocationdisabling / deletion scheduling (actor, key ID, reason, timestamp)
    • Key destruction (actor, key ID, verification hash, timestamp)
    • Access grant/revoke (actor, grantee, key ID, permissions, timestamp)
    • Failed access attempts (actor, key ID, reason, timestamp)

    Log destination: {{SIEM_TOOL}}AWS CloudTrail → S3 (immutable, append-onlyonly) + BetterStack aggregation Log retention: 25 years (PCI-DSS)AML /compliance 3 years (SOC 2)minimumwhicheverHvitvaskingsloven is§ longer30) Alert on:

    Unusual
      access
    • Decrypt volume,operations off-hoursby accessunexpected toIAM KEKs,role
    • failed
    • Failed KMS access attempts > 3 in 5 minutes
    • Off-hours access to drop-national-id-key or drop-kyc-key
    • Any ScheduleKeyDeletion event (immediate alert)

    8. Fødselsnummer Field Encryption — Implementation Pattern

    Key: drop-national-id-key (AWS KMS — separate from database master key) Stored: Only AES-256-GCM ciphertext — never plaintext fødselsnummer in database

    // Envelope encryption for fødselsnummer — src/drop-app/src/lib/encrypt.ts (Phase 2)
    // Key: drop-national-id-key (AWS KMS — separate from db master)
    // Stored: base64(encryptedDEK || iv || tag || ciphertext)
    
    async function encryptNationalId(fodselsnummer: string): Promise<string> {
        const iv = crypto.randomBytes(12);  // 96-bit random IV — never reused
        const dek = await kmsClient.generateDataKey({
            KeyId: process.env.NATIONAL_ID_KEY_ARN,
            KeySpec: '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();
        // Securely zero DEK plaintext from memory after use
        dek.Plaintext.fill(0);
        // Return: base64(encryptedDEK || iv || tag || ciphertext)
        return Buffer.concat([dek.CiphertextBlob, iv, tag, ciphertext]).toString('base64');
    }
    
    async function decryptNationalId(encrypted: string): Promise<string> {
        const buf = Buffer.from(encrypted, 'base64');
        // AWS KMS CiphertextBlob is always 184 bytes for AES_256 DEK
        const encryptedDek = buf.subarray(0, 184);
        const iv = buf.subarray(184, 196);          // 12 bytes
        const tag = buf.subarray(196, 212);          // 16 bytes
        const ciphertext = buf.subarray(212);
        const dek = await kmsClient.decrypt({ CiphertextBlob: encryptedDek });
        const decipher = crypto.createDecipheriv('aes-256-gcm', dek.Plaintext, iv);
        decipher.setAuthTag(tag);
        const plaintext = decipher.update(ciphertext) + decipher.final('utf8');
        dek.Plaintext.fill(0);
        return plaintext;
    }
    

    Access restriction: Only the Compliance function (KYC verification, AML reporting) has IAM access to drop-compliance-decrypt role. Application code cannot decrypt fødselsnummer except during explicit compliance workflows.


    9. ComplianceException MappingProcess

    Exceptions are not permitted for: Restricted (L4) data (fødselsnummer, KYC documents) — no exceptions to field-level encryption requirement.

    Exception request process:

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

    Active exceptions:

    KMS encryption;publicDB
    RequirementSystem StandardException ControlExpiryCompensating Controls
    EncryptionJWT keysigning management(HS256 shared secret) PCI-DSSShared-secret Req.JWT 3.7instead 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) PCI-DSSFilesystem Req.encryption 3.7.1only, no PostgreSQL TDE HSMPhase for2 KEKs + KMS for DEKs
    Key custodian documentationmigration PCI-DSSFull Req.disk 3.7.2 Keyprivate inventorynetwork; tableno (§2)
    Key rotationPCI-DSS Req. 3.7.4Rotation schedule (§3.6)
    Retired key replacementPCI-DSS Req. 3.7.5Rotation + revocation procedures
    Split knowledgePCI-DSS Req. 3.7.6Shamir's Secret Sharing (§7)
    Key destructionPCI-DSS Req. 3.7.7Destruction procedures (§3.8)
    Access controlsSOC 2 CC6.1Access controls table (§6)
    Cryptographic controlsISO 27001 A.10This entire policy
    Personal data encryptionGDPR Art. 32See data-encryption-policy.mdaccess

    10. Emergency Procedures — Key Compromise

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

    □ Activate incident response:response #incident-key-compromise-{{DATE}} □ Notify:notify: Security Lead + CISO + Engineering LeadCTO
    □ Identify scope: Which data was accessible with compromised key?
    □ RevokeAWS KMS: Disable compromised key immediately
    □ For JWT_SECRET compromise: rotate immediately (seeall §3.7)sessions invalidated)
    □ Generate new replacement key
    □ Re-encrypt all data that was protected by compromised key (Restricted Rotatedata all derived keys that used compromised key as sourcefirst)
    □ Audit logs:CloudTrail: What was decrypted using the compromised key in the pastlast 30 days?
    □ Assess if breach notification requiredrequirement (see data-breach-response-plan.md §5)
       → GDPR Art. 33 / Personopplysningsloven § 32: 72h to Datatilsynet if personal data affected
       → Finanstilsynet notification if payment data affected
    □ Document everything in incident log
    □ Post-mortem within 48 hours
    

    Re-encryption priority order:priority:

    1. Most sensitive data firstFødselsnummer (drop-national-id-key) — Restricted (L4), Confidentialhighest → Internal)priority
    2. MostKYC recently accessed data firstdocuments (likelydrop-kyc-key) to haveRestricted been targeted)(L4)
    3. OldestDatabase databackup lastfiles (historicaldrop-backup-key) data, lowerRestricted immediate(L4)
    4. risk)
    5. Database master (drop-db-master-key) — Phase 2

    Estimated re-encryption time for {{N}} records: {{ESTIMATE}} — plan for {{ESTIMATE × SAFETY_FACTOR}}


    Approval

    Role Name Date Signature
    Author Security Architect 2026-02-23
    CISO
    CTO
    DPO (complianceGDPR relevance)
    Management