Skip to content

Commit 23f6fb9

Browse files
authored
feat: Add stac-auth-proxy. (#358)
1 parent bd095a0 commit 23f6fb9

File tree

20 files changed

+1098
-18
lines changed

20 files changed

+1098
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
## Changed
1818

1919
- Unified scripts and removed Makefile, combined all into one CLI command `eoapi-cli` [#359](https://github.com/developmentseed/eoapi-k8s/pull/359)
20+
- Added stac-auth-proxy for authentication and authorization on the STAC API [#358](https://github.com/developmentseed/eoapi-k8s/pull/358)
2021

2122
## [0.8.0] - 2025-11-20
2223

charts/eoapi/Chart.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,7 @@ dependencies:
7777
version: 10.2.0
7878
repository: https://grafana.github.io/helm-charts
7979
condition: observability.grafana.enabled
80+
- name: stac-auth-proxy
81+
version: "0.1.1"
82+
repository: "oci://ghcr.io/developmentseed/stac-auth-proxy/charts"
83+
condition: stac-auth-proxy.enabled

charts/eoapi/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ A Helm chart for deploying Earth Observation APIs with integrated STAC, raster,
77
## Features
88

99
- STAC API for metadata discovery and search
10+
- STAC Auth Proxy for authentication/authorization (optional)
1011
- Raster tile services (TiTiler)
1112
- Vector tile services (TIPG)
1213
- Multidimensional data support
@@ -42,6 +43,21 @@ helm install eoapi eoapi/eoapi -f profiles/experimental.yaml
4243
- PV provisioner support
4344
- PostgreSQL operator
4445

46+
## STAC Auth Proxy (Optional)
47+
48+
The chart includes support for [stac-auth-proxy](https://github.com/developmentseed/stac-auth-proxy) to add authentication and authorization to your STAC API. This feature is disabled by default and can be enabled, and will need a valid OIDC discovery URL.
49+
50+
### Configuration
51+
52+
```yaml
53+
stac-auth-proxy:
54+
enabled: true
55+
env:
56+
OIDC_DISCOVERY_URL: "https://your-auth-server/.well-known/openid-configuration"
57+
```
58+
59+
When enabled, the ingress will automatically route STAC API requests through the auth proxy instead of directly to the STAC service.
60+
4561
## Quick Start with Profiles
4662
4763
Use pre-configured profiles for common deployment scenarios:

charts/eoapi/profiles/experimental.yaml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,48 @@ ingress:
364364
tls:
365365
enabled: false
366366

367+
stac-auth-proxy:
368+
enabled: true
369+
service:
370+
port: 8080
371+
# For testing this will be set dynamically; for production, point to your OIDC server
372+
# env:
373+
# OIDC_DISCOVERY_URL: "http://eoapi-mock-oidc-server.eoapi.svc.cluster.local:8080/.well-known/openid-configuration"
374+
375+
######################
376+
# MOCK OIDC SERVER
377+
######################
378+
# Mock OIDC server for testing authentication
379+
# WARNING: Only for development/testing, never use in production!
380+
mockOidcServer:
381+
enabled: true
382+
replicaCount: 1
383+
image:
384+
repository: ghcr.io/alukach/mock-oidc-server
385+
tag: latest
386+
pullPolicy: IfNotPresent
387+
port: 8888
388+
clientId: "test-client"
389+
clientSecret: "test-secret"
390+
service:
391+
type: ClusterIP
392+
port: 8080
393+
ingress:
394+
enabled: true
395+
path: "/mock-oidc"
396+
resources:
397+
limits:
398+
cpu: 100m
399+
memory: 128Mi
400+
requests:
401+
cpu: 50m
402+
memory: 64Mi
403+
nodeSelector: {}
404+
tolerations: []
405+
affinity: {}
406+
imagePullSecrets: []
407+
extraEnv: []
408+
367409
######################
368410
# SERVICE
369411
######################

charts/eoapi/templates/_helpers/validation.tpl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,19 @@ so we use this helper function to check autoscaling rules
2626
{{- end }}
2727
{{- end }}
2828
{{- end -}}
29+
30+
{{/*
31+
Validate stac-auth-proxy configuration
32+
Ensures OIDC_DISCOVERY_URL is set when stac-auth-proxy is enabled
33+
Ensures stac-auth-proxy cannot be enabled when stac is disabled
34+
*/}}
35+
{{- define "eoapi.validateStacAuthProxy" -}}
36+
{{- if index .Values "stac-auth-proxy" "enabled" }}
37+
{{- if not .Values.stac.enabled }}
38+
{{- fail "stac-auth-proxy cannot be enabled when stac.enabled is false. Enable stac first or disable stac-auth-proxy." }}
39+
{{- end }}
40+
{{- if not (index .Values "stac-auth-proxy" "env" "OIDC_DISCOVERY_URL") }}
41+
{{- fail "stac-auth-proxy.env.OIDC_DISCOVERY_URL is required when stac-auth-proxy is enabled. Set it to your OpenID Connect discovery URL (e.g., https://your-auth-server/.well-known/openid-configuration)" }}
42+
{{- end }}
43+
{{- end }}
44+
{{- end -}}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{{/*
2-
This template validates the PostgreSQL configuration.
2+
This template validates various configurations.
33
It doesn't create any resources but ensures configuration consistency.
44
*/}}
55
{{- include "eoapi.validatePostgresql" . }}
6+
{{- include "eoapi.validateStacAuthProxy" . }}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
{{- if .Values.mockOidcServer.enabled }}
2+
apiVersion: apps/v1
3+
kind: Deployment
4+
metadata:
5+
name: {{ include "eoapi.fullname" . }}-mock-oidc-server
6+
namespace: {{ .Release.Namespace }}
7+
labels:
8+
{{- include "eoapi.labels" . | nindent 4 }}
9+
app.kubernetes.io/component: mock-oidc-server
10+
spec:
11+
replicas: {{ .Values.mockOidcServer.replicaCount | default 1 }}
12+
selector:
13+
matchLabels:
14+
{{- include "eoapi.selectorLabels" . | nindent 6 }}
15+
app.kubernetes.io/component: mock-oidc-server
16+
template:
17+
metadata:
18+
labels:
19+
{{- include "eoapi.selectorLabels" . | nindent 8 }}
20+
app.kubernetes.io/component: mock-oidc-server
21+
spec:
22+
{{- if .Values.mockOidcServer.imagePullSecrets }}
23+
imagePullSecrets:
24+
{{- toYaml .Values.mockOidcServer.imagePullSecrets | nindent 8 }}
25+
{{- end }}
26+
containers:
27+
- name: mock-oidc
28+
image: "{{ if .Values.mockOidcServer.image }}{{ .Values.mockOidcServer.image.repository | default "ghcr.io/alukach/mock-oidc-server" }}:{{ .Values.mockOidcServer.image.tag | default "latest" }}{{ else }}ghcr.io/alukach/mock-oidc-server:latest{{ end }}"
29+
imagePullPolicy: {{ if .Values.mockOidcServer.image }}{{ .Values.mockOidcServer.image.pullPolicy | default "IfNotPresent" }}{{ else }}IfNotPresent{{ end }}
30+
env:
31+
- name: MOCK_OIDC_PORT
32+
value: "{{ .Values.mockOidcServer.port | default 8888 }}"
33+
- name: MOCK_OIDC_CLIENT_ID
34+
value: "{{ .Values.mockOidcServer.clientId | default "test-client" }}"
35+
- name: MOCK_OIDC_CLIENT_SECRET
36+
value: "{{ .Values.mockOidcServer.clientSecret | default "test-secret" }}"
37+
{{- if .Values.mockOidcServer.extraEnv }}
38+
{{- toYaml .Values.mockOidcServer.extraEnv | nindent 8 }}
39+
{{- end }}
40+
ports:
41+
- name: http
42+
containerPort: {{ .Values.mockOidcServer.port | default 8888 }}
43+
protocol: TCP
44+
startupProbe:
45+
httpGet:
46+
path: /.well-known/openid-configuration
47+
port: http
48+
initialDelaySeconds: 10
49+
periodSeconds: 5
50+
failureThreshold: 12
51+
timeoutSeconds: 3
52+
livenessProbe:
53+
httpGet:
54+
path: /.well-known/openid-configuration
55+
port: http
56+
initialDelaySeconds: 30
57+
periodSeconds: 10
58+
failureThreshold: 3
59+
timeoutSeconds: 3
60+
readinessProbe:
61+
httpGet:
62+
path: /.well-known/openid-configuration
63+
port: http
64+
initialDelaySeconds: 5
65+
periodSeconds: 5
66+
failureThreshold: 3
67+
timeoutSeconds: 3
68+
{{- if .Values.mockOidcServer.resources }}
69+
resources:
70+
{{- toYaml .Values.mockOidcServer.resources | nindent 10 }}
71+
{{- end }}
72+
{{- if .Values.mockOidcServer.nodeSelector }}
73+
nodeSelector:
74+
{{- toYaml .Values.mockOidcServer.nodeSelector | nindent 8 }}
75+
{{- end }}
76+
{{- if .Values.mockOidcServer.affinity }}
77+
affinity:
78+
{{- toYaml .Values.mockOidcServer.affinity | nindent 8 }}
79+
{{- end }}
80+
{{- if .Values.mockOidcServer.tolerations }}
81+
tolerations:
82+
{{- toYaml .Values.mockOidcServer.tolerations | nindent 8 }}
83+
{{- end }}
84+
{{- end }}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{- if .Values.mockOidcServer.enabled }}
2+
apiVersion: v1
3+
kind: Service
4+
metadata:
5+
name: {{ include "eoapi.fullname" . }}-mock-oidc-server
6+
namespace: {{ .Release.Namespace }}
7+
labels:
8+
{{- include "eoapi.labels" . | nindent 4 }}
9+
app.kubernetes.io/component: mock-oidc-server
10+
spec:
11+
type: {{ if .Values.mockOidcServer.service }}{{ .Values.mockOidcServer.service.type | default "ClusterIP" }}{{ else }}ClusterIP{{ end }}
12+
ports:
13+
- port: {{ if .Values.mockOidcServer.service }}{{ .Values.mockOidcServer.service.port | default 8080 }}{{ else }}8080{{ end }}
14+
targetPort: http
15+
protocol: TCP
16+
name: http
17+
selector:
18+
{{- include "eoapi.selectorLabels" . | nindent 4 }}
19+
app.kubernetes.io/component: mock-oidc-server
20+
{{- end }}

charts/eoapi/templates/networking/ingress.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ spec:
4949
path: {{ $.Values.stac.ingress.path }}{{ if eq $.Values.ingress.className "nginx" }}(/|$)(.*){{ end }}
5050
backend:
5151
service:
52+
{{- if index $.Values "stac-auth-proxy" "enabled" }}
53+
name: {{ $.Release.Name }}-stac-auth-proxy
54+
{{- else }}
5255
name: {{ $.Release.Name }}-stac
56+
{{- end }}
5357
port:
5458
number: {{ $.Values.service.port }}
5559
{{- end }}
@@ -74,6 +78,16 @@ spec:
7478
number: {{ $.Values.service.port }}
7579
{{- end }}
7680

81+
{{- if and $.Values.mockOidcServer.enabled $.Values.mockOidcServer.ingress.enabled }}
82+
- pathType: {{ if eq $.Values.ingress.className "nginx" }}ImplementationSpecific{{ else }}Prefix{{ end }}
83+
path: {{ $.Values.mockOidcServer.ingress.path }}{{ if eq $.Values.ingress.className "nginx" }}(/|$)(.*){{ end }}
84+
backend:
85+
service:
86+
name: {{ $.Release.Name }}-mock-oidc-server
87+
port:
88+
number: {{ $.Values.mockOidcServer.service.port | default 8080 }}
89+
{{- end }}
90+
7791
{{- if $.Values.docServer.enabled }}
7892
- pathType: Prefix
7993
path: "/{{ $.Values.ingress.rootPath | default "" }}"
@@ -105,7 +119,11 @@ spec:
105119
path: {{ .Values.stac.ingress.path }}{{ if eq .Values.ingress.className "nginx" }}(/|$)(.*){{ end }}
106120
backend:
107121
service:
122+
{{- if index .Values "stac-auth-proxy" "enabled" }}
123+
name: {{ .Release.Name }}-stac-auth-proxy
124+
{{- else }}
108125
name: {{ .Release.Name }}-stac
126+
{{- end }}
109127
port:
110128
number: {{ .Values.service.port }}
111129
{{- end }}
@@ -130,6 +148,16 @@ spec:
130148
number: {{ .Values.service.port }}
131149
{{- end }}
132150

151+
{{- if and .Values.mockOidcServer.enabled .Values.mockOidcServer.ingress.enabled }}
152+
- pathType: {{ if eq .Values.ingress.className "nginx" }}ImplementationSpecific{{ else }}Prefix{{ end }}
153+
path: {{ .Values.mockOidcServer.ingress.path }}{{ if eq .Values.ingress.className "nginx" }}(/|$)(.*){{ end }}
154+
backend:
155+
service:
156+
name: {{ .Release.Name }}-mock-oidc-server
157+
port:
158+
number: {{ .Values.mockOidcServer.service.port | default 8080 }}
159+
{{- end }}
160+
133161
{{- if .Values.docServer.enabled }}
134162
- pathType: Prefix
135163
path: "/{{ $.Values.ingress.rootPath | default "" }}"

charts/eoapi/templates/networking/traefik-middleware.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ spec:
1919
{{- if .Values.multidim.enabled }}
2020
- {{ .Values.multidim.ingress.path }}
2121
{{- end }}
22+
{{- if and .Values.mockOidcServer.enabled .Values.mockOidcServer.ingress.enabled }}
23+
- {{ .Values.mockOidcServer.ingress.path }}
24+
{{- end }}
2225
{{- end }}

0 commit comments

Comments
 (0)