Key backends

django-ca allows you to store private keys of certificate authorities as files (on the file system or any other system supported via the Django file storage API) or in a hardware security module (HSM) using the #PKCS 11 protocol.

You can even write your own backend for storing private keys to handle private keys in more unique ways, see writing custom backends for more information.

Default configuration

The default configuration is to store private keys on the file system. This works on any system, but is not the most secure method possible.

# The "django-ca" storage alias is mandatory. Added by default in full project
# setups (from source, or with Docker or Docker Compose), but must be set if
# used as Django app. In full project setups, you can also just set CA_DIR to
# change the storage directory.
STORAGES = {
    "default": {
        "BACKEND": "django.core.files.storage.FileSystemStorage",
    },
    "staticfiles": {
        "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
    },
    "django-ca": {
        "BACKEND": "django.core.files.storage.FileSystemStorage",
        "OPTIONS": {
            "location": "files/",
            "file_permissions_mode": 0o600,
            "directory_permissions_mode": 0o700,
        },
    },
}

CA_KEY_BACKENDS = {
    "default": {
        "BACKEND": "django_ca.key_backends.storages.StoragesBackend",
        "OPTIONS": {"storage_alias": "django-ca"},
    }
}
# The "django-ca" storage alias is mandatory. Added by default in full project
# setups (from source, or with Docker or Docker Compose), but must be set if
# used as Django app. In full project setups, you can also just set CA_DIR to
# change the storage directory.
STORAGES:
  default:
    BACKEND: django.core.files.storage.FileSystemStorage
  staticfiles:
    BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
  django-ca:
    BACKEND: django.core.files.storage.FileSystemStorage
    OPTIONS:
      directory_permissions_mode: 0700
      file_permissions_mode: 0600
      location: files/

CA_KEY_BACKENDS:
  default:
    BACKEND: django_ca.key_backends.storages.StoragesBackend
    OPTIONS:
      storage_alias: django-ca

Multiple backends

You can configure multiple backends using the CA_KEY_BACKENDS setting. For example, if you want to be able to store private keys on the file system, but also in a hardware security module (HSM):

STORAGES = {  # type: ignore[var-annotated]
    # ... see default configuration
}

CA_KEY_BACKENDS = {
    "default": {
        "BACKEND": "django_ca.key_backends.storages.StoragesBackend",
        "OPTIONS": {"storage_alias": "django-ca"},
    },
    "hsm": {
        "BACKEND": "django_ca.key_backends.hsm.HSMBackend",
        "OPTIONS": {
            "library_path": "/usr/lib/softhsm/libsofthsm2.so",
            "token": "my_token_label",
            "user_pin": "secret_user_pin",
        },
    },
}
STORAGES:
  # ... see default configuration

CA_KEY_BACKENDS:
  default:
    BACKEND: django_ca.key_backends.storages.StoragesBackend
    OPTIONS:
      storage_alias: django-ca
  hsm:
      BACKEND: django_ca.key_backends.hsm.HSMBackend
      OPTIONS:
          library_path: /usr/lib/softhsm/libsofthsm2.so
          token: my_token_label
          user_pin: secret_user_pin

Command-line options added by any backend that is not named “default” will be prefixed with the name of the backend. In the above example, you can use the --password option normally (which is added by the default backend), but you must use --hsm-user-pin etc. when using the HSM key backend:

user@host:~$ python manage.py init_ca --password=mypassword CAInDefaultKeyBackend CN=Default
user@host:~$ python manage.py init_ca --key-backend=hsm \
>     --hsm-key-label=my_key_label --hsm-user-pin=1234 \
>     CAInHSM CN=HSM

If you run any command with --help, you’ll see all currently valid options.

Supported backends

Storages backend

The most common use case for this key backend is to store keys on the local file system. However, you can use any custom Django storage system, for example from django-storages.

This backend takes a single option, storage_alias. It defines the storage system (as defined in STORAGES) to use. The default configuration is a good example:

# The "django-ca" storage alias is mandatory. Added by default in full project
# setups (from source, or with Docker or Docker Compose), but must be set if
# used as Django app. In full project setups, you can also just set CA_DIR to
# change the storage directory.
STORAGES = {
    "default": {
        "BACKEND": "django.core.files.storage.FileSystemStorage",
    },
    "staticfiles": {
        "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
    },
    "django-ca": {
        "BACKEND": "django.core.files.storage.FileSystemStorage",
        "OPTIONS": {
            "location": "files/",
            "file_permissions_mode": 0o600,
            "directory_permissions_mode": 0o700,
        },
    },
}

CA_KEY_BACKENDS = {
    "default": {
        "BACKEND": "django_ca.key_backends.storages.StoragesBackend",
        "OPTIONS": {"storage_alias": "django-ca"},
    }
}
# The "django-ca" storage alias is mandatory. Added by default in full project
# setups (from source, or with Docker or Docker Compose), but must be set if
# used as Django app. In full project setups, you can also just set CA_DIR to
# change the storage directory.
STORAGES:
  default:
    BACKEND: django.core.files.storage.FileSystemStorage
  staticfiles:
    BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
  django-ca:
    BACKEND: django.core.files.storage.FileSystemStorage
    OPTIONS:
      directory_permissions_mode: 0700
      file_permissions_mode: 0600
      location: files/

CA_KEY_BACKENDS:
  default:
    BACKEND: django_ca.key_backends.storages.StoragesBackend
    OPTIONS:
      storage_alias: django-ca

HSM (Hardware Security Module) backend

The HSM backend provides the ability to store private keys in a Hardware Security Module (HSM) via the PKCS 11 protocol and python-pkcs11.

When using Docker or docker-compose, you need to make sure that the PKCS 11 library as well as the hardware device is available in the Docker container.

When using django-ca as a Django app or if you installed from source, you have to install django-ca with the hsm extra, e.g.

user@host:~$ pip install django-ca[hsm]

This backend has several mandatory options:

  • library_path specifies the path to the PKCS11 library (e.g. /usr/lib/softhsm/libsofthsm2.so for SoftHSM2 on Debian/Ubuntu).

  • token to specify the token to use.

  • Either an so_pin or user_pin (can be overwritten on the command-line).

For example:

CA_KEY_BACKENDS = {
    "default": {
        "BACKEND": "django_ca.key_backends.hsm.HSMBackend",
        "OPTIONS": {
            "library_path": "/usr/lib/softhsm/libsofthsm2.so",
            "token": "my_token_label",
            "user_pin": "secret_user_pin",
        },
    },
}
CA_KEY_BACKENDS:
    default:
        BACKEND: django_ca.key_backends.hsm.HSMBackend
        OPTIONS:
            library_path: /usr/lib/softhsm/libsofthsm2.so
            token: my_token_label
            user_pin: secret_user_pin

Usage via the command-line

Assuming the HSM backend is the default backend, you can create a certificate authority and sign a certificate like this:

user@host:~$ python manage.py init_ca --key-label=my-key-label --user-pin=1234 CAInHSM CN=ca.example.com
user@host:~$ python manage.py sign_cert --ca=... --alt=example.com

If the HSM backend is not the default backend but uses the name "hsm", you have to explicitly name the key backend and prefix options accordingly:

user@host:~$ python manage.py init_ca \
>     --key-backend=hsm --hsm-key-label=my-key-label --hsm-user-pin=1234 \
>     CAInHSM CN=ca.example.com
user@host:~$ python manage.py sign_cert --ca=... --alt=example.com

HSM pin handling

Any operation must either use an SO pin or a user pin. The configuration in CA_KEY_BACKENDS should provide the pin required for signing operations, usually the user pin.

If creating a new certificate authority requires an SO pin instead, you can specify it on the command line. However, you must also disable the user pin in this case. For example (assuming the HSM backend is your default backend):

user@host:~$ python manage.py init_ca --so-pin=1234 --user-pin="" ...

Database backend

The database backend allows you to store private keys in the database. It is a good choice if you have no local file system available.

Warning

Using this backend negates any security benefit of using a Celery worker on a different host, as the private key will always be accessible to the web server.

This backend takes no options and is thus very simple to configure:

CA_KEY_BACKENDS = {
    "default": {
        "BACKEND": "django_ca.key_backends.db.DBBackend",
    },
}
CA_KEY_BACKENDS:
    default:
        BACKEND: django_ca.key_backends.db.DBBackend

OCSP Key backends

Just like for certificate authorities, django-ca allows you to store private keys for OCSP responder certificates using different backends. By default, private keys are stored on the file system, but they can also be stored using any of the backends documented below.

Note that the OCSP key storage method does not have to match the method used for storing the private key of the certificate authority.

There are two things fundamentally different about OCSP key backends compared to CA key backends:

  1. The private key must be accessible by the web server to sign OCSP responses. This might be tricky in setups where the private key of the certificate authority is stored on a different host from the web server.

  2. The web server must be able to use the private key non-interactively. That means that all information to access the private key (including e.g. passwords) must either be in settings or the database.

Configuring the OCSP key backend

The available key backends can be configured using the CA_OCSP_KEY_BACKENDS option.

The OCSP key backend that is used for a specific certificate authority can be configured using the admin interface or with the –ocsp-key-backend option to manage.py init_ca, manage.py edit_ca and manage.py import_ca. Note that when you change the backend, you must manually regenerate OCSP keys (e.g. using manage.py regenerate_ocsp_keys).

Storages OCSP key backend

This backend is equivalent to the Storages backend backend and stores keys on the file system.

By default, private keys are encrypted with a random password before written to the files system, with the private key stored in the database. This provides a modest security benefit in some setups.

The backend takes three options: storage_alias has the same meaning as in the storages backend, path defines a sub-directory where to store keys. The encrypt_private_key can be set to false to disable encryption of private keys with a random password:

CA_OCSP_KEY_BACKENDS = {
    "default": {
        "BACKEND": "django_ca.key_backends.storages.StoragesOCSPBackend",
        "OPTIONS": {
            "storage_alias": "django-ca",
            # Store OCSP keys in a sub-path of the configured storage backend.
            # By default, keys are stored in the "ocsp" subfolder.
            # "path": "ocsp",
            # Disable private key encryption
            # "encrypt_private_key": False,
        },
    },
}
CA_OCSP_KEY_BACKENDS:
    default:
        BACKEND: django_ca.key_backends.storages.StoragesOCSPBackend
        OPTIONS:
            storage_alias: django-ca

            # Store OCSP keys in a sub-path of the configured storage backend.
            # By default, keys are stored in the "ocsp" subfolder.
            #path: ocsp

            # Disable private key encryption
            #encrypt_private_key: False

HSM (Hardware Security Module) OCSP key backend

The HSM OCSP key backend is equivalent to the HSM (Hardware Security Module) backend. It takes the same options as the normal backend:

CA_OCSP_KEY_BACKENDS = {
    "default": {
        "BACKEND": "django_ca.key_backends.hsm.HSMOCSPBackend",
        "OPTIONS": {
            "library_path": "/usr/lib/softhsm/libsofthsm2.so",
            "token": "my_token_label",
            "user_pin": "secret_user_pin",
        },
    },
}
CA_OCSP_KEY_BACKENDS:
    default:
        BACKEND: django_ca.key_backends.hsm.HSMOCSPBackend
        OPTIONS:
            library_path: /usr/lib/softhsm/libsofthsm2.so
            token: my_token_label
            user_pin: secret_user_pin

Database OCSP key backend

The database OCSP key backend is equivalent to the Database backend and stores OCSP private keys in the database. It also takes no options:

CA_OCSP_KEY_BACKENDS = {
    "default": {
        "BACKEND": "django_ca.key_backends.db.DBOCSPBackend",
    },
}
CA_OCSP_KEY_BACKENDS:
    default:
        BACKEND: django_ca.key_backends.db.DBOCSPBackend