diff --git a/chart/.helmignore b/chart/.helmignore new file mode 100644 index 0000000000000000000000000000000000000000..0e8a0eb36f4ca2c939201c0d54b5d82a1ea34778 --- /dev/null +++ b/chart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/chart/Chart.yaml b/chart/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4227288c0a757f8f347566dc0c9294d6ef31f4cb --- /dev/null +++ b/chart/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: Keys +description: Project to distribute SSH, OpenPGP, PKI, and Wireguard public keys + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.1.0" diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl new file mode 100644 index 0000000000000000000000000000000000000000..b628fc0f26439991347d72bec98258dab2f36a05 --- /dev/null +++ b/chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "k8s-templates.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "k8s-templates.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "k8s-templates.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "k8s-templates.labels" -}} +helm.sh/chart: {{ include "k8s-templates.chart" . }} +{{ include "k8s-templates.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "k8s-templates.selectorLabels" -}} +app.kubernetes.io/name: {{ include "k8s-templates.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "k8s-templates.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "k8s-templates.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/chart/templates/configmap.yaml b/chart/templates/configmap.yaml new file mode 100644 index 0000000000000000000000000000000000000000..031b4e704319395a3e06b68b4c42d897cb51babd --- /dev/null +++ b/chart/templates/configmap.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-nginx-config +data: + k8s-templates.conf: | + server { + client_max_body_size 25m; + listen 80; + location /static { + root /var/webcontent; + } + location /--healthz { + add_header Content-Type text/plain; + return 200 'All systems go!'; + } + location / { + include uwsgi_params; + uwsgi_pass {{ .Release.Name }}-backend-service:80; + uwsgi_param HTTP_X_FORWARDED_PROTO https; + } + } + diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7c00fd44ea1d682532d5687ca81c6019b92e08a3 --- /dev/null +++ b/chart/templates/deployment.yaml @@ -0,0 +1,207 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-backend + labels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: backend +spec: + replicas: {{ .Values.backend.replicas }} + selector: + matchLabels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: backend + template: + metadata: + labels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: backend + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: backend + image: "{{ .Values.backend.repository }}:{{ .Values.backend.tag }}" + ports: + - containerPort: 8080 + env: + - name: "DB_PASSWORD" + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-db-secret" + key: password + - name: DB_HOST + value: "{{ .Release.Name }}-database-service" + - name: COMPRESS + value: "1" + - name: PRODUCTION + value: "1" + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-app-secret" + key: password + - name: SUPER_EMAIL + value: {{ .Values.super.email | quote }} + - name: SUPER_USERNAME + value: {{ .Values.super.username | quote }} + - name: SUPER_PASSWORD + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-super-secret" + key: password + resources: + requests: + memory: 100M + cpu: 100m + limits: + memory: 2000M + cpu: 2000m + readinessProbe: + tcpSocket: + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 30 + + livenessProbe: + tcpSocket: + port: 8080 + initialDelaySeconds: 120 + periodSeconds: 60 + volumeMounts: + - mountPath: /app/webcontent/ + name: static-files + volumes: + - name: static-files + persistentVolumeClaim: + claimName: {{ .Release.Name }}-static-files-pvc +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-postgres + labels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: database +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: database + template: + metadata: + labels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: database + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: postgres + image: docker.sauerburger.com/postgres:14.0 + ports: + - containerPort: 5432 + env: + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-secret + key: password + - name: POSTGRES_USER + value: webapp + - name: POSTGRES_DB + value: keys + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + resources: + requests: + memory: 500M + cpu: 100m + limits: + memory: 2000M + cpu: 2000m + readinessProbe: + tcpSocket: + port: 5432 + initialDelaySeconds: 30 + periodSeconds: 30 + + livenessProbe: + tcpSocket: + port: 5432 + initialDelaySeconds: 120 + periodSeconds: 30 + volumeMounts: + - mountPath: /var/lib/postgresql/data + name: vol + volumes: + - name: vol + persistentVolumeClaim: + claimName: {{ .Release.Name }}-database-pvc +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-webserver + labels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: webserver +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: webserver + template: + metadata: + labels: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: webserver + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: backend + image: docker.sauerburger.com/nginx:1.21.5 + ports: + - containerPort: 80 + resources: + requests: + memory: 100M + cpu: 100m + limits: + memory: 2000M + cpu: 2000m + readinessProbe: + httpGet: + path: "/--healthz" + port: 80 + initialDelaySeconds: 15 + periodSeconds: 30 + livenessProbe: + httpGet: + path: "/--healthz" + port: 80 + initialDelaySeconds: 120 + periodSeconds: 60 + volumeMounts: + - mountPath: /var/webcontent/ + name: static-files + readOnly: true + - mountPath: /etc/nginx/conf.d + name: config + readOnly: true + volumes: + - name: static-files + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-static-files-pvc" + - name: config + configMap: + name: {{ .Release.Name }}-nginx-config diff --git a/chart/templates/ingress.yaml b/chart/templates/ingress.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7da253d2009c18687e0fa482b23756b816024b0f --- /dev/null +++ b/chart/templates/ingress.yaml @@ -0,0 +1,69 @@ +{{- if .Values.ingress.host -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + {{ .Values.ingress.tlsIssuerType}}: {{ .Values.ingress.tlsIssuer | quote }} + name: {{ .Release.Name }}-keys-ingress +spec: + ingressClassName: nginx + rules: + - host: {{ .Values.ingress.host | quote }} + http: + paths: + - backend: + service: + name: {{ .Release.Name }}-web-service + port: + number: 80 + path: / + pathType: Prefix + tls: + - hosts: + - {{ .Values.ingress.host | quote }} + secretName: {{ .Release.Name }}-keys-tls-secret +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-keys-hkp-ingress +spec: + ingressClassName: nginx-hkp + rules: + - host: {{ .Values.ingress.host | quote }} + http: + paths: + - backend: + service: + name: {{ .Release.Name }}-web-service + port: + number: 80 + path: /pks/lookup + pathType: Exact +{{- end -}} +{{- range $openpgpkey := .Values.ingress.openpgpkeys }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + {{ $.Values.ingress.tlsIssuerType}}: {{ $.Values.ingress.tlsIssuer | quote }} + name: {{ $.Release.Name }}-{{ .name }}-ingress +spec: + ingressClassName: nginx + rules: + - host: {{ .host | quote }} + http: + paths: + - backend: + service: + name: {{ $.Release.Name }}-web-service + port: + number: 80 + path: /.well-known/openpgpkey/ + pathType: ImplementationSpecific + tls: + - hosts: + - {{ .host | quote }} + secretName: {{ $.Release.Name }}-{{ .name }}-tls-secret +{{- end }} \ No newline at end of file diff --git a/chart/templates/pvc.yaml b/chart/templates/pvc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..410e9bb22775b328463c8cd53273a6852bdb7ecb --- /dev/null +++ b/chart/templates/pvc.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-database-pvc +spec: + accessModes: + - ReadWriteMany + {{- if .Values.storage.database.persistentStorageClass }} + storageClassName: {{ .Values.storage.database.persistentStorageClass | quote }} + {{- end}} + resources: + requests: + storage: {{ .Values.storage.database.requestSize | quote }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-static-files-pvc +spec: + accessModes: + - ReadWriteMany + {{- if .Values.storage.staticFiles.persistentStorageClass }} + storageClassName: {{ .Values.storage.staticFiles.persistentStorageClass | quote }} + {{- end }} + resources: + requests: + storage: 100Mi diff --git a/chart/templates/secrets.yaml b/chart/templates/secrets.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1a8445a3130aa3958b891b3889007c8b3a6e153d --- /dev/null +++ b/chart/templates/secrets.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .Release.Name }}-app-secret +data: + {{- if .Release.IsInstall }} + password: {{ randAlphaNum 20 | b64enc }} + {{- else }} + password: {{ (lookup "v1" "Secret" .Release.Namespace (print .Release.Name "-app-secret")).data.password }} + {{- end }} +--- +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .Release.Name }}-db-secret +data: + {{- if .Release.IsInstall }} + password: {{ randAlphaNum 20 | b64enc }} + {{- else }} + password: {{ (lookup "v1" "Secret" .Release.Namespace (print .Release.Name "-db-secret")).data.password }} + {{- end }} +--- +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .Release.Name }}-super-secret +data: + {{- if .Release.IsInstall }} + password: {{ randAlphaNum 20 | b64enc }} + {{- else }} + password: {{ (lookup "v1" "Secret" .Release.Namespace (print .Release.Name "-super-secret")).data.password }} + {{- end }} diff --git a/chart/templates/services.yaml b/chart/templates/services.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bfdb993e2c55fd4b925a5c434654ee0d5bd67f77 --- /dev/null +++ b/chart/templates/services.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-database-service +spec: + selector: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: database + ports: + - protocol: TCP + port: 5432 +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-backend-service +spec: + selector: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: backend + ports: + - protocol: TCP + port: 80 + targetPort: 8080 +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-web-service +spec: + selector: + app.kubernetes.io/name: {{ .Release.Name }} + app.kubernetes.io/component: webserver + ports: + - protocol: TCP + port: 80 diff --git a/chart/values.yaml b/chart/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a2bc82f3b67b3978bfe36a804fcaf6c3bd882355 --- /dev/null +++ b/chart/values.yaml @@ -0,0 +1,33 @@ + +ingress: + host: "keys.preview.sauerburger.com" # Leave empty to disable ingress + tlsIssuer: "letsencrypt-production" + tlsIssuerType: "cert-manager.io/cluster-issuer" + openpgpkeys: + - name: scom + host: "openpgpkey.sauerburger.com" + - name: sio + host: "openpgpkey.sauerburger.io" + +super: + email: "frank@sauerburger.com" + username: "esel" + +database: + user: webapp + name: keys + +backend: + replicas: 2 + repository: gitlab.sauerburger.com:5049/frank/sauerburger-keys/keys + tag: 0.2.0-rc.1 + +imagePullSecrets: [] + +storage: + database: + persistentStorageClass: "" # Leave empty to use default + requestSize: 100Mi + + staticFiles: + persistentStorageClass: "" # Leave empty to use default