diff --git a/voucher-vault/.helmignore b/voucher-vault/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/voucher-vault/.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/voucher-vault/Chart.yaml b/voucher-vault/Chart.yaml new file mode 100644 index 0000000..cd94f6c --- /dev/null +++ b/voucher-vault/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: voucher-vault +description: A Helm chart to deploy VoucherVault on Kubernetes + +type: application + +version: 1.0.0+up1.27.4 +appVersion: "1.27.4" + +maintainers: + - name: jklein \ No newline at end of file diff --git a/voucher-vault/templates/database.secret.yaml b/voucher-vault/templates/database.secret.yaml new file mode 100644 index 0000000..778d51c --- /dev/null +++ b/voucher-vault/templates/database.secret.yaml @@ -0,0 +1,6 @@ +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-database-secret +spec: + itemPath: {{ required "You must provide a databaseSecret Reference" .Values.secrets.databaseSecretRef }} diff --git a/voucher-vault/templates/oidc.secret.yaml b/voucher-vault/templates/oidc.secret.yaml new file mode 100644 index 0000000..c905d7d --- /dev/null +++ b/voucher-vault/templates/oidc.secret.yaml @@ -0,0 +1,6 @@ +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret +spec: + itemPath: {{ required "You must provide a oidcSecret Reference" .Values.secrets.oidcSecretRef }} diff --git a/voucher-vault/templates/voucher-vault.ingress.yaml b/voucher-vault/templates/voucher-vault.ingress.yaml new file mode 100644 index 0000000..d2227e8 --- /dev/null +++ b/voucher-vault/templates/voucher-vault.ingress.yaml @@ -0,0 +1,25 @@ +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-ingress + annotations: + cert-manager.io/cluster-issuer: {{ required "A Cluster-Issuer must be provided" .Values.ingress.clusterIssuer}} +spec: + ingressClassName: nginx + rules: + - host: {{ required "A Domain/Host must be provided" .Values.ingress.domain }} + http: + paths: + - backend: + service: + name: {{ .Release.Name }}-{{ .Chart.Name }}-service + port: + name: http + path: / + pathType: Prefix + tls: + - hosts: + - {{ required "A Domain/Host must be provided" .Values.ingress.domain }} + secretName: tls-{{ .Release.Name }}-{{ .Chart.Name }}-ingress +{{- end }} \ No newline at end of file diff --git a/voucher-vault/templates/voucher-vault.pvc.yaml b/voucher-vault/templates/voucher-vault.pvc.yaml new file mode 100644 index 0000000..f7f59d4 --- /dev/null +++ b/voucher-vault/templates/voucher-vault.pvc.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.storage.amount }} + {{- if .Values.storage.storageClass }} + storageClassName: {{ .Values.storage.storageClass }} + {{- end }} \ No newline at end of file diff --git a/voucher-vault/templates/voucher-vault.secret.yaml b/voucher-vault/templates/voucher-vault.secret.yaml new file mode 100644 index 0000000..204a7ea --- /dev/null +++ b/voucher-vault/templates/voucher-vault.secret.yaml @@ -0,0 +1,6 @@ +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-secret +spec: + itemPath: {{ required "You must provide a voucherVaultSecret Reference" .Values.secrets.voucherVaultSecretRef }} diff --git a/voucher-vault/templates/voucher-vault.service.yaml b/voucher-vault/templates/voucher-vault.service.yaml new file mode 100644 index 0000000..a5cfa09 --- /dev/null +++ b/voucher-vault/templates/voucher-vault.service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-service +spec: + selector: + app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + ports: + - protocol: TCP + port: 80 + targetPort: http + name: http + type: ClusterIP diff --git a/voucher-vault/templates/voucher-vault.sfs.yaml b/voucher-vault/templates/voucher-vault.sfs.yaml new file mode 100644 index 0000000..781976c --- /dev/null +++ b/voucher-vault/templates/voucher-vault.sfs.yaml @@ -0,0 +1,127 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + labels: + app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs +spec: + replicas: 1 + serviceName: {{ .Release.Name }}-{{ .Chart.Name }}-service + selector: + matchLabels: + app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + template: + metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + labels: + app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + spec: + automountServiceAccountToken: false + securityContext: + {{- toYaml .Values.voucherVault.securityContext.pod | nindent 8 }} + containers: + - name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + image: "l4rm4nd/vouchervault:{{ .Chart.AppVersion }}" + imagePullPolicy: IfNotPresent + env: + {{- range $value := .Values.voucherVault.env }} + {{- if $value.value }} + - name: {{ $value.name }} + value: {{ tpl $value.value $ }} + {{- else if $value.valueFrom }} + {{- if $value.valueFrom.secretKeyRef }} + - name: {{ $value.name }} + valueFrom: + secretKeyRef: + name: {{ tpl $value.valueFrom.secretKeyRef.name $ }} + key: {{ tpl $value.valueFrom.secretKeyRef.key $ }} + {{- else if $value.valueFrom.configMapKeyRef }} + - name: {{ $value.name }} + valueFrom: + configMapKeyRef: + name: {{ tpl $value.valueFrom.configMapKeyRef.name $ }} + key: {{ tpl $value.valueFrom.configMapKeyRef.key $ }} + {{- end }} + {{- end }} + {{- end }} + ports: + {{- toYaml .Values.voucherVault.ports | nindent 12 }} + livenessProbe: + {{- toYaml .Values.voucherVault.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.voucherVault.readinessProbe | nindent 12 }} + startupProbe: + {{- toYaml .Values.voucherVault.startupProbe | nindent 12 }} + resources: + {{- toYaml .Values.voucherVault.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.voucherVault.securityContext.container | nindent 12 }} + volumeMounts: + {{- if .Values.voucherVault.storage.volumeMounts }} + {{- range $value := .Values.voucherVault.storage.volumeMounts }} + - name: {{ tpl $value.name $ }} + mountPath: {{ tpl $value.mountPath $ }} + {{- if $value.subPath }} + subPath: {{ tpl $value.subPath $ }} + {{- end }} + {{- if $value.subPathExpr }} + subPathExpr: {{ tpl $value.subPathExpr $ }} + {{- end }} + {{- if $value.readOnly }} + readOnly: {{ tpl $value.readOnly $ }} + {{- end }} + {{- end }} + {{- else }} + [] + {{- end }} + restartPolicy: Always + volumes: + {{- if .Values.voucherVault.storage.volumes }} + {{- range $value := .Values.voucherVault.storage.volumes }} + - name: {{ tpl $value.name $ }} + {{- if $value.persistentVolumeClaim }} + persistentVolumeClaim: + claimName: {{ tpl $value.persistentVolumeClaim.claimName $ }} + {{- if $value.persistentVolumeClaim.readOnly }} + readOnly: {{ tpl $value.persistentVolumeClaim.readOnly $ }} + {{- end }} + {{- else if $value.configMap }} + configMap: + name: {{ tpl $value.configMap.name $ }} + {{- if $value.configMap.defaultMode }} + defaultMode: {{ tpl $value.configMap.defaultMode $ }} + {{- end }} + {{- else if $value.secret }} + secret: + secretName: {{ tpl $value.secret.secretName $ }} + {{- if $value.secret.defaultMode }} + defaultMode: {{ tpl $value.secret.defaultMode $ }} + {{- end }} + {{- if $value.secret.optional }} + optional: {{ tpl $value.secret.optional $ }} + {{- end }} + {{- if $value.secret.items }} + items: + {{ range $item := $value.secret.items }} + - key: {{ tpl $item.key $ }} + {{- if $item.path }} + path: {{ tpl $item.path $ }} + {{- end }} + {{- if $item.mode }} + mode: {{ tpl $item.mode $ }} + {{- end }} + {{- end }} + {{- end }} + {{- else if $value.emptyDir }} + emptyDir: + {{- if $value.emptyDir.medium }} + medium: {{ tpl $value.emptyDir.medium $ }} + {{- end }} + {{- if $value.emptyDir.sizeLimit }} + sizeLimit: {{ tpl $value.emptyDir.sizeLimit $ }} + {{- end }} + {{- end }} + {{- end }} + {{- else }} + [] + {{- end }} \ No newline at end of file diff --git a/voucher-vault/values.yaml b/voucher-vault/values.yaml new file mode 100644 index 0000000..b103926 --- /dev/null +++ b/voucher-vault/values.yaml @@ -0,0 +1,178 @@ +secrets: + voucherVaultSecretRef: null + oidcSecretRef: null + databaseSecretRef: null + +voucherVault: + resources: + requests: + cpu: 0.1 + memory: 256Mi + ephemeral-storage: 10Mi + limits: + cpu: 1 + memory: 384Mi + ephemeral-storage: 100Mi + # TODO: Refine liness, readiness, startup probes + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + startupProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + securityContext: + pod: + runAsNonRoot: true + runAsUser: 20000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: Always + container: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + capabilities: + drop: + - ALL + add: [] + ports: + - containerPort: 8000 + protocol: TCP + name: http + env: + - name: DOMAIN + value: "{{ .Values.ingress.domain }}" + - name: SECURE_COOKIES + value: "True" + - name: SESSION_COOKIE_AGE + value: "30" + - name: SESSION_EXPIRE_AT_BROWSER_CLOSE + value: "True" + - name: EXPIRY_THRESHOLD_DAYS + value: "90" + - name: EXPIRY_LAST_NOTIFICATION_DAYS + value: "7" + - name: TZ + value: "UTC" + - name: PORT + value: "8000" + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-secret" + key: "secretKey" + - name: REDIS_URL + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-secret" + key: "redis-url" + - name: CELERY_WORKER_CONCURRENCY + value: "1" + - name: CELERY_WORKER_PREFETCH_MULTIPLIER + value: "1" + - name: OIDC_ENABLED + value: "True" + - name: OIDC_AUTOLOGIN + value: "True" + - name: OIDC_CREATE_USER + value: "True" + - name: OIDC_RP_SIGN_ALGO + value: "RS256" + - name: OIDC_OP_JWKS_ENDPOINT + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret" + key: "oidc-jwks-endpoint" + - name: OIDC_RP_CLIENT_ID + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret" + key: "client-id" + - name: OIDC_RP_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret" + key: "client-secret" + - name: OIDC_OP_AUTHORIZATION_ENDPOINT + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret" + key: "authorization-endpoint" + - name: OIDC_OP_TOKEN_ENDPOINT + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret" + key: "token-endpoint" + - name: OIDC_OP_USER_ENDPOINT + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-oidc-secret" + key: "user-endpoint" + - name: DB_ENGINE + value: "postgres" + - name: POSTGRES_HOST + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-db-secret" + key: "host" + - name: POSTGRES_PORT + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-db-secret" + key: "port" + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-db-secret" + key: "user" + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-db-secret" + key: "password" + - name: POSTGRES_DB + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-db-secret" + key: "database" + - name: ENV_FROM_CONFIGMAP + valueFrom: + configMapKeyRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-config-map" + key: "configMapKey" + storage: + volumes: + - name: voucher-vault-data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-{{ .Chart.Name }}-pvc" + volumeMounts: + - name: voucher-vault-data + mountPath: /opt/app/database + subPath: voucher-vault-data + +storage: + amount: 10Gi + storageClass: null + +ingress: + enabled: true + clusterIssuer: null + domain: null \ No newline at end of file