Merge pull request #21589 from overleaf/jpa-s3-ssec-hkdf
[object-persistor] s3SSEC: add HKDF layer to KEK GitOrigin-RevId: 1def9e378e1dfd90f449ad392b0db2101584e17f
This commit is contained in:
@@ -39,7 +39,10 @@ const {
|
||||
NotImplementedError,
|
||||
NoKEKMatchedError,
|
||||
} = require('@overleaf/object-persistor/src/Errors')
|
||||
const PerProjectEncryptedS3Persistor = require('@overleaf/object-persistor/src/PerProjectEncryptedS3Persistor')
|
||||
const {
|
||||
PerProjectEncryptedS3Persistor,
|
||||
RootKeyEncryptionKey,
|
||||
} = require('@overleaf/object-persistor/src/PerProjectEncryptedS3Persistor')
|
||||
const crypto = require('crypto')
|
||||
|
||||
describe('Filestore', function () {
|
||||
@@ -1118,33 +1121,39 @@ describe('Filestore', function () {
|
||||
})
|
||||
|
||||
describe('kek rotation', function () {
|
||||
const newKEK = crypto.generateKeySync('aes', { length: 256 }).export()
|
||||
const oldKEK = crypto.generateKeySync('aes', { length: 256 }).export()
|
||||
const newKEK = new RootKeyEncryptionKey(
|
||||
crypto.generateKeySync('aes', { length: 256 }).export(),
|
||||
Buffer.alloc(32)
|
||||
)
|
||||
const oldKEK = new RootKeyEncryptionKey(
|
||||
crypto.generateKeySync('aes', { length: 256 }).export(),
|
||||
Buffer.alloc(32)
|
||||
)
|
||||
const migrationStep0 = new PerProjectEncryptedS3Persistor({
|
||||
...s3SSECConfig(),
|
||||
automaticallyRotateDEKEncryption: false,
|
||||
async getKeyEncryptionKeys() {
|
||||
async getRootKeyEncryptionKeys() {
|
||||
return [oldKEK] // only old key
|
||||
},
|
||||
})
|
||||
const migrationStep1 = new PerProjectEncryptedS3Persistor({
|
||||
...s3SSECConfig(),
|
||||
automaticallyRotateDEKEncryption: false,
|
||||
async getKeyEncryptionKeys() {
|
||||
async getRootKeyEncryptionKeys() {
|
||||
return [oldKEK, newKEK] // new key as fallback
|
||||
},
|
||||
})
|
||||
const migrationStep2 = new PerProjectEncryptedS3Persistor({
|
||||
...s3SSECConfig(),
|
||||
automaticallyRotateDEKEncryption: true, // <- different compared to partiallyRotated
|
||||
async getKeyEncryptionKeys() {
|
||||
async getRootKeyEncryptionKeys() {
|
||||
return [newKEK, oldKEK] // old keys as fallback
|
||||
},
|
||||
})
|
||||
const migrationStep3 = new PerProjectEncryptedS3Persistor({
|
||||
...s3SSECConfig(),
|
||||
automaticallyRotateDEKEncryption: true,
|
||||
async getKeyEncryptionKeys() {
|
||||
async getRootKeyEncryptionKeys() {
|
||||
return [newKEK] // only new key
|
||||
},
|
||||
})
|
||||
|
||||
@@ -2,6 +2,9 @@ const fs = require('fs')
|
||||
const Path = require('path')
|
||||
const crypto = require('crypto')
|
||||
const https = require('https')
|
||||
const {
|
||||
RootKeyEncryptionKey,
|
||||
} = require('@overleaf/object-persistor/src/PerProjectEncryptedS3Persistor')
|
||||
|
||||
// use functions to get a fresh copy, not a reference, each time
|
||||
function s3BaseConfig() {
|
||||
@@ -26,15 +29,21 @@ function s3Config() {
|
||||
}
|
||||
}
|
||||
|
||||
const S3SSECKeys = [crypto.generateKeySync('aes', { length: 256 }).export()]
|
||||
const S3SSECKeys = [
|
||||
new RootKeyEncryptionKey(
|
||||
crypto.generateKeySync('aes', { length: 256 }).export(),
|
||||
Buffer.alloc(32)
|
||||
),
|
||||
]
|
||||
|
||||
function s3SSECConfig() {
|
||||
return {
|
||||
...s3Config(),
|
||||
ignoreErrorsFromDEKReEncryption: false,
|
||||
automaticallyRotateDEKEncryption: true,
|
||||
pathIsProjectFolder(_bucketName, path) {
|
||||
return !!path.match(/^[a-f0-9]+\/$/)
|
||||
pathToProjectFolder(_bucketName, path) {
|
||||
const [projectFolder] = path.match(/^[a-f0-9]+\//)
|
||||
return projectFolder
|
||||
},
|
||||
pathToDataEncryptionKeyPath(_bucketName, path) {
|
||||
const [projectFolder] = path.match(/^[a-f0-9]+\//)
|
||||
@@ -43,7 +52,7 @@ function s3SSECConfig() {
|
||||
path: Path.join(projectFolder, 'dek'),
|
||||
}
|
||||
},
|
||||
async getKeyEncryptionKeys() {
|
||||
async getRootKeyEncryptionKeys() {
|
||||
return S3SSECKeys
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user