This the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Installation and Setup

Start using elekto for your organisation.

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:

1 - Development Installation

Create a dev install on your laptop

This guide will help you create a development installation of Elekto on your laptop, for hacking and testing purposes.

Create a development environment

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

Setup env variables

The repository has a .env.example file which can be used as a template for .env file, update the environment file after copying from .env.example.

# 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

Migrate and Sync DB with Meta

The 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

Run the application Server locally

The flask server will start on 5000 by default but can be changed using --port option.

# 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

2 - Installation

Full server installation documentation

This guide walks you through installing Elekto by hand on a server or VM.

Installation Concepts

For Elekto to run in production, you need the following small application stack:

  • The Elekto python/flask/uWSGI application
  • A backing SQL database instance
  • A web proxy such as Nginx or Kubernetes Ingress
  • A GitHub repository
  • An Oauth authentication source

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

Installing Requirements and Python Binaries

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:

  • Python3 Pip and supporting build tools (like gcc), or Conda
  • uWSGI server
  • Database client libraries for your chosen database (see below)
  • git

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.

Backing SQL Database

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:

  • PostgreSQL
  • MySQL (and its forks)
  • SQLite

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.

Web Server

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 http mode.

GitHub Repository

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.

See Configuration for how to set up this GitHub repository, and the Administration Guide for what files go into it.

Oauth Authentication Source

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.

Other System Requirements

Elekto does not require elevated privileges to run, so for security, we recommend running it under an elekto, www, or 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.

3 - Configuration

Setting up and configuring Elekto for operation

Configuration and Setup

Elekto’s configuration is divided into three parts:

  1. Oauth and GitHub configuration
  2. Runtime environment
  3. Per-election configuration

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].

Oauth and Repository Configuration

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.

GitHub Setup

GitHub Oauth

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:

  • Application Name: whatever you’ve named your Elekto instance
  • Homepage URL: the url of your Elekto instance
  • Authorization Callback URL: 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.

GitHub Repository Webhook

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:

  • Payload URL: https://your.election.domain/v1/webhooks/meta/sync
  • Content type: application/json
  • Secret set to the same as META_SECRET
  • Enable SSL Verification
  • Just The Push Event
  • Check “Active” to turn it on

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.

The Environment File

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:

  • as the .bashrc for the elekto application user
  • as ENV variables for a container running Elekto
  • preloaded in a systemd unit file
  • injected through a ConfigMap and a Secret into a Kubernetes pod

Since we use ENV for Elekto configuration, this does mean that Elekto must be launched under a shell.

ENV Variables

What follows are the ENV variables that must be set for Elekto to run.

Application Information

APP_NAME

Required Name of the Elekto instance you are running. Displays in some parts of the UI. For user information only.

Example: k8s.elections

APP_ENV

Optional Status of this Elekto instance, for CI/CD purposes. Not used internally by Elekto.

Example: production or development

APP_KEY

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.

Example: 2400229255

APP_DEBUG

Required Whether to run in Debug mode for troubleshooting purposes. In Debug mode, will output stack traces for errors and reload templates.

Example: True or False

APP_URL

Optional URL of the Elekto instance. Used by some uWSGI and/or Nginx configurations. Not used internally by Elekto.

Example: http://elections.knative.dev

APP_PORT

Optional Used in some uWSGI start scripts, and when running Flask in standalone mode. Port on which to serve Elekto.

Example: 5000

APP_HOST

Optional Used in some webserver startup scripts, and by the Flask server in standalone mode. Name of the host served by this Elekto instance.

Example: localhost

APP_CONNECT

Optional Whether to serve uWSGI over HTTP or via a local Unix socket. Used by some startup scripts; see entrypoint.sh for an example.

Example: http or socket

MIN_PASSCODE_LENGTH

Optional: Integer. Minimum length for a voter-ballot passphrase in order to deter hacking. Set to 6 if left blank.

Example: 8

Database Connection

DB_CONNECTION

Required Which database connection type to use. Currently only PostgreSQL, MySQL, and SQLite backends are supported.

Example: postgresql, mysql, or sqlite

DB_HOST

Required The URL, IP, or hostname of the database server. Ignored if using SQLite (set to N/A).

Example: pgdb-1a.prod.elekto.dev

DB_PORT

Required The network port for the database server. Ignored if using SQLite (set to 1001).

Example: 3306

DB_PATH

Optional Used only for SQLite. Path to the database filesystem.

Example: /var/db/elekto-db

DB_USERNAME

Required Login user for the Elekto database. Not used by SQLite.

Example: elekto

DB_PASSWORD

Required Authentication password for the Elekto database. Not used by SQLite.

Example: 1a6e4b3f55dc

Repository Configuration

META_REPO

Required GIT clone URL for the repository which contains the election configurations. Should be the .git link, not the .html one.

Example: https://github.com/kalkayan/k8s.elections.meta.git

ELECTION_DIR

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 /.

Example: elections, gov/steering/elections

META_DEPLOYMENT

Optional Reserved for future advanced configuration use.

Example: local, sidecar

META_PATH

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.

Example: meta, /tmp/meta

META_BRANCH

Required Which git branch has the merged version of the election data. Defaults to main.

Example: main, master, prod

META_SECRET

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.

Example: 92a488d11c0d27bbfea0a97e3332e08a

Oauth Settings

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.

GITHUB_REDIRECT

Required Flask path for the GitHub authentication callback. Defaults to /oauth/github/callback, and there’s no good reason to change it.

Example: /oauth/github/callback

GITHUB_CLIENT_ID

Required The Client ID from the GitHub Oauth Application.

Example: 0b9138c0b2ffeefd9fc1

GITHUB_CLIENT_SECRET

Required The Client Secret from the GitHub Oauth Application.

Example: dd37278f8e9d57571590ad9288f0aae62228c2e8

4 - Kubernetes Installation

Installing Elekto on Kubernetes

This guide walks you through installing Elekto on a Kubernetes cluster.

TBD.

5 - Upgrading Elekto

How to upgrade Elekto

Upgrading

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

Upgrading from 0.5 to 0.6

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:

  1. Shut the Elekto web application down
  2. Upgrade Elekto software
  3. Run 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 console --migrate.