invoice-ninja: Deploy Invoice Ninja
Invoice Ninja is a small business management tool. Tabitha wants to use it for HLC. I am a bit concerned about the code quality of this application, and definitely alarmed at the data it send upstream, so I have tried to be extra careful with it. All privileges are revoked, including access to the Internet.etcd
parent
a5d186b461
commit
4e15a9d71d
|
@ -0,0 +1,13 @@
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
path: invoice-ninja
|
||||||
|
repoURL: https://git.pyrocufflink.blue/infra/kubernetes.git
|
||||||
|
targetRevision: master
|
|
@ -0,0 +1,72 @@
|
||||||
|
# Invoice Ninja
|
||||||
|
|
||||||
|
[Invoice Ninja][0] is a free invoice and customer management system. Tabitha
|
||||||
|
uses it to manage her tutoring and learning center billing and payments.
|
||||||
|
|
||||||
|
[0]: https://www.invoiceninja.org/
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
|
@ -0,0 +1,19 @@
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: invoiceninja.pyrocufflink.blue
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: invoice-ninja
|
||||||
|
port:
|
||||||
|
name: http
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cp -r /var/www/app/. /app
|
||||||
|
|
||||||
|
# The Invoice Ninja logo on PDF invoices is always loaded from upstream's
|
||||||
|
# server, despite the APP_URL setting.
|
||||||
|
sed -i \
|
||||||
|
-e 's@invoicing.co/images/new_logo.png@invoiceninja.pyrocufflink.blue/images/logo.png@' \
|
||||||
|
/app/app/Utils/HtmlEngine.php
|
||||||
|
|
||||||
|
chown -R invoiceninja:invoiceninja /app
|
||||||
|
|
||||||
|
if [ "$(stat -c %u /storage)" -ne "$(id -u invoiceninja)" ]; then
|
||||||
|
chown -R invoiceninja:invoiceninja /storage
|
||||||
|
chmod -R u=rwx,go= /storage
|
||||||
|
fi
|
|
@ -0,0 +1,16 @@
|
||||||
|
APP_LOGO=https://invoiceninja.pyrocufflink.blue/images/logo.png
|
||||||
|
APP_URL=https://invoiceninja.pyrocufflink.blue
|
||||||
|
TRUSTED_PROXIES=172.30.0.171,172.30.0.172,172.30.0.173
|
||||||
|
|
||||||
|
MAIL_MAILER=smtp
|
||||||
|
MAIL_HOST=mail.pyrocufflink.blue
|
||||||
|
MAIL_PORT=25
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDRESS=invoice-ninja@pyrocufflink.net
|
||||||
|
MAIL_FROM_NAME='Invoice Ninja'
|
||||||
|
|
||||||
|
EXPANDED_LOGGING=true
|
||||||
|
|
||||||
|
http_proxy=http://172.30.0.1:3128
|
||||||
|
https_proxy=http://172.30.0.1:3128
|
||||||
|
NO_PROXY=local,pyrocufflink.blue,localhost
|
|
@ -0,0 +1,218 @@
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteMany
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 8000
|
||||||
|
targetPort: http
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
type: ClusterIP
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
initContainers:
|
||||||
|
- name: init
|
||||||
|
image: &image docker.io/invoiceninja/invoiceninja:5.8.16
|
||||||
|
command:
|
||||||
|
- /init.sh
|
||||||
|
securityContext:
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- CHOWN
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsGroup: 0
|
||||||
|
runAsNonRoot: false
|
||||||
|
runAsUser: 0
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /app
|
||||||
|
name: app
|
||||||
|
- mountPath: /init.sh
|
||||||
|
name: init
|
||||||
|
subPath: init.sh
|
||||||
|
- mountPath: /storage
|
||||||
|
name: data
|
||||||
|
subPath: storage
|
||||||
|
containers:
|
||||||
|
- name: invoice-ninja
|
||||||
|
image: *image
|
||||||
|
env: &env
|
||||||
|
- name: DB_HOST
|
||||||
|
value: invoice-ninja-db
|
||||||
|
- name: DB_DATABASE
|
||||||
|
value: ninja
|
||||||
|
- name: DB_USERNAME
|
||||||
|
value: ninja
|
||||||
|
- name: DB_PASSWORD_FILE
|
||||||
|
value: /run/secrets/invoiceninja/db.password
|
||||||
|
- name: APP_KEY_FILE
|
||||||
|
value: /run/secrets/invoiceninja/app.key
|
||||||
|
- name: APP_CIPHER
|
||||||
|
value: AES-256-GCM
|
||||||
|
- name: TRUSTED_PROXIES
|
||||||
|
value: '*'
|
||||||
|
envFrom: &envFrom
|
||||||
|
- configMapRef:
|
||||||
|
name: invoice-ninja
|
||||||
|
readinessProbe: &probe
|
||||||
|
tcpSocket:
|
||||||
|
port: 9000
|
||||||
|
periodSeconds: 60
|
||||||
|
startupProbe:
|
||||||
|
<<: *probe
|
||||||
|
periodSeconds: 1
|
||||||
|
failureThreshold: 60
|
||||||
|
securityContext:
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
volumeMounts: &mounts
|
||||||
|
- mountPath: /run/secrets/invoiceninja
|
||||||
|
name: secrets
|
||||||
|
readOnly: true
|
||||||
|
- mountPath: /tmp
|
||||||
|
name: tmp
|
||||||
|
subPath: tmp
|
||||||
|
- mountPath: /var/www/app
|
||||||
|
name: app
|
||||||
|
- mountPath: /var/www/app/public/storage
|
||||||
|
name: data
|
||||||
|
subPath: storage-public
|
||||||
|
- mountPath: /var/www/app/storage
|
||||||
|
name: data
|
||||||
|
subPath: storage
|
||||||
|
- mountPath: /var/www/app/storage/logs
|
||||||
|
name: tmp
|
||||||
|
subPath: logs
|
||||||
|
- name: nginx
|
||||||
|
image: docker.io/library/nginx:1
|
||||||
|
ports:
|
||||||
|
- containerPort: 8000
|
||||||
|
name: http
|
||||||
|
readinessProbe: &probe
|
||||||
|
httpGet:
|
||||||
|
port: 8000
|
||||||
|
path: /health
|
||||||
|
periodSeconds: 60
|
||||||
|
startupProbe:
|
||||||
|
<<: *probe
|
||||||
|
periodSeconds: 1
|
||||||
|
failureThreshold: 30
|
||||||
|
securityContext:
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsUser: 101
|
||||||
|
runAsGroup: 101
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /etc/nginx/nginx.conf
|
||||||
|
name: nginx-conf
|
||||||
|
subPath: nginx.conf
|
||||||
|
readOnly: true
|
||||||
|
- mountPath: /run/nginx
|
||||||
|
name: run
|
||||||
|
subPath: nginx
|
||||||
|
- mountPath: /var/cache/nginx
|
||||||
|
name: nginx-cache
|
||||||
|
- mountPath: /var/www/app/public
|
||||||
|
name: app
|
||||||
|
subPath: public
|
||||||
|
readOnly: true
|
||||||
|
- mountPath: /var/www/app/public/storage
|
||||||
|
name: data
|
||||||
|
subPath: storage-public
|
||||||
|
readOnly: true
|
||||||
|
- name: cron
|
||||||
|
image: *image
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
cleanup() { kill -TERM $!; exit; }
|
||||||
|
trap cleanup TERM
|
||||||
|
while sleep 60; do php artisan schedule:run; done
|
||||||
|
env: *env
|
||||||
|
envFrom: *envFrom
|
||||||
|
securityContext:
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
volumeMounts: *mounts
|
||||||
|
enableServiceLinks: false
|
||||||
|
affinity:
|
||||||
|
podAffinity:
|
||||||
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- weight: 1
|
||||||
|
podAffinityTerm:
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
labelSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: app.kubernetes.io/name
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- invoice-ninja-db
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: True
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
volumes:
|
||||||
|
- name: app
|
||||||
|
emptyDir: {}
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: invoice-ninja
|
||||||
|
- name: init
|
||||||
|
configMap:
|
||||||
|
name: invoice-ninja-init
|
||||||
|
defaultMode: 0755
|
||||||
|
- name: nginx-cache
|
||||||
|
emptyDir: {}
|
||||||
|
- name: nginx-conf
|
||||||
|
configMap:
|
||||||
|
name: nginx
|
||||||
|
- name: run
|
||||||
|
emptyDir:
|
||||||
|
medium: Memory
|
||||||
|
- name: secrets
|
||||||
|
secret:
|
||||||
|
secretName: invoice-ninja
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
|
@ -0,0 +1,30 @@
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
namespace: invoice-ninja
|
||||||
|
|
||||||
|
labels:
|
||||||
|
- pairs:
|
||||||
|
app.kubernetes.io/instance: invoice-ninja
|
||||||
|
includeSelectors: false
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
|
- secrets.yaml
|
||||||
|
- network-policy.yaml
|
||||||
|
- mariadb.yaml
|
||||||
|
- invoice-ninja.yaml
|
||||||
|
- ingress.yaml
|
||||||
|
|
||||||
|
configMapGenerator:
|
||||||
|
- name: invoice-ninja-init
|
||||||
|
files:
|
||||||
|
- init.sh
|
||||||
|
|
||||||
|
- name: invoice-ninja
|
||||||
|
envs:
|
||||||
|
- invoice-ninja.env
|
||||||
|
|
||||||
|
- name: nginx
|
||||||
|
files:
|
||||||
|
- nginx.conf
|
|
@ -0,0 +1,111 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja-db
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja-db
|
||||||
|
app.kubernetes.io/component: mysql
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja-db
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja-db
|
||||||
|
app.kubernetes.io/component: mysql
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 3306
|
||||||
|
targetPort: mysql
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: invoice-ninja-db
|
||||||
|
app.kubernetes.io/component: mysql
|
||||||
|
type: ClusterIP
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja-db
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja-db
|
||||||
|
app.kubernetes.io/component: mysql
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
serviceName: invoice-ninja-db
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja-db
|
||||||
|
app.kubernetes.io/component: mysql
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja-db
|
||||||
|
app.kubernetes.io/component: mysql
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: mariadb
|
||||||
|
image: docker.io/library/mariadb:10.11.6
|
||||||
|
env:
|
||||||
|
- name: MARIADB_ROOT_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: mysql-root
|
||||||
|
key: password
|
||||||
|
- name: MARIADB_DATABASE
|
||||||
|
value: ninja
|
||||||
|
- name: MARIADB_USER
|
||||||
|
value: ninja
|
||||||
|
- name: MARIADB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: invoice-ninja
|
||||||
|
key: db.password
|
||||||
|
ports:
|
||||||
|
- containerPort: 3306
|
||||||
|
name: mysql
|
||||||
|
readinessProbe: &probe
|
||||||
|
tcpSocket:
|
||||||
|
port: mysql
|
||||||
|
periodSeconds: 60
|
||||||
|
startupProbe:
|
||||||
|
<<: *probe
|
||||||
|
periodSeconds: 1
|
||||||
|
failureThreshold: 60
|
||||||
|
securityContext:
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /run/mysqld
|
||||||
|
name: run
|
||||||
|
subPath: mysqld
|
||||||
|
- mountPath: /tmp
|
||||||
|
name: tmp
|
||||||
|
subPath: tmp
|
||||||
|
- mountPath: /var/lib/mysql
|
||||||
|
name: data
|
||||||
|
subPath: mysql
|
||||||
|
enableServiceLinks: false
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 3306
|
||||||
|
runAsGroup: 3306
|
||||||
|
fsGroup: 3306
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: invoice-ninja-db
|
||||||
|
- name: run
|
||||||
|
emptyDir:
|
||||||
|
medium: Memory
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
|
@ -0,0 +1,46 @@
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
spec:
|
||||||
|
egress:
|
||||||
|
- to:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
- to:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: kube-system
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
k8s-app: kube-dns
|
||||||
|
ports:
|
||||||
|
- port: 53
|
||||||
|
protocol: UDP
|
||||||
|
- port: 53
|
||||||
|
protocol: TCP
|
||||||
|
- to:
|
||||||
|
- ipBlock:
|
||||||
|
cidr: 172.30.0.12/32
|
||||||
|
ports:
|
||||||
|
- port: 25
|
||||||
|
- to:
|
||||||
|
- ipBlock:
|
||||||
|
cidr: 172.30.0.160/28
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
- port: 443
|
||||||
|
- to:
|
||||||
|
- ipBlock:
|
||||||
|
cidr: 172.30.0.1/32
|
||||||
|
ports:
|
||||||
|
- port: 3128
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
policyTypes:
|
||||||
|
- Egress
|
|
@ -0,0 +1,68 @@
|
||||||
|
worker_processes auto;
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log notice;
|
||||||
|
|
||||||
|
pid /run/nginx/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
upstream backend {
|
||||||
|
server 127.0.0.1:9000;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8000 default;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /var/www/app/public;
|
||||||
|
|
||||||
|
index index.php;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /health {
|
||||||
|
return 200 'UP';
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
|
fastcgi_pass backend;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_intercept_errors on;
|
||||||
|
fastcgi_buffer_size 16k;
|
||||||
|
fastcgi_buffers 4 16k;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /\.ht {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
location = /50x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
apiVersion: bitnami.com/v1alpha1
|
||||||
|
kind: SealedSecret
|
||||||
|
metadata:
|
||||||
|
name: mysql-root
|
||||||
|
namespace: invoice-ninja
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: mysql-root
|
||||||
|
app.kubernetes.io/component: mysql
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
encryptedData:
|
||||||
|
password: AgCWJhpMd/GmSzYZv+lofE9vQrTBewpeUO7rPnZGy5n9lvwwSin3DSzqeUCh37byCQ086VjIA1AqcJAXkur8dcZWXRAXY3H26rDoEMjGIyfrUEByCLhSNhL3sK7AcE14QWOuoxtUSbGk5RmYc+qvIw8b4l/dNpEnatLCRUeF9CefMgnTk2phVMlzkasvXjxAvxcBIvDg7DLcBOsenGg1xNG8j8wQ8flGsX6bWHmlt1+EBhyp+8PS+GyOT1BmjnVyQeo2mKwXm+FY9WHlEswypKTVQAsV6F0fUh9gIFoAdklOMwxbaW8321xLfQQvB4Qkbx8N0YJYy1jFNMF6plwcZhE7KwxXoNjW3GQhyGqTq/iFDi/oLJmAjxH9Vz8RPGT5IyOLRIkrQjCDhWrIHAEh1TUVF2BorrV8gIQOLV2xP2Lxa20KIjVZdosntWPc8bp8Br4RiP0JIK/ktRIMt+cCOwwrux8FhJe8WklujnaiZ1HX7G8dgidtjmUXYBxyNOZ9FMs2+c7D3bgqNQsTQ/NMlyP02l5oXUNzQpIVNbY4t+AT0ISn8NP9xDmLVwFw0Y3lJbx5rDtqaSFivkMOsp20l/JVUkeyig3Trm6OLh9FzI6Qr4Qo6fPBSrqKu1ieQPF76C80phrTWwtiK67i2LSmtb2zAvm3Hwj4X4Ag7HIi8F7zF7HjgOcmmS+6fIgyaIufE6IeQtwFwekbWGTHWDFddias9qHBuM1QcnQP/SJZkZrR/A==
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: mysql-root
|
||||||
|
namespace: invoice-ninja
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: bitnami.com/v1alpha1
|
||||||
|
kind: SealedSecret
|
||||||
|
metadata:
|
||||||
|
name: invoice-ninja
|
||||||
|
namespace: invoice-ninja
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: invoice-ninja
|
||||||
|
app.kubernetes.io/component: invoice-ninja
|
||||||
|
app.kubernetes.io/part-of: invoice-ninja
|
||||||
|
spec:
|
||||||
|
encryptedData:
|
||||||
|
app.key: AgA1p4ay2avNqkFYzLIB5VXxIjFBoZ8YZksf89Q81vCXrUs9mxd2/PuaRFeVu9WZwYXElT/esF2TV8P0JfXI3OJrRqDTSDnPwphTTxDYokFTvK01kCMwjaGWnINX02aFL+N5rCpETBw2Ptojq3SRltbIG5xe9e1sfe0ltWU2YiwQ7Zp9ekQKV2A5TZjZ55rtjO6C3HqBYWz/AnxiizWGgBAIxHuM4D0mPHOK4u/7tnfC3CIaD8UqINE1Dz3qfeDDgf0rzgVq+b6pbaoEquCkvvbng2rFfY/MVq3tb3gFGR6G1qWA+XKPJwBm9ODWcHxAliqzMsvja26izwtK8ci3VBmaL6mWcyuaWcfA4Wbjo2sb7srcS9COjUvuZf6NiTqehBpplUHkqoyFq9+QO2zfVUZ0PMltEEuTmoG6K0PSnzROUjim5FavnVCzKlvLv8ChG/GE3sYMWxBFfJCpnXhfPkNyghok+WGiTqc4pBIy3KnqbCs1xxZhfJ3UVvd1Rkq1xEW3VnEJSg76EDerj5J526Q6V6i4dbXHnxeeoHLUfIGapIa4Pv63DwxSaH72gJXrtrT4X6XgQjEuZofLvm2q8QToTxSezT4Fc76ojVOJF3ssPJMwC7mx8hcYDjy1cWkw5pNvLgj5QDAspAgKSMuoe0YQU2ES7oOtTHZ7peSAGz+8zoJNoy1gQCGH95uztt/tkCyYPl3JaYF0A9j8oOWxAfJJMVBcxszt9EqD+j246JofJM5Gnn5SpgrIyWngpiK3G2xiM68=
|
||||||
|
db.password: AgCtaz+QGcnKsKonIsAmT9oiZHd9cmj4ntKZ2vhH4cwDzCw0mHu3s1NKGTFxqVkrxyn0S2PbM+6gSXFyz6FtxI+nhb1gP6+QbSLmbJk35+sdC90WYj51r+k1tjugGaw8RpdAACxHSe7Vf8S0fPS5JFqrLR5HzmthoqNwzChcXjALCkArSXEG2kuQj0Dx72NTStYOQCPth0pPFytako3gHlSHFgGrjQ/g/hOnrP/booIFl4GMAZnJ5CgwI4XQKP4VvyK8msF93T278pyFr7fFFVSLrYrzpqFYfpKrHdiwirooed52Xlwpy6tfFsD64kZ0hDd5xbzXStNxDBkPOOgEu+KSbqUuGu5s/TmqOhxD394RU3AcwiFiQ5nASldeTmzVqC1et5Wx2IuD1b0hVcqGTNh/6uaZRSSchM7enja1v++nd9W7eYkCLdzxUjMC5+GDC/MwNYrrPoIOZAjOLii2UTH0WmvvTu8R79wRmgqCzLykS2VQWaBcMlVQsbyj/IjBbAhTwZ1bu0HKwDQbWckCFQTixR1k612U3gK8P/TsqspSkip9WtlaR3eSwrjqImTe4fhdLI8B6oEYm/D6h4ciXthkl2uYtyd3gwMf3TsHlrev+aOV0K98oaAPkV4EkbDTSQfZDEvAlFwoLScPHBIUahWKPADES7O37cFwkYPo8JOC2yLjYGOlWh997EUsnB/rk2cIdlbVaS8HIWwO1QdPWHelOgBYo1lcWesxRswB1SM7bQ==
|
Loading…
Reference in New Issue