diff --git a/helm/.helmignore b/helm/.helmignore new file mode 100644 index 000000000..39f5c78fe --- /dev/null +++ b/helm/.helmignore @@ -0,0 +1,24 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +*conf.yaml diff --git a/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 000000000..3e5f42052 --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: mas +description: A Helm chart for matrix-authentication-service +type: application +version: 0.1.2 +appVersion: "0.13.0" diff --git a/helm/README.md b/helm/README.md new file mode 100644 index 000000000..575bbe9a6 --- /dev/null +++ b/helm/README.md @@ -0,0 +1,41 @@ +# Oddities with MAS + +## general + +After initialising the pod you need to sync MAS with it's config + +```bash +kubectl exec -it -n mas deployments/mas -- mas-cli config sync +``` + +otherwise you'll run into issues with synapse reporting "*unable to introspect token*" and MAS complaining about not knowing about the configured `client_id`s + +## migrating users from synapse db to mas + +you need to run the tool `syn2mas` which isn't at all included in the mas itself. +While an container exits for it it's still quite difficult to use. + +- You're much quicker by spawning up a container such as +```bash +kubectl run -i --tty --rm debug --image=node:lts --restart=Never -- bash +``` +- add your homeserver.yaml and mas config.yaml +- install the `syn2mas` +```bash +npx @matrix-org/syn2mas +``` +- run preadvisor **or** +```bash +npx @matrix-org/syn2mas --command=advisor --synapseConfigFile homeserver.yaml +``` +- run migration +```bash +npx @matrix-org/syn2mas --command=migrate --synapseConfigFile homeserver.yaml --masConfigFile config.yaml +``` + +## troubleshooting + +mas offers a diagnostic tool which is rather help full, you can run it with +```bash +kubectl exec -it -n mas deployments/mas -- mas-cli doctor +``` diff --git a/helm/configs/config.yaml b/helm/configs/config.yaml new file mode 100644 index 000000000..7c3e2064e --- /dev/null +++ b/helm/configs/config.yaml @@ -0,0 +1,318 @@ +http: + # Public URL base used when building absolute public URLs + public_base: "{{ required "you need to set a URL for .Values.config.http.public_base" .Values.config.http.public_base -}}/" + + # OIDC issuer advertised by the service. Defaults to `public_base` + issuer: {{ .Values.config.http.issuer | default .Values.config.http.public_base | quote }} + + # Each listener can serve multiple resources, and listen on multiple TCP ports or UNIX sockets. + # List of HTTP listeners, see below + listeners: + # The name of the listener, used in logs and metrics + - name: web + + # List of resources to serve + resources: {{- range .Values.config.listeners.resources }} + - name: {{ .name }} + {{- if .path }} + path: {{ .path -}} + {{- end }} + {{- if .playground }} + playground: {{ .playground }} + {{- end }} + {{- end }} + - name: health + path: /health + {{- if .Values.telemetry.metrics.enabled }} + - name: prometheus + path: /health + {{- end }} + + binds: + - address: '[::]:8080' + proxy_protocol: {{ .Values.config.listeners.proxy_protocol }} + trusted_proxies: {{ range .Values.config.trusted_proxies }} + - {{ . }} + {{- end }} + + # Configure how to connect to the PostgreSQL database. +database: + # Full connection string as per + # https://www.postgresql.org/docs/13/libpq-connect.html#id-1.7.3.8.3.6 + #uri: postgresql://user:password@hostname:5432/database?sslmode=require + + # -- OR -- + # Separate parameters + host: {{ .Values.database.host }} + port: {{ .Values.database.port }} + #socket: + username: {{ .Values.database.username }} + password: {{ .Values.database.password }} + database: {{ .Values.database.dbName }} + + # Additional parameters for the connection pool + min_connections: {{ .Values.database.min_connections }} + max_connections: {{ .Values.database.max_connections }} + connect_timeout: {{ .Values.database.connect_timeout }} + idle_timeout: {{ .Values.database.idle_timeout }} + max_lifetime: {{ .Values.database.max_lifetime }} + + # Settings related to the connection to the Matrix homeserver +matrix: + # The homeserver name, as per the `server_name` in the Synapse configuration file + homeserver: {{ .Values.matrix.homeserver }} + + # Shared secret used to authenticate the service to the homeserver + # This must be of high entropy, because leaking this secret would allow anyone to perform admin actions on the homeserver + secret: {{ .Values.matrix.sharedSecret | quote }} + + # URL to which the homeserver is accessible from the service + endpoint: {{ .Values.matrix.homeserverUrl | quote }} + + # Allows loading custom templates +{{- if .Values.templates.enabled }} +templates: + path: {{ .Values.templates.path }} + assets_manifest: {{ .Values.templates.assets }} +{{- end }} + + # List of OAuth 2.0/OIDC clients and their keys/secrets. Each client_id must be a ULID. +clients: + # Confidential client + - client_id: {{ .Values.clients.client_id }} + client_auth_method: {{ .Values.clients.client_auth_method }} + client_secret: {{ .Values.clients.client_secret }} + # List of authorized redirect URIs + redirect_uris: {{ .Values.clients.redirect_uris | toYaml | nindent 6 }} + # Public client + - client_id: {{ .Values.clients.pub_id }} + client_auth_method: {{ .Values.clients.pubAuthMethod }} + + # Signing and encryption secrets +secrets: + encryption: {{ randAlphaNum 32 | printf "%x" }} + + # Signing keys + keys: + - kid: {{ randAlphaNum 10 }} + key: | + {{- genPrivateKey "rsa" | nindent 10 }} + - kid: {{ randAlphaNum 10 }} + key: | + {{- genPrivateKey "ecdsa" | nindent 10 }} + - kid: {{ randAlphaNum 10 }} + key: | + {{- genPrivateKey "ecdsa" | nindent 10 }} + - kid: {{ randAlphaNum 10 }} + key: | + {{- genPrivateKey "ecdsa" | nindent 10 }} + + +passwords: + # Whether to enable the password database. + # If disabled, users will only be able to log in using upstream OIDC providers + enabled: {{ .Values.passwords.enabled }} + + # List of password hashing schemes being used + # /!\ Only change this if you know what you're doing + schemes: {{- range .Values.passwords.schemes }} + - version: {{ .version }} + algorithm: {{ .algorithm }} +{{- end}} + +account: + email_change_allowed: {{ .Values.account.email_change_allowed | default "true" }} + displayname_change_allowed: {{ .Values.account.displayname_change_allowed | default "true" }} + password_registration_enabled: {{ .Values.account.password_registration_enabled | default "false" }} + password_change_allowed: {{ .Values.account.password_change_allowed | default "true" }} + password_recovery_enabled: {{ .Values.account.password_recovery_enabled | default "false" }} + +policy: + data: + {{- if .Values.policy.data.hasAdminUsers }} + {{ with .Values.policy.data.admins }} + admin_users: + {{- . | toYaml | nindent 6 }} + {{- end }} + # Client IDs which are allowed to ask for admin access with a + # client_credentials grant + {{- with .Values.policy.data.admin_clients }} + admin_clients: + {{- . | toYaml | nindent 6 }} + {{- end }} + {{- end }} + # Dynamic Client Registration + client_registration: + # don't require URIs to be on the same host. default: false + allow_host_mismatch: {{ .Values.policy.data.clientHostMismatch | default "false" }} + # allow non-SSL and localhost URIs. default: false + allow_insecure_uris: {{ .Values.policy.data.clientNoSsl | default "false" }} + # don't require clients to provide a client_uri. default: false + allow_missing_client_uri: {{ .Values.policy.data.clientMissingUri | default "false" }} + # don't require clients to provide a contacts field. default: false + allow_missing_contacts: {{ .Values.policy.data.missingContacts | default "false" }} + + # Registration using passwords + passwords: + # minimum length of a password. default: ? + min_length: {{ .Values.policy.data.pass.minLength }} + # require at least one lowercase character in a password. default: false + require_lowercase: {{ .Values.policy.data.pass.reqLowCase | default "false" }} + # require at least one uppercase character in a password. default: false + require_uppercase: {{ .Values.policy.data.pass.reqUpCase | default "false" }} + # require at least one number in a password. default: false + require_number: {{ .Values.policy.data.pass.reqNum | default "false" }} + +rate_limiting: + {{- with .Values.rate_limiting.account_recovery }} + account_recovery: + per_ip: + burst: {{ .ip.burst }} + per_second: {{ .ip.second }} + per_address: + burst: {{ .address.burst }} + per_second: {{ .address.second }} + {{- end }} + {{- with .Values.rate_limiting.login }} + login: + per_ip: + burst: {{ .ip.burst }} + per_second: {{ .ip.second }} + per_account: + burst: {{ .account.burst }} + per_second: {{ .account.second }} + {{- end }} + {{- with .Values.rate_limiting.registration }} + registration: + burst: {{ .burst }} + per_second: {{ .second }} + {{- end }} + +{{- if .Values.telemetry.enabled }} +telemetry: + tracing: + # List of propagators to use for extracting and injecting trace contexts + propagators: {{ .Values.telemetry.propagators }} + + # The default: don't export traces + exporter: {{ .Values.telemetry.exporter }} + {{- if .Values.telemetry.useOTLP.enabled }} + endpoint: {{ .Values.telemetry.useOTLP.endpoint }} + {{- end }} + {{- if .Values.telemetry.metrics.enabled}} + metrics: + exporter: {{ .Values.telemetry.metrics.exporter }} + endpoint: {{ .Values.telemetry.metrics.enpoint }} + {{- end }} + {{- if .Values.telemetry.sentry.enabled}} + sentry: + dsn: {{ .Values.telemetry.sentry.dsn }} + {{- end }} +{{- end }} + +email: + from: {{ .Values.email.from | squote }} + reply_to: {{ .Values.email.reply2 | squote }} + transport: {{ .Values.email.transport | default "blackhole" }} +{{- if eq .Values.email.transport "smtp" }} + hostname: {{ .Values.email.hostname }} + mode: {{ .Values.email.mode }} + port: {{ .Values.email.port }} + username: {{ .Values.email.username }} + password: {{ .Values.email.password }} +{{- end }} +{{- if eq .Values.email.transport "sendmail" }} + command: {{ .Values.email.command }} +{{- end }} + +{{- if .Values.upstream_oauth2.enabled | default false }} + # Sample configurations for popular providers can be found in the upstream provider setup guide. + # https://element-hq.github.io/matrix-authentication-service/setup/sso.html +upstream_oauth2: + providers: + {{- range .Values.upstream_oauth2.providers }} + {{- if .id }} + - id: {{ .id | quote }} + {{- if .client_id }} + client_id: {{ .client_id | quote }} + {{- end }} + {{- else if .client_id }} + - client_id: {{ .client_id | quote }} + {{- end }} + {{- if .human_name }} + human_name: {{ .human_name }} + {{- end }} + {{- if .brand_name }} + brand_name: {{ .brand_name }} + {{- end }} + {{- if .discovery_uri }} + discovery_mode: {{ .discovery_mode }} + {{- end }} + {{- if .fetch_userinfo }} + fetch_userinfo: {{ .fetch_userinfo }} + {{- end }} + {{- if .token_endpoint_auth_method }} + token_endpoint_auth_method: {{ .token_endpoint_auth_method | quote }} + {{- end }} + {{- if .sign_in_with_apple }} + sign_in_with_apple: + private_key: | + {{- with .sign_in_with_apple.private_key }} + {{ . | indent 12 | trim }} + {{- end }} + team_id: {{ .sign_in_with_apple.team_id | quote }} + key_id: {{ .sign_in_with_apple.key_id | quote }} + {{- end }} + {{- if .client_secret }} + client_secret: {{ .client_secret | quote }} + {{- end }} + {{- if .authorization_endpoint }} + authorization_endpoint: {{ .authorization_endpoint | quote }} + {{- end }} + {{- if .token_endpoint }} + token_endpoint: {{ .token_endpoint | quote }} + {{- end }} + {{- if .userinfo_endpoint }} + userinfo_endpoint: {{ .userinfo_endpoint | quote }} + {{- end }} + scope: {{ .scope | quote }} + {{- if .response_mode }} + response_mode: {{ .response_mode | quote }} + {{- end }} + {{- if .discovery_mode}} + discovery_mode: {{ .discovery_mode | quote }} + {{- end }} + claims_imports: + {{- if .claims_imports.subject }} + subject: + template: {{ .claims_imports.subject.template | quote }} + {{- end }} + {{- if .claims_imports.displayname }} + displayname: + action: {{ .claims_imports.displayname.action }} + template: {{ .claims_imports.displayname.template | quote }} + {{- end }} + {{- if .claims_imports.localpart }} + localpart: + action: {{ .claims_imports.localpart.action }} + {{- end }} + {{- if .claims_imports.email }} + email: + action: {{ .claims_imports.email.action }} + template: {{ .claims_imports.email.template | quote }} + {{- if .claims_imports.email.set_email_verification }} + set_email_verification: {{ .claims_imports.email.set_email_verification | quote }} + {{- end }} + {{- end }} + {{- if .claims_imports.account_name }} + account_name: + template: {{ .claims_imports.account_name.template | quote }} + {{- end }} + {{- if .issuer }} + issuer: {{ .issuer | quote }} + {{- end }} + {{- if .jwks_uri }} + jwks_uri: {{ .jwks_uri | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/helm/templates/NOTES.txt b/helm/templates/NOTES.txt new file mode 100644 index 000000000..44d755b8a --- /dev/null +++ b/helm/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "mas.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "mas.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "mas.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "mas.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl new file mode 100644 index 000000000..3b0997118 --- /dev/null +++ b/helm/templates/_helpers.tpl @@ -0,0 +1,74 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "mas.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- 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 "mas.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 }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mas.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "mas.labels" -}} +helm.sh/chart: {{ include "mas.chart" . }} +{{ include "mas.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} +{{- define "well-known.labels" -}} +helm.sh/chart: {{ include "mas.chart" . }} +{{ include "well-known.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "mas.selectorLabels" -}} +app.kubernetes.io/name: {{ include "mas.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} +{{- define "well-known.selectorLabels" -}} +app.kubernetes.io/name: well-known-{{ include "mas.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "mas.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "mas.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml new file mode 100644 index 000000000..1e1666fde --- /dev/null +++ b/helm/templates/configmap.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: config-main + labels: +data: +{{ tpl (.Files.Glob "configs/config.yaml").AsConfig . | nindent 2 }} diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml new file mode 100644 index 000000000..fe39ac5b7 --- /dev/null +++ b/helm/templates/deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "mas.fullname" . }} + labels: + {{- include "mas.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "mas.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "mas.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "mas.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- 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/helm/templates/hpa.yaml b/helm/templates/hpa.yaml new file mode 100644 index 000000000..b47d1ee1b --- /dev/null +++ b/helm/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "mas.fullname" . }} + labels: + {{- include "mas.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "mas.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/helm/templates/ingress.yaml b/helm/templates/ingress.yaml new file mode 100644 index 000000000..04fed8b04 --- /dev/null +++ b/helm/templates/ingress.yaml @@ -0,0 +1,126 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "mas.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "mas.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} + - path: /.well-known/openid-configuration + pathType: Exact + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + - path: /authorize + pathType: Exact + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + - path: /oauth2/token + pathType: Exact + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + - path: /keys.json + pathType: Exact + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + - path: /registration + pathType: Exact + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + - path: /introspect + pathType: Exact + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + - path: /revoke + pathType: Exact + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + - path: /health + pathType: Exact + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- if .Values.telemetry.metrics.enabled }} + - path: /metrics + pathType: Exact + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- end }} +{{- end }} diff --git a/helm/templates/service.yaml b/helm/templates/service.yaml new file mode 100644 index 000000000..2a429a220 --- /dev/null +++ b/helm/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mas.fullname" . }} + labels: + {{- include "mas.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "mas.selectorLabels" . | nindent 4 }} diff --git a/helm/templates/serviceaccount.yaml b/helm/templates/serviceaccount.yaml new file mode 100644 index 000000000..a1c862e89 --- /dev/null +++ b/helm/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "mas.serviceAccountName" . }} + labels: + {{- include "mas.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/helm/templates/tests/test-connection.yaml b/helm/templates/tests/test-connection.yaml new file mode 100644 index 000000000..16a074eba --- /dev/null +++ b/helm/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "mas.fullname" . }}-test-connection" + labels: + {{- include "mas.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "mas.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/helm/values.yaml b/helm/values.yaml new file mode 100644 index 000000000..a47bdcaa1 --- /dev/null +++ b/helm/values.yaml @@ -0,0 +1,396 @@ +# Default values for mas. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: ghcr.io/element-hq/matrix-authentication-service + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "0.13.0" + # debug images are available with have a shell use $imageTag-debug + # the debug version has the mas-cli in /usr/local/bin + # the command `mas-cli doctor` can test some functionality + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: false + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "mas-sa" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 8080 + +ingress: + enabled: false + className: "nginx" + annotations: {} + # cert-manager.io/cluster-issuer: "letsencrypt-prod" + # kubernetes.io/tls-acme: "true" + # nginx.ingress.kubernetes.io/use-regex: "true" + hosts: + - host: auth.example.com + paths: + - path: / + pathType: ImplementationSpecific + - host: synapse.example.com + paths: + - path: /_matrix/client/(.*)/(login|logout|refresh) + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +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 + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +livenessProbe: + httpGet: + path: /health + port: http +readinessProbe: + httpGet: + path: /health + port: http + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 2 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# Additional volumes on the output Deployment definition. +volumes: + - name: config-main + configMap: + name: "config-main" + items: + - key: config.yaml + path: config.yaml +# - name: foo +# secret: +# secretName: mysecret +# optional: false + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: + - name: config-main + mountPath: "/config.yaml" + subPath: config.yaml +# - name: foo +# mountPath: "/etc/foo" +# readOnly: true + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +config: + http: + # MAS URL + # dont add trailing slash + public_base: https://auth.example.com + # OIDC issuer advertised by the service. Defaults to `public_base` + issuer: + listeners: + resources: + - name: discovery # Serves the .well-known/openid-configuration document + - name: human # Serves the human-facing pages, such as the login page + - name: oauth # Serves the OAuth 2.0/OIDC endpoints + - name: compat # Serves the Matrix C-S API compatibility endpoints + - name: graphql # Serve the GraphQL API used by the frontend, and optionally the GraphQL playground + playground: false + - name: assets # Serve the given folder on the /assets/ path + path: /usr/local/share/mas-cli/assets/ + + proxy_protocol: false + trusted_proxies: + - 192.168.0.0/16 + - 172.16.0.0/12 + - 10.0.0.0/10 + - 127.0.0.1/8 + - fd00::/8 + - ::1/128 + +# must be PostgreSQL +database: + host: postgres + port: 5432 + username: user1 + password: password + dbName: database + min_connections: 0 + max_connections: 10 + connect_timeout: 30 + idle_timeout: 600 + max_lifetime: 1800 + +# Settings related to the connection to the Matrix homeserver +matrix: + # `server_name` in the Synapse configuration file + homeserver: example.com + sharedSecret: someRandomSecret + homeserverUrl: https://synapse.example.com + +# Allows loading custom templates +# From where to load the templates +# This is relative to the current working directory, *not* the config file +templates: + enabled: false + path: /usr/local/share/mas-cli/templates/ + # Path to the frontend assets manifest file + assets: /to/manifest.json + +clients: + # Confidential client + # Each client_id must be a ULID https://github.com/ulid/spec + client_id: 0000000000000000000SYNAPSE + client_auth_method: client_secret_post + client_secret: secret + redirect_uris: + - http://localhost:1234/callback + # Public client + pub_id: 0000000000000000000SYNAPSX + pubAuthMethod: none + + +passwords: + # Whether to enable the password database. + # If disabled, users will only be able to log in using upstream OIDC providers + enabled: true + schemes: + - version: 2 + algorithm: argon2id + - version: 1 + algorithm: bcrypt + +account: + # Whether users are allowed to change their email addresses. + # + # Defaults to `true`. + email_change_allowed: true + # Whether users are allowed to change their display names + # + # Defaults to `true`. + # This should be in sync with the policy in the homeserver configuration. + displayname_change_allowed: true + # Whether to enable self-service password registration + # + # Defaults to `false`. + # This has no effect if password login is disabled. + password_registration_enabled: false + # Whether users are allowed to change their passwords + # + # Defaults to `true`. + # This has no effect if password login is disabled. + password_change_allowed: true + # Whether email-based password recovery is enabled + # + # Defaults to `false`. + # This has no effect if password login is disabled. + password_recovery_enabled: false + + +policy: + data: + hasAdminUsers: false + admins: + - system-admin + admin_clients: + - My_Admin_Client + # defaults to false + clientHostMismatch: true + # defaults to false + clientNoSsl: true + # defaults to false + clientMissingUri: false + # defaults to false + missingContacts: false + pass: + minLength: 8 + reqLowCase: true + reqUpCase: true + reqNum: true + + +rate_limiting: + # Limits how many account recovery attempts are allowed. + # These limits can protect against e-mail spam. + # + # Note: these limit also apply to recovery e-mail re-sends. + account_recovery: + # Controls how many account recovery attempts are permitted + # based on source IP address. + ip: + burst: 3 + second: 0.0008 + + # Controls how many account recovery attempts are permitted + # based on the e-mail address that is being used for recovery. + address: + burst: 3 + second: 0.0002 + + # Limits how many login attempts are allowed. + # + # Note: these limit also applies to password checks when a user attempts to + # change their own password. + login: + # Controls how many login attempts are permitted + # based on source IP address. + # This can protect against brute force login attempts. + ip: + burst: 3 + second: 0.05 + + # Controls how many login attempts are permitted + # based on the account that is being attempted to be logged into. + # This can protect against a distributed brute force attack + # but should be set high enough to prevent someone's account being + # casually locked out. + account: + burst: 1800 + second: 0.5 + + # Limits how many registrations attempts are allowed, + # based on source IP address. + # This limit can protect against e-mail spam and against people registering too many accounts. + registration: + burst: 3 + second: 0.0008 + + +telemetry: + # disables telemetry, metrics export sentry + enabled: false + propagators: + #- tracecontext #Propagate according to the W3C Trace Context specification + #- baggage #Propagate according to the W3C Baggage specification + #- b3 #Propagate trace context with Zipkin compatible headers (single `b3` header variant) + #- b3multi #Propagate trace context with Zipkin compatible headers (multiple `x-b3-*` headers variant) + + # telementry exporter can be none, otlp + exporter: none + useOTLP: + enabled: false + endpoint: https://localhost:4317 + + metrics: + # disables only metrics export/collection + enabled: false + # can be otlp, prometheus (requires mounting the `prometheus` resource to an HTTP listener) + exporter: none + endpoint: https://localhost:4317 + + sentry: + enabled: true + dsn: https://public@host:port/1 + +email: + from: '"The almighty auth service" ' + reply2: '"No reply" ' + # possible values: smtp, sendmail, blackhole (don't send any) default: blackhole + transport: blackhole + hostname: localhost + # path of your sendmail binary + command: "/usr/sbin/sendmail" + # possinle values: plain, tls, starttls + mode: starttls + port: 587 + username: + password: + + # Sample configurations for popular providers can be found in the upstream provider setup guide. + # https://element-hq.github.io/matrix-authentication-service/setup/sso.html +upstream_oauth2: + enabled: false + providers: {} + # - id: "01HFS67GJ145HCM9ZASYS9DC3J" + # human_name: GitHub + # brand_name: github + # discovery_mode: disabled + # fetch_userinfo: true + # token_endpoint_auth_method: "client_secret_post" + # client_id: "" # TO BE FILLED + # client_secret: "" # TO BE FILLED + # authorization_endpoint: "https://github.com/login/oauth/authorize" + # token_endpoint: "https://github.com/login/oauth/access_token" + # userinfo_endpoint: "https://api.github.com/user" + # scope: "read:user" + # claims_imports: + # subject: + # template: "{{ userinfo_claims.id }}" + # displayname: + # action: suggest + # template: "{{`{{ userinfo_claims.name }}" + # localpart: + # action: ignore + # email: + # action: suggest + # template: "{{ userinfo_claims.email }}" + # account_name: + # template: "@{{ userinfo_claims.login }}" + # - client_id: 01JAYS74TCG3BTWKADN5Q4518C + # client_name: "" # TO BE FILLED + # scope: "openid name email" + # response_mode: "form_post" + # token_endpoint_auth_method: "sign_in_with_apple" + # sign_in_with_apple: + # private_key: | + # # Content of the PEM-encoded private key file, TO BE FILLED + # team_id: "" # TO BE FILLED + # key_id: "" # TO BE FILLED + # claims_imports: + # localpart: + # action: ignore + # displayname: + # action: suggest + # # SiWA passes down the user infos as query parameters in the callback + # # which is available in the extra_callback_parameters variable + # template: | + # {%- set u = extra_callback_parameters["user"] | from_json -%} + # {{- u.name.firstName }} {{ u.name.lastName -}} + # email: + # action: suggest + # account_name: + # template: | + # {%- set u = extra_callback_parameters["user"] | from_json -%} + # {{- u.name.firstName }} {{ u.name.lastName -}}