Deployment guide

Kinto

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. Data is organised into buckets, collections and records, with fine-grained per-object permissions and offline-first synchronisation support.

The SecureAnyCloud image installs Kinto 26.3 as a Pyramid application served by gunicorn behind nginx. PostgreSQL 16 is 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 you get:

  • Kinto 26.3.2 in a Python 3.12 virtualenv at /opt/kinto/venv
  • A 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)
  • The accounts plugin enabled, with account creation and every global write restricted to account:admin
  • A 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 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet.

The recommended size is Standard_B2s, since Kinto is lightweight. Open inbound 443, plus 80 for the HTTPS redirect and 22 for SSH. PostgreSQL and gunicorn never leave the loopback interface.

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 that is regenerated for each VM. For that reason, the API calls in this guide use curl -k. Step 7 shows how to install a real certificate for your own domain.

2

Confirm the services and the attack surface

Run the following to check the services, the Kinto version and the listening ports:

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, and Kinto is version 26.3.2. Only ports 22, 80 and 443 face the network. gunicorn (8888) and PostgreSQL (5432) stay on 127.0.0.1.

3

Retrieve the admin credentials

On first boot, the administrator username and a unique per-VM password are written to a root-only file. Read the file, 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. This confirms that account-based authentication is active.

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

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. Run the following to 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 that account as admin (PUT /v1/accounts/<name> with a password) and grant it permission on the bucket or collection. Alternatively, widen the principals in /etc/kinto/kinto.ini and restart kinto.service.

6

Where everything lives

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

Enable a real TLS certificate

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

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
8

Security hardening

  • Restrict the NSG so that 443 reaches only 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.
9

Support and licensing

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

  • Email: sales@secureanycloud.com
  • Support hours: 24/7, with a one-hour average response for critical issues

Deploy on Azure

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

Deploy on Azure

Launch Kinto 26.3 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure