Skip to main content
Version: 0.2 (next)

Expose Infrared over HTTPS

:::note GKE and EKS An install with installation.edge: gateway, as on GKE and EKS, doesn't need this page. Its Envoy Gateway edge publishes Infrared at installation.previews.signInURL behind Cloudflare, and makes the DNS records and origin certificate itself. This page is for an install on the Traefik edge, the default when installation.edge is empty, such as a single k3s node. :::

A port-forward is enough to install Infrared. To reach it without one, from any browser, and so GitHub can reach it with webhooks, give it a hostname and a certificate. On k3s, Traefik is already there, and cert-manager comes from your gitops repo at sync wave 10.

Finish the setup wizard before you expose Infrared: until the platform admin exists, the setup token is the only credential.

1. Open the ports and add the DNS record​

  • Allow TCP 80 and 443 to the node. Let's Encrypt's HTTP-01 challenge needs port 80 reachable from the internet.
  • Point an A record for your host at the node's public address. With a CDN or proxy in front, turn it off (DNS only) until the certificate is issued.

2. Add the issuer and the Ingress to the gitops repo​

These files are yours. Hydration never deletes a file and never rewrites one the template doesn't write, so they survive template upgrades.

registry/clusters/<cluster>/components/infrared-ingress.yaml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: infrared-ingress
namespace: argocd
labels:
app.kubernetes.io/part-of: infrared-gitops
annotations:
argocd.argoproj.io/sync-wave: "45" # after cert-manager (10) and Infrared (40)
spec:
project: platform
source:
repoURL: https://github.com/<org>/gitops
targetRevision: main
path: components/infrared-ingress
destination:
server: https://kubernetes.default.svc
namespace: infrared
syncPolicy:
automated: { prune: true, selfHeal: true }
syncOptions: [SkipDryRunOnMissingResource=true]

components/infrared-ingress/ holds a kustomization.yaml that lists the two files below.

issuer.yaml:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-http01
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-http01-account
solvers:
- http01:
ingress:
ingressClassName: traefik

ingress.yaml sends HTTPS to the infrared Service and redirects plain HTTP to it. cert-manager's challenge path is longer than /, so Traefik routes challenges to cert-manager ahead of the redirect.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: infrared
namespace: infrared
annotations:
cert-manager.io/cluster-issuer: letsencrypt-http01
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
ingressClassName: traefik
tls:
- hosts: [<host>]
secretName: infrared-tls
rules:
- host: <host>
http:
paths:
- path: /
pathType: Prefix
backend: { service: { name: infrared, port: { number: 80 } } }
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: https-redirect
namespace: infrared
spec:
redirectScheme: { scheme: https, permanent: true }
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: infrared-http
namespace: infrared
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.middlewares: infrared-https-redirect@kubernetescrd
spec:
ingressClassName: traefik
rules:
- host: <host>
http:
paths:
- path: /
pathType: Prefix
backend: { service: { name: infrared, port: { number: 80 } } }

Open a pull request with the three files and merge it. Argo CD syncs the Application, and cert-manager usually issues the certificate within a minute.

3. Check it​

kubectl -n infrared get certificate infrared-tls # READY True
curl -sI http://<host>/ | head -1 # 301
curl -s -o /dev/null -w '%{http_code}\n' https://<host>/api/v1/orgs # 401 without a session

The API works out its own address from the X-Forwarded-Proto and X-Forwarded-Host headers Traefik sets. Session cookies are marked Secure over HTTPS, and the addresses Infrared gives GitHub and Google use your host, with no chart change.

4. Point the GitHub App at the new URL​

If you ran the setup wizard over a port-forward, the GitHub App has no sign-in callback URL and no webhook URL yet. Open Settings → GitHub App at the new address. It shows the Callback URL and Webhook URL to copy, and Edit on GitHub opens the App's settings. Then:

  • add the callback URL, so people can sign in with GitHub and link their GitHub accounts through the App;
  • activate the webhook with that URL and its secret, so opening an issue or a pull request starts work in Infrared (Connect the webhook).

5. Add the address to Sign in with Google​

If people sign in with Google, add the new address's redirect URI to the install's Google OAuth client, under Authorized redirect URIs:

https://<host>/api/v1/auth/google/callback

Infrared gives Google the redirect URI of the address a sign-in starts at, so the client needs one for every address people open Infrared at. A second hostname, or an address on a private network, each needs its own. Settings → Sign-in shows the exact URI for the address you opened it at. Without it, Google stops the sign-in with redirect_uri_mismatch.

6. Add the address to git connectors​

A git connector with an OAuth application of its own sends people back to the address they link from, so register the new address's callback on the forge's application too:

https://<host>/api/v1/me/links/<connector>/callback

Access → Git connectors, opened at the new address, shows each connector's exact callback. A connector through the platform org's GitHub App needs nothing beyond step 4, and one on Infrared's own Gitea picks up the address when you save it again there.

HTTPS everywhere​

Infrared's Ingress serves only HTTPS, and plain HTTP redirects to it. The Product charts Infrared scaffolds do the same for every environment address: their Ingresses listen on Traefik's websecure entrypoint only. To redirect every other plain-HTTP request on the cluster too, add a lowest-priority catch-all route on the web entrypoint that redirects to HTTPS. cert-manager's HTTP-01 challenge routes are more specific, so they keep winning and certificates keep renewing:

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: http-catch-all
namespace: infrared
spec:
entryPoints: [web]
routes:
- match: PathPrefix(`/`)
kind: Rule
priority: 1
middlewares:
- name: https-redirect # a redirectScheme Middleware: scheme https, permanent
services:
- name: infrared
port: 80

Don't redirect the whole web entrypoint in Traefik's own settings instead. That also redirects Let's Encrypt's HTTP-01 challenges, and certificates stop renewing.