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

Datasette secret mechanism - initially for signed cookies #785

Closed
simonw opened this issue May 31, 2020 · 11 comments
Closed

Datasette secret mechanism - initially for signed cookies #785

simonw opened this issue May 31, 2020 · 11 comments

Comments

@simonw
Copy link
Owner

simonw commented May 31, 2020

See comment in #784 (comment)

Datasette needs to be able to set signed cookies - which means it needs a mechanism for safely handling a signing secret.

Since Datasette is a long-running process the default behaviour here can be to create a random secret on startup. This means that if the server restarts any signed cookies will be invalidated.

If the user wants a persistent secret they'll have to generate it themselves - maybe by setting an environment variable?

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

I previously solved this for the datasette-auth-existing-cookies plugin as described in this issue: simonw/datasette-auth-existing-cookies#1

Concrete plan: you have to pass a secret to the class constructor. The Datasette plugin (the code in __init__.py) uses the following in order of preference (first things are most preferred):

I originally planned to have separate support for an environment variable, but the existence of the secret configuration values mechanism means this is already handled.

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

That user_state_dir solution may have been more trouble than it was worth though - I seem to remember it causing issues on some hosting providers.

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

Maybe Datasette should have a --secrets=path/to/secrets.json command-line option for storing these?

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

I'm going to use https://github.com/pallets/itsdangerous for this.

Annoyingly they're very close to release v2.0 which adds support for key rotation... but it's not quite out of pre-release yet. I'll go with 1.1.0 for the moment and upgrade to 2.0 as soon as that is out.

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

First version of cookie signing will use a secret that is either pulled from DATASETTE_SECRET environment variable or generated every time the server starts. I'll add a non-environment-variable based secret later.

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

... actually no I'll do it using a CLI option that can also be in an environment variable:

https://click.palletsprojects.com/en/7.x/options/#values-from-environment-variables

@click.command()
@click.option('--secret', envvar='DATASETTE_SECRET')
def greet(secret):
    ...

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

I'll add two utility methods to the Datasette class:

  • datasette.sign(value, "namespace") - returns signed string
  • datasette.unsign(signed, "namespace") - returns value OR raises BadSignature

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

This is nearly ready to close. I'm going to add documentation for --secret and the DATASETTE_SECRET environment variable.

@simonw
Copy link
Owner Author

simonw commented May 31, 2020

I'll add a section about secrets to this page: https://datasette.readthedocs.io/en/latest/config.html

@simonw
Copy link
Owner Author

simonw commented Jun 1, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant