1
0
Fork 0
kubernetes/invoice-ninja/README.md

3.3 KiB

Invoice Ninja

Invoice Ninja is a free invoice and customer management system. Tabitha uses it to manage her tutoring and learning center billing and payments.

Components

Invoice Ninja is a web-based application, written in PHP. The official container image only includes the application itself and PHP-FPM, but no HTTP server, so a separate nginx container is necessary. The image is also of dubious quality, doing weird things like copying "backup" files to persistent storage at startup, then deleting them from the container filesystem. To work around this, an init container is necessary to copy the application into writable ephemeral storage.

Persistent storage is handled in a somewhat ad-hoc way. There are three paths that are expected to be persistent:

  • /var/www/app/public
  • /var/www/app/storage
  • /var/www/app/public/storage

The distinction between these is not really clear. Both "public" directories have to be served by the web server, as well.

In addition to the main process, a "cron" process is required. This has to run every minute, apparently.

Invoice Ninja also requires a MySQL or MariaDB database. Supposedly, PostgreSQL can be used as well, but it is not supported by upstream and apparently requires patching some PHP code.

Phone Home

Although Invoice Ninja can be self hosed, it relies on some cloud services for some features. Notably, generating PDF invoices makes a few connections to external services:

  • fonts.googleapis.com: Fetches CSS resources
  • invoicing.io: Fetches the Invoice Ninja logo to print at the bottom

Both of these remote resources are hard-coded into the HTML document template that is used to render the PDF. The former is probably innocent, but I suspect the latter is some kind of "phone home," informing upstream of field deployments. Additionally, when certain actions are performed in the web UI, the backend makes requests to www.google-analytics.com, obviously for telemetry. Further, the Invoice Ninja documentation lists some "terms of service" for self-hosting, which include sending personally identifiable information to the Invoice Ninja, including company name and contact information, email addresses, etc.

The point of self-hosting applications is not to avoid paying for them (in fact, I pay for some cloud services offered by open source developers, even though I self-host their software), but to avoid dependencies on cloud services. For Invoice Ninja, that means we should be able to make invoices any time, even if upstream ceases offering their cloud service. Including a "phone home" in the invoice generation that can prevent the feature from working, even if it is by accident, is unacceptable.

To that end, I have neutered Invoice Ninja's phone-home capabilities. First, a script runs before the main container starts that replaces the hard-coded URL of the Invoice Ninja logo with the URL to the same logo in the local installation. Next, I have blocked all outbound communication from Invoice Ninja pods using a NetworkPolicy, except for Kubernetes services and the forward proxy on the firewall. Finally, I have configured the forward proxy (Squid) on the firewall to only allow access to fonts.googleapis.com, so that invoices render correctly, blocking all telemetry and other phone-home communication.