Skip to content

implement certManager automatic configuration #217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions charts/matrix-stack/ci/test-cluster-mixin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
# It is a mixin to be used with other values file to enable
# usage of the test cluster

ingress:
tlsSecret: ess-selfsigned
certManager:
clusterIssuer: ess-selfsigned
7 changes: 7 additions & 0 deletions charts/matrix-stack/source/common/sub_schema_values.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
matrixTools:
{{ image(registry="ghcr.io", repository="element-hq/ess-helm/matrix-tools", tag="0.3.0") | indent(2) }}

## CertManager Issuer to configure by default automatically on all ingresses
## If configured, the chart will automatically generate the tlsSecret name for all ingresses
certManager: {}
## Choose one of clusterIssuer or issuer
# clusterIssuer:
# issuer:

## The server name of the Matrix Stack. This gets embedded in user IDs & room IDs
## It can not change after the initial deployment.
# serverName: ess.localhost
Expand Down
11 changes: 11 additions & 0 deletions charts/matrix-stack/source/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@
"labels": {
"$ref": "file://common/labels.json"
},
"certManager": {
"type": "object",
"properties": {
"clusterIssuer": {
"type": "string"
},
"issuer": {
"type": "string"
}
}
},
"matrixTools": {
"type": "object",
"properties": {
Expand Down
4 changes: 2 additions & 2 deletions charts/matrix-stack/templates/element-web/ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
{{- include "element-io.ess-library.ingress.annotations" (dict "root" $ "context" .ingress.annotations) | nindent 2 }}
{{- include "element-io.ess-library.ingress.annotations" (dict "root" $ "context" .ingress) | nindent 2 }}
labels:
{{- include "element-io.element-web.labels" (dict "root" $ "context" .) | nindent 4 }}
name: {{ $.Release.Name }}-element-web
namespace: {{ $.Release.Namespace }}
spec:
{{- include "element-io.ess-library.ingress.tlsSecret" (dict "root" $ "context" (dict "hosts" (list (required "elementWeb.ingress.host is required" .ingress.host)) "tlsSecret" .ingress.tlsSecret)) | nindent 2 }}
{{- include "element-io.ess-library.ingress.tlsSecret" (dict "root" $ "context" (dict "hosts" (list (required "elementWeb.ingress.host is required" .ingress.host)) "tlsSecret" .ingress.tlsSecret "ingressName" "element-web")) | nindent 2 }}
{{- include "element-io.ess-library.ingress.className" (dict "root" $ "context" .ingress.className) | nindent 2 }}
rules:
- host: {{ (tpl .ingress.host $) | quote }}
Expand Down
19 changes: 16 additions & 3 deletions charts/matrix-stack/templates/ess-library/_ingress.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,19 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
{{- fail "element-io.ess-library.ingress.annotations missing context" -}}
{{- end }}
{{- $annotations := dict -}}
{{- $tlsSecret := coalesce .context.tlsSecret $root.Values.ingress.tlsSecret -}}
{{- if and (not $tlsSecret) $root.Values.certManager -}}
{{- with $root.Values.certManager -}}
{{- with .clusterIssuer -}}
{{- $annotations = merge $annotations (dict "cert-manager.io/cluster-issuer" .) -}}
{{- end -}}
{{- with .issuer -}}
{{- $annotations = merge $annotations (dict "cert-manager.io/issuer" .) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- $annotations = mustMergeOverwrite $annotations ($root.Values.ingress.annotations | deepCopy) -}}
{{- $annotations = mustMergeOverwrite $annotations (.context | deepCopy) -}}
{{- $annotations = mustMergeOverwrite $annotations (.context.annotations | deepCopy) -}}
{{- with $annotations -}}
annotations:
{{- toYaml . | nindent 2 }}
Expand All @@ -21,14 +32,16 @@ annotations:
{{- define "element-io.ess-library.ingress.tlsSecret" -}}
{{- $root := .root -}}
{{- with required "element-io.ess-library.ingress.tlsSecret missing context" .context -}}
{{- $ingressName := required "element-io.ess-library.ingress.tlsSecret missing ingress name" .ingressName -}}
{{- $hosts := .hosts -}}
{{- with coalesce .tlsSecret $root.Values.ingress.tlsSecret -}}
{{- $tlsSecret := coalesce .tlsSecret $root.Values.ingress.tlsSecret -}}
{{- if or $tlsSecret $root.Values.certManager -}}
tls:
- hosts:
{{- range $host := $hosts }}
- {{ (tpl $host $root) | quote }}
{{- end }}
secretName: {{ (tpl . $root) | quote }}
secretName: {{ (tpl ($tlsSecret | default (printf "{{ .Release.Name }}-%s-certmanager-tls" $ingressName)) $root) | quote }}
{{- end -}}
{{- end -}}
{{- end -}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
{{- include "element-io.ess-library.ingress.annotations" (dict "root" $ "context" .ingress.annotations) | nindent 2 }}
{{- include "element-io.ess-library.ingress.annotations" (dict "root" $ "context" .ingress) | nindent 2 }}
labels:
{{- include "element-io.matrix-authentication-service.labels" (dict "root" $ "context" .) | nindent 4 }}
name: {{ $.Release.Name }}-matrix-authentication-service
namespace: {{ $.Release.Namespace }}
spec:
{{- include "element-io.ess-library.ingress.tlsSecret" (dict "root" $ "context" (dict "hosts" (list (required "matrixAuthenticationService.ingress.host is required" .ingress.host)) "tlsSecret" .ingress.tlsSecret)) | nindent 2 }}
{{- include "element-io.ess-library.ingress.tlsSecret" (dict "root" $ "context" (dict "hosts" (list (required "matrixAuthenticationService.ingress.host is required" .ingress.host)) "tlsSecret" .ingress.tlsSecret "ingressName" "matrix-authentication-service")) | nindent 2 }}
{{- include "element-io.ess-library.ingress.className" (dict "root" $ "context" .ingress.className) | nindent 2 }}
rules:
- host: {{ (tpl .ingress.host $) | quote }}
Expand Down
4 changes: 2 additions & 2 deletions charts/matrix-stack/templates/synapse/synapse_ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
{{- include "element-io.ess-library.ingress.annotations" (dict "root" $ "context" .ingress.annotations) | nindent 2 }}
{{- include "element-io.ess-library.ingress.annotations" (dict "root" $ "context" .ingress) | nindent 2 }}
labels:
{{- include "element-io.synapse-ingress.labels" (dict "root" $ "context" $.Values.haproxy) | nindent 4 }}
name: {{ $.Release.Name }}-synapse
namespace: {{ $.Release.Namespace }}
spec:
{{- include "element-io.ess-library.ingress.tlsSecret" (dict "root" $ "context" (dict "hosts" (list (required "synapse.ingress.host is required" .ingress.host)) "tlsSecret" .ingress.tlsSecret)) | nindent 2 }}
{{- include "element-io.ess-library.ingress.tlsSecret" (dict "root" $ "context" (dict "hosts" (list (required "synapse.ingress.host is required" .ingress.host)) "tlsSecret" .ingress.tlsSecret "ingressName" "synapse")) | nindent 2 }}
{{- include "element-io.ess-library.ingress.className" (dict "root" $ "context" .ingress.className) | nindent 2 }}
rules:
- host: {{ (tpl .ingress.host $) | quote }}
Expand Down
4 changes: 2 additions & 2 deletions charts/matrix-stack/templates/well-known/ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
{{- include "element-io.ess-library.ingress.annotations" (dict "root" $ "context" .ingress.annotations) | nindent 2 }}
{{- include "element-io.ess-library.ingress.annotations" (dict "root" $ "context" .ingress) | nindent 2 }}
labels:
{{- include "element-io.well-known-delegation-ingress.labels" (dict "root" $ "context" $.Values.haproxy) | nindent 4 }}
name: {{ $.Release.Name }}-well-known
namespace: {{ $.Release.Namespace }}
spec:
{{- include "element-io.ess-library.ingress.tlsSecret" (dict "root" $ "context" (dict "hosts" (list (.ingress.host | default $.Values.serverName)) "tlsSecret" .ingress.tlsSecret)) | nindent 2 }}
{{- include "element-io.ess-library.ingress.tlsSecret" (dict "root" $ "context" (dict "hosts" (list (.ingress.host | default $.Values.serverName)) "tlsSecret" .ingress.tlsSecret "ingressName" "well-known")) | nindent 2 }}
{{- include "element-io.ess-library.ingress.className" (dict "root" $ "context" .ingress.className) | nindent 2 }}
rules:
- host: "{{ tpl ($.Values.wellKnownDelegation.ingress.host | default $.Values.serverName) $ }}"
Expand Down
12 changes: 12 additions & 0 deletions charts/matrix-stack/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@
]
}
},
"certManager": {
"type": "object",
"properties": {
"clusterIssuer": {
"type": "string"
},
"issuer": {
"type": "string"
}
},
"additionalProperties": false
},
"matrixTools": {
"type": "object",
"properties": {
Expand Down
7 changes: 7 additions & 0 deletions charts/matrix-stack/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ matrixTools:
## - name: dockerhub
pullSecrets: []

## CertManager Issuer to configure by default automatically on all ingresses
## If configured, the chart will automatically generate the tlsSecret name for all ingresses
certManager: {}
## Choose one of clusterIssuer or issuer
# clusterIssuer:
# issuer:

## The server name of the Matrix Stack. This gets embedded in user IDs & room IDs
## It can not change after the initial deployment.
# serverName: ess.localhost
Expand Down
1 change: 1 addition & 0 deletions newsfragments/217.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a value to automatically configure CertManager on all ingresses.
19 changes: 0 additions & 19 deletions scripts/setup_test_cluster.sh
Original file line number Diff line number Diff line change
Expand Up @@ -120,24 +120,5 @@ metadata:
pod-security.kubernetes.io/audit-version: ${server_version}
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: ${server_version}
EOF
cat <<EOF | kubectl --context $kind_context_name --namespace "$namespace" apply -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ess-selfsigned
namespace: ${namespace}
spec:
commonName: "${namespace}.localhost"
secretName: ess-selfsigned
privateKey:
algorithm: RSA
issuerRef:
name: ess-selfsigned
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- "${namespace}.localhost"
- "*.${namespace}.localhost"
EOF
done
4 changes: 3 additions & 1 deletion tests/integration/test_synapse.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ async def test_synapse_media_upload_fetch_authenticated(
)

media_pod_suffix = (
"synapse-media-repository-0" if value_file_has("synapse.workers.media-repository.enabled", True) else "synapse-main-0"
"synapse-media-repository-0"
if value_file_has("synapse.workers.media-repository.enabled", True)
else "synapse-main-0"
)
media_pod = f"{generated_data.release_name}-{media_pod_suffix}"

Expand Down
46 changes: 46 additions & 0 deletions tests/manifests/test_ingresses.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,49 @@ async def test_ingress_services(templates):
f"Port number {backend_service['port']['number']} "
f"not found in service {backend_service['name']}"
)


@pytest.mark.parametrize("values_file", values_files_with_ingresses)
@pytest.mark.asyncio_cooperative
async def test_ingress_certManager_clusterissuer(make_templates, values):
values.setdefault("certManager", {})["clusterIssuer"] = "cluster-issuer-name"
for template in await make_templates(values):
if template["kind"] == "Ingress":
assert "cert-manager.io/cluster-issuer" in template["metadata"]["annotations"], (
f"Ingress {template['name']} does not have cert-manager annotation"
)
assert template["metadata"]["annotations"]["cert-manager.io/cluster-issuer"] == "cluster-issuer-name"
assert template["spec"]["tls"][0]["secretName"] == f"{template['metadata']['name']}-certmanager-tls", (
f"Ingress {template['name']} does not have correct secret name for cert-manager tls"
)


@pytest.mark.parametrize("values_file", values_files_with_ingresses)
@pytest.mark.asyncio_cooperative
async def test_ingress_certManager_issuer(make_templates, values):
values.setdefault("certManager", {})["issuer"] = "issuer-name"
for template in await make_templates(values):
if template["kind"] == "Ingress":
assert "cert-manager.io/issuer" in template["metadata"]["annotations"], (
f"Ingress {template['name']} does not have cert-manager annotation"
)
assert template["metadata"]["annotations"]["cert-manager.io/issuer"] == "issuer-name"
assert template["spec"]["tls"][0]["secretName"] == f"{template['metadata']['name']}-certmanager-tls", (
f"Ingress {template['name']} does not have correct secret name for cert-manager tls"
)


@pytest.mark.parametrize("values_file", values_files_with_ingresses)
@pytest.mark.asyncio_cooperative
async def test_component_ingress_tlsSecret_beats_certManager(component, values, make_templates):
values[component].setdefault("ingress", {})["tlsSecret"] = "component"
values.setdefault("certManager", {})["issuer"] = "issuer-name"

for template in await make_templates(values):
if template["kind"] == "Ingress":
assert "tls" in template["spec"]
assert len(template["spec"]["tls"]) == 1
assert len(template["spec"]["tls"][0]["hosts"]) == 1
assert template["spec"]["tls"][0]["hosts"][0] == template["spec"]["rules"][0]["host"]
assert template["spec"]["tls"][0]["secretName"] == "component"
assert not template["metadata"].get("annotations")
Loading