Add option to configure TLS/mTLS endpoint for Tornjak (#338)

Co-authored-by: Marco Franssen <[email protected]>
This commit is contained in:
Mariusz Sabath
2023-07-19 14:32:32 +02:00
committed by GitHub
co-authored by Marco Franssen
parent f461a01701
commit f05cb4fe1e
12 changed files with 265 additions and 22 deletions
+6 -2
View File
@@ -398,7 +398,10 @@ Now you can interact with the Spire agent socket from your own application. The
| spire-server.tools.kubectl.image.tag | string | `""` | Overrides the image tag |
| spire-server.tools.kubectl.image.version | string | `""` | This value is deprecated in favor of tag. (Will be removed in a future release) |
| spire-server.topologySpreadConstraints | list | `[]` | |
| spire-server.tornjak.config.dataStore | object | `{"driver":"sqlite3","file":"/run/spire/data/tornjak.sqlite3"}` | persistent DB for storing Tornjak specific information |
| spire-server.tornjak.config.dataStore | object | `{"driver":"sqlite3","file":"/run/spire/data/tornjak.sqlite3"}` | Persistent DB for storing Tornjak specific information |
| spire-server.tornjak.config.tlsSecret | string | `"tornjak-tls-secret"` | Name of the secret containing server side key and certificate for TLS verification (required for `tls` or `mtls` connectionType) |
| spire-server.tornjak.config.userCA.name | string | `"tornjak-user-ca"` | |
| spire-server.tornjak.config.userCA.type | string | `"Secret"` | Type of delivery for the user CA for mTLS client verification options are `Secret` or `ConfigMap` (required for `mtls` connectionType) |
| spire-server.tornjak.enabled | bool | `false` | Deploys Tornjak API (backend) (Not for production) |
| spire-server.tornjak.image.pullPolicy | string | `"IfNotPresent"` | The Tornjak image pull policy |
| spire-server.tornjak.image.registry | string | `"ghcr.io"` | The OCI registry to pull the Tornjak image from |
@@ -407,7 +410,8 @@ Now you can interact with the Spire agent socket from your own application. The
| spire-server.tornjak.image.version | string | `""` | This value is deprecated in favor of tag. (Will be removed in a future release) |
| spire-server.tornjak.resources | object | `{}` | |
| spire-server.tornjak.service.annotations | object | `{}` | |
| spire-server.tornjak.service.port | int | `10000` | |
| spire-server.tornjak.service.portHttp | int | `10080` | |
| spire-server.tornjak.service.portHttps | int | `10443` | |
| spire-server.tornjak.service.type | string | `"ClusterIP"` | |
| spire-server.tornjak.startupProbe.failureThreshold | int | `3` | |
| spire-server.tornjak.startupProbe.initialDelaySeconds | int | `5` | Initial delay seconds for |
+59 -2
View File
@@ -28,6 +28,59 @@ A Helm chart to install the SPIRE server.
* <https://github.com/spiffe/helm-charts/tree/main/charts/spire>
## Tornjak
Tornjak is the UI and Control Plane for SPIRE [https://github.com/spiffe/tornjak](https://github.com/spiffe/tornjak) and it is composed of two components:
* Backend (this chart) - Tornjak APIs that extend SPIRE APIs with Control Plane functionality
* [Frontend](../tornjak-frontend/README.md) - Tornjak UI
When Tornjak is enabled, it is exposed on both http and https (if TLS server certs are configured). Tornjak handles a permanent redirect from `http` to `https` to ensure users always use the https endpoint.
In addition, you can configure a `client certificate authority`, this will make Tornjak backend verify Client certificates signed by this authority to enable mTLS authentication.
**Warning**: For production, we recommend configuring TLS certificates and client CA to protect Tornjak from unauthorized access.
### Tornjak with TLS Connection Type
TLS connection requires Tornjak to have access to TLS key and certificate.
Complete instruction on creating your own TLS certificate can be found [here](https://github.com/spiffe/tornjak/blob/main/examples/tls_mtls/README.md).
TLS Certificate and the private key must be provided to Tornjak via *TLS Secret*. Prior to deploying this Helm chart, create TLS Secret in the deployment namespace (e.g. `spire-server`)
```console
kubectl -n spire-server create secret tls tornjak-tls-secret --cert=client.crt --key=client.key
```
Once the charts are deployed, you can test the TLS connection with the following command (assuming localhost):
```console
curl --cacert CA/rootCA.crt https://localhost:10443
```
### Tornjak with mTLS Connection Type
mTLS connection allows Tornjak server validation by client and Tornjak client validation by Tornjak server. The server validation is identical to above TLS. Follow the steps to create
TLS secret with key and the certificate.
Additionally, you must provide the user CA to Tornjak server via `Secret` or `ConfigMap`.
Follow the steps to [create user CA for mTLS](https://github.com/spiffe/tornjak/blob/main/examples/tls_mtls/README.md), then create a *Secret* (or *ConfigMap*) prior to deploying this Helm chart.
Here is an example using a *Secret* in `spire-server` namespace:
```console
kubectl -n spire-server create secret generic tornjak-user-ca --from-file=ca.crt="CA/rootCA.crt"
```
Once the charts are deployed, you can test the mTLS connection with the following command (assuming localhost):
```console
curl --cacert CA/rootCA.crt --key client.key --cert client.crt https://localhost:10443
```
### Tornjak with HTTP Connection Type
In order to run Tornjak with simple HTTP Connection only, make sure you don't create any `Secrets` or `ConfigMaps` listed above.
## Values
| Key | Type | Default | Description |
@@ -145,7 +198,10 @@ A Helm chart to install the SPIRE server.
| tools.kubectl.image.tag | string | `""` | Overrides the image tag |
| tools.kubectl.image.version | string | `""` | This value is deprecated in favor of tag. (Will be removed in a future release) |
| topologySpreadConstraints | list | `[]` | |
| tornjak.config.dataStore | object | `{"driver":"sqlite3","file":"/run/spire/data/tornjak.sqlite3"}` | persistent DB for storing Tornjak specific information |
| tornjak.config.dataStore | object | `{"driver":"sqlite3","file":"/run/spire/data/tornjak.sqlite3"}` | Persistent DB for storing Tornjak specific information |
| tornjak.config.tlsSecret | string | `"tornjak-tls-secret"` | Name of the secret containing server side key and certificate for TLS verification (required for `tls` or `mtls` connectionType) |
| tornjak.config.userCA.name | string | `"tornjak-user-ca"` | |
| tornjak.config.userCA.type | string | `"Secret"` | Type of delivery for the user CA for mTLS client verification options are `Secret` or `ConfigMap` (required for `mtls` connectionType) |
| tornjak.enabled | bool | `false` | Deploys Tornjak API (backend) (Not for production) |
| tornjak.image.pullPolicy | string | `"IfNotPresent"` | The Tornjak image pull policy |
| tornjak.image.registry | string | `"ghcr.io"` | The OCI registry to pull the Tornjak image from |
@@ -154,7 +210,8 @@ A Helm chart to install the SPIRE server.
| tornjak.image.version | string | `""` | This value is deprecated in favor of tag. (Will be removed in a future release) |
| tornjak.resources | object | `{}` | |
| tornjak.service.annotations | object | `{}` | |
| tornjak.service.port | int | `10000` | |
| tornjak.service.portHttp | int | `10080` | |
| tornjak.service.portHttps | int | `10443` | |
| tornjak.service.type | string | `"ClusterIP"` | |
| tornjak.startupProbe.failureThreshold | int | `3` | |
| tornjak.startupProbe.initialDelaySeconds | int | `5` | Initial delay seconds for |
@@ -23,6 +23,59 @@
{{ template "chart.requirementsSection" . }}
## Tornjak
Tornjak is the UI and Control Plane for SPIRE [https://github.com/spiffe/tornjak](https://github.com/spiffe/tornjak) and it is composed of two components:
* Backend (this chart) - Tornjak APIs that extend SPIRE APIs with Control Plane functionality
* [Frontend](../tornjak-frontend/README.md) - Tornjak UI
When Tornjak is enabled, it is exposed on both http and https (if TLS server certs are configured). Tornjak handles a permanent redirect from `http` to `https` to ensure users always use the https endpoint.
In addition, you can configure a `client certificate authority`, this will make Tornjak backend verify Client certificates signed by this authority to enable mTLS authentication.
**Warning**: For production, we recommend configuring TLS certificates and client CA to protect Tornjak from unauthorized access.
### Tornjak with TLS Connection Type
TLS connection requires Tornjak to have access to TLS key and certificate.
Complete instruction on creating your own TLS certificate can be found [here](https://github.com/spiffe/tornjak/blob/main/examples/tls_mtls/README.md).
TLS Certificate and the private key must be provided to Tornjak via *TLS Secret*. Prior to deploying this Helm chart, create TLS Secret in the deployment namespace (e.g. `spire-server`)
```console
kubectl -n spire-server create secret tls tornjak-tls-secret --cert=client.crt --key=client.key
```
Once the charts are deployed, you can test the TLS connection with the following command (assuming localhost):
```console
curl --cacert CA/rootCA.crt https://localhost:10443
```
### Tornjak with mTLS Connection Type
mTLS connection allows Tornjak server validation by client and Tornjak client validation by Tornjak server. The server validation is identical to above TLS. Follow the steps to create
TLS secret with key and the certificate.
Additionally, you must provide the user CA to Tornjak server via `Secret` or `ConfigMap`.
Follow the steps to [create user CA for mTLS](https://github.com/spiffe/tornjak/blob/main/examples/tls_mtls/README.md), then create a *Secret* (or *ConfigMap*) prior to deploying this Helm chart.
Here is an example using a *Secret* in `spire-server` namespace:
```console
kubectl -n spire-server create secret generic tornjak-user-ca --from-file=ca.crt="CA/rootCA.crt"
```
Once the charts are deployed, you can test the mTLS connection with the following command (assuming localhost):
```console
curl --cacert CA/rootCA.crt --key client.key --cert client.crt https://localhost:10443
```
### Tornjak with HTTP Connection Type
In order to run Tornjak with simple HTTP Connection only, make sure you don't create any `Secrets` or `ConfigMaps` listed above.
{{ template "chart.valuesSection" . }}
----------------------------------------------
@@ -15,9 +15,23 @@ Tornjak runs without authentication and is therefore NOT suitable to run in prod
Only use in test environments!
Access Tornjak:
kubectl -n {{ include "spire-server.namespace" . }} port-forward service/{{ include "spire-tornjak.servicename" . }} {{ .Values.tornjak.service.portHttp }}:10080
{{- if eq (include "spire-tornjak.connectionType" .) "http" }}
Open browser to: http://localhost:{{ .Values.tornjak.service.portHttp }}
{{- else if eq (include "spire-tornjak.connectionType" .) "tls" }}
Open browser to: https://localhost:{{ .Values.tornjak.service.portHttps }}
kubectl -n {{ include "spire-server.namespace" . }} port-forward service/{{ include "spire-tornjak.backend" . }} {{ .Values.tornjak.service.port }}:10000
*** NOTE: You might get a security warning if using self-signed certificate
or use curl:
Open browser to: http://localhost:{{ .Values.tornjak.service.port }}
curl --cacert certs/ca.crt https://localhost:{{ .Values.tornjak.service.portHttps }}
{{- if eq (include "spire-tornjak.connectionType" .) "mtls" }}
Or provide a client certificate and key to use mTLS authentication:
curl --cacert certs/ca.crt --key client.key --cert client.crt https://localhost:{{ .Values.tornjak.service.portHttps }}
{{- end }}
{{- else }}
ERROR! Incorrect value selected for "Values.tornjak.config.connectionType"
{{- end }}
{{- end }}
@@ -168,3 +168,29 @@ Tornjak specific section
{{- define "spire-tornjak.backend" -}}
{{ include "spire-tornjak.fullname" . }}-backend
{{- end }}
{{/*
Tornjak automatically determines the connection type based on provided configuration.
When TLS Secret is provided, it enables TLS connection.
When TLS Secret and User CA Secret (or ConfigMap) are provided, it enables mTLS connection.
Otherwise it starts HTTP Connection
The code below determines what connection type should be used.
*/}}
{{- define "spire-tornjak.connectionType" -}}
{{- if (lookup "v1" "Secret" (include "spire-server.namespace" .) .Values.tornjak.config.tlsSecret) -}}
{{- $caType := default "INVALID" .Values.tornjak.config.userCA.type }}
{{- if (lookup "v1" $caType (include "spire-server.namespace" .) .Values.tornjak.config.userCA.name) -}}
{{- printf "mtls" -}}
{{- else }}
{{- printf "tls" -}}
{{- end -}}
{{- else -}}
{{- printf "http" -}}
{{- end -}}
{{- end -}}
{{- define "spire-tornjak.servicename" -}}
{{- include "spire-tornjak.backend" . -}}
{{- end -}}
@@ -175,20 +175,25 @@ spec:
{{- toYaml .Values.controllerManager.securityContext | nindent 12 }}
image: {{ template "spire-lib.image" (dict "appVersion" $.Chart.AppVersion "image" .Values.tornjak.image "global" .Values.global) }}
imagePullPolicy: {{ .Values.tornjak.image.pullPolicy }}
{{- if eq (include "spire-tornjak.connectionType" .) "http" }}
startupProbe:
httpGet:
scheme: HTTP
path: /api/tornjak/serverinfo
port: 10000
port: 10080
{{- toYaml .Values.tornjak.startupProbe | nindent 12 }}
{{- end }}
args:
- --spire-config
- /run/spire/config/server.conf
- --tornjak-config
- /run/spire/tornjak-config/server.conf
ports:
- name: tornjak
containerPort: 10000
- name: tornjak-http
containerPort: 10080
protocol: TCP
- name: tornjak-https
containerPort: 10443
protocol: TCP
resources:
{{- toYaml .Values.tornjak.resources | nindent 12 }}
@@ -204,6 +209,14 @@ spec:
- name: spire-data
mountPath: /run/spire/data
readOnly: false
{{- if or (eq (include "spire-tornjak.connectionType" .) "tls") (eq (include "spire-tornjak.connectionType" .) "mtls") }}
- name: server-cert
mountPath: /opt/spire/server
{{- end }}
{{- if eq (include "spire-tornjak.connectionType" .) "mtls" }}
- name: user-cert
mountPath: /opt/spire/user
{{- end }}
{{- end }}
{{- if gt (len .Values.extraContainers) 0 }}
@@ -233,6 +246,24 @@ spec:
emptyDir: {}
- name: spire-controller-manager-tmp
emptyDir: {}
{{- if or (eq (include "spire-tornjak.connectionType" .) "tls") (eq (include "spire-tornjak.connectionType" .) "mtls") }}
- name: server-cert
secret:
defaultMode: 256
secretName: {{ .Values.tornjak.config.tlsSecret }}
{{- end }}
{{- if eq (include "spire-tornjak.connectionType" .) "mtls" }}
{{- if eq .Values.tornjak.config.userCA.type "Secret" }}
- name: user-cert
secret:
defaultMode: 256
secretName: {{ .Values.tornjak.config.userCA.name }}
{{- else if eq .Values.tornjak.config.userCA.type "ConfigMap" }}
- name: user-cert
configMap:
name: {{ .Values.tornjak.config.userCA.name }}
{{- end }}
{{- end }}
{{- if eq (.Values.upstreamAuthority.disk.enabled | toString) "true" }}
- name: upstream-ca
secret:
@@ -1,4 +1,5 @@
{{- if eq (.Values.tornjak.enabled | toString) "true" }}
{{- if eq (include "spire-tornjak.connectionType" .) "http" }}
apiVersion: v1
kind: Pod
metadata:
@@ -15,14 +16,15 @@ spec:
- name: curl-tornjak-backend
image: {{ template "spire-lib.image" (dict "image" .Values.tests.bash.image "global" .Values.global) }}
command: ['curl']
args: ['-k', '-s', '-f', 'http://{{ include "spire-tornjak.backend" . }}.{{ include "spire-server.namespace" . }}.svc.{{ include "spire-lib.cluster-domain" . }}:{{ .Values.tornjak.service.port }}/api/tornjak/serverinfo']
args: ['-k', '-s', '-f', 'http://{{ include "spire-tornjak.servicename" . }}.{{ include "spire-server.namespace" . }}.svc.{{ include "spire-lib.cluster-domain" . }}:{{ .Values.tornjak.service.portHttp }}/api/tornjak/serverinfo']
securityContext:
{{- toYaml .Values.securityContext | nindent 8 }}
- name: curl-tornjak-backend-and-spire
image: {{ template "spire-lib.image" (dict "image" .Values.tests.bash.image "global" .Values.global) }}
command: ['curl']
args: ['-k', '-s', '-f', 'http://{{ include "spire-tornjak.backend" . }}.{{ include "spire-server.namespace" . }}.svc.{{ include "spire-lib.cluster-domain" . }}:{{ .Values.tornjak.service.port }}/api/healthcheck']
args: ['-k', '-s', '-f', 'http://{{ include "spire-tornjak.servicename" . }}.{{ include "spire-server.namespace" . }}.svc.{{ include "spire-lib.cluster-domain" . }}:{{ .Values.tornjak.service.portHttp }}/api/healthcheck']
securityContext:
{{- toYaml .Values.securityContext | nindent 8 }}
restartPolicy: Never
{{- end }}
{{- end }}
@@ -8,11 +8,29 @@ data:
server.conf: |
server {
spire_socket_path = "unix:///tmp/spire-server/private/api.sock" # socket to communicate with SPIRE server
{{- if eq (include "spire-tornjak.connectionType" .) "http" }}
http {
enabled = true # if true, opens HTTP server
port = "10000" # if HTTP enabled, opens HTTP listen port at container port 10000
port = "10080" # if HTTP enabled, opens HTTP listen port at specified container port
}
{{- end }}
{{- if eq (include "spire-tornjak.connectionType" .) "tls" }}
tls {
enabled = true
port = "10443" # container port for TLS connection
cert = "/opt/spire/server/tls.crt" # TLS server cert
key = "/opt/spire/server/tls.key" # TLS server key
}
{{- end }}
{{- if eq (include "spire-tornjak.connectionType" .) "mtls" }}
mtls {
enabled = true
port = "10443" # container port for mTLS connection
cert = "/opt/spire/server/tls.crt" # mTLS server cert
key = "/opt/spire/server/tls.key" # mTLS server key
ca = "/opt/spire/user/ca.crt" # mTLS user CA
}
{{- end }}
}
plugins {
@@ -3,7 +3,7 @@ apiVersion: v1
kind: Service
metadata:
namespace: {{ include "spire-server.namespace" . }}
name: {{ include "spire-tornjak.backend" . }}
name: {{ include "spire-tornjak.servicename" . }}
{{- with .Values.tornjak.service.annotations }}
annotations:
{{- toYaml . | nindent 8 }}
@@ -15,8 +15,12 @@ spec:
selector:
{{- include "spire-server.selectorLabels" . | nindent 4 }}
ports:
- name: {{ include "spire-tornjak.backend" . }}
port: {{ .Values.tornjak.service.port }}
targetPort: tornjak
- name: tornjak-srv-http
port: {{ .Values.tornjak.service.portHttp }}
targetPort: tornjak-http
protocol: TCP
- name: tornjak-srv-https
port: {{ .Values.tornjak.service.portHttps }}
targetPort: tornjak-https
protocol: TCP
{{- end }}
+23 -3
View File
@@ -344,7 +344,7 @@ nodeAttestor:
enabled: true
serviceAccountAllowList: []
# tornjak - Tornjak specific configuration
# tornjak - Tornjak default values
tornjak:
# -- Deploys Tornjak API (backend) (Not for production)
enabled: false
@@ -359,9 +359,11 @@ tornjak:
version: ""
# -- Overrides the image tag
tag: "v1.2.2"
service:
type: ClusterIP
port: 10000
portHttp: 10080
portHttps: 10443
annotations: {}
startupProbe:
@@ -372,11 +374,29 @@ tornjak:
successThreshold: 1
timeoutSeconds: 5
# tornjak - Tornjak default values
config:
# -- persistent DB for storing Tornjak specific information
# -- Persistent DB for storing Tornjak specific information
dataStore:
driver: "sqlite3"
file: "/run/spire/data/tornjak.sqlite3"
# Tornjak supports 3 connection types: `http`, `tls`, and `mtls`.
# The connections are determined based on provided configuration
# When `tlsSecret` is created in this chart namespace, the TLS connection is started
# When `tlsSecret` and `userCa.tornjak-user-ca` are created in this chart namespace, the mTLS connection is started
# When none of them are created, Tornjak starts with HTTP connection only
# -- Name of the secret containing server side key and certificate for TLS verification
# (required for `tls` or `mtls` connectionType)
tlsSecret: tornjak-tls-secret
userCA:
# -- Type of delivery for the user CA for mTLS client verification
# options are `Secret` or `ConfigMap`
# (required for `mtls` connectionType)
type: Secret
name: tornjak-user-ca
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
@@ -21,13 +21,20 @@ A Helm chart to deploy Tornjak frontend
| Tornjak | `1.0.x` |
| Helm | `3.x` |
## Tornjak
Tornjak is the UI and Control Plane for SPIRE [https://github.com/spiffe/tornjak](https://github.com/spiffe/tornjak) and it is composed of two components:
* [Backend](../spire-server/README.md) - Tornjak APIs that extend SPIRE APIs with Control Plane functionality
* Frontend (this chart) - Tornjak UI
## Prerequisites
This chart requires access to Tornjak Backend (`tornjakFrontend.apiServerURL`).
This URL needs to be reachable from your web browser and can therefore not be a cluster internal URL.
Obtain the URL for Tornjak APIs. If deployed in the same cluster, locally,
Tornjak APIs are typically available at `http://localhost:10000`.
Tornjak APIs are typically available at `http://localhost:10080`.
Review Tornjak documentation for more details.
## Usage
@@ -23,13 +23,20 @@
| Tornjak | `1.0.x` |
| Helm | `3.x` |
## Tornjak
Tornjak is the UI and Control Plane for SPIRE [https://github.com/spiffe/tornjak](https://github.com/spiffe/tornjak) and it is composed of two components:
* [Backend](../spire-server/README.md) - Tornjak APIs that extend SPIRE APIs with Control Plane functionality
* Frontend (this chart) - Tornjak UI
## Prerequisites
This chart requires access to Tornjak Backend (`tornjakFrontend.apiServerURL`).
This URL needs to be reachable from your web browser and can therefore not be a cluster internal URL.
Obtain the URL for Tornjak APIs. If deployed in the same cluster, locally,
Tornjak APIs are typically available at `http://localhost:10000`.
Tornjak APIs are typically available at `http://localhost:10080`.
Review Tornjak documentation for more details.
## Usage