Introduction of Tornjak to SPIRE Server helm charts (#144)

This PR introduces a simplified version of
[Tornjak](https://github.com/spiffe/tornjak) to support UI and SPIRE
control plane.

It extends the `/charts/spire-server` sub-chart by injecting *tornjak*
container to the *spire-server* pod. Tornjak image consists of Tornjak
API (Tornjak Backend), Tornjak UI (Frontend), and database for storing
Tornjak specific information.

Tornjak Backend communicates with SPIRE API via SPIRE Server socket. 

Since Tornjak UI (Frontend) is a React code that renders in a browser,
it needs to communicate with Tornjak APIs, and that requires
communication ports to be open, either via Ingress (in Cloud deployment)
or via port forwarding in local deployments (e.g. kind, minikube etc).
Typically port 10000 is used for HTTP connection to Backend, and port
3000 for the HTTP connection to Frontend.

End user management, TLS, and mTLS connections will be addressed by
future PRs.

This PR resolves issue #31

---------

Signed-off-by: Mariusz Sabath <[email protected]>
Signed-off-by: Marco Franssen <[email protected]>
Co-authored-by: Kevin Fox <[email protected]>
Co-authored-by: Marco Franssen <[email protected]>
Co-authored-by: Pete Cable <[email protected]>
Co-authored-by: Dennis Gove <[email protected]>
This commit is contained in:
Mariusz Sabath
2023-03-22 13:09:09 -04:00
committed by GitHub
co-authored by Kevin Fox Marco Franssen Pete Cable Dennis Gove
parent b25dc773bc
commit 05d0f4778d
8 changed files with 219 additions and 1 deletions
@@ -89,6 +89,14 @@ A Helm chart to install the SPIRE server.
| telemetry.prometheus.enabled | bool | `false` | |
| tolerations | list | `[]` | |
| topologySpreadConstraints | list | `[]` | |
| tornjak.config.backend.dataStore.driver | string | `"sqlite3"` | |
| tornjak.config.backend.dataStore.file | string | `"/run/spire/data/tornjak.sqlite3"` | |
| tornjak.config.frontend.apiServerURL | string | `"http://localhost:10000"` | |
| tornjak.enabled | bool | `true` | |
| tornjak.image.pullPolicy | string | `"IfNotPresent"` | |
| tornjak.image.registry | string | `"ghcr.io"` | |
| tornjak.image.repository | string | `"spiffe/tornjak"` | |
| tornjak.image.version | string | `"latest"` | |
| trustDomain | string | `"example.org"` | |
| upstreamAuthority.certManager.enabled | bool | `false` | |
| upstreamAuthority.certManager.issuer_group | string | `"cert-manager.io"` | |
@@ -4,3 +4,21 @@ Installed {{ .Chart.Name }}…
kubectl exec -n {{ .Release.Namespace }} {{ include "spire-server.fullname" . }}-0 -c spire-server -- \
spire-server entry show
{{- if eq (.Values.tornjak.enabled | toString) "true" }}
### WARNING ###
This Tornjak is configured without authentication and it is intended for
testing only. Please do not use this version in production.
Tornjak APIs (Backend):
kubectl -n {{ include "spire-server.namespace" . }} port-forward {{ include "spire-server.fullname" . }}-0 10000:10000
Tornjak UI (Frontend):
kubectl -n {{ include "spire-server.namespace" . }} port-forward {{ include "spire-server.fullname" . }}-0 3000:3000
Tornjak API access: {{ include "tornjak.apiURL" . }}
Tornjak UI access: {{ include "tornjak.FrontendURL" . }}
Installed {{ include "spire-tornjak.fullname" . }}…
{{- end }}
@@ -84,7 +84,6 @@ Create the name of the service account to use
{{- end -}}
{{- end }}
{{- define "spire-server.upstream-ca-secret" -}}
{{- $root := . }}
{{- with .Values.upstreamAuthority.disk -}}
@@ -111,3 +110,35 @@ Create the name of the service account to use
[{{ printf "%s:%s-agent" .Release.Namespace .Release.Name | quote }}]
{{- end }}
{{- end }}
{{/*
Tornjak specific section
*/}}
{{- define "spire-tornjak.fullname" -}}
{{ include "spire-server.fullname" . | trimSuffix "-server" }}-tornjak
{{- end }}
{{- define "spire-tornjak.config" -}}
{{ include "spire-tornjak.fullname" . }}-config
{{- end }}
{{- define "spire-tornjak.frontend" -}}
{{ include "spire-tornjak.fullname" . }}-fe
{{- end }}
{{- define "spire-tornjak.backend" -}}
{{ include "spire-tornjak.fullname" . }}-be
{{- end }}
{{/*
Create URL for accessing Tornjak Backend
*/}}
{{- define "tornjak.apiURL" -}}
{{- default .Values.tornjak.config.frontend.apiServerURL }}
{{- end }}
{{/*
Create URL for accessing Tornjak Frontend
*/}}
{{- define "tornjak.FrontendURL" -}}
{{- $feurl := print "http://localhost:3000" }}
{{- $feurl }}
{{- end }}
@@ -26,3 +26,36 @@ spec:
{{- end }}
selector:
{{- include "spire-server.selectorLabels" . | nindent 4 }}
{{- if eq (.Values.tornjak.enabled | toString) "true" }}
---
apiVersion: v1
kind: Service
metadata:
namespace: {{ include "spire-server.namespace" . }}
name: {{ include "spire-tornjak.frontend" . }}
spec:
type: {{ .Values.service.type }} # ClusterIP
selector:
{{- include "spire-server.selectorLabels" . | nindent 4 }}
ports:
- name: {{ include "spire-tornjak.frontend" . }}
port: 3000
targetPort: 3000
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
namespace: {{ include "spire-server.namespace" . }}
name: {{ include "spire-tornjak.backend" . }}
spec:
type: {{ .Values.service.type }} # ClusterIP
selector:
{{- include "spire-server.selectorLabels" . | nindent 4 }}
ports:
- name: {{ include "spire-tornjak.backend" . }}
port: 10000
targetPort: 10000
protocol: TCP
{{- end }}
@@ -1,5 +1,6 @@
{{- $configSum := (include (print $.Template.BasePath "/configmap.yaml") . | sha256sum) }}
{{- $configSum2 := (include (print $.Template.BasePath "/controller-manager-configmap.yaml") . | sha256sum) }}
{{- $configSumTornjak := (include (print $.Template.BasePath "/tornjak-config.yaml") . | sha256sum) }}
{{- $fullname := include "spire-server.fullname" . }}
apiVersion: apps/v1
kind: StatefulSet
@@ -21,6 +22,7 @@ spec:
annotations:
checksum/config: {{ $configSum }}
checksum/config2: {{ $configSum2 }}
checksum/configTornjak: {{ $configSumTornjak }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
@@ -144,6 +146,51 @@ spec:
mountPath: /tmp
readOnly: false
{{- end }}
{{- if eq (.Values.tornjak.enabled | toString) "true" }}
- name: tornjak
securityContext:
{{- toYaml .Values.controllerManager.securityContext | nindent 12 }}
image: {{ template "spire-server.image" (dict "appVersion" $.Chart.AppVersion "image" .Values.tornjak.image) }}
imagePullPolicy: {{ .Values.tornjak.image.pullPolicy }}
startupProbe:
httpGet:
scheme: HTTP
port: 3000
failureThreshold: 6
initialDelaySeconds: 60
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 10
env:
{{- if .Values.tornjak.config.frontend }}
- name: REACT_APP_API_SERVER_URI
value: {{ include "tornjak.apiURL" . | required "Either .Values.tornjak.config.backend.ingress or .Values.tornjak.config.frontend.apiServerURL is required." }}
{{- end }}
args:
- -c
- /run/spire/config/server.conf
- -t
- /run/spire/tornjak-config/server.conf
ports:
- containerPort: 3000
protocol: TCP
volumeMounts:
- name: {{ include "spire-tornjak.config" . }}
mountPath: /run/spire/tornjak-config
- name: spire-server-socket
mountPath: /tmp/spire-server/private
readOnly: true
- name: spire-config
mountPath: /run/spire/config
readOnly: true
{{- if eq (.Values.dataStorage.enabled | toString) "true" }}
- name: spire-data
mountPath: /run/spire/data
readOnly: false
{{- end }}
{{- end }}
{{- if gt (len .Values.extraContainers) 0 }}
{{- toYaml .Values.extraContainers | nindent 8 }}
{{- end }}
@@ -181,6 +228,14 @@ spec:
configMap:
name: {{ include "spire-controller-manager.fullname" . }}
{{- end }}
{{- if eq (.Values.tornjak.enabled | toString) "true" }}
{{- if .Values.tornjak.config }}
- name: {{ include "spire-tornjak.config" . }}
configMap:
defaultMode: 420
name: {{ include "spire-tornjak.config" . }}
{{- end }}
{{- end }}
{{- if gt (len .Values.extraVolumes) 0 }}
{{- toYaml .Values.extraVolumes | nindent 8 }}
{{- end }}
@@ -0,0 +1,27 @@
{{- if eq (.Values.tornjak.enabled | toString) "true" }}
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "spire-tornjak.fullname" . }}-test-connection"
namespace: {{ include "spire-server.namespace" . }}
labels:
annotations:
"helm.sh/hook": test
spec:
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 4 }}
containers:
- name: wget-tornjak-backend
image: busybox
command: ['wget']
args: ['--no-check-certificate', '-O', '/dev/null', 'http://{{ include "spire-tornjak.backend" . }}:10000/api/tornjak/serverinfo']
securityContext:
{{- toYaml .Values.securityContext | nindent 8 }}
- name: wget-tornjak-frontend
image: busybox
command: ['wget']
args: ['--no-check-certificate', '-O', '/dev/null', 'http://{{ include "spire-tornjak.frontend" . }}:3000']
securityContext:
{{- toYaml .Values.securityContext | nindent 8 }}
restartPolicy: Never
{{- end }}
@@ -0,0 +1,23 @@
{{- if eq (.Values.tornjak.enabled | toString) "true" }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "spire-tornjak.config" . }}
namespace: {{ include "spire-server.namespace" . }}
data:
server.conf: |
server {
metadata = "insert metadata"
}
plugins {
{{- if .Values.tornjak.config.backend.dataStore }}
DataStore "sql" {
plugin_data {
drivername = "{{ .Values.tornjak.config.backend.dataStore.driver }}"
filename = "{{ .Values.tornjak.config.backend.dataStore.file }}"
}
}
{{- end }}
}
{{- end }}
@@ -203,3 +203,26 @@ nodeAttestor:
k8sPsat:
enabled: true
serviceAccountAllowList: []
# tornjak - Tornjak specific configuration
tornjak:
enabled: true
# image - Tornjak image (frontend + backend) if not separated above
image: # ghcr.io/spiffe/tornjak
registry: ghcr.io
repository: spiffe/tornjak
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
# TODO we should use a specific Tornjak version instead of 'latest'
version: "latest"
config:
# Front-end specific configuration:
frontend:
# apiServerURL - URL of the Tornjak back-end
apiServerURL: "http://localhost:10000" # 👈 Use it for minikube or kind
# Back-end specific configuration
backend:
# dataStore - persistent DB for storing Tornjak specific information
dataStore:
driver: "sqlite3"
file: "/run/spire/data/tornjak.sqlite3"