Storage Azure

Kinto 26.3 on Ubuntu 24.04 on Azure User Guide

| Product: Kinto 26.3 on Ubuntu 24.04 LTS on Azure

Overview

Kinto is a generic JSON document store with sharing and synchronisation, developed by Mozilla and used in production as the backend behind Firefox Remote Settings. It gives applications a lightweight REST API for storing, versioning, sharing and syncing structured JSON records, organised into buckets, collections and records with fine-grained per-object permissions and offline-first synchronisation support.

The cloudimg image installs Kinto 26.3 as a Pyramid application served by gunicorn behind nginx, with PostgreSQL 16 wired up as the storage, permission and cache backend. Every secret is generated per instance on first boot, and the authentication configuration is locked down by default.

What is included:

  • Kinto 26.3.2 in a Python 3.12 virtualenv at /opt/kinto/venv
  • PostgreSQL 16 storage, permission and cache backend on loopback 127.0.0.1:5432
  • gunicorn on loopback 127.0.0.1:8888, fronted by nginx (HTTPS 443, HTTP 80 redirect + /healthz)
  • accounts plugin enabled; account creation and every global write restricted to account:admin
  • Per-VM userid_hmac_secret, PostgreSQL password, admin password and TLS certificate generated at first boot
  • Admin credentials written to /root/kinto-credentials.txt (mode 0600)
  • kinto.service, nginx.service and postgresql running on the instance
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet with a subgroup. Recommended size Standard_B2s (Kinto is light). Open inbound 443 (and 80 for the HTTPS redirect) plus 22 for SSH; PostgreSQL and gunicorn never leave the loopback interface.

Step 1: Deploy and connect

Deploy the image from the Azure Marketplace, then connect over SSH:

ssh azureuser@<vm-ip>

The image ships with a self-signed TLS certificate regenerated per VM, so API calls in this guide use curl -k. Step 7 covers installing a real certificate for your own domain.

Step 2: Confirm the services and the attack surface

systemctl is-active kinto.service nginx.service postgresql | paste -sd' ' -
/opt/kinto/venv/bin/pip show kinto | grep -E "^(Name|Version)"
ss -Hltn | awk '{print $4}' | sort -u

kinto.service, nginx.service and postgresql all report active, Kinto is version 26.3.2, and only ports 22, 80 and 443 face the network — gunicorn (8888) and PostgreSQL (5432) stay on 127.0.0.1.

kinto.service, nginx.service and postgresql active; Kinto 26.3.2; only 22/80/443 exposed, gunicorn 8888 and postgres 5432 on loopback

Step 3: Retrieve the admin credentials

The administrator username and a unique per-VM password are written to a root-only file on first boot. Read them, then call the public /v1/ hello endpoint, which advertises the enabled capabilities:

sudo cat /root/kinto-credentials.txt
curl -sk https://localhost/v1/ | python3 -m json.tool | head -22

The hello response lists accounts under capabilities, confirming the secure account-based authentication is active.

Per-VM admin username and password in /root/kinto-credentials.txt; /v1/ hello advertises the accounts capability

Step 4: Create your first bucket, collection and record

Kinto organises data as buckets, which hold collections, which hold JSON records. Authenticate with the admin credentials and do a full round trip:

PASS=$(sudo grep '^kinto.admin.password=' /root/kinto-credentials.txt | cut -d= -f2-)

# Create a bucket and a collection
curl -sk -u "admin:${PASS}" -X PUT https://localhost/v1/buckets/myapp
curl -sk -u "admin:${PASS}" -X PUT https://localhost/v1/buckets/myapp/collections/settings

# Store a JSON record and read it back
RID=$(curl -sk -u "admin:${PASS}" -H 'Content-Type: application/json' \
  -X POST https://localhost/v1/buckets/myapp/collections/settings/records \
  -d '{"data":{"theme":"dark","refreshMinutes":15}}' \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"]["id"])')

curl -sk -u "admin:${PASS}" \
  https://localhost/v1/buckets/myapp/collections/settings/records/"${RID}" \
  | python3 -m json.tool

The record comes back with its data, a server-assigned id, a last_modified timestamp, and permissions granting write to account:admin. That is the whole Kinto model: store structured JSON, version it, and share it with fine-grained permissions.

Authenticated round trip: PUT bucket and collection return 201, POST stores a record, GET returns the JSON with id, last_modified and account:admin write permission

Step 5: Verify the secure-by-default posture

A stock Kinto install allows anonymous account creation and, with permissive settings, anonymous writes. This image ships the opposite. Confirm it:

grep -E 'account_create_principals|_write_principals' /etc/kinto/kinto.ini

# Anonymous write, anonymous signup and a default credential must all be rejected
curl -sk -o /dev/null -w 'anon write:   HTTP %{http_code}\n' -X PUT https://localhost/v1/buckets/anon
curl -sk -o /dev/null -w 'anon signup:  HTTP %{http_code}\n' -H 'Content-Type: application/json' \
  -X PUT https://localhost/v1/accounts/intruder -d '{"data":{"password":"x"}}'
curl -sk -o /dev/null -w 'admin:admin:  HTTP %{http_code}\n' -u admin:admin https://localhost/v1/buckets/myapp

Every principal is set to account:admin, and each of the three unauthorised requests returns HTTP 401. To let another account create records, create it as admin (PUT /v1/accounts/<name> with a password) and grant it permission on the bucket or collection, or widen the principals in /etc/kinto/kinto.ini and restart kinto.service.

kinto.ini principals all set to account:admin; anonymous write, anonymous signup and admin:admin each return HTTP 401 rejected

Step 6: Where everything lives

Component Path
Virtualenv /opt/kinto/venv
Configuration /etc/kinto/kinto.ini
systemd unit /etc/systemd/system/kinto.service
Firstboot /usr/local/sbin/kinto-firstboot.sh
Credentials /root/kinto-credentials.txt (mode 0600)
TLS certificate /etc/kinto/tls/cert.pem, /etc/kinto/tls/key.pem
nginx vhost /etc/nginx/sites-available/kinto
PostgreSQL database kinto, role kinto on 127.0.0.1:5432

Step 7: Enable a real TLS certificate

The image ships a per-VM self-signed certificate. For a public domain, install Let's Encrypt with certbot and point nginx at the issued certificate:

sudo apt-get update && sudo apt-get install -y certbot
sudo certbot certonly --standalone -d kinto.your-domain.com
sudo sed -i 's#/etc/kinto/tls/cert.pem#/etc/letsencrypt/live/kinto.your-domain.com/fullchain.pem#; s#/etc/kinto/tls/key.pem#/etc/letsencrypt/live/kinto.your-domain.com/privkey.pem#' /etc/nginx/sites-available/kinto
sudo systemctl reload nginx

Step 8: Security hardening

  • Restrict the NSG so 443 only reaches the client networks that need the API.
  • Keep account creation admin-only unless you deliberately open self-service signup.
  • Rotate the admin password with sudo /opt/kinto/venv/bin/kinto create-user --ini /etc/kinto/kinto.ini --username admin --password <new-password>.
  • Back up PostgreSQL regularly with pg_dump kinto.
  • Patch monthly with sudo apt-get update && sudo apt-get upgrade followed by a reboot.

Step 9: Support and licensing

Kinto is licensed under the Apache License 2.0 and is free to use. cloudimg provides commercial support for this image separately.

  • Email: support@cloudimg.co.uk
  • Support hours: 24/7, one hour average response for critical issues

Deploy on Azure

Launch Kinto 26.3 with 24/7 support from cloudimg. All product and company names are trademarks of their respective holders.