Spiffarena 4.0.0
Overview
This guide covers launching and using the SpiffArena 4.0.0 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud developer and API tools listing on AWS Marketplace. You pick it as the software version when you launch.
SpiffArena is an open source workflow platform built on the SpiffWorkflow engine. You draw a business process as a BPMN diagram (or a decision table as DMN) in the browser, add forms, script tasks and service calls, and run it. SpiffArena keeps every process instance, the tasks waiting for people, their data and the full history.
What you get, on top of SpiffArena:
- HTTPS from the first boot. nginx serves SpiffArena on port 443 with a certificate generated on your instance's first boot. Port 80 only redirects to HTTPS, and a request for any other name gets no answer.
- No demo logins. SpiffArena's built-in sign-in ships with demonstration users and fixed passwords. None of them exist on this image. First boot creates one administrator with a random name (
spiffadmin-<random>) and a random password, and writes both to/root/spiffarena-credentials.txt. - A login gate in front of the built-in OpenID provider. Upstream's built-in provider is meant for demonstrations: its token endpoint signs in whoever presents a sign-in code. On this image, a small gate on the loopback address checks the password and binds the sign-in to it. nginx refuses the provider's token and refresh endpoints, the metrics and the webhooks from the network.
- Per-instance secrets. The Flask session key, the encryption key, the OpenID client secret, the OpenID signing key, the gate key, the administrator password and the TLS key are all generated on your instance's first boot. The image ships with an empty data directory.
- Script tasks cannot reach metadata or your network. SpiffArena runs the Python in script tasks on the server. On this image the SpiffArena account is fenced. It can reach public HTTPS but not the EC2 instance metadata service, link-local, private, shared, loopback or multicast addresses.
- A hardened front door. Sign-in requests are rate limited per client address for every spelling of the sign-in paths, nginx always replaces
X-Forwarded-For, cross-site requests are refused, and request sizes and types are limited. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: SpiffArena 4.0.0 (/opt/spiffarena, the upstream v4.0.0 release with SpiffWorkflow pinned to its release commit and its Python dependencies raised to fixed releases), its React web interface built from the same release, SQLite, nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The build record, SpiffArena's licences and the source reference are in /usr/share/doc/sac-spiffarena.
Default user: ubuntu. Architecture: x86_64. Recommended instance type: m5.large.
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
- A security group that allows TCP 443 (SpiffArena), TCP 80 (redirects to HTTPS) and TCP 22 (SSH). Open 443 to the networks your users work from, and open 22 to your own networks only.
- A current web browser.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick SpiffArena 4.0.0 on Ubuntu 24.04 as the software version, pick your Region, and choose Launch through EC2. Choose the instance type, key pair, subnet and the security group above.
Or launch with the AWS CLI. 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=spiffarena}]'An Elastic IP keeps the server's address, and so its name and certificate, the same across stops and starts.
Connect to your instance
Connect to SpiffArena 4.0.0 on Ubuntu 24.04 over SSH as the user ubuntu:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot takes about a minute. It sets the server's name, generates the certificate, lays down SpiffArena's database and example process model, creates the administrator and mints every key. Only then does it start SpiffArena and nginx.
Check that everything is running:
systemctl is-active spiffarena-egress-fence spiffarena-authgate spiffarena spiffarena-scheduler nginx \
&& sudo test -f /var/lib/sac/data/spiffarena-firstboot.done && echo FIRSTBOOT_DONEactive active active active active FIRSTBOOT_DONEspiffarena is the API (gunicorn), spiffarena-scheduler runs timers and background work, spiffarena-authgate is the login gate and spiffarena-egress-fence loads the outbound fence.
Only SSH and nginx listen on the network. The API and the gate listen on the loopback address only:
sudo ss -lntp | awk 'NR>1 && $4 !~ /^127\.0\.0\.5[34]/ {print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u | tee /dev/stderr \
| awk '$1 !~ /^127\./ {sub(/.*:/, "", $1); print $1}' | sort -un | xargs | grep -qx '22 80 443' && echo "network listeners: 22 80 443"0.0.0.0:22 users:(("sshd"),("systemd")) 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) 127.0.0.1:7000 users:(("gunicorn"),("gunicorn"),("gunicorn")) 127.0.0.1:7001 users:(("python3")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx")) network listeners: 22 80 443Get your address and sign-in
Run sudo cat /root/spiffarena-credentials.txt to see your address, user name and password. The file is readable by root only and holds these settings, all generated for this instance:
sudo sed -n 's/^\(SPIFFARENA_[A-Z0-9_]*\)=.*/\1/p' /root/spiffarena-credentials.txt | tee /dev/stderr \
| grep -qx SPIFFARENA_PASSWORD && echo "credentials present"SPIFFARENA_URL SPIFFARENA_HOST SPIFFARENA_USERNAME SPIFFARENA_PASSWORD SPIFFARENA_TLS_CERT SPIFFARENA_TLS_SHA256_FINGERPRINT credentials presentSPIFFARENA_URL is https://<your instance's public DNS name>/, the address you open in a browser. SPIFFARENA_USERNAME is the administrator's user name and SPIFFARENA_PASSWORD is its password.
To show the settings that are not secret on their own:
sudo grep -E '^SPIFFARENA_(URL|HOST|USERNAME)=' /root/spiffarena-credentials.txt \
| tee /dev/stderr | grep -q '^SPIFFARENA_USERNAME=spiffadmin-' && echo "per-instance administrator"SPIFFARENA_URL=https://ec2-203-0-113-10.compute-1.amazonaws.com/ SPIFFARENA_HOST=ec2-203-0-113-10.compute-1.amazonaws.com SPIFFARENA_USERNAME=spiffadmin-3f9a1c per-instance administratorThe database holds no user except your administrator (SpiffArena adds a user's row at that user's first sign-in). The upstream demo users are not there:
U="$(sudo sed -n 's/^SPIFFARENA_USERNAME=//p' /root/spiffarena-credentials.txt)"
sudo -u spiffarena sqlite3 -readonly /var/lib/spiffarena/db.sqlite3 "SELECT 'other users: ' || count(*) FROM user WHERE username <> '$U'" \
| tee /dev/stderr | grep -qx 'other users: 0'other users: 0Sign in
The certificate is self-signed and generated on your instance, so your browser warns about it the first time. Compare the fingerprint that the browser shows with SPIFFARENA_TLS_SHA256_FINGERPRINT and accept it, or use your own domain and certificate (Step 10).
Open SPIFFARENA_URL in your browser. SpiffArena sends you to its sign-in form. Sign in with SPIFFARENA_USERNAME and SPIFFARENA_PASSWORD. The form's note about demonstration use is upstream's text. On this image the form checks your per-instance password through the login gate.
After you sign in, the home page opens. It lists the tasks waiting for you and the workflows you started:
Change the password with sudo spiffarena-rotate-password (Step 9).
The built-in sign-in reads its users from /etc/spiffarena/permissions.yml (readable by root and the spiffarena account only). To add people, give each their own entry under users: with a long random password, add them to a group under groups:, and run sudo systemctl restart spiffarena. For more than a few people, connect SpiffArena to your own OpenID provider instead, as SpiffArena's documentation describes.
See Step 12 for who should be allowed to edit process models.
Build and run a process
The Processes page lists process groups and the process models inside them. The image ships one example, SecureAnyCloud Examples > Hello World. It has a start event, a script task that sets some process data, and an end event.
Open a model's BPMN file to edit the diagram in the browser. The palette on the left adds events, tasks, gateways and data objects. The panel on the right sets each element's properties, such as a script task's Python, a user task's form or a service task's connector:
Press Start to run the model. SpiffArena runs the instance, and its page shows the status, who started it, the milestones, the events and the task data:
Process models are stored as files in /var/lib/spiffarena/process-models, a git repository that SpiffArena commits to on every save, so each instance records the revision it ran. Add Process Group and Add a process model create your own. SpiffArena's documentation covers forms, user tasks, service tasks, messages and DMN decision tables.
Script tasks and the egress fence
Script tasks run Python on the server, inside SpiffArena's API process, as the spiffarena account. On a cloud instance, a script that can open network connections is a server-side request forgery risk. The spiffarena account is therefore fenced at two layers:
- nftables (
spiffarena-egress-fence.service) rejects any connection thespiffarenauser opens to metadata, link-local, private (RFC 1918), shared, loopback (except SpiffArena's own API port), multicast or reserved addresses, IPv4 and IPv6. - systemd (
IPAddressDeny=onspiffarena.serviceandspiffarena-scheduler.service) drops the same ranges, except loopback, for anything running in those services, whatever user it runs as.
The SpiffArena services refuse to start unless the nftables table is loaded, and nginx cannot reach the metadata service either.
Check the fence:
sudo spiffarena-egress-fence check && echo "egress fence loaded" systemctl show -p IPAddressDeny --value spiffarena.service | tr ' ' '\n' | grep -cE '^(10\.0\.0\.0/8|172\.16\.0\.0/12|192\.168\.0\.0/16|169\.254\.0\.0/16)$' \
| tee /dev/stderr | grep -qx 4 && echo "private and link-local ranges denied to spiffarena.service"egress fence loaded 4 private and link-local ranges denied to spiffarena.serviceThe metadata service and this instance's own private address refuse the spiffarena user at once, while public HTTPS works:
P="$(hostname -I | awk '{print $1}')" for u in http://169.254.169.254/latest/meta-data/ "https://$P/" https://secureanycloud.com/; do printf '%s %s\n' "$(sudo -u spiffarena curl -sk -m 8 -o /dev/null -w '%{http_code}' "$u" || true)" "${u/$P/PRIVATE_IP}" done | tee /dev/stderr | awk '{print $1}' | xargs | grep -qx '000 000 200' && echo "fenced: metadata and private refused, public HTTPS allowed"000 http://169.254.169.254/latest/meta-data/ 000 https://PRIVATE_IP/ 200 https://secureanycloud.com/ fenced: metadata and private refused, public HTTPS allowedInside SpiffArena, a script task that tries to connect to a fenced address gets a timeout (the systemd layer drops the packets) or a refusal, and the task fails with that error. The same script reaches public addresses normally.
To let SpiffArena reach a service in your own network, open just that range. Metadata, link-local and loopback ranges are always refused. The helper updates both layers and restarts SpiffArena:
sudo spiffarena-egress-allow add 10.20.30.40/32
sudo spiffarena-egress-allow list
sudo spiffarena-egress-allow remove 10.20.30.40/32What the front door refuses
nginx answers only for the server's own names and passes requests to SpiffArena on loopback:
H="$(sudo sed -n 's/^SPIFFARENA_HOST=//p' /root/spiffarena-credentials.txt)" { curl -s -o /dev/null -w '%{http_code}\n' --cacert /etc/ssl/spiffarena/spiffarena.crt --resolve "$H:443:127.0.0.1" "https://$H/" curl -s -o /dev/null -w '%{http_code}\n' -k -H 'Host: someone-else.example' https://127.0.0.1/ curl -s -o /dev/null -w '%{http_code}\n' --resolve "$H:80:127.0.0.1" "http://$H/" curl -s -o /dev/null -w '%{http_code}\n' --cacert /etc/ssl/spiffarena/spiffarena.crt --resolve "$H:443:127.0.0.1" -H 'Origin: https://evil.example' "https://$H/v1.0/status" } | xargs | tee /dev/stderr | grep -qx '200 000 301 403' && echo "front door OK"200 000 301 403 front door OK- Sign-in. The sign-in routes are limited to 60 a minute per client address, for every spelling of the paths. The OpenID provider's token and refresh endpoints, the metrics endpoint and the webhooks are refused from the network.
- X-Forwarded-For. nginx replaces any
X-Forwarded-Forheader with the address it accepted the connection from and blanksX-Real-IP,Forwardedand similar headers, so a client cannot change the address the rate limits and logs see. - Cross-site requests. Requests whose
Originis not the instance's own address get403, so a web page elsewhere cannot use a signed-in user's session. - Sizes and types. Request bodies to the API (
/v1.0/, which carries file uploads) are limited to 64 MiB, sign-in forms to 64 KiB and everything else to 16 MiB. Compressed request bodies (Content-Encoding) get415andTRACEgets405. - Headers. Responses carry
Strict-Transport-Security,X-Content-Type-Options: nosniff,Referrer-PolicyandX-Frame-Options, and nginx does not reveal its version.
nginx's access log records the client address, request path and status, without query strings. SpiffArena's API keeps no access log.
Run the self-test, change the password
The image ships a self-test. It checks that the upstream demo logins and a wrong password are refused, and that your administrator signs in through the login gate. It also checks that the gate refuses a missing, altered or borrowed cookie, that the token, refresh, metrics and webhook routes are refused from the network, and that unauthenticated and cross-site writes are refused. Finally, it confirms that the example process runs to completion:
sudo spiffarena-selftest | tail -n 1 | tee /dev/stderr | grep -q '^SPIFFARENA_SELFTEST_OK 'SPIFFARENA_SELFTEST_OK SpiffArena 4.0.0 at https://ec2-203-0-113-10.compute-1.amazonaws.com/: the upstream demo logins and a wrong password are refused, spiffadmin-3f9a1c signs in through the login gate (login_return refused without its cookie, with an altered cookie, for another user and off-site), the token/refresh back channel, metrics and webhooks are refused in every spelling, unauthenticated and cross-site writes are refused, process instance 2 of sac-demo:hello-world ran to completion (answer 42)To give the administrator a new random password and write it to the credentials file:
sudo spiffarena-rotate-passwordUse your own domain
Point a DNS name at the instance (an Elastic IP keeps it stable), then make it the server's address. The command generates a new certificate for that name, pins nginx to it and tells SpiffArena its public address:
sudo spiffarena-set-site spiff.example.comTo use a certificate from a public CA instead, for example one issued by certbot with a DNS challenge, run spiffarena-set-site first, then replace /etc/ssl/spiffarena/spiffarena.crt (full chain) and /etc/ssl/spiffarena/spiffarena.key and run sudo systemctl reload nginx.
Back up and restore
Everything SpiffArena stores is in /var/lib/spiffarena: the SQLite database db.sqlite3 (instances, tasks, users, history) and the process models in process-models. The configuration and keys are in /etc/spiffarena and /etc/spiffarena-authgate.
Take a consistent copy of the database with SQLite's online backup, then archive the models:
sudo -u spiffarena sqlite3 /var/lib/spiffarena/db.sqlite3 ".backup /var/lib/spiffarena/backup-$(date +%F).sqlite3"
sudo tar -C /var/lib/spiffarena -czf spiffarena-$(date +%F).tar.gz backup-$(date +%F).sqlite3 process-modelsCopy the archive off the instance, for example to Amazon S3.
To restore on a new instance of this image, run sudo systemctl stop spiffarena spiffarena-scheduler. Put the database back as /var/lib/spiffarena/db.sqlite3 and the models under /var/lib/spiffarena/process-models (owned by spiffarena). Then run sudo systemctl start spiffarena spiffarena-scheduler.
The new instance keeps its own administrator, keys and certificate, so everyone signs in again. Copy any accounts you added to /etc/spiffarena/permissions.yml into the new instance's file. Re-enter the values under Configuration > Secrets, because SpiffArena encrypts them with the instance's own key.
Security notes and the build record
The certificate generated at first boot is a server certificate only: it cannot sign other certificates.
openssl x509 -in /etc/ssl/spiffarena/spiffarena.crt -noout -ext basicConstraints,keyUsage,extendedKeyUsage | tee /dev/stderr | grep -q 'CA:FALSE'X509v3 Basic Constraints: critical CA:FALSE X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server AuthenticationThe build record names the release, its licences and the dependencies raised to fixed releases:
sed -n '1,2p' /usr/share/doc/sac-spiffarena/BUILD-INFO.txt | tee /dev/stderr | grep -q '^SpiffArena *4\.0\.0 'SpiffArena 4.0.0 (github.com/sartography/spiff-arena tag v4.0.0), LGPL-2.1; SpiffWorkflow 902055aa5c214581c4ca01bbe7dbed79c985c65f LGPL-3.0; web interface with bpmn-js / dmn-js (MIT + bpmn.io watermark clause). SOURCE.txt- Who may edit process models. A script task is Python that runs as the
spiffarenaaccount, inside the API. Anyone allowed to create or edit process models can therefore read what that account can read, including the database and SpiffArena's own keys. The egress fence keeps such code off the metadata service and your network. Even so, grant model editing to administrators only, and give everyone else permission to start processes and complete tasks. - Isolation. SpiffArena runs as its own unprivileged user
spiffarenawith no login shell and no capabilities, a read-only view of the system except/var/lib/spiffarena, hidden process lists and a memory limit. The login gate runs as a separate user,spiffgate, that has no network access beyond loopback, andspiffarenacannot read the gate's key. - Licences. SpiffArena is licensed LGPL-2.1 and SpiffWorkflow LGPL-3.0. The diagram editors are bpmn-js and dmn-js, licensed MIT with the bpmn.io condition that their watermark stays visible; the image keeps it. The licences are in
/usr/share/doc/sac-spiffarena.
Keep it up to date
Ubuntu security updates, including nginx and SQLite, install automatically. To apply everything now:
sudo apt-get update && sudo apt-get upgrade -yNew SpiffArena releases arrive as new versions of the AWS Marketplace listing. Launch the new version and restore your database and process models into it (Step 11). If you use your own domain, run sudo spiffarena-set-site with it.
Support
- Email: sales@secureanycloud.com
- Website: https://secureanycloud.com
The other versions on this listing are on the developer and API tools guide.
Deploy on AWS
Launch SpiffArena 4.0.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