diff --git a/charts/plex/Chart.yaml b/charts/plex/Chart.yaml index e8eb73ec..959e8455 100644 --- a/charts/plex/Chart.yaml +++ b/charts/plex/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 appVersion: 1.19.1.2645-ccb6eb67e description: Plex Media Server name: plex -version: 1.2.0 +version: 1.3.0 keywords: - plex home: https://plex.tv/ diff --git a/charts/plex/configs/41-plex-preferences b/charts/plex/configs/41-plex-preferences index d9283e80..5f13bd2a 100644 --- a/charts/plex/configs/41-plex-preferences +++ b/charts/plex/configs/41-plex-preferences @@ -1,4 +1,5 @@ #!/usr/bin/with-contenv bash + # This file is based off of the official 40-plex-first-run # Here: https://github.com/plexinc/pms-docker/blob/master/root/etc/cont-init.d/40-plex-first-run # It should live in /etc/cont-init.d/ @@ -8,6 +9,12 @@ if [ "${DEBUG,,}" = "true" ]; then set -x fi +function getPref { + local key="$1" + + xmlstarlet sel -T -t -m "/Preferences" -v "@${key}" -n "${prefFile}" +} + function setPref { local key="$1" local value="$2" diff --git a/charts/plex/configs/42-pkcs-mangler b/charts/plex/configs/42-pkcs-mangler new file mode 100644 index 00000000..8a4fb1e2 --- /dev/null +++ b/charts/plex/configs/42-pkcs-mangler @@ -0,0 +1,53 @@ +#!/usr/bin/with-contenv bash + +# This file contains part of the official PLEX 40-plex-first-run +# Here: https://github.com/plexinc/pms-docker/blob/master/root/etc/cont-init.d/40-plex-first-run +# It should live in /etc/cont-init.d/ + +# If we are debugging, enable trace +if [ "${DEBUG,,}" = "true" ]; then + set -x +fi + +function setPref { + local key="$1" + local value="$2" + + count="$(xmlstarlet sel -t -v "count(/Preferences/@${key})" "${prefFile}")" + count=$(($count + 0)) + if [[ $count > 0 ]]; then + xmlstarlet ed --inplace --update "/Preferences/@${key}" -v "${value}" "${prefFile}" + else + xmlstarlet ed --inplace --insert "/Preferences" --type attr -n "${key}" -v "${value}" "${prefFile}" + fi +} + +home="$(echo ~plex)" +pmsApplicationSupportDir="${PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR:-${home}/Library/Application Support}" +prefFile="${pmsApplicationSupportDir}/Plex Media Server/Preferences.xml" + +# If PKCSMANGLER__PFXINCONTAINERPATH is set, then assume we want to move the PFX Cert to that location +if [ ! -z "${PKCSMANGLER_PFXINCONTAINERPATH}" ]; then + # If it ends up a problem, we may need to set some kind of "don't replace existing PFX cert" + cp -f /shared/cert.pfx "${PKCSMANGLER_PFXINCONTAINERPATH}" + # If PKCSMANGLER__CUSTOMCERTDOMAIN is set, then assume we want to set the PLEX Preference customCertificatePath because we enabled setting PLEX Preferences + if [ ! -z "${PKCSMANGLER_CUSTOMCERTDOMAIN}" ]; then + setPref "customCertificatePath" "${PKCSMANGLER_PFXINCONTAINERPATH}" + fi +fi + +# If PKCSMANGLER_PFXPASSWORD is set, then assume we want to set the PLEX Preference customCertificateKey +if [ ! -z "${PKCSMANGLER_PFXPASSWORD}" ]; then + setPref "customCertificateKey" "${PKCSMANGLER_PFXPASSWORD}" +fi + +# If PKCSMANGLER__CUSTOMCERTDOMAIN is set, then assume we want to set the PLEX Preference customCertificateDomain +if [ ! -z "${PKCSMANGLER_CUSTOMCERTDOMAIN}" ]; then + PreferenceValue=${PKCSMANGLER_CUSTOMCERTDOMAIN#*=} + PreferenceKey=${PKCSMANGLER_CUSTOMCERTDOMAIN%=*} + setPref $PreferenceKey $PreferenceValue +fi + +# touch /.firstRunComplete +# echo "Plex Media Server first run setup complete" +echo "PKCS Mangler run complete" \ No newline at end of file diff --git a/charts/plex/templates/configmap.yaml b/charts/plex/templates/configmap.yaml index a309a573..ff5b183c 100644 --- a/charts/plex/templates/configmap.yaml +++ b/charts/plex/templates/configmap.yaml @@ -17,4 +17,26 @@ data: # At some point figure out how to use a value/Variable here to be able to specify # a different file or something. {{ (tpl (.Files.Glob "configs/41-plex-preferences").AsConfig . ) | indent 2 }} +{{- end -}} + +{{- if .Values.certificate.pkcsMangler.enabled }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.certificate.pkcsMangler.configmap.name }} + labels: + {{- include "plex.labels" . | nindent 4 }} +{{- if .Values.certificate.pkcsMangler.configmap.labels }} +{{ toYaml .Values.certificate.pkcsMangler.configmap.labels | indent 4 }} +{{- end }} +{{- with .Values.certificate.pkcsMangler.configmap.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} + +data: +# At some point figure out how to use a value/Variable here to be able to specify +# a different file or something. +{{ (tpl (.Files.Glob "configs/42-pkcs-mangler").AsConfig . ) | indent 2 }} {{- end -}} \ No newline at end of file diff --git a/charts/plex/templates/deployment.yaml b/charts/plex/templates/deployment.yaml index b5c15c73..8315b365 100644 --- a/charts/plex/templates/deployment.yaml +++ b/charts/plex/templates/deployment.yaml @@ -35,6 +35,28 @@ spec: {{- end }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- if .Values.certificate.pkcsMangler.enabled }} + initContainers: + # This is ugly, but it does work to create a pks file that will work with PLEX from the tls.crt and tls.key that cert-manager normally creates + {{- if .Values.certificate.pkcsMangler.enabled }} + - name: pkcsmangler-init-container + image: tlsprint/openssl:1.1.1f + imagePullPolicy: Always + command: ["/bin/sh"] + args: ["-c", "openssl pkcs12 -export -passout pass:$(PKCSMANGLER_PFXPASSWORD) -out /shared/cert.pfx -inkey {{ .Values.certificate.pkcsMangler.certificateSecret.volume.mountPath }}/{{ .Values.certificate.pkcsMangler.certificateSecret.keyName }} -in {{ .Values.certificate.pkcsMangler.certificateSecret.volume.mountPath }}/{{ .Values.certificate.pkcsMangler.certificateSecret.crtName }}; chmod 0444 /shared/cert.pfx"] + env: + - name: "PKCSMANGLER_PFXPASSWORD" + valueFrom: + secretKeyRef: + name: {{ .Values.certificate.pkcsMangler.pfxPassword.secretName }} + key: {{ .Values.certificate.pkcsMangler.pfxPassword.passwordKey }} + volumeMounts: + - name: shared + mountPath: /shared + - name: {{ .Values.certificate.pkcsMangler.certificateSecret.volume.name }} + mountPath: {{ .Values.certificate.pkcsMangler.certificateSecret.volume.mountPath }} + {{- end }} + {{- end }} containers: - name: {{ .Chart.Name }} securityContext: @@ -44,10 +66,6 @@ spec: ports: - name: pms containerPort: 32400 - - name: http - containerPort: 32400 - - name: https - containerPort: 32443 env: - name: TZ value: "{{ .Values.timezone }}" @@ -81,7 +99,7 @@ spec: {{- else }} value: "{{ template "plex.fullname" . }}-config" {{- end }} - {{- if .Values.proxy.enable }} + {{- if .Values.proxy.enabled }} {{- if .Values.proxy.http }} - name: "HTTP_PROXY" value: "{{.Values.proxy.http}}" @@ -119,6 +137,20 @@ spec: {{- range $key, $value := .Values.extraEnv }} - name: {{ $key }} value: {{ $value }} +{{- end }} +# This is part of pkcsMangler +{{- if .Values.certificate.pkcsMangler.enabled }} + - name: "PKCSMANGLER_PFXINCONTAINERPATH" + value: "{{.Values.certificate.pkcsMangler.pfxInContainerPath}}" +{{- if .Values.certificate.pkcsMangler.setPlexPreferences.enabled }} + - name: "PKCSMANGLER_PFXPASSWORD" + valueFrom: + secretKeyRef: + name: {{ .Values.certificate.pkcsMangler.pfxPassword.secretName }} + key: {{ .Values.certificate.pkcsMangler.pfxPassword.passwordKey }} + - name: "PKCSMANGLER_CUSTOMCERTDOMAIN" + value: "customCertificateDomain={{.Values.certificate.pkcsMangler.plexPreferences.customCertificateDomain}}" +{{- end }} {{- end }} readinessProbe: httpGet: @@ -161,6 +193,11 @@ spec: mountPath: {{ .Values.plexPreferences.volume.mountPath }} subPath: {{ .Values.plexPreferences.volume.subPath }} {{- end }} + {{- if .Values.certificate.pkcsMangler.enabled }} + - name: {{ .Values.certificate.pkcsMangler.volume.name }} + mountPath: {{ .Values.certificate.pkcsMangler.volume.mountPath }} + subPath: {{ .Values.certificate.pkcsMangler.volume.subPath }} + {{- end }} resources: {{- toYaml .Values.resources | nindent 12 }} {{- with .Values.nodeSelector }} @@ -192,10 +229,10 @@ spec: {{- end }} {{- else }} {{- if .Values.persistence.transcode.emptyDir.medium }} - emptyDir: + emptyDir: medium: "{{ .Values.persistence.transcode.emptyDir.medium }}" {{- else }} - emptyDir: {} + emptyDir: {} {{- end }} {{- end }} {{- range .Values.persistence.extraData }} @@ -215,6 +252,16 @@ spec: name: {{ .Values.plexPreferences.configmap.name }} defaultMode: {{ .Values.plexPreferences.volume.defaultMode }} {{- end }} + {{- if .Values.certificate.pkcsMangler.enabled }} + - name: {{ .Values.certificate.pkcsMangler.volume.name }} + configMap: + name: {{ .Values.certificate.pkcsMangler.configmap.name }} + defaultMode: {{ .Values.certificate.pkcsMangler.volume.defaultMode }} + - name: {{ .Values.certificate.pkcsMangler.certificateSecret.volume.name }} + secret: + secretName: {{ .Values.certificate.pkcsMangler.certificateSecret.name }} + {{- end }} +##### VOLUMES END ##### {{- with .Values.affinity }} affinity: {{- toYaml . | nindent 8 }} diff --git a/charts/plex/templates/secrets.yaml b/charts/plex/templates/secrets.yaml new file mode 100644 index 00000000..6f838fcd --- /dev/null +++ b/charts/plex/templates/secrets.yaml @@ -0,0 +1,18 @@ +{{- if .Values.certificate.pkcsMangler.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.certificate.pkcsMangler.pfxPassword.secretName }} + labels: + {{- include "plex.labels" . | nindent 4 }} +{{- if .Values.certificate.pkcsMangler.pfxPassword.labels }} +{{ toYaml .Values.certificate.pkcsMangler.pfxPassword.labels | indent 4 }} +{{- end }} +{{- with .Values.certificate.pkcsMangler.pfxPassword.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +type: Opaque +stringData: + {{ .Values.certificate.pkcsMangler.pfxPassword.passwordKey }}: {{ .Values.certificate.pkcsMangler.pfxPassword.value }} +{{- end -}} \ No newline at end of file diff --git a/charts/plex/templates/service.yaml b/charts/plex/templates/service.yaml index 563a9c7e..a0cc6c3a 100644 --- a/charts/plex/templates/service.yaml +++ b/charts/plex/templates/service.yaml @@ -49,6 +49,6 @@ spec: targetPort: pms - name: https port: 443 - targetPort: 32443 + targetPort: pms selector: {{- include "plex.selectorLabels" . | nindent 4 }} diff --git a/charts/plex/values.yaml b/charts/plex/values.yaml index 9e777348..086cb1d2 100644 --- a/charts/plex/values.yaml +++ b/charts/plex/values.yaml @@ -44,7 +44,6 @@ timezone: "UTC" ##### END --> Official PLEX container environment variables - # You can add as many Additional ENV variables here # The following is the same as --set extraEnv.TMPDIR="/transcode" # extraEnv: @@ -102,7 +101,6 @@ ingress: # hosts: # - chart-example.local - plexPreferences: # Enable init script that will read all environment variables starting with PLEX_PREFERENCE_ # and take the value (of PLEX_PREFERENCE_) as the Key:Value option to set in Plex Preference.xml @@ -162,9 +160,11 @@ persistence: # If not using a transcode PVC, specify emptyDir.medium="Memory" to use a tmpfs (in-memory) # Volume for /transcode. Warning! this will greatly increase the amount of memory the plex pod is using # AND it will count toward any ram pod/namespace limits. Additionally all data will be lost if/when the - # pod is moved to another node. - # emptyDir: - # medium: "Memory" + # pod is moved to another node. --set persistence.transcode.emptyDir.medium="Memory" ` + emptyDir: + medium: "" + # medium: "Memory" + data: # Optionally specify claimName to manually override the PVC to be used for @@ -205,6 +205,57 @@ persistence: # Access mode for this volume accessMode: ReadWriteOnce +# Certificate(s) in Plex +certificate: + # Assuming you have a kubernetes certificate secret (say from cert-manager) that has a tls.crt and tls.key but NO PFX! + # pkcsMangler to the rescue. The pkcsMangler part will add the supplied pfxPassword to a kubernetes secret + # This is so it's not in the clear in the YAML of the deployment in the kubernetes api. + # We will then use an OpenSSL init container to create a pfx file using the supplied secret (only available in container) + # Then we will use an init script (via configMap) to move the pfx file out of /shared (it's temporary storage) to + # the location specified in pfxInContainerPath. + pkcsMangler: + enabled: false + configmap: + labels: {} + annotations: {} + # Right now you can't really change this, additionally the configmap data is + # not configurable. + name: 42-pkcs-mangler + volume: + name: 42-pkcs-mangler + defaultMode: 493 # 0755 in octal permission notation + # Using mountPath & SubPath allow you to volume mount a configMap AS A FILE + # Unfortunately this also means that updates to the configMap are not automtically + # propagated to the file contents. But it's better then replacing the entire + # /etc/cont-init.d/ directory which is the "normal" behavior when doing volume + # mounts. + mountPath: /etc/cont-init.d/42-pkcs-mangler + subPath: 42-pkcs-mangler + setPlexPreferences: + enabled: true # Set Plex Preferences related to Certificates + customCertificateDomain: "" # If not empty, Set the Plex Preference customCertificateDomain + # Use spec.certificate.pkcsMangler.pfxPassword.value to Set the Plex Preference customCertificateKey + # Use spec.certificate.pkcsMangler.pfxInContainerPath to Set the Plex Preference customCertificatePath + pfxPassword: + value: "setpassword" + # We wlll create a Kubernetes Secret for spec.certificate.pkcsMangler.pfxPassword.value + # These are your options. + secretName: "plex-media-server-pfx-password" + passwordKey: "pfx-password" + labels: {} + annotations: {} + pfxInContainerPath: "/config/plex.pfx" # This is full path in the container pkcsMangler will copy the pfx file to + # This is the SSL Certificate Secret that will provide our crt and key file. If you used cert-manager to create + # the certificate, these defaults should work for you. This Secret (and volume details) are only used by the + # pkcsMangler Init Container. + certificateSecret: + name: "" + keyName: "tls.key" + crtName: "tls.crt" + volume: + name: plex-certs + mountPath: /etc/plex-certs + # Probes configuration probes: liveness: @@ -240,7 +291,7 @@ deploymentAnnotations: {} proxy: # This allows to set a proxy environment variable, which PMS uses to fetch the token and assets like movie cover - enable: false + enabled: false # http: "http://proxy:8080" # https: "https://proxy:8080" # noproxy: "localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/12"