diff --git a/argocd-apps/cloudflared.yaml b/argocd-apps/cloudflared.yaml new file mode 100644 index 0000000..2007a54 --- /dev/null +++ b/argocd-apps/cloudflared.yaml @@ -0,0 +1,21 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: cloudflared + namespace: argocd +spec: + project: infra + destination: + server: https://kubernetes.default.svc + namespace: traefik + source: + repoURL: https://git.dvirlabs.com/dvirlabs/infra.git + targetRevision: HEAD + path: charts/cloudflared + helm: + valueFiles: + - ../../manifests/cloudflared/values.yaml + syncPolicy: + automated: + selfHeal: true + prune: false # set to true once you're ready to delete the old deployment diff --git a/charts/cloudflare-tunnel/.helmignore b/charts/cloudflare-tunnel/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/cloudflare-tunnel/.helmignore @@ -0,0 +1,23 @@ +# 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/ diff --git a/charts/cloudflare-tunnel/Chart.yaml b/charts/cloudflare-tunnel/Chart.yaml new file mode 100644 index 0000000..ac2ab2f --- /dev/null +++ b/charts/cloudflare-tunnel/Chart.yaml @@ -0,0 +1,22 @@ +apiVersion: v2 +name: cloudflare-tunnel +description: Creation of a cloudflared deployment - a reverse tunnel for an environment + +# A chart can be either an 'application' or a 'library' chart. +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +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.3.2 + +# 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. +# It is recommended to use it with quotes. +appVersion: "2024.8.3" + +# Let's look professional with a Cloudflare icon. +icon: https://developers.cloudflare.com/cloudflare-one/favicon-32x32.png diff --git a/charts/cloudflare-tunnel/templates/_helpers.tpl b/charts/cloudflare-tunnel/templates/_helpers.tpl new file mode 100644 index 0000000..9d85624 --- /dev/null +++ b/charts/cloudflare-tunnel/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "cloudflare-tunnel.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 "cloudflare-tunnel.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 "cloudflare-tunnel.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cloudflare-tunnel.labels" -}} +helm.sh/chart: {{ include "cloudflare-tunnel.chart" . }} +{{ include "cloudflare-tunnel.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cloudflare-tunnel.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cloudflare-tunnel.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/cloudflare-tunnel/templates/configmap.yaml b/charts/cloudflare-tunnel/templates/configmap.yaml new file mode 100644 index 0000000..07d5219 --- /dev/null +++ b/charts/cloudflare-tunnel/templates/configmap.yaml @@ -0,0 +1,29 @@ +# This configmap stores the configuration used by cloudflared. +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "cloudflare-tunnel.fullname" . }} +data: + config.yaml: | + # Name of the tunnel you want to run + tunnel: {{ .Values.cloudflare.tunnelName }} + # The location of the secret containing the tunnel credentials + credentials-file: /etc/cloudflared/creds/credentials.json + # General purpose TCP routing for the network + warp-routing: + enabled: {{ .Values.cloudflare.enableWarp }} + # Serves the metrics server under /metrics and the readiness server under /ready + metrics: 0.0.0.0:2000 + # Autoupdates applied in a k8s pod will be lost when the pod is removed or restarted, so + # autoupdate doesn't make sense in Kubernetes. However, outside of Kubernetes, we strongly + # recommend using autoupdate. + no-autoupdate: true + # The `ingress` block tells cloudflared which local service to route incoming + # requests to. For more about ingress rules, see + # https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/ingress + ingress: + {{- with .Values.cloudflare.ingress }} + {{- toYaml . | nindent 6 }} + {{- end }} + # This rule matches any traffic which didn't match a previous rule, and responds with HTTP 404. + - service: http_status:404 diff --git a/charts/cloudflare-tunnel/templates/deployment.yaml b/charts/cloudflare-tunnel/templates/deployment.yaml new file mode 100644 index 0000000..7b50786 --- /dev/null +++ b/charts/cloudflare-tunnel/templates/deployment.yaml @@ -0,0 +1,105 @@ +# Here we deploy cloudflared images. The tunnel credentials are stored in +# a k8s secret, and the configuration is stored in a k8s configmap. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "cloudflare-tunnel.fullname" . }} + labels: + {{- include "cloudflare-tunnel.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "cloudflare-tunnel.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + # These are here so the deployment rolls when the config or secret change. + checksum/configmap: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "cloudflare-tunnel.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "cloudflare-tunnel.fullname" . }} + 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 }} + args: + - tunnel + # Points cloudflared to the config file, which configures what + # cloudflared will actually do. This file is created by a ConfigMap. + - --config + - /etc/cloudflared/config/config.yaml + - run + livenessProbe: + httpGet: + # Cloudflared has a /ready endpoint which returns 200 if and only if + # it has an active connection to the edge. + path: /ready + port: 2000 + failureThreshold: 1 + initialDelaySeconds: 10 + periodSeconds: 10 + volumeMounts: + - name: config + mountPath: /etc/cloudflared/config + readOnly: true + # Each tunnel has an associated "credentials file" which authorizes machines + # to run the tunnel. cloudflared will read this file from its local filesystem, + # and it'll be stored in a k8s secret. + - name: creds + mountPath: /etc/cloudflared/creds + readOnly: true + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumes: + - name: creds + secret: + secretName: {{ .Values.cloudflare.secretName | default (include "cloudflare-tunnel.fullname" .) }} + - name: config + configMap: + name: {{ include "cloudflare-tunnel.fullname" . }} + items: + - key: config.yaml + path: config.yaml + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + affinity: + {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- else }} + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 10 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchExpressions: + {{- range $k, $v := include "cloudflare-tunnel.selectorLabels" . | fromYaml }} + - key: {{ $k }} + operator: In + values: + - {{ $v }} + {{- end }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/cloudflare-tunnel/templates/secret.yaml b/charts/cloudflare-tunnel/templates/secret.yaml new file mode 100644 index 0000000..8316526 --- /dev/null +++ b/charts/cloudflare-tunnel/templates/secret.yaml @@ -0,0 +1,17 @@ +{{- if and (and .Values.cloudflare.account .Values.cloudflare.tunnelId .Values.cloudflare.secret) (not .Values.cloudflare.secretName) }} +# This credentials secret allows cloudflared to authenticate itself +# to the Cloudflare infrastructure. +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "cloudflare-tunnel.fullname" . }} + labels: + {{- include "cloudflare-tunnel.labels" . | nindent 4 }} +stringData: + credentials.json: |- + { + "AccountTag": {{ .Values.cloudflare.account | quote }}, + "TunnelID": {{ .Values.cloudflare.tunnelId | quote }}, + "TunnelSecret": {{ .Values.cloudflare.secret | quote }} + } +{{- end }} diff --git a/charts/cloudflare-tunnel/templates/serviceaccount.yaml b/charts/cloudflare-tunnel/templates/serviceaccount.yaml new file mode 100644 index 0000000..ecb321e --- /dev/null +++ b/charts/cloudflare-tunnel/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +# Here we create a service account with no privileges to run the +# deployment - just in case the default service account is different. +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "cloudflare-tunnel.fullname" . }} + labels: + {{- include "cloudflare-tunnel.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} diff --git a/charts/cloudflare-tunnel/values.yaml b/charts/cloudflare-tunnel/values.yaml new file mode 100644 index 0000000..c6d0e02 --- /dev/null +++ b/charts/cloudflare-tunnel/values.yaml @@ -0,0 +1,82 @@ +# Default values for cloudflare-tunnel. + +# Cloudflare parameters. +cloudflare: + # Your Cloudflare account number. + account: "" + # The name of the tunnel this instance will serve + tunnelName: "" + # The ID of the above tunnel. + tunnelId: "" + # The secret for the tunnel. + secret: "" + # If defined, no secret is created for the credentials, and instead, the secret referenced is used + secretName: null + # If true, turn on WARP routing for TCP + enableWarp: false + # Define ingress rules for the tunnel. See + # https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/configuration-file/ingress + ingress: [] + # The first rule proxies traffic to the httpbin sample service named web-server at port 80 + # - hostname: tunnel.example.com + # service: http://web-service:80 + # This rule sends traffic to the built-in hello-world HTTP server. This can help debug connectivity + # issues. If hello.example.com resolves and tunnel.example.com does not, then the problem is + # in the connection from cloudflared to your local service, not from the internet to cloudflared. + # - hostname: hello.example.com + # service: hello_world + +image: + repository: cloudflare/cloudflared + pullPolicy: IfNotPresent + # If supplied, this overrides "appVersion" + tag: "" + +replicaCount: 2 + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # 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: "" + +podAnnotations: {} +podLabels: {} + +# Security items common to everything in the pod. Here we require that it +# does not run as the user defined in the image, literally named "nonroot". +podSecurityContext: + runAsNonRoot: true + runAsUser: 65532 + +# Security items for one container. We lock it down. +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + +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 + +nodeSelector: {} + +tolerations: [] + +# Default affinity is to spread out over nodes; use this to override. +affinity: {} diff --git a/cloudflared-config.yaml b/cloudflared-config.yaml new file mode 100644 index 0000000..b50d099 --- /dev/null +++ b/cloudflared-config.yaml @@ -0,0 +1,135 @@ +apiVersion: v1 +data: + config.yaml: | + tunnel: b50bbf48-0a2f-47ce-b73e-336b6718318b + credentials-file: /etc/cloudflared/credentials.json + + ingress: + - hostname: traefik.dvirlabs.com + service: http://traefik-dashboard.traefik.svc.cluster.local:8080 + + - hostname: rancher.dvirlabs.com + service: https://rancher.cattle-system.svc.cluster.local:443 + originRequest: + noTLSVerify: true + + - hostname: grafana.dvirlabs.com + service: http://grafana-prod.monitoring.svc.cluster.local:80 + + - hostname: grafana-int.dvirlabs.com + service: http://grafana-int.monitoring.svc.cluster.local:80 + + - hostname: pve.dvirlabs.com + service: https://192.168.10.120:8006 + originRequest: + noTLSVerify: true + + - hostname: git.dvirlabs.com + service: http://gitea-http.dev-tools.svc.cluster.local:3000 + + - hostname: woodpecker.dvirlabs.com + service: http://woodpecker-server.dev-tools.svc.cluster.local:80 + + - hostname: argocd.dvirlabs.com + service: http://argocd-server.argocd.svc.cluster.local:80 + + - hostname: prometheus.dvirlabs.com + service: http://prometheus-prod-server.monitoring.svc.cluster.local:80 + + - hostname: prometheus-int.dvirlabs.com + service: http://prometheus-int-server.monitoring.svc.cluster.local:80 + + - hostname: wiki.dvirlabs.com + service: http://wikijs.dev-tools.svc.cluster.local:3000 + + - hostname: minio.dvirlabs.com + service: http://minio-bitnami.infra.svc.cluster.local:9001 + + - hostname: s3.dvirlabs.com + service: http://minio-bitnami.infra.svc.cluster.local:9000 + + - hostname: keycloak.dvirlabs.com + service: http://keycloak.infra.svc.cluster.local:8080 + + - hostname: vault.dvirlabs.com + service: http://vault-ui.dev-tools.svc.cluster.local:8200 + + - hostname: kibana.dvirlabs.com + service: http://kibana-prod-kb-http.monitoring.svc.cluster.local:5601 + + - hostname: kibana-int.dvirlabs.com + service: http://kibana-int-kb-http.monitoring.svc.cluster.local:5601 + + - hostname: oramap.dvirlabs.com + service: http://oramap-oramap.my-apps.svc.cluster.local:80 + + - hostname: navix.dvirlabs.com + service: http://navix-frontend.my-apps.svc.cluster.local:80 + + - hostname: webmail.dvirlabs.com + service: https://mailu-front.mail-services.svc.cluster.local:443 + originRequest: + noTLSVerify: true + + - hostname: harbor.dvirlabs.com + service: https://traefik.traefik.svc.cluster.local:443 + originRequest: + originServerName: harbor.dvirlabs.com + noTLSVerify: true + + - hostname: nas.dvirlabs.com + service: https://192.168.10.155:10000 + originRequest: + noTLSVerify: true + + - hostname: vered.dvirlabs.com + service: http://192.168.10.118:1212 + + + + - service: http_status:404 +kind: ConfigMap +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: > + {"apiVersion":"v1","data":{"config.yaml":"tunnel: + b50bbf48-0a2f-47ce-b73e-336b6718318b\ncredentials-file: + /etc/cloudflared/credentials.json\n\ningress:\n - hostname: + traefik.dvirlabs.com\n service: + http://traefik-dashboard.traefik.svc.cluster.local:8080\n\n - hostname: + rancher.dvirlabs.com\n service: + https://rancher.cattle-system.svc.cluster.local:443\n + originRequest:\n noTLSVerify: true\n\n - hostname: + woodpecker.dvirlabs.com\n service: + http://woodpecker.woodpecker.svc.cluster.local:80\n\n - hostname: + gitea.dvirlabs.com\n service: + http://gitea.gitea.svc.cluster.local:3000\n\n - hostname: + grafana.dvirlabs.com\n #service: + http://traefik.traefik.svc.cluster.local:8000\n service: + http://192.168.10.170:31612\n\n\n\n - service: + http_status:404\n"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"cloudflared-config","namespace":"traefik"}} + creationTimestamp: '2025-04-13T19:36:21Z' + managedFields: + - apiVersion: v1 + fieldsType: FieldsV1 + fieldsV1: + f:data: {} + f:metadata: + f:annotations: + .: {} + f:kubectl.kubernetes.io/last-applied-configuration: {} + manager: kubectl-client-side-apply + operation: Update + time: '2025-04-15T23:19:06Z' + - apiVersion: v1 + fieldsType: FieldsV1 + fieldsV1: + f:data: + f:config.yaml: {} + manager: rancher + operation: Update + time: '2025-06-04T22:52:30Z' + name: cloudflared-config + namespace: traefik + resourceVersion: '12779879' + uid: 3ed87e59-09b9-4993-9646-9f463a9c97f3 diff --git a/manifests/cloudflared/values.yaml b/manifests/cloudflared/values.yaml new file mode 100644 index 0000000..3c18f5c --- /dev/null +++ b/manifests/cloudflared/values.yaml @@ -0,0 +1,13 @@ +tunnel: + name: b50bbf48-0a2f-47ce-b73e-336b6718318b + credentialsSecretName: cloudflared-creds + +config: + existingConfig: cloudflared-config + +cloudflared: + image: + repository: cloudflare/cloudflared + tag: latest + metrics: + enabled: false