diff --git a/changelog.d/5-internal/restund-chart b/changelog.d/5-internal/restund-chart new file mode 100644 index 0000000000..b0addd486b --- /dev/null +++ b/changelog.d/5-internal/restund-chart @@ -0,0 +1 @@ +Add a helm chart that deploys [restund](https://docs.wire.com/understand/restund.html) diff --git a/charts/restund/Chart.yaml b/charts/restund/Chart.yaml new file mode 100644 index 0000000000..423fbbe799 --- /dev/null +++ b/charts/restund/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +name: restund +description: Restund - a modular STUN/TURN server +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.0.1 + +# 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. +appVersion: 0.4.17 diff --git a/charts/restund/README.md b/charts/restund/README.md new file mode 100644 index 0000000000..8af0d2d344 --- /dev/null +++ b/charts/restund/README.md @@ -0,0 +1,14 @@ +This chart deploys [Restund](https://docs.wire.com/understand/restund.html), a +STUN and TURN server. + +You need to supply the zrestSecret at key `secrets.zrestSecret`. Make sure this +matches `secrets.turn.secret` of the brig chart. + +Restund pods are deployed with `hostNetwork: true`, because restund needs to +listen on a wide range of udp ports. See `values.yaml` for additional tcp ports +that need to be exposed on the hosting node. + +The Restund server might also expose the internal network to which the hosting +node is connected to. It is therefore recommended to run restund on a separate +network (cluster) than the rest of wire's services. See +[details](https://docs.wire.com/understand/restund.html#network). diff --git a/charts/restund/templates/_helpers.tpl b/charts/restund/templates/_helpers.tpl new file mode 100644 index 0000000000..2aff503be0 --- /dev/null +++ b/charts/restund/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{- define "restund.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "restund.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "restund.labels" -}} +helm.sh/chart: {{ include "restund.chart" . }} +{{ include "restund.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- 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 "restund.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 }} + +{{- define "restund.selectorLabels" -}} +app.kubernetes.io/name: {{ include "restund.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/restund/templates/configmap-restund-conf-template.yaml b/charts/restund/templates/configmap-restund-conf-template.yaml new file mode 100644 index 0000000000..b25263f79f --- /dev/null +++ b/charts/restund/templates/configmap-restund-conf-template.yaml @@ -0,0 +1,51 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "restund.fullname" . }} + labels: + {{- include "restund.selectorLabels" . | nindent 4 }} + +data: + restund.conf.template: | + ## core + daemon no + debug no + realm dummy.io + syncinterval 600 + udp_listen ${RESTUND_HOST}:{{ .Values.restundUDPListenPort }} + udp_sockbuf_size 524288 + tcp_listen ${RESTUND_HOST}:{{ .Values.restundTCPListenPort }} + # tls_listen + + ## modules + module_path /usr/local/lib/restund/modules + module stat.so + module drain.so + module binding.so + module auth.so + module turn.so + module zrest.so + module status.so + + ## auth + auth_nonce_expiry 3600 + + ## turn + turn_max_allocations 64000 + turn_max_lifetime 3600 + turn_relay_addr ${RESTUND_HOST} + # # turn_public_addr is an IP which must be reachable for UDP traffic from other restund servers (and from this server itself). If unset, defaults to 'turn_relay_addr' + # turn_public_addr + + # syslog + syslog_facility 24 + + ## status + status_http_addr ${POD_IP} + status_http_port {{ .Values.restundHTTPStatusPort }} + # status_udp_addr + # status_udp_port + + # zrest + zrest_listen ${POD_IP} + zrest_secret ${ZREST_SECRET} diff --git a/charts/restund/templates/secret.yaml b/charts/restund/templates/secret.yaml new file mode 100644 index 0000000000..f5652f9dac --- /dev/null +++ b/charts/restund/templates/secret.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Secret +metadata: + name: restund + labels: + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +type: Opaque +data: + zrest_secret.txt: {{ .Values.secrets.zrestSecret | b64enc | quote }} diff --git a/charts/restund/templates/service-account.yaml b/charts/restund/templates/service-account.yaml new file mode 100644 index 0000000000..1708744dd6 --- /dev/null +++ b/charts/restund/templates/service-account.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "restund.fullname" . }} + labels: + {{- include "restund.labels" . | nindent 4 }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "restund.fullname" . }} + labels: + {{- include "restund.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: [nodes] + verbs: [get] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "restund.fullname" . }} + labels: + {{- include "restund.labels" . | nindent 4 }} +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: {{ include "restund.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "restund.fullname" . }} + namespace: {{ .Release.Namespace }} diff --git a/charts/restund/templates/service.yaml b/charts/restund/templates/service.yaml new file mode 100644 index 0000000000..d5f0a7b940 --- /dev/null +++ b/charts/restund/templates/service.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "restund.fullname" . }} + labels: + {{- include "restund.labels" . | nindent 4 }} +spec: + # Needs to be headless + # See: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ + clusterIP: None + ports: + - name: restund-tcp + port: 3478 + targetPort: restund-tcp + - name: sft-config + port: 8000 + targetPort: sft-config + selector: + {{- include "restund.selectorLabels" . | nindent 4 }} diff --git a/charts/restund/templates/statefulset.yaml b/charts/restund/templates/statefulset.yaml new file mode 100644 index 0000000000..1b5715cde3 --- /dev/null +++ b/charts/restund/templates/statefulset.yaml @@ -0,0 +1,129 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "restund.fullname" . }} + labels: + {{- include "restund.labels" . | nindent 4 }} + +spec: + replicas: {{ .Values.replicaCount }} + + # Allows restund to start up and shut down in parallel when scaling up and down. + # However this does not affect upgrades. + podManagementPolicy: Parallel + + serviceName: {{ include "restund.fullname" . }} + selector: + matchLabels: + {{- include "restund.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + + labels: + {{- include "restund.selectorLabels" . | nindent 8 }} + spec: + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + hostNetwork: true + serviceAccountName: {{ include "restund.fullname" . }} + volumes: + - name: external-ip + emptyDir: {} + - name: restund-config-template + configMap: + name: {{ include "restund.fullname" . }} + - name: secrets + secret: + secretName: restund + initContainers: + - name: get-external-ip + image: bitnami/kubectl:1.19.7 + volumeMounts: + - name: external-ip + mountPath: /external-ip + command: + - /bin/sh + - -c + - | + set -e + + # In the cloud, this setting is available to indicate the true IP address + addr=$(kubectl get node $HOSTNAME -ojsonpath='{.status.addresses[?(@.type=="ExternalIP")].address}') + + # On on-prem we allow people to set "wire.com/external-ip" to override this + if [ -z "$addr" ]; then + addr=$(kubectl get node $HOSTNAME -ojsonpath='{.metadata.annotations.wire\.com/external-ip}') + fi + echo -n "$addr" | tee /dev/stderr > /external-ip/ip + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + volumeMounts: + - name: external-ip + mountPath: /external-ip + - name: restund-config-template + mountPath: /restund-template/restund.conf.template + subPath: restund.conf.template + - name: secrets + mountPath: /secrets/ + readOnly: true + command: + - /bin/sh + - -c + - | + set -e + EXTERNAL_IP=$(cat /external-ip/ip) + export RESTUND_HOST="$EXTERNAL_IP" + export ZREST_SECRET="$(cat /secrets/zrest_secret.txt)" + envsubst '$RESTUND_HOST $POD_IP $ZREST_SECRET' < /restund-template/restund.conf.template > /home/restund/restund.conf + exec /usr/local/sbin/restund -n -f /home/restund/restund.conf + + ports: + - name: restund-tcp + containerPort: 3478 + protocol: TCP + - name: sft-config + containerPort: 8000 + protocol: TCP + - name: status-http + containerPort: {{ .Values.restundHTTPStatusPort }} + protocol: TCP + + livenessProbe: + httpGet: + path: / + port: status-http + + readinessProbe: + httpGet: + path: / + port: status-http + + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/restund/values.yaml b/charts/restund/values.yaml new file mode 100644 index 0000000000..2a8b04cf0f --- /dev/null +++ b/charts/restund/values.yaml @@ -0,0 +1,29 @@ +# The amount of Restund instances to run. NOTE: Only one Restund can run per node due +# to `hostNetwork`. If this number is higher than the amount of nodes that can +# be used for scheduling (Also see `nodeSelector`) pods will remain in a +# pending state untill you add more capacity. +replicaCount: 1 + +image: + repository: quay.io/wire/restund + pullPolicy: IfNotPresent + # overwrite the tag here, otherwise `appVersion` of the chart will be used + tag: "" + +# If you have multiple deployments of Restund running in one cluster, it is +# important that they run on disjoint sets of nodes, you can use nodeSelector to enforce this +nodeSelector: {} + +podSecurityContext: + fsGroup: 31337 + +securityContext: + # Pick a high number that is unlikely to conflict with the host + # https://kubesec.io/basics/containers-securitycontext-runasuser/ + runAsUser: 31337 + +restundUDPListenPort: 3478 +restundTCPListenPort: 3478 +restundUDPStatusPort: 33000 +restundHTTPStatusPort: 8080 +restundMetricsListenPort: 8443