Elekto is a DIY service, so in order to start using it, you’re going to have to install it:
And then regardless of how you installed it:
This the multi-page printable view of this section. Click here to print.
This guide will help you create a development installation of Elekto on your laptop, for hacking and testing purposes.
The application is written in Python using Flask and SQLAlchemy. This repository ships a
requirements.txt and an
environment.yml for conda users.
# Installation with pip pip install -r requirements.txt # Installation with Conda conda env create -f environment.yml && conda activate elekto
The repository has a
.env.example file which can be used as a template for
.env file, update the environment file after copying from
# create a new .env file from .env.example cp .env.example .env
Set the basic information about the application in the upper section
APP_NAME=k8s.elections # set the name of the application APP_ENV=development # development | production APP_KEY= # random secret key (!! important !!) APP_DEBUG=True # True | False (production) APP_URL=http://localhost # Url where the application is hosted APP_PORT=5000 # Default Running port for development APP_HOST=localhost # Default Host for developmemt
Update the database credentials,
DB_CONNECTION=mysql # Mysql is only supported DB_HOST=localhost DB_PORT=3306 DB_DATABASE=name DB_USERNAME=user DB_PASSWORD=password
Update the meta repository info
META_REPO=https://github.com/elekto-io/elekto.meta.test.git META_DEPLOYMENT=local META_PATH=meta META_BRANCH=main META_SECRET=db5a951969c379e75d0bf15ad6ff8b4a36fbeb02 # same as webhook of the same meta repository
Update the Oauth info, create a GitHub Oauth app if already not created.
GITHUB_REDIRECT=/oauth/github/callback GITHUB_CLIENT_ID=d79f002c1d2e3cf20521 GITHUB_CLIENT_SECRET=2f64fff6612c46f87314ad5bb81d05c8fd29c561
console script in the repository is used to perform all the table creations and syncing of the meta files.
# to migrate the database from the command line python console --migrate
To sync the database with the meta files
# to the sync the database with the meta python console --sync
The flask server will start on
5000 by default but can be changed using
# to run the server on default configs python console --run # to change host and port python console --port 8080 --host 0.0.0.0 --run
This guide walks you through installing Elekto by hand on a server or VM.
For Elekto to run in production, you need the following small application stack:
Elekto can be installed either as a native application or as a container. The instructions below cover installation as a native application. For installation in a container, see Kubernetes installation
Elekto is a Python/Flask/uWSGI application developed in Python 3. Building it from source requires the following prerequisites, which should be installed using your OS’s packaging system:
Having installed those prerequisites, you can now install the python requirements using Pip, which will build the python source:
# Installation with pip pip install -r requirements.txt # Installation with Conda conda env create -f environment.yml && conda activate elekto
Please check the above build process carefully for error messages; the only acceptable errors are (a) warnings about out-of-date versions and (b) missing database libraries for the databases you’re not using.
It is possible that you could run Elekto using fastcgi instead of uWSGI, but at this time we have no documentation on how to do this.
Github stores ballots and some metadata in a designated SQL database, which is up to you to install and run. Currently, Elekto supports the following:
However, as Elekto uses SQLAlchemy, it can potentially support any SQL database that SQLAlchemy supports. Adding new databases will require a PR to Elekto.
Database requirements are very light, so it is completely feasible to run the database on the same server as the python application. The database server needs less than 2 CPUs, 1GB memory, and 25GB storage. You can also use a cloud database service; the included database support was chosen specifically because there are multiple cloud database services available. In that case, you are likely to use the smallest size of cloud database available.
The Elekto database user needs to have permission to create tables. The database must be configured with user/password login. Other forms of authentication are not yet supported.
Here’s an example of doing this on PostgreSQL:
postgres=# create role elekto with login password 'TEST'; CREATE ROLE postgres=# create database elekto owner elekto; CREATE DATABASE
The Elekto application will not run if the database is unavailable. The ballot data contained in the database is not stored anywhere else, and as such is unrecoverable if the database is lost. For this reason, it is up to the administrator to set up and manage backups and high availability. This is particularly a concern for SQLite, which is an embedded database; you will need to set up cron jobs on the server to back this up.
Elekto runs in the python uWSGI web application server. uWSGI is not very scalable, though, and does not handle SSL connections. As such, for anything other than developer mode, we recommend that you put a web server in front of it.
Nginx works well for this, whether as a standalone or as part of Kubernetes Ingress. See the sample Nginx configuration in the installation directory of the Elekto repository for an example setup. If running directly on a host with an Nginx proxy, you’ll want to run Eletko in “socket” connection mode. Other web servers would also work, but Nginx is the only sample configuration supplied.
On Kubernetes, you’ll want to access Elekto via Ingress. See
installation/deployment for an example of this. In a Kubernetes setup, you want to run Elekto in
Elekto’s workflow is GitOps-based. This means that to use Elekto, you must have a GitHub (GitLab TBD) repository for Elekto to attach to. This must be a repository you own and have administration rights on, as you will be setting up a webhook and directories.
It does not need to be a repository that’s exclusively dedicated to Elekto. Most organizations using Elekto place its election metadata into a subdirectory of a repository that’s used for other community documents (e.g.
knative/community/elections). Given that Elekto will refresh for every webhook push, however, it’s probably better if it’s not a repository that gets multiple commits per hour.
Elekto does not maintain user authentication; by design, it relies on an outside Oauth source for user login. Currently the only Oauth source supported is GitHub. If you want to add other sources, contributions are very welcome.
See Configuration for how to configure this in GitHub.
Elekto does not require elevated privileges to run, so for security, we recommend running it under an
python application account with restricted permissions.
Elekto caches a copy of the election respository on disk, and as such needs a file location to which it can write, with storage equal to the storage size of a git clone of that repository.
If you’ve completed everything in Installation, please proceed to Configuration.
Elekto’s configuration is divided into three parts:
This document covers the first two, which consists of the items that need to be configured before Elekto will run. The third part is covered in the [Administrator Guide].
Elekto relies on an external Oauth provider for user authentication, by design. This provider must be configured to accept authentication requests from Elekto. You may only have one Oauth provider per Elekto instance, as authentication happens before selecting an election.
You must also configure the repository that contains the election metadata (hereafter “the repo”) to push changes to Elekto.
Currently, the only Oauth provider offered is GitHub. Contributions of additional providers are extremely welcome.
You must set up an “Oauth Application” that Elekto can use. In GitHub, this is under Settings–>Developer Tools–>Oauth Applications. Note that Oauth Apps are belong to accounts rather than organizations, so you’ll want to set up an account with shared access in your infra team. We also recommend setting up a separate Oauth App for Elekto rather than re-using ones created for other purposes, and giving each Elekto instance its own secret key.
The Oauth App must have the following settings:
https://your.elekto.domain/oauth/github/callback(note that this can be changed in ENV)
Once you create the Oauth App, GitHub will create a ClientID for it, which you populate in GITHUB_CLIENT_ID in ENV. You then create a new Oauth secret under the app and copy the value for that, and that gets populated in GITHUB_CLIENT_SECRET.
To receive changes from the repo, you need to add a webhook that pushes changes whenever you merge. Webhooks are under “settings” for the individual repository (which also means you must be a repo owner).
The Webhook should have the following settings:
This “secret” is an arbitrary string that authenticates the push to the Elekto server. It can be any string, such as one created by a password generator or a passphrase you like. This string then gets set in META_SECRET.
Elekto is designed to accept its runtime configuration as ENV variables in its shell environment. A sample
.env.example file can be found in the base directory of the Elekto source. These ENV configuration variables are not expected to change frequently, or at all, for any particular running Elekto instance. Changing them generally requires restarting Elekto.
All of these env variables need to be set before starting Elekto as a uWSGI application, or even in developer mode; without them, Elekto will error out and refuse to start. You can set this up however you please:
.bashrcfor the elekto application user
Since we use ENV for Elekto configuration, this does mean that Elekto must be launched under a shell.
What follows are the ENV variables that must be set for Elekto to run.
Required Name of the Elekto instance you are running. Displays in some parts of the UI. For user information only.
Optional Status of this Elekto instance, for CI/CD purposes. Not used internally by Elekto.
Optional Encryption seed for application cookies. Most users should leave blank, in which case it will be set automatically as a random 8-byte key by the startup code. Set manually to an 8-16 character key if you need to run multiple Elekto instances for the same organization.
Required Whether to run in Debug mode for troubleshooting purposes. In Debug mode, will output stack traces for errors and reload templates.
Optional URL of the Elekto instance. Used by some uWSGI and/or Nginx configurations. Not used internally by Elekto.
Optional Used in some uWSGI start scripts, and when running Flask in standalone mode. Port on which to serve Elekto.
Optional Used in some webserver startup scripts, and by the Flask server in standalone mode. Name of the host served by this Elekto instance.
Optional Whether to serve uWSGI over HTTP or via a local Unix socket. Used by some startup scripts; see
entrypoint.sh for an example.
Optional: Integer. Minimum length for a voter-ballot passphrase in order to deter hacking. Set to 6 if left blank.
Required Which database connection type to use. Currently only PostgreSQL, MySQL, and SQLite backends are supported.
Required The URL, IP, or hostname of the database server. Ignored if using SQLite (set to
Required The network port for the database server. Ignored if using SQLite (set to
Optional Used only for SQLite. Path to the database filesystem.
Required Login user for the Elekto database. Not used by SQLite.
Required Authentication password for the Elekto database. Not used by SQLite.
Required GIT clone URL for the repository which contains the election configurations. Should be the
.git link, not the
Required Directory, relative to the Git repository root, containing the set of election subdirectories. Must be a parent directory. Can be an arbitrarily deep path. Do not use a leading or trailing
Optional Reserved for future advanced configuration use.
Required Local file location at which to store a clone of the election data repository. This directory will be created by Elekto at sync time, so the application must have the ability to write to the parent directory. The directory may be absolute or relative; if it is relative, it will be under the Eletko source directory. Otherwise it defaults to
meta. For containers, a directory under
/tmp is recommended to make sure the location is writeable.
Required Which git branch has the merged version of the election data. Defaults to
Required The shared secret string used in the Github webhook for updates of the election data repository. Can be set to anything you like; we recommend a random md5 string or generated password.
At this time, there are only settings available for GitHub because other Oauth sources haven’t been implemented. When other sources get added to Elekto, each will get its own configuration variables.
Required Flask path for the GitHub authentication callback. Defaults to
/oauth/github/callback, and there’s no good reason to change it.
Required The Client ID from the GitHub Oauth Application.
Required The Client Secret from the GitHub Oauth Application.
This guide walks you through installing Elekto on a Kubernetes cluster.
In most cases, you should be able to upgrade Elekto just by replacing the Python/Flask code or the container image and restarting the service. The cases where that is not true are documented below.
If you are running Elekto as Python code, you should also update the dependencies every time you upgrade, as we usually upgrade python library versions to current ones.
pip3 install -r requirements.txt
This Upgrade Requires Extra Steps
Version 0.6 involves several major changes to the database schema which require a multi-step database migration. At this time, this process is only automated for PostgreSQL.
The Elekto Project Recommends Backing Up Your Database Before Upgrading
For users on PostgreSQL, the process should be as simple as:
python console --migrate
If you are using the official container image, or others built like it, then the container image should automatically do the above when you delete and replace the container or pod.
This may fail on PostgreSQL, either because you have modified your database schema after creation by Elekto, or because the Elekto database user does not have permissions to modify tables. In either case, you may need to run the database migration manually. If so, you will need to run the following SQL statements as the database owner or superuser:
CREATE TABLE schema_version ( version INT PRIMARY KEY ); INSERT INTO schema_version VALUES ( 2 ); ALTER TABLE voter ADD COLUMN salt BYTEA, ADD COLUMN ballot_id BYTEA; CREATE INDEX voter_election_id ON voter(election_id); ALTER TABLE ballot DROP COLUMN created_at, DROP COLUMN updated_at; ALTER TABLE ballot DROP CONSTRAINT ballot_pkey; ALTER TABLE ballot ALTER COLUMN id TYPE CHAR(32) USING to_char(id , 'FM00000000000000000000000000000000'); ALTER TABLE ballot ALTER COLUMN id DROP DEFAULT; ALTER TABLE ballot ADD CONSTRAINT ballot_pkey PRIMARY KEY ( id ); CREATE INDEX ballot_election_id ON ballot(election_id);
We do not yet have instructions for upgrading MySQL or SQLite. Those are in development. If you have an Elekto/MySQL instance, please contact us via Elekto slack channel on CNCF Slack, or by commenting on the issue; we would like to work with you on this.
If you do not care about preserving election history, your other option is
to simply delete the old database and create a new, empty one. In that case,
Elekto will generate a new, updated schema through