Skip to main content

Manage secrets such as API keys for use with other Datasette plugins

Project description

datasette-secrets

PyPI Changelog Tests License

Manage secrets such as API keys for use with other Datasette plugins

This plugin requires a Datasette 1.0 alpha release.

Datasette plugins sometimes need access to secrets, such as API keys used to integrate with tools hosted outside of Datasette - things like geocoders or hosted AI language models.

This plugin provides ways to configure those secrets:

  • Secrets can be configured using environment variables, such as DATASETTE_SECRETS_OPENAI_API_KEY
  • Secrets can be stored, encrypted, in a SQLite database table which administrator users can then update through the Datasette web interface

Installation

Install this plugin in the same environment as Datasette.

datasette install datasette-secrets

Configuration

First you will need to generate an encryption key for this plugin to use. Run this command:

datasette secrets generate-encryption-key

Store this secret somewhere secure. It will be used to both encrypt and decrypt secrets stored by this plugin - if you lose it you will not be able to recover your secrets.

Configure the plugin with these these two plugin settings:

plugins:
  datasette-secrets:
    encryption_key:
      $env: DATASETTE_SECRETS_ENCRYPTION_KEY
    database: name_of_database

The encryption_key setting should be set to the encryption key you generated earlier. You can store it in an environment variable if you prefer.

database is the name of the database that the encrypted keys should be stored in. Omit this setting to use the internal database.

Using the internal database

While the secrets stored in the datasette_secrets table are encrypted, we still recommend hiding that table from view.

One way to do that is to keep the table in Datasette's internal database, which is invisible to all users, even users who are logged in.

By default, the internal database is an in-memory database that is reset when Datasette restarts. This is no good for persistent secret storage!

Instead, you should switch Datasette to using an on-disk internal database. You can do this by starting Datasette with the --internal option:

datasette data.db --internal internal.db

Your secrets will be stored in the datasette_secrets table in that database file.

Permissions

Only users with the manage-secrets permission will have access to manage secrets through the Datasette web interface.

You can grant that permission to the root user (or the user with an ID of your choice) by including this in your datasette.yml file:

permissions:
  manage-secrets:
    id: root

Then start Datasette like this (with --root to get a URL to login as the root user):

datasette data.db --internal internal.db -c datasette.yml --root

Alternatively, use the -s option to set that setting without creating a configuration file:

datasette data.db --internal internal.db \
  -s permissions.manage-secrets.id root \
  --root

Usage

users with the manage-secrets permission will see a new "Manage secrets" link in the Datasette navigation menu. This interface can also be accessed at /-/secrets.

The page with the list of secrets will show the user who last updated each secret. This will use the actors_from_ids() mechanism, displaying the actor's username if available, otherwise the name, otherwise the id.

For plugin authors

Plugins can depend on this plugin if they want to implement secrets.

datasette-secrets to the dependencies list in pyproject.toml.

Then declare the name and description of any secrets you need using the register_secrets() plugin hook:

from datasette import hookimpl
from datasette_secrets import Secret

@hookimpl
def register_secrets():
    return [
        Secret(
            name="OPENAI_API_KEY",
            description="An OpenAI API key"
        ),
    ]

You can also provide optional obtain_url and obtain_label fields to link to a page where a user can obtain an API key:

@hookimpl
def register_secrets():
    return [
        Secret(
            name="OPENAI_API_KEY",
            obtain_url="https://platform.openai.com/api-keys",
            obtain_label="Get an OpenAI API key"
        ),
    ]

The hook can take an optional datasette argument. It can return a list or an async def function that, when awaited, returns a list.

The list should consist of Secret() instances, each with a name and an optional description. The description can contain HTML.

To obtain the current value of the secret, use the await get_secret() method:

from datasette_secrets import get_secret

# Third argument is the actor_id, optional
secret = await get_secret(datasette, "OPENAI_API_KEY", "root")

If the Datasette administrator set a DATASETTE_SECRETS_OPENAI_API_KEY environment variable, that will be returned.

Otherwise the encrypted value in the database table will be decrypted and returned - or None if there is no configured secret.

The last_used_at column is updated every time a secret is accessed. The last_used_by column will be set to the actor ID passed to get_secret(), or null if no actor ID was passed.

Development

To set up this plugin locally, first checkout the code. Then create a new virtual environment:

cd datasette-secrets
python3 -m venv venv
source venv/bin/activate

Now install the dependencies and test dependencies:

pip install -e '.[test]'

To run the tests:

pytest

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

datasette_secrets-0.2.tar.gz (16.6 kB view details)

Uploaded Source

Built Distribution

datasette_secrets-0.2-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

File details

Details for the file datasette_secrets-0.2.tar.gz.

File metadata

  • Download URL: datasette_secrets-0.2.tar.gz
  • Upload date:
  • Size: 16.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/5.0.0 CPython/3.12.3

File hashes

Hashes for datasette_secrets-0.2.tar.gz
Algorithm Hash digest
SHA256 5727ecb4be6e385ad44ba7c1b30f80e8fc3036fbcc184518c6b3e0a830c53b91
MD5 63a169f5a46366d3e7550589d9094f67
BLAKE2b-256 f3c78b9b3fbe357d103f98d575721694331604ec81fa8deaa506d310e76cadcd

See more details on using hashes here.

File details

Details for the file datasette_secrets-0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for datasette_secrets-0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a5e21d4e4d550ebc668b3e795ffc57b99ecbd6f852fe55a0b44f17a4d6a49455
MD5 c6bf40f54e3be98e77c8f09806f5d2a1
BLAKE2b-256 a4022b6bbbbd670362422823a2b76c078a6d2d6994de991b798dbed0c59be779

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page