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

feat(xo-web): remote level encryption #6321

Merged
merged 6 commits into from
Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

- [Dashboard/Health] Detect broken VHD chains and display missing parent VDIs (PR [#6356](https://github.com/vatesfr/xen-orchestra/pull/6356))
- [Proxy] Ability to bind a licence to an existing proxy (PR [#6348](https://github.com/vatesfr/xen-orchestra/pull/6348))
- [Backup] Implement encryption for backup files on storage (PR [#6321](https://github.com/vatesfr/xen-orchestra/pull/6321))

### Bug fixes

Expand Down
2 changes: 1 addition & 1 deletion packages/xo-server/src/sensitive-values.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const merge = (newValue, oldValue) => {

export const obfuscate = value => replace(value, OBFUSCATED_VALUE)

const SENSITIVE_PARAMS = ['token', /password/i]
const SENSITIVE_PARAMS = ['token', /password/i, 'encryptionKey']
const isSensitiveParam = name =>
SENSITIVE_PARAMS.some(pattern => (typeof pattern === 'string' ? pattern === name : pattern.test(name)))

Expand Down
10 changes: 9 additions & 1 deletion packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
const forEach = require('lodash/forEach')

const messages = {
alpha: 'Alpha',
creation: 'Creation',
description: 'Description',
expiration: 'Expiration',
Expand Down Expand Up @@ -601,7 +602,14 @@ const messages = {
'Store backup as multiple data blocks instead of a whole VHD file. (disables file level restore but allows faster merge)',
remoteUseVhdDirectoryTooltip:
'Your remote must be able to handle parallel access (up to 16 write processes per backup) and the number of files (500 files per GB of backed up data)',

remoteEncryptionBackupSize: 'Size of backup is not updated when using encryption.',
remoteEncryptionEncryptedfiles:
'All the files of the remote except the encryption.json are encrypted, that means you can only activate encryption or change key on an empty remote.',
remoteEncryptionMustUseVhd:
'Delta backup must use VHD saved as blocks (note: should be enforced when saving settings)',
remoteEncryptionKey: 'Encrypt all new data sent to this remote',
remoteEncryptionKeyStorageLocation:
"You won't be able to get your data back if you lose the encryption key. The encryption key is saved in the XO config backup, they should be secured correctly. Be careful, if you saved it on an encrypted remote, then you won't be able to access it without the remote encryption key.",
Rajaa-BARHTAOUI marked this conversation as resolved.
Show resolved Hide resolved
// ------ New Storage -----

newSr: 'New SR',
Expand Down
33 changes: 33 additions & 0 deletions packages/xo-web/src/xo-app/settings/remotes/remote.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default decorate([
region: undefined,
allowUnauthorized: undefined,
useVhdDirectory: undefined,
encryptionKey: undefined,
}),
effects: {
linkState,
Expand All @@ -69,6 +70,7 @@ export default decorate([
username = remote.username,
protocol = remote.protocol || 'https',
region = remote.region,
encryptionKey = remote.encryptionKey,
} = state

let {
Expand Down Expand Up @@ -99,6 +101,7 @@ export default decorate([
region,
allowUnauthorized,
useVhdDirectory,
encryptionKey: encryptionKey.trim() !== '' ? encryptionKey : undefined,
}),
options: options !== '' ? options : null,
proxy: proxyId,
Expand Down Expand Up @@ -128,6 +131,7 @@ export default decorate([
type = 'nfs',
username,
useVhdDirectory = undefined,
encryptionKey = '',
} = state

const urlParams = {
Expand All @@ -136,6 +140,7 @@ export default decorate([
port,
type,
useVhdDirectory,
encryptionKey: encryptionKey.trim() !== '' ? encryptionKey : undefined,
}
if (type === 's3') {
const { allowUnauthorized, bucket, directory, protocol = 'https' } = state
Expand Down Expand Up @@ -202,7 +207,11 @@ export default decorate([
username = remote.username || '',
allowUnauthorized = remote.allowUnauthorized || false,
useVhdDirectory = remote.useVhdDirectory || type === 's3',
encryptionKey = remote.encryptionKey || '',
} = state

const isEncrypted = encryptionKey.trim() !== ''

return (
<div>
<h2>{_('newRemote')}</h2>
Expand Down Expand Up @@ -469,6 +478,30 @@ export default decorate([
</div>
</fieldset>
)}
<div className='form-group'>
<label>
{_('remoteEncryptionKey')}
<span className='tag tag-pill tag-info ml-1'>{_('alpha')}</span>
</label>
{isEncrypted && !useVhdDirectory && (
<p className='text-warning'>
<Icon icon='alarm' /> {_('remoteEncryptionMustUseVhd')}
</p>
)}
<ul className='small'>
<li>{_('remoteEncryptionEncryptedfiles')}</li>
<li>{_('remoteEncryptionKeyStorageLocation')}</li>
<li>{_('remoteEncryptionBackupSize')}</li>
</ul>
<input
className='form-control'
name='encryptionKey'
julien-f marked this conversation as resolved.
Show resolved Hide resolved
onChange={effects.linkState}
julien-f marked this conversation as resolved.
Show resolved Hide resolved
pattern='^.{32}$'
type='password'
value={encryptionKey}
julien-f marked this conversation as resolved.
Show resolved Hide resolved
/>
</div>
julien-f marked this conversation as resolved.
Show resolved Hide resolved
{type !== 's3' && (
<fieldset className='form-group form-group'>
<div className='input-group form-group'>
Expand Down