Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fileKey rotation to GridFSBucketAdapter #6768

Merged
merged 17 commits into from
Oct 26, 2020

Conversation

cbaker6
Copy link
Contributor

@cbaker6 cbaker6 commented Jul 2, 2020

Adds the ability to rotate fileKeys for:

  • GridFSBucketAdapter - This will only be compatible with parse-server > 4.2.0 as older versions won't contain the source-code.
  • FSFilesAdapter - described here. If used with parse-server versions <= 4.2.0, DO NOT PASS in PARSE_SERVER_FILE_KEY or fileKey. Instead pass your key directly to FSFilesAdapter. parse-server versions > 4.2.0 can pass in PARSE_SERVER_FILE_KEY or fileKey.

If you have no files on your parse-server currently, but plan on adding them, simply add a PARSE_SERVER_FILE_KEY. There's no need to rotateKeys now, but you may want to do it in the future

Periodically you may want to rotate your fileKey for security reasons. When this is the case, it is recommended to start up a development parse-server (or a separate process from your main process) that has the same configuration as your production server. On the development server, initialize the file adapter with the new key and do the following in your index.js:

Pass the newKey as env var PARSE_SERVER_FILE_KEY, pass in --fileKey "newKey"in the CL, or initialize ParseServer with fileKey="newKey".

An example using GridFSBucketAdapter :

const api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: process.env.PARSE_SERVER_CLOUD || __dirname + '/cloud/main.js',
  appId: process.env.PARSE_SERVER_APPLICATION_ID || 'myAppId',
  masterKey: process.env.PARSE_SERVER_MASTER_KEY || '', 
  fileKey: process.env.PARSE_SERVER_FILE_KEY, //Add your new fileKey here. Keep it secret
  ...
});

An example using FileSystemAdapter:

const api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: process.env.PARSE_SERVER_CLOUD || __dirname + '/cloud/main.js',
  appId: process.env.PARSE_SERVER_APPLICATION_ID || 'myAppId',
  masterKey: process.env.PARSE_SERVER_MASTER_KEY || '', 
  filesAdapter: new FSFilesAdapter({fileKey: process.env.PARSE_SERVER_FILE_KEY}), //Add your new fileKey here. Keep it secret.
  ...
});

Files were previously unencrypted and you want to encrypt them with a fileKey

You probably want to back up your unencrypted files before doing this the first time.

//After initializing your ParseServer with one of the file adapters above.....

//This can take awhile depending on how many files and how large they are. It will attempt to rotate the key of all files in your filesSubDirectory
const {rotated, notRotated} =  await api.filesAdapter.rotateFileKey();
console.log('Files rotated to newKey: ' + rotated);
console.log('Files that couldn't be rotated to newKey: ' + notRotated);

Files were previously encrypted with oldKey and you want to encrypt with newKey

The same process as above, but pass in your oldKey to rotateFileKey().

//This can take awhile depending on how many files and how large they are. It will attempt to rotate the key of all files in your filesSubDirectory
const {rotated, notRotated} =  await api.filesAdapter.rotateFileKey({oldKey: oldKey});
console.log('Files rotated to newKey: ' + rotated);
console.log('Files that couldn't be rotated to newKey: ' + notRotated);

Files were previously encrypted with oldKey and you want to decrypt all files

Different from the previous process, don't initialize your fileAdapter with a fileKey. Pass in your oldKey to rotateFileKey().

For GridFSBucketAdapter, omit the key:

const api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: process.env.PARSE_SERVER_CLOUD || __dirname + '/cloud/main.js',
  appId: process.env.PARSE_SERVER_APPLICATION_ID || 'myAppId',
  masterKey: process.env.PARSE_SERVER_MASTER_KEY || '', 
  //No fileKey here
  ...
});

For FileSystemAdapter, don't pass the fileKey option:

const api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: process.env.PARSE_SERVER_CLOUD || __dirname + '/cloud/main.js',
  appId: process.env.PARSE_SERVER_APPLICATION_ID || 'myAppId',
  masterKey: process.env.PARSE_SERVER_MASTER_KEY || '', 
  filesAdapter: new FSFilesAdapter(), //No fileKey supplied
  ...
});
//This can take awhile depending on how many files and how larger they are. It will attempt to rotate the key of all files in your filesSubDirectory
//It is not recommended to do this on the production server, deploy a development server to complete the process.
const {rotated, notRotated} =  await api.filesAdapter.rotateFileKey({oldKey: oldKey});
console.log('Files rotated to unencrypted with noKey: ' + rotated);
console.log('Files that couldn't be rotated to unencrypted with noKey: ' + notRotated);

Only rotate a select list of files that were previously encrypted with oldKey and you want to encrypt with newKey

This is useful if for some reason there errors and some of the files werent rotated and returned in notRotated. The same process as above, but pass in your oldKey along with the array of fileNames to rotateFileKey().

//This can take awhile depending on how many files and how large they are. It will attempt to rotate the key of all files in your filesSubDirectory
const {rotated, notRotated} =  await api.filesAdapter.rotateFileKey({oldKey: oldKey, fileNames: ["fileName1.png","fileName2.png"]});
console.log('Files rotated to newKey: ' + rotated);
console.log('Files that couldn't be rotated to newKey: ' + notRotated);

@codecov
Copy link

codecov bot commented Jul 2, 2020

Codecov Report

Merging #6768 into master will decrease coverage by 0.03%.
The diff coverage is 90.38%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #6768      +/-   ##
==========================================
- Coverage   93.88%   93.84%   -0.04%     
==========================================
  Files         169      169              
  Lines       12353    12403      +50     
==========================================
+ Hits        11597    11639      +42     
- Misses        756      764       +8     
Impacted Files Coverage Δ
src/Options/Definitions.js 100.00% <ø> (ø)
src/Adapters/Files/GridFSBucketAdapter.js 80.32% <90.38%> (+2.68%) ⬆️
src/Routers/FunctionsRouter.js 92.59% <0.00%> (-1.53%) ⬇️
src/Adapters/Storage/Mongo/MongoStorageAdapter.js 92.92% <0.00%> (-0.67%) ⬇️
src/RestWrite.js 93.98% <0.00%> (+0.16%) ⬆️
src/Adapters/Auth/httpsRequest.js 100.00% <0.00%> (+4.76%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e6ac3b6...de06117. Read the comment docs.

if (filename.indexOf('tfss-') === 0) {
fileObject['url'] =
'http://files.parsetfss.com/' +
config.fileKey +
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed "fileKey" from being appended to urls. I assumed legacy parse.com used the fileKey for encryption, didn't realize is was only appended. I made the modification to the legacy test of removing the fileKey from the links there also.

Now "fileKey" is repurposed as an encryption key

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dplewis do you have any thoughts on this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure. I'd prefer to have a new parameter for the encryption as this change will be a breaking change and may affect a lot of apps using it not only changing their files urls but also encrypting their files (and not being able to decrypt the current ones)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for my last comment. I've just checked the code again and fileKey is only being used here in this piece of code. I believe this current code is actually useless now and can be replaced to only

fileObject['url'] = this.adapter.getFileLocation(config, filename);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm only afraid that some developers may have fileKey in their config since parse.com migration and in this case they will have their files being encrypted (maybe without noticing that).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a new parameter would definitely prevent an accidental usage from people who have the old fileKey set. I think there was an old issue someone opened up where I mentioned for them to remove fileKey from their configuration. I was trying to save an old parameter, but it may not be the best solution here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added and option for encryptionKey and used that instead of fileKey. Let me know if this works and I can make the change in the docs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted this particular file since I’m no longer using fileKey

@ghost
Copy link

ghost commented Oct 23, 2020

Danger run resulted in 1 fail and 1 markdown; to find out more, see the checks page.

Generated by 🚫 dangerJS

@cbaker6
Copy link
Contributor Author

cbaker6 commented Oct 23, 2020

@davimacedo @dplewis I updated the comments here to reflect deploying a development server for key rotation like the FS adapter. You should also check the review comment I left as I removed some code from FilesController.js just in case it had the potential of exposing the fileKey.

Copy link
Member

@davimacedo davimacedo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@davimacedo davimacedo merged commit 7f3ea3f into parse-community:master Oct 26, 2020
@cbaker6 cbaker6 mentioned this pull request Nov 7, 2021
4 tasks
@cbaker6 cbaker6 deleted the rotate_keys branch September 25, 2022 12:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants