diff --git a/config/clusters/2i2c/staging.values.yaml b/config/clusters/2i2c/staging.values.yaml index eef509dbf5..c4ce17f9a0 100644 --- a/config/clusters/2i2c/staging.values.yaml +++ b/config/clusters/2i2c/staging.values.yaml @@ -2,6 +2,13 @@ dex: enabled: true hubHostName: staging.2i2c.cloud +staticSites: + enabled: true + repo: https://github.com/inferentialthinking/inferentialthinking.github.io + branch: master + host: staging.2i2c.cloud + path: /textbook + jupyterhub: custom: 2i2c: @@ -27,6 +34,7 @@ jupyterhub: dex: url: http://dex:5556 oauth_redirect_uri: https://staging.2i2c.cloud/services/dex/callback + oauth_no_confirm: true oauth2-proxy: url: http://dex:9000 config: diff --git a/helm-charts/basehub/templates/dex/configmap.yaml b/helm-charts/basehub/templates/dex/configmap.yaml index 2955f484c6..0d623a567f 100644 --- a/helm-charts/basehub/templates/dex/configmap.yaml +++ b/helm-charts/basehub/templates/dex/configmap.yaml @@ -7,10 +7,6 @@ metadata: app: dex data: dex.yaml: | - # dex expands env vars in values, but does *not* interpolate - # them. So we can use an env var for OAUTH2_CLIENT_SECRET as - # it is just an expansion, but can not use env vars when constructing - # URLs as there's no interpolation! grr. issuer: https://{{ .Values.dex.hubHostName }}/services/dex storage: type: sqlite3 @@ -24,7 +20,7 @@ data: oauth2: # Don't explicitly require users to grant access via the - # dex interface, for a smoother interface + # dex interface, for a smoother experience skipApprovalScreen: true connectors: @@ -32,9 +28,10 @@ data: id: hub name: hub config: - # Connector config values starting with a "$" will read from the environment. clientID: service-dex - clientSecret: $HUB_OAUTH2_CLIENT_SECRET + # Env vars are expanded via gomplate, which is present in the + # upstream dex docker image + clientSecret: {{ "{{" }} .Env.HUB_OAUTH2_CLIENT_SECRET {{ "}}" }} redirectURI: https://{{ .Values.dex.hubHostName }}/services/dex/callback userIDKey: name tokenURL: http://proxy-public/hub/api/oauth2/token @@ -46,15 +43,25 @@ data: redirectURIs: - https://{{ .Values.dex.hubHostName }}/services/oauth2-proxy/oauth2/callback name: oauth2-proxy - secret: $OAUTH2_PROXY_CLIENT_SECRET + # Env vars are expanded via gomplate, which is present in the + # upstream dex docker image + secret: {{ "{{" }} .Env.OAUTH2_PROXY_CLIENT_SECRET {{ "}}" }} oauth2-proxy.cfg: | provider = "oidc" + # This is hardcoded in the dex config client_id = "oauth2-proxy" redirect_url = "https://{{ .Values.dex.hubHostName }}/services/oauth2-proxy/oauth2/callback" oidc_issuer_url = "https://{{ .Values.dex.hubHostName }}/services/dex" oidc_email_claim = "sub" + # We don't actually use email for anything here, so skip email verification insecure_oidc_allow_unverified_email = true email_domains = "*" + # Listen on port 9000 http_address = "http://0.0.0.0:9000" + # Don't require user interaction to log in - treat this more like SSO skip_provider_button = true + # This is exposed to the internet as a JupyterHub service, + # so it is only available prefixed with this URL + reverse_proxy = true + proxy_prefix = "/services/oauth2-proxy/oauth2" {{- end }} diff --git a/helm-charts/basehub/templates/dex/deployment.yaml b/helm-charts/basehub/templates/dex/deployment.yaml index 37c2fc63d0..19fa311299 100644 --- a/helm-charts/basehub/templates/dex/deployment.yaml +++ b/helm-charts/basehub/templates/dex/deployment.yaml @@ -34,6 +34,7 @@ spec: - name: dex containerPort: 5556 env: + # These are expanded by the dex config - name: HUB_OAUTH2_CLIENT_SECRET valueFrom: secretKeyRef: @@ -49,7 +50,9 @@ spec: mountPath: /srv/config - name: db mountPath: /srv/db - command: + # Needs to be args, not cmd - this allows gomplate based + # expansion of config file + args: - dex - serve - /srv/config/dex.yaml @@ -65,6 +68,7 @@ spec: - name: oauth2-proxy containerPort: 9000 env: + # This is read by oauth2-proxy - name: OAUTH2_PROXY_COOKIE_SECRET valueFrom: secretKeyRef: diff --git a/helm-charts/basehub/templates/static/configmap.yaml b/helm-charts/basehub/templates/static/configmap.yaml new file mode 100644 index 0000000000..f7bdf93076 --- /dev/null +++ b/helm-charts/basehub/templates/static/configmap.yaml @@ -0,0 +1,17 @@ +{{- if .Values.staticSites.enabled -}} +kind: ConfigMap +apiVersion: v1 +metadata: + name: static-sites + labels: + app: static-sites +data: + nginx.conf: | + server { + listen 8080; + location {{ .Values.staticSites.path }} { + index index.html; + alias /srv/content/repo; + } + } +{{- end }} diff --git a/helm-charts/basehub/templates/static/deployment.yaml b/helm-charts/basehub/templates/static/deployment.yaml new file mode 100644 index 0000000000..54669eb3b2 --- /dev/null +++ b/helm-charts/basehub/templates/static/deployment.yaml @@ -0,0 +1,71 @@ +{{- if .Values.staticSites.enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: static-sites +spec: + replicas: 1 + selector: + matchLabels: + app: static-sites + template: + metadata: + labels: + app: static-sites + annotations: + checksum/config: {{ include (print $.Template.BasePath "/static/configmap.yaml") . | sha256sum }} + spec: + volumes: + - name: nginx-config + configMap: + name: static-sites + - name: content + emptyDir: {} + initContainers: + - name: site-clone + image: alpine/git + args: + - clone + - --depth=1 + - --branch={{ .Values.staticSites.branch | required "staticSites.branch is required with staticSite.enabled set to true" }} + - --single-branch + - -- + - '{{ .Values.staticSites.repo | required "staticSites.repo is required with staticSites.enabled set to true" }}' + - /srv/content/repo + securityContext: + runAsUser: 1000 + allowPrivilegeEscalation: False + readOnlyRootFilesystem: True + volumeMounts: + - name: content + mountPath: /srv/content + containers: + - name: content-sync + image: alpine/git + workingDir: /srv/content + command: + - /bin/sh + args: + - -c + - "while true; do git fetch origin; git reset --hard origin/{{ .Values.staticSites.branch }}; sleep\ + \ 5m; done" + securityContext: + runAsUser: 1000 + allowPrivilegeEscalation: False + readOnlyRootFilesystem: True + volumeMounts: + - name: content + mountPath: /srv/content + - name: server + image: nginx:1.19 + command: ["/usr/sbin/nginx", "-g", "daemon off;"] + ports: + - name: nginx + containerPort: 8080 + volumeMounts: + - name: nginx-config + mountPath: /etc/nginx/conf.d/default.conf + subPath: nginx.conf + - name: content + mountPath: /srv/content +{{- end }} diff --git a/helm-charts/basehub/templates/static/ingress.yaml b/helm-charts/basehub/templates/static/ingress.yaml new file mode 100644 index 0000000000..216f20413b --- /dev/null +++ b/helm-charts/basehub/templates/static/ingress.yaml @@ -0,0 +1,24 @@ +{{- if .Values.staticSites.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + # Authenticate with oauth2-proxy so only hub logged-in users see this + # https://kubernetes.github.io/ingress-nginx/examples/auth/oauth-external-auth/ + nginx.ingress.kubernetes.io/auth-url: "http://dex.{{ .Release.Namespace }}.svc.cluster.local:9000/services/oauth2-proxy/oauth2/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://$host/services/oauth2-proxy/oauth2/start?rd=$escaped_request_uri" + name: static-sites +spec: + ingressClassName: nginx + rules: + - host: {{ .Values.staticSites.host}} + http: + paths: + - path: {{ .Values.staticSites.path }} + pathType: Prefix + backend: + service: + name: static-sites + port: + number: 80 +{{- end }} \ No newline at end of file diff --git a/helm-charts/basehub/templates/static/service.yaml b/helm-charts/basehub/templates/static/service.yaml new file mode 100644 index 0000000000..9d7cefc353 --- /dev/null +++ b/helm-charts/basehub/templates/static/service.yaml @@ -0,0 +1,16 @@ +{{- if .Values.staticSites.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: static-sites + labels: + app: static-sites +spec: + type: ClusterIP + ports: + - name: http + port: 80 + targetPort: nginx + selector: + app: static-sites +{{- end }} diff --git a/helm-charts/basehub/values.schema.yaml b/helm-charts/basehub/values.schema.yaml index b22fdcea48..540a0f920c 100644 --- a/helm-charts/basehub/values.schema.yaml +++ b/helm-charts/basehub/values.schema.yaml @@ -18,7 +18,11 @@ required: - jupyterhub - userServiceAccount - dex + - staticSites properties: + staticSites: + type: object + additionalProperties: true dex: type: object additionalProperties: false diff --git a/helm-charts/basehub/values.yaml b/helm-charts/basehub/values.yaml index 8ee90f4cee..1608461d2e 100644 --- a/helm-charts/basehub/values.yaml +++ b/helm-charts/basehub/values.yaml @@ -8,6 +8,15 @@ userServiceAccount: dex: enabled: false +staticSites: + enabled: false + + repo: + branch: + + host: + path: + azureFile: enabled: false pv: