Skip to content

Client side encryption support for remote storage #468

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

Merged
merged 1 commit into from
May 1, 2023

Conversation

hifi
Copy link
Collaborator

@hifi hifi commented Apr 16, 2023

Extremely simple Age wrapper that supports separate recipients and identities. Encrypts both snapshots and WAL files transparently. Technically possible to not have the private key at all if you never restore or do manual restores only.

You can migrate between encrypted/plain by adjusting the identities and recipients respectively but restoring will not work correctly if the remote files aren't encrypted when an identity is configured and vice versa so some care needs to be taken.

Intended use is to encrypt all data before sending out to a potentially untrusted storage provider.

This may conflict with #458 and fixes #88.

@benbjohnson
Copy link
Owner

@hifi Any objections to upgrading to age v1.1.1?

@benbjohnson benbjohnson self-requested a review May 1, 2023 02:52
return nil, err
}

r.AgeIdentities = append(r.AgeIdentities, identities...)
Copy link
Owner

Choose a reason for hiding this comment

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

Why the append() instead of just assigning the identities? Same goes for the recipients below.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

age.ParseIdentities and age.ParseRecipients work with NL terminated lists and in the config format I chose to use real YAML lists instead of a multi line string to store them, hence need to loop and append them when parsed one by one.

If preferred I can change both to string from []string, then it's just an assignment.

Copy link
Owner

Choose a reason for hiding this comment

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

Ah, sorry, I misread it. Yeah, that's fine. 👍

Comment on lines +72 to +74
// Encryption identities and recipients
AgeIdentities []age.Identity
AgeRecipients []age.Recipient
Copy link
Owner

Choose a reason for hiding this comment

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

I don't mind the stutter as much on the struct here. Mostly just the config.

replica.go Outdated
Comment on lines 505 to 506
// We need to ensure the pipe is closed.
defer pw.Close()
Copy link
Owner

Choose a reason for hiding this comment

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

This seems like it should go at the start of this anonymous function rather than in this if block.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Indeed. It wasn't a problem with the compressor that the pipe wasn't closed but with age the last chunk was cut off so I if guarded it. Shouldn't be a problem it's deferred at the beginning.

@hifi hifi force-pushed the for-upstream/encryption branch 2 times, most recently from 0b4929f to f165958 Compare May 1, 2023 05:39
@hifi hifi force-pushed the for-upstream/encryption branch from f165958 to 6f495fa Compare May 1, 2023 05:43
return nil, err
}

r.AgeIdentities = append(r.AgeIdentities, identities...)
Copy link
Owner

Choose a reason for hiding this comment

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

Ah, sorry, I misread it. Yeah, that's fine. 👍

@benbjohnson benbjohnson merged commit a34a92c into benbjohnson:main May 1, 2023
@benbjohnson
Copy link
Owner

Thanks, @hifi! Sorry for the delay.

@ixxie
Copy link

ixxie commented Jun 20, 2023

I would love to use this feature; is it documented anywhere? I can't seem to find it...

@hifi
Copy link
Collaborator Author

hifi commented Jun 20, 2023

@ixxie It's not yet in a final release so the website hasn't been updated.

TL;DR for configuration using v0.3.10 beta if my memory serves right:

dbs:
  - path: /path/to/database.sqlite3
    replicas:
      - type: file
        path: /path/to/backups
        age:
          identities:
            - <identity>
          recipients:
            - <recipient>

For how to generate age identities (private keys) and recipients (public keys), refer to the age documentation. Public keys are used for restore only and private keys are used for encryption only so it's possible to create a setup where a Litestream instance only encrypts with a public key but cannot restore from the destination on itself without giving it the private key.

@ixxie
Copy link

ixxie commented Jun 21, 2023

Thanks for the clarification @hifi!

Is there somewhere I can keep track of the release schedule?

@hifi
Copy link
Collaborator Author

hifi commented Jun 22, 2023

As far as I know, the releases aren't on a schedule so they'll happen at their own pace.

@ixxie
Copy link

ixxie commented Jul 2, 2023

I see, thanks @hifi!

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.

Encryption
3 participants