Storage Options

Dex requires persisting state to perform various tasks such as track refresh tokens, preventing replays, and rotating keys. This document is a summary of the storage configurations supported by dex.

Storage breaches are serious as they can affect applications that rely on dex. Dex saves sensitive data in its backing storage, including signing keys and bcrypt’d passwords. As such, transport security and database ACLs should both be used, no matter which storage option is chosen.

Etcd

Dex supports persisting state to etcd v3.

An example etcd configuration is using these values:

  1. storage:
  2. type: etcd
  3. config:
  4. # list of etcd endpoints we should connect to
  5. endpoints:
  6. - http://localhost:2379
  7. namespace: my-etcd-namespace/

Etcd storage can be customized further using the following options:

  • endpoints: list of etcd endpoints we should connect to
  • namespace: etcd namespace to be set for the connection. All keys created by etcd storage will be prefixed with the namespace. This is useful when you share your etcd cluster amongst several applications. Another approach for setting namespace is to use etcd proxy
  • username: username for etcd authentication
  • password: password for etcd authentication
  • ssl: ssl setup for etcd connection
    • serverName: ensures that the certificate matches the given hostname the client is connecting to.
    • caFile: path to the ca
    • keyFile: path to the private key
    • certFile: path to the certificate

Kubernetes custom resource definitions (CRDs)

Kubernetes custom resource definitionsare a way for applications to create new resources types in the Kubernetes API.

The Custom Resource Definition (CRD) API object was introduced in Kubernetes version 1.7 to replace the Third Party Resource (TPR) extension. CRDs allow dex to run on top of an existing Kubernetes cluster without the need for an external database. While this storage may not be appropriate for a large number of users, it’s extremely effective for many Kubernetes use cases.

The rest of this section will explore internal details of how dex uses CRDs. Admins should not interact with these resources directly, except while debugging. These resources are only designed to store state and aren’t meant to be consumed by end users. For modifying dex’s state dynamically see the API documentation .

The following is an example of the AuthCode resource managed by dex:

  1. apiVersion: apiextensions.k8s.io/v1beta1
  2. kind: CustomResourceDefinition
  3. metadata:
  4. creationTimestamp: 2017-09-13T19:56:28Z
  5. name: authcodes.dex.coreos.com
  6. resourceVersion: "288893"
  7. selfLink: /apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/authcodes.dex.coreos.com
  8. uid: a1cb72dc-98bd-11e7-8f6a-02d13336a01e
  9. spec:
  10. group: dex.coreos.com
  11. names:
  12. kind: AuthCode
  13. listKind: AuthCodeList
  14. plural: authcodes
  15. singular: authcode
  16. scope: Namespaced
  17. version: v1
  18. status:
  19. acceptedNames:
  20. kind: AuthCode
  21. listKind: AuthCodeList
  22. plural: authcodes
  23. singular: authcode
  24. conditions:
  25. - lastTransitionTime: null
  26. message: no conflicts found
  27. reason: NoConflicts
  28. status: "True"
  29. type: NamesAccepted
  30. - lastTransitionTime: 2017-09-13T19:56:28Z
  31. message: the initial names have been accepted
  32. reason: InitialNamesAccepted
  33. status: "True"
  34. type: Established

Once the CustomResourceDefinition is created, custom resources can be created and stored at a namespace level. The CRD type and the custom resources can be queried, deleted, and edited like any other resource using kubectl.

dex requires access to the non-namespaced CustomResourceDefinition type. For example, clusters using RBAC authorization would need to create the following roles and bindings:

  1. apiVersion: rbac.authorization.k8s.io/v1beta1
  2. kind: ClusterRole
  3. metadata:
  4. name: dex
  5. rules:
  6. - apiGroups: ["dex.coreos.com"] # API group created by dex
  7. resources: ["*"]
  8. verbs: ["*"]
  9. - apiGroups: ["apiextensions.k8s.io"]
  10. resources: ["customresourcedefinitions"]
  11. verbs: ["create"] # To manage its own resources identity must be able to create customresourcedefinitions.
  12. ---
  13. apiVersion: rbac.authorization.k8s.io/v1beta1
  14. kind: ClusterRoleBinding
  15. metadata:
  16. name: dex
  17. roleRef:
  18. apiGroup: rbac.authorization.k8s.io
  19. kind: ClusterRole
  20. name: dex
  21. subjects:
  22. - kind: ServiceAccount
  23. name: dex # Service account assigned to the dex pod.
  24. namespace: dex-namespace # The namespace dex is running in.

Removed: Kubernetes third party resources(TPRs)

TPR support in dex has been removed. The last version to support TPR is v2.17.0

If you are currently running dex using TPRs, you will need to migrate to CRDsbefore you upgrade to a post v2.17 dex. The script mentioned in the instructions can be found here

Configuration

The storage configuration is extremely limited since installations running outside a Kubernetes cluster would likely prefer a different storage option. An example configuration for dex running inside Kubernetes:

  1. storage:
  2. type: kubernetes
  3. config:
  4. inCluster: true

Dex determines the namespace it’s running in by parsing the service account token automatically mounted into its pod.

SQL

Dex supports three flavors of SQL: SQLite3, Postgres and MySQL.

Migrations are performed automatically on the first connection to the SQL server (it does not support rolling back). Because of this dex requires privileges to add and alter the tables for its database.

NOTE: Previous versions of dex required symmetric keys to encrypt certain values before sending them to the database. This feature has not yet been ported to dex v2. If it is added later there may not be a migration path for current v2 users.

SQLite3

SQLite3 is the recommended storage for users who want to stand up dex quickly. It is not appropriate for real workloads.

The SQLite3 configuration takes a single argument, the database file.

  1. storage:
  2. type: sqlite3
  3. config:
  4. file: /var/dex/dex.db

Because SQLite3 uses file locks to prevent race conditions, if the “:memory:” value is provided dex will automatically disable support for concurrent database queries.

Postgres

When using Postgres, admins may want to dedicate a database to dex for the following reasons:

  1. Dex requires privileged access to its database because it performs migrations.
  2. Dex’s database table names are not configurable; when shared with other applications there may be table name clashes.
  1. CREATE DATABASE dex_db;
  2. CREATE USER dex WITH PASSWORD '66964843358242dbaaa7778d8477c288';
  3. GRANT ALL PRIVILEGES ON DATABASE dex_db TO dex;

An example config for Postgres setup using these values:

  1. storage:
  2. type: postgres
  3. config:
  4. database: dex_db
  5. user: dex
  6. password: 66964843358242dbaaa7778d8477c288
  7. ssl:
  8. mode: verify-ca
  9. caFile: /etc/dex/postgres.ca

The SSL “mode” corresponds to the github.com/lib/pq package connection options. If unspecified, dex defaults to the strictest mode “verify-full”.

MySQL

Dex requires MySQL 5.7 or later version. When using MySQL, admins may want to dedicate a database to dex for the following reasons:

  1. Dex requires privileged access to its database because it performs migrations.
  2. Dex’s database table names are not configurable; when shared with other applications there may be table name clashes.
  1. CREATE DATABASE dex_db;
  2. CREATE USER dex IDENTIFIED BY '66964843358242dbaaa7778d8477c288';
  3. GRANT ALL PRIVILEGES ON dex_db.* TO dex;

An example config for MySQL setup using these values:

  1. storage:
  2. type: mysql
  3. config:
  4. database: dex_db
  5. user: dex
  6. password: 66964843358242dbaaa7778d8477c288
  7. ssl:
  8. mode: custom
  9. caFile: /etc/dex/mysql.ca

The SSL “mode” corresponds to the github.com/go-sql-driver/mysql package connection options. If unspecified, dex defaults to the strictest mode “true”.

Adding a new storage options

Each storage implementation bears a large ongoing maintenance cost and needs to be updated every time a feature requires storing a new type. Bugs often require in depth knowledge of the backing software, and much of this work will be done by developers who are not the original author. Changes to dex which add new storage implementations require a strong use case to be considered for inclusion.

New storage option references

Those who still want to construct a proposal for a new storage should review the following packages:

  • github.com/dexidp/dex/storage: Interface definitions which the storage must implement. NOTE: This package is not stable.
  • github.com/dexidp/dex/storage/conformance: Conformance tests which storage implementations must pass.

New storage option requirements

Any proposal to add a new implementation must address the following:

  • Integration testing setups (Travis and developer workstations).
  • Transactional requirements: atomic deletes, updates, etc.
  • Is there an established and reasonable Go client?