diff --git a/kubernetes/apps/network/cloudflared/app/config/config.yaml b/kubernetes/apps/network/cloudflared/app/config/config.yaml new file mode 100644 index 00000000..5bcc6fc8 --- /dev/null +++ b/kubernetes/apps/network/cloudflared/app/config/config.yaml @@ -0,0 +1,14 @@ +--- +originRequest: + http2Origin: true + +ingress: + - hostname: hsn.dev + service: https://ingress-nginx-hsn-controller.network.svc.cluster.local:443 + originRequest: + originServerName: external.hsn.dev + - hostname: "*.hsn.dev" + service: https://ingress-nginx-hsn-controller.network.svc.cluster.local:443 + originRequest: + originServerName: external.hsn.dev + - service: http_status:404 diff --git a/kubernetes/apps/network/cloudflared/app/dnsendpoint.yaml b/kubernetes/apps/network/cloudflared/app/dnsendpoint.yaml new file mode 100644 index 00000000..f67d50e6 --- /dev/null +++ b/kubernetes/apps/network/cloudflared/app/dnsendpoint.yaml @@ -0,0 +1,11 @@ +--- +# yaml-language-server: $schema=https://ks.hsn.dev/externaldns.k8s.io/dnsendpoint_v1alpha1.json +apiVersion: externaldns.k8s.io/v1alpha1 +kind: DNSEndpoint +metadata: + name: cloudflared +spec: + endpoints: + - dnsName: external.hsn.dev + recordType: CNAME + targets: ["${SECRET_CLUSTER_CLOUDFLARE_TUNNEL_ID}.cfargotunnel.com"] diff --git a/kubernetes/apps/network/cloudflared/app/externalsecret.yaml b/kubernetes/apps/network/cloudflared/app/externalsecret.yaml new file mode 100644 index 00000000..32584648 --- /dev/null +++ b/kubernetes/apps/network/cloudflared/app/externalsecret.yaml @@ -0,0 +1,29 @@ +--- +# yaml-language-server: $schema=https://ks.hsn.dev/external-secrets.io/externalsecret_v1beta1.json +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: cloudflared +spec: + secretStoreRef: + kind: ClusterSecretStore + name: onepassword-connect + target: + name: cloudflared-secret + creationPolicy: Owner + template: + engineVersion: v2 + data: + credentials.json: | + { + "AccountTag": "{{ .cloudflare_tunnel_account_tag }}", + "TunnelSecret": "{{ .cloudflare_tunnel_secret }}", + "TunnelID": "{{ .cloudflare_tunnel_id }}" + } + dataFrom: + - extract: + key: Cloudflare + rewrite: + - regexp: + source: "(.*)" + target: "cloudflare_$1" diff --git a/kubernetes/apps/network/cloudflared/app/helmrelease.yaml b/kubernetes/apps/network/cloudflared/app/helmrelease.yaml new file mode 100644 index 00000000..39eb7cd0 --- /dev/null +++ b/kubernetes/apps/network/cloudflared/app/helmrelease.yaml @@ -0,0 +1,112 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/helm.toolkit.fluxcd.io/helmrelease_v2beta2.json +apiVersion: helm.toolkit.fluxcd.io/v2beta2 +kind: HelmRelease +metadata: + name: &app cloudflared +spec: + interval: 30m + chart: + spec: + chart: app-template + version: 2.4.0 + sourceRef: + kind: HelmRepository + name: bjw-s + namespace: flux-system + install: + remediation: + retries: 3 + upgrade: + cleanupOnFail: true + remediation: + retries: 3 + uninstall: + keepHistory: false + dependsOn: + - name: cluster-apps-ingress-nginx-external + namespace: network + values: + controllers: + main: + replicas: 2 + strategy: RollingUpdate + annotations: + reloader.stakater.com/auto: "true" + containers: + main: + image: + repository: docker.io/cloudflare/cloudflared + tag: 2024.1.2@sha256:116171d734c606a7d67f86f6309b56193095e19fd3af478e83fee3f24d93c692 + env: + NO_AUTOUPDATE: "true" + TUNNEL_CRED_FILE: /etc/cloudflared/creds/credentials.json + TUNNEL_METRICS: 0.0.0.0:8080 + TUNNEL_TRANSPORT_PROTOCOL: quic + TUNNEL_POST_QUANTUM: true + args: + - tunnel + - --config + - /etc/cloudflared/config/config.yaml + - run + - "${CLUSTER_CLOUDFLARE_TUNNEL_ID}" + probes: + liveness: &probes + enabled: true + custom: true + spec: + httpGet: + path: /ready + port: &port 8080 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + readiness: *probes + startup: + enabled: false + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: { drop: ["ALL"] } + resources: + requests: + cpu: 10m + limits: + memory: 256Mi + pod: + securityContext: + runAsUser: 568 + runAsGroup: 568 + runAsNonRoot: true + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + app.kubernetes.io/name: *app + service: + main: + ports: + http: + port: *port + serviceMonitor: + main: + enabled: true + persistence: + config: + enabled: true + type: configMap + name: cloudflared-configmap + globalMounts: + - path: /etc/cloudflared/config/config.yaml + subPath: config.yaml + readOnly: true + creds: + type: secret + name: cloudflared-tunnel-secret + globalMounts: + - path: /etc/cloudflared/creds/credentials.json + subPath: credentials.json + readOnly: true diff --git a/kubernetes/apps/network/cloudflared/app/kustomization.yaml b/kubernetes/apps/network/cloudflared/app/kustomization.yaml new file mode 100644 index 00000000..4dbb6acf --- /dev/null +++ b/kubernetes/apps/network/cloudflared/app/kustomization.yaml @@ -0,0 +1,14 @@ +--- +# yaml-language-server: $schema=https://json.schemastore.org/kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./externalsecret.yaml + - ./dnsendpoint.yaml + - ./helmrelease.yaml +configMapGenerator: + - name: cloudflared-configmap + files: + - config.yaml=./config/config.yaml +generatorOptions: + disableNameSuffixHash: true diff --git a/kubernetes/apps/network/cloudflared/ks.yaml b/kubernetes/apps/network/cloudflared/ks.yaml new file mode 100644 index 00000000..42bd86af --- /dev/null +++ b/kubernetes/apps/network/cloudflared/ks.yaml @@ -0,0 +1,25 @@ +--- +# yaml-language-server: $schema=https://ks.hsn.dev/kustomize.toolkit.fluxcd.io/kustomization_v1.json +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: &app cloudflared + namespace: flux-system + labels: + substitution.flux.home.arpa/enabled: "true" +spec: + targetNamespace: network + commonMetadata: + labels: + app.kubernetes.io/name: *app + dependsOn: + - name: cluster-apps-external-secrets-stores + path: ./kubernetes/apps/network/cloudflared/app + prune: false + sourceRef: + kind: GitRepository + name: homelab + wait: true + interval: 30m + retryInterval: 1m + timeout: 5m diff --git a/kubernetes/apps/network/ingress-nginx/external/externalsecret.yaml b/kubernetes/apps/network/ingress-nginx/external/externalsecret.yaml index cd93cd40..6c480a92 100644 --- a/kubernetes/apps/network/ingress-nginx/external/externalsecret.yaml +++ b/kubernetes/apps/network/ingress-nginx/external/externalsecret.yaml @@ -17,4 +17,4 @@ spec: MAXMIND_LICENSE_KEY: "{{ .homelab_nginx }}" dataFrom: - extract: - key: maxmind + key: Maxmind diff --git a/kubernetes/flux/vars/cluster-secrets.sops.yaml b/kubernetes/flux/vars/cluster-secrets.sops.yaml index b94ff80e..0f0237f2 100644 --- a/kubernetes/flux/vars/cluster-secrets.sops.yaml +++ b/kubernetes/flux/vars/cluster-secrets.sops.yaml @@ -8,6 +8,7 @@ stringData: SECRET_PUSHOVER_ALERT_MANAGER_APIKEY: ENC[AES256_GCM,data:n0cFsAwCX1/y5HhsNxr/c2KT/5dzt55Ygi17rX+OV7cwKPKMImmLinb6GhD9fDIz1AINGBijXuXvD8TL,iv:4nwdHlSJEUSyMEDvh+5mhONXCGTJ3qyTITwG6CxeG3A=,tag:kurCrF2rGQFBF2u7Hhinuw==,type:str] SECRET_HEALTHCHECKS_WEBHOOK: ENC[AES256_GCM,data:YG8/g4i8inIQnCIsQyEkPdNyVmbFYU4bhixacOEEEcuJMl8ax8TH1yBRl5ziQmBggp/CETorWCmNiC3jkUXYYta/znlo76T5,iv:SGdg9htpyFP38jbAJDg+zq4Rs+axgM5m3SsgBG38Bu8=,tag:TTIVFki9e03rqVvNmtsFuw==,type:str] SECRET_CLOUDFLARE_ACCOUNT_ID: ENC[AES256_GCM,data:bKGSKh/TxNtCMRa83/i44fX7XC5mRxBLVeZ94UltjOo=,iv:Ji0tUnrvDywxMeCvNwBrG/a8JVudfK4sXYL8q0i/cz8=,tag:j4Bwvcz73RdIInsiz0F0JA==,type:str] + SECRET_CLUSTER_CLOUDFLARE_TUNNEL_ID: ENC[AES256_GCM,data:bl9psiIxkDTchopNuPNxaGy7fQWJLdZwfnqTi8AOSl5cFMAZ,iv:CKYrQHv8fiHU4312Wfo6XlMofiR6uWP+AafO1n1y970=,tag:iyceSr/VUtE2cNbndkmV1g==,type:str] K8S_SERVICE_ENDPOINT: ENC[AES256_GCM,data:3s9EeJwFzDQ=,iv:a4oU9bf7ESscw6o9YqhBx8kRm/rL1l2ydjjd1ngn/P0=,tag:TAwJ2UmFuEHeHsEhfiVH9g==,type:str] sops: kms: [] @@ -24,8 +25,8 @@ sops: ZGRUUFpKTXpjWW9HQ0R1VDk2RmVmQ2MKJwHW3q0vCZClJFfDrWSLw6C43vWVfyLr 1ACvmNWml+xv/MOQwoRRMx6OVF74X83UyTFdVrXXk7SkzRcwQr4j+A== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-01-11T22:06:29Z" - mac: ENC[AES256_GCM,data:kpt0cEtZo9e2wRcnbp7VosxzVdRTUsnNOmCfjFW/6dAVt3PQuck4hoQ+5ZVO/kL02JDxfLFDaSrbEGwWyf3pwvWV0IQHPFH1W0DcgHe0bSHLBB1AAufISuaQ+OfrO6igYiUjJ1ijk8sErT64qY0WN1NTnMbhbGpXrmKl9jSxpbc=,iv:bVeu6F3V6dkx/VvHume/KdxVPArMzPCkTS+e5M9+ru8=,tag:u8MdtwtUcbk2/XFvdfvomw==,type:str] + lastmodified: "2024-01-12T19:24:10Z" + mac: ENC[AES256_GCM,data:EdmF3LFSmBFe6Vn5LzVmOb6tyOYto4iwIfJlUL50pjIobvw073oTwd99NkZ9m6aXB2no6ghgPc2RU8jOAtK9gg71kvLOGP45VZ07zLbcxsM8iEkSp2UX2k07/WavdXXGY4yBswGCZgnuPKah6uVNs1s8zEQNCkQQu0D1Ukf3SJY=,iv:7+sUShSrv6iwBJUgT03l38Wg9yX4G1LeXpGgHlOuMnE=,tag:rgXF0E/BIfeyYwnAYYJBsQ==,type:str] pgp: [] encrypted_regex: ^(data|stringData)$ version: 3.8.1