From 22e38f0c35ff8a5a7a60b4529457b313da9d31b7 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 13 May 2024 15:36:40 -0500 Subject: [PATCH 1/5] update README --- README.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0e6a322..4530fc7 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,13 @@ +A custom Django field that integrates with the 1Password `op` CLI to securely access secrets via the [`op://` secret reference URI](https://developer.1password.com/docs/cli/secret-references/). + ## Requirements - Python 3.8, 3.9, 3.10, 3.11, 3.12 - Django 4.2, 5.0 +- [1Password CLI](https://developer.1password.com/docs/cli) and a [1Password Service Account](https://developer.1password.com/docs/service-accounts/) ## Getting Started @@ -20,17 +23,54 @@ python -m pip install django-opfield ``` -2. Add the app to your Django project's `INSTALLED_APPS`: +2. Install the [1Password `op` CLI tool](https://developer.1password.com/docs/cli/get-started). + +3. Create a [1Password service account](https://developer.1password.com/docs/service-accounts/get-started). + +## Usage + +`OPField` allows Django models to securely access secrets stored in a 1Password vault, enabling the integration of sensitive data without exposing it directly in your codebase. Secrets are stored using the `op://` URI scheme and can be retrieved dynamically using a corresponding model attribute, `_secret`. + +### Defining a model + +First, let's define a model that includes the `OPField`. This field will store the reference to the secret in 1Password, not the secret itself. ```python -INSTALLED_APPS = [ - ..., - "django_opfield", - ..., -] +from django.db import models + +from django_opfield.fields import OPField + + +class APIService(models.Model): + name = models.CharField(max_length=255) + api_key = OPField() + + def __str__(self): + return self.name ``` -## Usage +### Accessing the secret + +Assume you have a secret API key stored in a 1Password vault named "my_vault" under the item "my_api" with the field "api_key". Here's how you can store and access this secret within your Django project: + +```pycon +>>> from example.models import APIService +>>> +>>> my_api = APIService.objects.create( +... name="My API", api_key="op://my_vault/my_api/api_key" +... ) +>>> +>>> print(my_api) + +>>> print(my_api.name) +'My API' +>>> print(my_api.api_key) +'op://my_vault/my_api/api_key' +>>> +>>> # Retrieving the actual secret value is done using the automatically generated '_secret' attribute +>>> print(my_api.api_key_secret) +'your_super_secret_api_token_here' +``` ## Documentation From e341c9c63d7e1820ce82133e6a260c3c04c7e673 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 13 May 2024 15:38:28 -0500 Subject: [PATCH 2/5] get rid of extra >>> --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 4530fc7..a47c700 100644 --- a/README.md +++ b/README.md @@ -55,18 +55,15 @@ Assume you have a secret API key stored in a 1Password vault named "my_vault" un ```pycon >>> from example.models import APIService ->>> >>> my_api = APIService.objects.create( ... name="My API", api_key="op://my_vault/my_api/api_key" ... ) ->>> >>> print(my_api) >>> print(my_api.name) 'My API' >>> print(my_api.api_key) 'op://my_vault/my_api/api_key' ->>> >>> # Retrieving the actual secret value is done using the automatically generated '_secret' attribute >>> print(my_api.api_key_secret) 'your_super_secret_api_token_here' From a96a98fef7e146fd39b6c39d45a296c5a37383b3 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 13 May 2024 15:45:35 -0500 Subject: [PATCH 3/5] add note about storage --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a47c700..11f0d01 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,8 @@ Assume you have a secret API key stored in a 1Password vault named "my_vault" un 'your_super_secret_api_token_here' ``` +This ensures that only the URI reference to the secret is ever stored in the Django admin interface and the database. The actual secret itself is never stored and is only retrieved dynamically when accessed. This approach enables secure management and access to secrets throughout your Django application, safeguarding against potential security vulnerabilities associated with direct exposure. + ## Documentation Please refer to the [documentation](https://django-opfield.westervelt.dev/) for more information. From f226f06d4228cc48ba5b9a53ea7aaa38b0eab64d Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 13 May 2024 15:48:10 -0500 Subject: [PATCH 4/5] add new heading --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 11f0d01..29ac04a 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,9 @@ Assume you have a secret API key stored in a 1Password vault named "my_vault" un 'your_super_secret_api_token_here' ``` -This ensures that only the URI reference to the secret is ever stored in the Django admin interface and the database. The actual secret itself is never stored and is only retrieved dynamically when accessed. This approach enables secure management and access to secrets throughout your Django application, safeguarding against potential security vulnerabilities associated with direct exposure. +### Storing references, not secrets + +Only the URI reference to the secret is ever stored in the Django admin interface and the database. The actual secret itself is never stored and is only retrieved dynamically when accessed. This approach enables secure management and access to secrets throughout your Django application, safeguarding against potential security vulnerabilities associated with direct exposure. ## Documentation From 796c742c62ec038be2e810aae19986a88f6f51ac Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 13 May 2024 15:50:12 -0500 Subject: [PATCH 5/5] slight tweak --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29ac04a..6df472a 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Assume you have a secret API key stored in a 1Password vault named "my_vault" un ### Storing references, not secrets -Only the URI reference to the secret is ever stored in the Django admin interface and the database. The actual secret itself is never stored and is only retrieved dynamically when accessed. This approach enables secure management and access to secrets throughout your Django application, safeguarding against potential security vulnerabilities associated with direct exposure. +Only the URI reference to the secret is ever stored and exposed in the Django admin interface and the database. The actual secret itself is never stored and is only retrieved dynamically when accessed. This approach enables secure management and access to secrets throughout your Django application, safeguarding against potential security vulnerabilities associated with direct exposure. ## Documentation