Kinto 26.5.0
Overview
Kinto is an open-source JSON document store with sharing and synchronisation, originally built by Mozilla. It is the storage behind Firefox Remote Settings. Your applications keep JSON records in collections inside buckets through a REST API, with per-object permissions, groups, change-history timestamps and a sync protocol that lets offline clients pull only what changed.
Kinto has no user interface. You work with it through curl, the kinto-http JavaScript and Python clients, or any HTTP library.
This guide covers the Kinto 26.5.0 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud file sharing and sync listing on AWS Marketplace. You select it as the software version when you subscribe and launch.
What you get:
- No default account. Upstream Kinto lets anyone create an account and write. This image ships no database at all. On first boot it creates the PostgreSQL cluster and the
adminaccount, with a password unique to your instance (stored as a bcrypt hash), and writes the password to/root/kinto-credentials.txt(root only). Onlyadminmay create accounts, buckets, collections, groups or records. Anonymous writes and anonymous sign-ups are refused. - HTTPS from the first boot. nginx serves the API on port 443 with a self-signed certificate generated on your instance's first boot. Its SHA-256 fingerprint is in the credentials file so you can check it. Port 80 redirects to HTTPS, and requests for a host name the instance does not serve are dropped.
- No database password, no database port. PostgreSQL 16 listens on its local socket only (there is no TCP port 5432 at all). Kinto signs in to it by operating system identity, so there is no database password to steal.
- Per-instance secrets. Kinto's HMAC secret (used for user IDs and the sign-in cache) and the TLS key are generated on each instance. Nothing secret is baked into the image.
- Browsers limited to your own origin. Kinto answers cross-origin (CORS) requests from this server's own addresses only, instead of upstream's "any site". You add the origin of your own web app when you need one (Step 8).
- Metadata service blocked. Kinto, nginx and PostgreSQL cannot reach the EC2 instance metadata service, and the AMI requires IMDSv2.
- Pinned and patched. Kinto 26.5.0 and every one of its Python dependencies are installed from PyPI wheels pinned by SHA-256. Ubuntu 24.04 LTS is fully patched at build time, with unattended security upgrades switched on.
What is on the image: Kinto 26.5.0 (Apache-2.0) in a Python 3.12 virtual environment under /opt/kinto/venv, served by waitress behind nginx, plus PostgreSQL 16, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The licence, the pinned package list and the build record are in /usr/share/doc/sac/.
Default user: ubuntu. Architecture: x86_64. Recommended instance type: m5.large.
Prerequisites
You need:
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet
- A security group that allows TCP 22 (SSH) from your management network, and TCP 443 (the Kinto API) and TCP 80 (redirects to HTTPS) from the networks your applications use
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Select Kinto 26.5.0 on Ubuntu 24.04 as the software version, choose your Region, and select Launch through EC2.
Choose m5.large, your key pair, a security group as described in Prerequisites, and a subnet.
To launch with the AWS CLI instead, replace the values in angle brackets:
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=kinto}]'Connect to your instance
For Kinto 26.5.0 on Ubuntu 24.04, the SSH user is ubuntu. Connect with your key pair:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
On first boot, the instance creates the database, the administrator and the certificate. It then starts Kinto and opens the HTTPS port. This takes about half a minute. Check the services:
systemctl is-active postgresql@16-main kinto nginxactive active activeOnly SSH (22) and nginx (80, 443) listen on the network. Kinto listens on 127.0.0.1:8888 for nginx only. PostgreSQL has no TCP port at all. The remaining loopback entries are Ubuntu's local DNS resolver. List the listening ports:
sudo ss -lntp | awk 'NR>1 {print $4}' | sort -u0.0.0.0:22 0.0.0.0:443 0.0.0.0:80 127.0.0.1:8888 127.0.0.53%lo:53 127.0.0.54:53 [::]:22 [::]:443 [::]:80If nginx is not running, first boot has not finished or has failed. In that case the API is never served. Check systemctl status kinto-firstboot and sudo cat /var/log/sac/kinto-firstboot.log.
Get your URL, password and certificate fingerprint
Read the credentials file. Only root can read it:
sudo cat /root/kinto-credentials.txtThe file contains the API URL, the administrator user and password, and the certificate fingerprint:
# Kinto 26.5.0 - per-instance credentials, generated on first boot (sac). Keep this file secret (0600 root).
# Sign in with HTTP Basic authentication. Change the password:
sudo kinto-set-admin-password admin ... KINTO_URL=https://ec2-203-0-113-10.compute-1.amazonaws.com/v1/ KINTO_ADMIN_USER=admin KINTO_ADMIN_PASSWORD=<KINTO_ADMIN_PASSWORD> KINTO_TLS_SHA256=AB:CD:...:EFRun the built-in self-test. It checks the redirect, the host rules, an authenticated document round trip and every refusal: anonymous write, anonymous sign-up, a wrong password, admin:admin and a foreign CORS origin.
sudo /usr/local/sbin/kinto-verify.shKINTO_ROUNDTRIP_OK admin auth + document round trip + anonymous/wrong/default refusals + CORS + host checksCall the API
The root of the API is public and describes the server. On the instance, localhost is one of the certificate's names, so curl can verify the certificate instead of skipping the check:
curl -s --cacert /etc/ssl/kinto/kinto.crt https://localhost/v1/ | python3 -m json.tool | head -18The response names the server's address, the Kinto version and the one plugin this image enables, accounts:
{ "project_name": "kinto", "project_version": "26.5.0", "http_api_version": "1.23", "project_docs": "https://kinto.readthedocs.io/", "url": "https://ec2-203-0-113-10.compute-1.amazonaws.com/v1/", "config": null, "settings": { "readonly": false, "batch_max_requests": 25, "explicit_permissions": true }, "capabilities": { "accounts": { "description": "Manage user accounts.",From your own computer, first check that the certificate the instance presents matches the fingerprint in the credentials file. Then copy the certificate and use it with --cacert. Do not add it to your system's trust store:
openssl s_client -connect <public-ip>:443 -servername <public-dns-name> </dev/null 2>/dev/null \
| openssl x509 -noout -fingerprint -sha256 scp -i <your-key.pem> ubuntu@<public-ip>:/etc/ssl/kinto/kinto.crt kinto.crt curl --cacert kinto.crt -u admin https://<public-dns-name>/v1/curl -u admin prompts for the password, so the password does not end up in your shell history.
Store and read documents
Create a bucket and a collection, add a record, then read it back. Replace <KINTO_ADMIN_PASSWORD> with the password from Step 4, as follows:
K="curl -s --cacert /etc/ssl/kinto/kinto.crt -u admin:<KINTO_ADMIN_PASSWORD>" $K -o /dev/null -w 'bucket %{http_code}\n' -X PUT https://localhost/v1/buckets/demo $K -o /dev/null -w 'collection %{http_code}\n' -X PUT https://localhost/v1/buckets/demo/collections/notes $K -H 'Content-Type: application/json' -X POST https://localhost/v1/buckets/demo/collections/notes/records \
-d '{"data": {"title": "hello kinto", "done": false}}' | python3 -m json.tool $K https://localhost/v1/buckets/demo/collections/notes/records | python3 -m json.toolbucket 201 collection 201 { "data": { "title": "hello kinto", "done": false, "id": "2b0b4a6c-...", "last_modified": 1793400000000 }, "permissions": { "write": [ "account:admin" ] } }Clients that synchronise ask only for what changed since their last sync, for example ?_since=<last_modified>. See the Kinto API documentation for filtering, sorting, pagination, groups and permissions.
To remove the demo data, run:
curl -s --cacert /etc/ssl/kinto/kinto.crt -u admin:<KINTO_ADMIN_PASSWORD> -o /dev/null -w '%{http_code}\n' -X DELETE https://localhost/v1/buckets/demoSee what is refused
Anonymous visitors can read the public server description and nothing else. They cannot write, create an account or read your records. Try it:
curl -s --cacert /etc/ssl/kinto/kinto.crt -o /dev/null -w 'anonymous write %{http_code}\n' -X PUT https://localhost/v1/buckets/anon
curl -s --cacert /etc/ssl/kinto/kinto.crt -o /dev/null -w 'anonymous sign up %{http_code}\n' -H 'Content-Type: application/json' \
-X PUT https://localhost/v1/accounts/intruder -d '{"data": {"password": "intruder-password"}}'
curl -s --cacert /etc/ssl/kinto/kinto.crt -o /dev/null -w 'admin:admin %{http_code}\n' -u admin:admin https://localhost/v1/bucketsanonymous write 401 anonymous sign up 401 admin:admin 401The rules are in /etc/kinto/kinto.ini. Every *_principals setting lists account:admin only.
To let your own users sign up, add system.Everyone to kinto.account_create_principals. Each new account can then write only what it is given permission on. Restart Kinto with sudo systemctl restart kinto.
Use your own host name, certificate and web app origin
Point a DNS record at the instance. An Elastic IP keeps the address across stop and start. Then tell the instance its name.
The command below creates a new self-signed certificate for that name. It updates the nginx host rule, Kinto's kinto.http_host and CORS origins, and the address and fingerprint in the credentials file. The name is kept across reboots.
sudo kinto-set-hostname kinto.example.comTo use a certificate from a public authority instead, replace /etc/ssl/kinto/kinto.crt (full chain) and /etc/ssl/kinto/kinto.key (mode 0600, owned by root) with your own. Then run sudo systemctl reload nginx. Running kinto-set-hostname again later replaces them with a new self-signed pair.
If a browser application on another origin calls the API, add that origin (space-separated) to kinto.cors_origins in /etc/kinto/kinto.ini. For example, kinto.cors_origins = https://kinto.example.com https://app.example.com. Then run sudo systemctl restart kinto. kinto-set-hostname keeps the origins you add.
Change the password, back up and update
Change the administrator password. The command reads it from the terminal or standard input, never the command line, and the old password stops working at once. Afterwards, update or remove the password line in the credentials file.
sudo kinto-set-admin-password adminEvery service is enabled, so Kinto returns after a reboot or a stop and start with your data intact. Unattended security upgrades keep the operating system, PostgreSQL and nginx patched. Confirm that the services are enabled:
systemctl is-enabled kinto nginx unattended-upgradesenabled enabled enabledYour data lives in PostgreSQL in /var/lib/postgresql/16/main on the root volume. Back it up with a dump, or with an EBS snapshot or AWS Backup of the instance:
sudo -u postgres pg_dump -Fc kinto > kinto-$(date +%F).dumpPostgreSQL has no network listener. If another host must reach it, add listen_addresses and a pg_hba.conf rule with a password role yourself, and open the port only to that host.
SecureAnyCloud publishes a new version of the image when a newer Kinto release is available.
Security notes
- No shared secret ships in the image. No database, account, password, password hash, HMAC secret, TLS key or credentials file exists until your instance's first boot generates them. nginx refuses to start until first boot has finished.
- Fail closed. If first boot cannot complete, the HTTPS port is closed again and nothing is served.
- Kinto is confined. It runs as the unprivileged
kintoaccount with no writable path at all. Its code is owned by root and read-only to it, and every byte of data is in PostgreSQL. It cannot read the credentials file or the TLS key. It is blocked from the EC2 instance metadata service, as are nginx and PostgreSQL. - Host and client address come from configuration and the connection, never from request headers, so a forged
HostorX-Forwarded-Forheader changes nothing. - No plugin that would widen the attack surface. The image enables only the
accountsplugin: no anonymous default bucket, no OpenID login, no flush endpoint and no admin web UI. - Known residual findings, not reachable here. Kinto 26.5.0 requires setuptools older than 82. setuptools 81.0.0 has a moderate advisory (GHSA-h35f-9h28-mq5c) and a low advisory (GHSA-xmj3-9gf7-h52w). Both affect building source packages or installing legacy packages on Windows, which this image never does. The PostgreSQL driver's wheel bundles its own OpenSSL 3.5.8 and libpq. Kinto connects over the local socket, so their network code is unused.
- Restrict 22/tcp to your management network, and 80/443 to the networks that use the API.
Architecture summary
- Document store: Kinto 26.5.0 (Apache-2.0), virtual environment /opt/kinto/venv (root-owned, every wheel pinned by SHA-256)
- Application server: waitress (via pserve) on 127.0.0.1:8888, unit kinto.service, account kinto
- Settings: /etc/kinto/kinto.ini, mode 0640 root:kinto (HMAC secret, host, CORS origins, permissions)
- Database: PostgreSQL 16, local socket only, peer authentication, database and role kinto
- Web server: nginx on 443 (HTTPS, per-instance certificate in /etc/ssl/kinto), with port 80 redirecting to HTTPS
- Sign-in: Kinto accounts (HTTP Basic), bcrypt hashes in PostgreSQL, administrator admin
- Credentials: /root/kinto-credentials.txt, mode 0600, root only
- First boot: kinto-firstboot.service, log /var/log/sac/kinto-firstboot.log
- Tools: kinto-set-admin-password, kinto-set-hostname, kinto-verify.sh
- Ports: 22 SSH, 80 redirect, 443 Kinto API
- Base image: Ubuntu 24.04 LTS, fully patched, unattended security upgrades enabled, IMDSv2 required
Support
SecureAnyCloud images come with 24/7 support. Email sales@secureanycloud.com with your AWS account ID and the instance ID. For Kinto itself, see the Kinto documentation and the Kinto project on GitHub.
Kinto is an open source project originally created by Mozilla. SecureAnyCloud is not affiliated with or endorsed by Mozilla or the Kinto project.
Deploy on AWS
Launch Kinto 26.5.0 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com