Skip to content
Open
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
84 changes: 84 additions & 0 deletions charts/plane-enterprise/templates/ingress-traefik.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{{- if and .Values.ingress.enabled (eq .Values.ingress.ingressClass "traefik") .Values.license.licenseDomain }}

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: {{ .Release.Name }}-ingress
namespace: {{ .Release.Namespace }}
spec:
entryPoints:
- websecure

routes:

# IMPORTANT: specific paths FIRST

- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/spaces/`)
kind: Rule
services:
- name: {{ .Release.Name }}-space
port: 3000

- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/god-mode/`)
kind: Rule
services:
- name: {{ .Release.Name }}-admin
port: 3000

- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/api/`)
kind: Rule
services:
- name: {{ .Release.Name }}-api
port: 8000

- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/auth/`)
kind: Rule
services:
- name: {{ .Release.Name }}-api
port: 8000

- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/graphql/`)
kind: Rule
services:
- name: {{ .Release.Name }}-api
port: 8000

- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/marketplace/`)
kind: Rule
services:
- name: {{ .Release.Name }}-api
port: 8000

- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/live/`)
kind: Rule
services:
- name: {{ .Release.Name }}-live
port: 3000

- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/silo/`)
kind: Rule
services:
- name: {{ .Release.Name }}-silo
port: 3000

{{- if and .Values.services.minio.local_setup .Values.env.docstore_bucket }}
- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/{{ .Values.env.docstore_bucket }}`)
kind: Rule
services:
- name: {{ .Release.Name }}-minio
port: 9000
{{- end }}

# LAST: catch all
- match: Host(`{{ .Values.license.licenseDomain }}`) && PathPrefix(`/`)
kind: Rule
middlewares:
- name: {{ .Release.Name }}-body-limit
services:
- name: {{ .Release.Name }}-web
port: 3000
Comment on lines +72 to +79
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Body-limit middleware applied only to the catch-all, not to API/upload routes.

In the nginx Ingress the proxy-body-size: 5m annotation applies globally to all paths. Here the body-limit middleware is only on the / catch-all, leaving /api/, /auth/, etc. without a request-body cap. If the intent is to enforce a 5 MB upload limit consistently, the middleware should be attached to all routes (or at least the API route that handles uploads).

If selective application is intentional, a brief comment explaining the rationale would help future maintainers.

🤖 Prompt for AI Agents
In `@charts/plane-enterprise/templates/ingress-traefik.yaml` around lines 72 - 79,
The body-limit middleware ({{ .Release.Name }}-body-limit) is only attached to
the catch-all rule (Host(`{{ .Values.license.licenseDomain }}`) &&
PathPrefix(`/`)) so API/upload routes like /api/ and /auth/ remain uncapped;
update the Traefik ingress rules to include the same middleware on the
API/auth/upload rules that point to the {{ .Release.Name }}-web service (or
apply it globally to all host rules) so the 5 MB limit is enforced consistently,
and if you intentionally want selective coverage, add a short comment next to
the rule(s) explaining that rationale.


tls:
secretName: {{ default (printf "%s-ssl-cert" .Release.Name) .Values.ssl.tls_secret_name }}
Comment on lines +81 to +82
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

No HTTP-to-HTTPS redirect or cert-manager integration.

Two things to be aware of:

  1. HTTP→HTTPS redirect: This IngressRoute only listens on the websecure entrypoint. There's no companion IngressRoute for the web (HTTP) entrypoint with a redirect middleware, so HTTP requests will get connection-refused rather than a graceful redirect. This may need to be handled at the Traefik deployment level, but it's worth documenting.

  2. cert-manager: The nginx path supports ssl.generateCerts / ssl.createIssuer for automated certificate provisioning. This Traefik template only references a pre-existing secret. Users migrating from the nginx path with cert-manager will need manual steps.

Consider documenting these gaps in the chart's README or values.yaml comments.

🤖 Prompt for AI Agents
In `@charts/plane-enterprise/templates/ingress-traefik.yaml` around lines 81 - 82,
The template only sets tls.secretName ({{ .Values.ssl.tls_secret_name }}) for
Traefik's websecure entrypoint and lacks both an HTTP (web) IngressRoute with a
redirect middleware and cert-manager integration; update the chart documentation
(README and values.yaml comments) to (1) explain that this IngressRoute listens
on the websecure entrypoint only and instruct users to either add a companion
IngressRoute for the web entrypoint that references a redirect middleware or
enable a Traefik static HTTP→HTTPS redirect, and (2) explain the current
requirement for a pre-existing secret (tls.secretName) and provide migration
steps for users coming from nginx's ssl.generateCerts / ssl.createIssuer
workflow—include sample steps to create a cert-manager Issuer and Certificate
that produce the expected secret or guidance on modifying the template to
support cert-manager annotations if they want automated provisioning.


{{- end }}
2 changes: 1 addition & 1 deletion charts/plane-enterprise/templates/ingress.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{- if and .Values.ingress.enabled .Values.license.licenseDomain }}
{{- if and .Values.ingress.enabled (eq .Values.ingress.ingressClass "nginx") .Values.license.licenseDomain }}

apiVersion: networking.k8s.io/v1
kind: Ingress
Expand Down
11 changes: 11 additions & 0 deletions charts/plane-enterprise/templates/traefik-middleware.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{{- if and .Values.ingress.enabled (eq .Values.ingress.ingressClass "traefik") }}
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: {{ .Release.Name }}-body-limit
namespace: {{ .Release.Namespace }}
spec:
buffering:
maxRequestBodyBytes: 5242880

{{- end }}
38 changes: 38 additions & 0 deletions charts/plane-enterprise/templates/traefik-rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{- $traefik := .Values.ingress.traefik | default dict }}
{{- if and .Values.ingress.enabled (eq .Values.ingress.ingressClass "traefik") ($traefik.createSecretReadRBAC) }}
# Role: allows reading secrets in this namespace (for TLS certs used by IngressRoute).
# RoleBinding: grants the Traefik controller's service account that permission.
# Required so Traefik can load the TLS certificate referenced in the IngressRoute.
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ .Release.Name }}-traefik-secret-reader
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: plane-enterprise
app.kubernetes.io/component: traefik-rbac
app.kubernetes.io/managed-by: helm
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ .Release.Name }}-traefik-secret-reader
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: plane-enterprise
app.kubernetes.io/component: traefik-rbac
app.kubernetes.io/managed-by: helm
subjects:
- kind: ServiceAccount
name: {{ $traefik.serviceAccountName | default "traefik" }}
namespace: {{ $traefik.serviceAccountNamespace | default "traefik" }}
roleRef:
kind: Role
name: {{ .Release.Name }}-traefik-secret-reader
apiGroup: rbac.authorization.k8s.io
{{- end }}
1 change: 1 addition & 0 deletions charts/plane-enterprise/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ ingress:
rabbitmqHost: ''
ingressClass: 'nginx'
ingress_annotations: { "nginx.ingress.kubernetes.io/proxy-body-size": "5m" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Default ingress_annotations are nginx-specific but the default class is now Traefik.

"nginx.ingress.kubernetes.io/proxy-body-size": "5m" has no effect on a Traefik IngressRoute. With traefik-external as the default, this annotation is dead config and may confuse users. Consider either clearing the default annotations or making them conditional on the ingress class.

Possible fix
-  ingress_annotations: { "nginx.ingress.kubernetes.io/proxy-body-size": "5m" }
+  ingress_annotations: {}

Users who select nginx can supply annotations via their own values override.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ingress_annotations: { "nginx.ingress.kubernetes.io/proxy-body-size": "5m" }
ingress_annotations: {}
🤖 Prompt for AI Agents
In `@charts/plane-enterprise/values.yaml` at line 29, The default
ingress_annotations map currently contains an nginx-specific key
("nginx.ingress.kubernetes.io/proxy-body-size": "5m") which is ineffective when
the default ingress class is Traefik; update the values.yaml entry for
ingress_annotations (the ingress_annotations map) to not include nginx-only
annotations by default — either set ingress_annotations to an empty map or make
the default conditional on the ingressClass (e.g., only populate the nginx
annotation when ingressClass == "nginx" or leave it empty so users choosing
nginx can supply their own overrides).

# ingressClass: 'traefik'

ssl:
tls_secret_name: '' # If you have a custom TLS secret name
Expand Down