From bf53b81115a05b15aa1efab8f6e1b50ff0fe6f57 Mon Sep 17 00:00:00 2001 From: Felix Delattre Date: Tue, 16 Dec 2025 16:45:50 +0100 Subject: [PATCH 1/2] Added helm chart auth options. --- helm/AUTHORIZATION.md | 150 ++++++++++++++++++++ helm/data/custom_filters.py | 27 ++++ helm/templates/_helpers.tpl | 73 ++++++++++ helm/templates/configmap.yaml | 11 ++ helm/templates/deployment.yaml | 12 +- helm/tests/authorization_test.yaml | 220 +++++++++++++++++++++++++++++ helm/tests/configmap_test.yaml | 51 +++++++ helm/values.yaml | 75 +++++++--- 8 files changed, 597 insertions(+), 22 deletions(-) create mode 100644 helm/AUTHORIZATION.md create mode 100644 helm/data/custom_filters.py create mode 100644 helm/templates/configmap.yaml create mode 100644 helm/tests/authorization_test.yaml create mode 100644 helm/tests/configmap_test.yaml diff --git a/helm/AUTHORIZATION.md b/helm/AUTHORIZATION.md new file mode 100644 index 00000000..f4e8433c --- /dev/null +++ b/helm/AUTHORIZATION.md @@ -0,0 +1,150 @@ +# Authorization configuration guide + +The chart provides two levels of authorization: + +1. **[Route-level authorization](https://developmentseed.org/stac-auth-proxy/user-guide/route-level-auth/)**: Controls which API endpoints are accessible and by whom +2. **[Record-level authorization](https://developmentseed.org/stac-auth-proxy/user-guide/record-level-auth/)**: Filters collections and items based on user permissions + +## Route-Level Authorization + +Configure via `authorization.route` section in `values.yaml`. + +### Mode: `default` (Recommended) + +Public catalog with protected write operations. This is the most common configuration. + +```yaml +authorization: + route: + mode: "default" +``` + +This automatically sets `DEFAULT_PUBLIC=true`, making all read endpoints public while requiring authentication for write operations. + +### Mode: `custom` + +Define specific public and private endpoints with custom rules. + +```yaml +authorization: + route: + mode: "custom" + publicEndpoints: + "^/collections$": ["GET"] + "^/search$": ["GET", "POST"] + "^/api.html$": ["GET"] + "^/healthz": ["GET"] + privateEndpoints: + "^/collections$": [["POST", "collection:create"]] + "^/collections/([^/]+)$": [["PUT", "collection:update"], ["DELETE", "collection:delete"]] + "^/collections/([^/]+)/items$": [["POST", "item:create"]] +``` + +**Endpoint format:** +- `publicEndpoints`: Maps regex paths to HTTP methods arrays +- `privateEndpoints`: Maps regex paths to HTTP methods or `[method, scope]` tuples + - Scopes define required OAuth2 scopes for the operation + +### Mode: `disabled` + +No route-level authorization applied. + +```yaml +authorization: + route: + mode: "disabled" +``` + +## Record-Level Authorization + +Configure via `authorization.record` section in `values.yaml`. + +### Mode: `disabled` (Default) + +No record-level filtering applied. All collections and items are visible to authenticated users. + +```yaml +authorization: + record: + mode: "disabled" +``` + +### Mode: `custom` + +Use Python filter classes to control visibility of collections and items. + +```yaml +authorization: + record: + mode: "custom" + custom: + filtersFile: "data/custom_filters.py" +``` + +This automatically: +- Creates a ConfigMap from your Python file +- Mounts it at `/app/src/stac_auth_proxy/custom_filters.py` +- Sets `COLLECTIONS_FILTER_CLS=stac_auth_proxy.custom_filters:CollectionsFilter` +- Sets `ITEMS_FILTER_CLS=stac_auth_proxy.custom_filters:ItemsFilter` + +Review the stac-auth-proxy [documentation for more information on custom filters](https://developmentseed.org/stac-auth-proxy/user-guide/record-level-auth/#custom-filter-factories). + +### Mode: `opa` + +Use Open Policy Agent for policy-based filtering. + +```yaml +authorization: + record: + mode: "opa" + opa: + url: "http://opa-service:8181" + policy: "stac/items/allow" +``` + +This sets: +- `ITEMS_FILTER_CLS=stac_auth_proxy.filters.opa:Opa` +- `ITEMS_FILTER_ARGS='["http://opa-service:8181", "stac/items/allow"]'` + +## Some configuration examples + +### Example 1: Default for public catalog, protected writes + +```yaml +authorization: + route: + mode: "default" + record: + mode: "disabled" +``` + +### Example 2: Fully protected catalog + +```yaml +authorization: + route: + mode: "custom" + publicEndpoints: + "^/healthz": ["GET"] + privateEndpoints: + "^/collections$": [["GET", "stac:read"], ["POST", "stac:write"]] + "^/search$": [["GET", "stac:read"], ["POST", "stac:read"]] + record: + mode: "custom" + custom: + filtersFile: "data/custom_filters.py" +``` + +## Direct configuration + +Existing charts using `env` variables directly continue to work: + +```yaml +env: + DEFAULT_PUBLIC: "false" + PUBLIC_ENDPOINTS: '{"^/search$": ["GET"]}' + PRIVATE_ENDPOINTS: '{"^/collections$": [["POST", "collection:create"]]}' + ITEMS_FILTER_CLS: "custom.module:Filter" +``` + +**Environment variables specified in `env` take precedence over `authorization` settings.** diff --git a/helm/data/custom_filters.py b/helm/data/custom_filters.py new file mode 100644 index 00000000..47224674 --- /dev/null +++ b/helm/data/custom_filters.py @@ -0,0 +1,27 @@ +""" +Sample custom filters for STAC Auth Proxy. +This file demonstrates the structure needed for custom collection and item filters. +""" + +import dataclasses +from typing import Any + + +@dataclasses.dataclass +class CollectionsFilter: + """Filter collections based on user permissions.""" + + async def __call__(self, context: dict[str, Any]) -> str: + """Return True if user can access this collection.""" + # Example: Allow all collections for authenticated users + return "1=1" + + +@dataclasses.dataclass +class ItemsFilter: + """Filter items based on user permissions.""" + + async def __call__(self, context: dict[str, Any]) -> str: + """Return True if user can access this item.""" + # Example: Allow all items for authenticated users + return "1=1" diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 8bab877e..cb52fd88 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -69,3 +69,76 @@ Render env var value based on type {{- . | toJson | quote -}} {{- end -}} {{- end -}} + +{{/* +Generate authorization environment variables +*/}} +{{- define "stac-auth-proxy.authorizationEnv" -}} +{{- $routeMode := .Values.authorization.route.mode | default "default" -}} +{{- $recordMode := .Values.authorization.record.mode | default "disabled" -}} + +{{- /* Route-level authorization */ -}} +{{- if eq $routeMode "default" -}} +{{- if not (hasKey .Values.env "DEFAULT_PUBLIC") }} +- name: DEFAULT_PUBLIC + value: "true" +{{- end }} +{{- else if eq $routeMode "custom" -}} +{{- if not (hasKey .Values.env "DEFAULT_PUBLIC") }} +- name: DEFAULT_PUBLIC + value: "false" +{{- end }} +{{- if and .Values.authorization.route.publicEndpoints (gt (len .Values.authorization.route.publicEndpoints) 0) (not (hasKey .Values.env "PUBLIC_ENDPOINTS")) }} +- name: PUBLIC_ENDPOINTS + value: {{ .Values.authorization.route.publicEndpoints | toJson | quote }} +{{- end }} +{{- if and .Values.authorization.route.privateEndpoints (gt (len .Values.authorization.route.privateEndpoints) 0) (not (hasKey .Values.env "PRIVATE_ENDPOINTS")) }} +- name: PRIVATE_ENDPOINTS + value: {{ .Values.authorization.route.privateEndpoints | toJson | quote }} +{{- end }} +{{- end }} + +{{- /* Record-level authorization */ -}} +{{- if eq $recordMode "custom" -}} +{{- if not (hasKey .Values.env "COLLECTIONS_FILTER_CLS") }} +- name: COLLECTIONS_FILTER_CLS + value: "stac_auth_proxy.custom_filters:CollectionsFilter" +{{- end }} +{{- if not (hasKey .Values.env "ITEMS_FILTER_CLS") }} +- name: ITEMS_FILTER_CLS + value: "stac_auth_proxy.custom_filters:ItemsFilter" +{{- end }} +{{- else if eq $recordMode "opa" -}} +{{- if not (hasKey .Values.env "ITEMS_FILTER_CLS") }} +- name: ITEMS_FILTER_CLS + value: "stac_auth_proxy.filters:opa.Opa" +{{- end }} +{{- if and (not (hasKey .Values.env "ITEMS_FILTER_ARGS")) .Values.authorization.record.opa }} +- name: ITEMS_FILTER_ARGS + value: {{ list .Values.authorization.record.opa.url .Values.authorization.record.opa.policy | toJson | quote }} +{{- end }} +{{- end }} +{{- end -}} + +{{/* +Generate authorization volumes +*/}} +{{- define "stac-auth-proxy.authorizationVolumes" -}} +{{- if and (eq (.Values.authorization.record.mode | default "disabled") "custom") .Values.authorization.record.custom.filtersFile }} +- name: custom-filters + configMap: + name: {{ include "stac-auth-proxy.fullname" . }}-filters +{{- end }} +{{- end -}} + +{{/* +Generate authorization volume mounts +*/}} +{{- define "stac-auth-proxy.authorizationVolumeMounts" -}} +{{- if and (eq (.Values.authorization.record.mode | default "disabled") "custom") .Values.authorization.record.custom.filtersFile }} +- name: custom-filters + mountPath: /app/src/stac_auth_proxy/custom_filters.py + subPath: custom_filters.py + readOnly: true +{{- end }} +{{- end -}} diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml new file mode 100644 index 00000000..be4eafe5 --- /dev/null +++ b/helm/templates/configmap.yaml @@ -0,0 +1,11 @@ +{{- if and (eq (.Values.authorization.record.mode | default "disabled") "custom") .Values.authorization.record.custom.filtersFile }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "stac-auth-proxy.fullname" . }}-filters + labels: + {{- include "stac-auth-proxy.labels" . | nindent 4 }} +data: + custom_filters.py: | +{{ .Files.Get .Values.authorization.record.custom.filtersFile | nindent 4 }} +{{- end }} diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml index 72625e9d..928a8df8 100644 --- a/helm/templates/deployment.yaml +++ b/helm/templates/deployment.yaml @@ -34,19 +34,21 @@ spec: resources: {{- toYaml .Values.resources | nindent 12 }} env: + {{- include "stac-auth-proxy.authorizationEnv" . | nindent 12 }} {{- range $key, $value := .Values.env }} - name: {{ $key }} value: {{ include "stac-auth-proxy.envValue" $value }} {{- end }} - {{- with .Values.extraVolumeMounts }} volumeMounts: + {{- include "stac-auth-proxy.authorizationVolumeMounts" . | nindent 12 }} + {{- with .Values.extraVolumeMounts }} {{- toYaml . | nindent 12 }} - {{- end }} - - {{- with .Values.extraVolumes }} + {{- end }} volumes: + {{- include "stac-auth-proxy.authorizationVolumes" . | nindent 8 }} + {{- with .Values.extraVolumes }} {{- toYaml . | nindent 8 }} - {{- end }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/helm/tests/authorization_test.yaml b/helm/tests/authorization_test.yaml new file mode 100644 index 00000000..3bd433b0 --- /dev/null +++ b/helm/tests/authorization_test.yaml @@ -0,0 +1,220 @@ +suite: test authorization configuration +templates: + - deployment.yaml +tests: + # Route Authorization tests + - it: should set DEFAULT_PUBLIC=true when route mode is default + set: + authorization.route.mode: "default" + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: DEFAULT_PUBLIC + value: "true" + + - it: should not set authorization env vars when route mode is disabled + set: + authorization.route.mode: "disabled" + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: DEFAULT_PUBLIC + + - it: should set custom route authorization when mode is custom + set: + authorization.route.mode: "custom" + authorization.route.publicEndpoints: + "^/collections$": ["GET"] + "^/search$": ["GET", "POST"] + authorization.route.privateEndpoints: + "^/collections$": [["POST", "collection:create"]] + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: DEFAULT_PUBLIC + value: "false" + - contains: + path: spec.template.spec.containers[0].env + content: + name: PUBLIC_ENDPOINTS + value: '{"^/collections$":["GET"],"^/search$":["GET","POST"]}' + - contains: + path: spec.template.spec.containers[0].env + content: + name: PRIVATE_ENDPOINTS + value: '{"^/collections$":[["POST","collection:create"]]}' + + - it: should allow env vars to override route authorization + set: + authorization.route.mode: "default" + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + env.DEFAULT_PUBLIC: "false" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: DEFAULT_PUBLIC + value: "false" + + # Record Authorization tests + - it: should not set filter env vars when record mode is disabled + set: + authorization.record.mode: "disabled" + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: ITEMS_FILTER_CLS + - notContains: + path: spec.template.spec.containers[0].env + content: + name: COLLECTIONS_FILTER_CLS + + - it: should set custom filter env vars when record mode is custom + set: + authorization.record.mode: "custom" + authorization.record.custom.filtersFile: "data/custom_filters.py" + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: COLLECTIONS_FILTER_CLS + value: "stac_auth_proxy.custom_filters:CollectionsFilter" + - contains: + path: spec.template.spec.containers[0].env + content: + name: ITEMS_FILTER_CLS + value: "stac_auth_proxy.custom_filters:ItemsFilter" + + - it: should create volume mount when record mode is custom + set: + authorization.record.mode: "custom" + authorization.record.custom.filtersFile: "data/custom_filters.py" + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: custom-filters + mountPath: /app/src/stac_auth_proxy/custom_filters.py + subPath: custom_filters.py + readOnly: true + - contains: + path: spec.template.spec.volumes + content: + name: custom-filters + configMap: + name: RELEASE-NAME-stac-auth-proxy-filters + + - it: should set OPA filter env vars when record mode is opa + set: + authorization.record.mode: "opa" + authorization.record.opa.url: "http://opa-service:8181" + authorization.record.opa.policy: "stac/items/allow" + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ITEMS_FILTER_CLS + value: "stac_auth_proxy.filters:opa.Opa" + - contains: + path: spec.template.spec.containers[0].env + content: + name: ITEMS_FILTER_ARGS + value: '["http://opa-service:8181","stac/items/allow"]' + + - it: should allow env vars to override record authorization + set: + authorization.record.mode: "opa" + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + env.ITEMS_FILTER_CLS: "custom.module:CustomFilter" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ITEMS_FILTER_CLS + value: "custom.module:CustomFilter" + + # Raw configuration tests + - it: should preserve extraVolumes and extraVolumeMounts + set: + authorization.record.mode: "custom" + authorization.record.custom.filtersFile: "data/custom_filters.py" + extraVolumes: + - name: extra-volume + emptyDir: {} + extraVolumeMounts: + - name: extra-volume + mountPath: /extra + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + asserts: + - contains: + path: spec.template.spec.volumes + content: + name: custom-filters + configMap: + name: RELEASE-NAME-stac-auth-proxy-filters + - contains: + path: spec.template.spec.volumes + content: + name: extra-volume + emptyDir: {} + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: custom-filters + mountPath: /app/src/stac_auth_proxy/custom_filters.py + subPath: custom_filters.py + readOnly: true + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: extra-volume + mountPath: /extra + + # Combined configuration test + - it: should handle both route and record authorization together + set: + authorization.route.mode: "custom" + authorization.route.publicEndpoints: + "^/search$": ["GET"] + authorization.record.mode: "opa" + authorization.record.opa.url: "http://opa:8181" + authorization.record.opa.policy: "stac/allow" + env.UPSTREAM_URL: "https://example.com" + env.OIDC_DISCOVERY_URL: "https://example.com/.well-known/openid-configuration" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: DEFAULT_PUBLIC + value: "false" + - contains: + path: spec.template.spec.containers[0].env + content: + name: PUBLIC_ENDPOINTS + value: '{"^/search$":["GET"]}' + - contains: + path: spec.template.spec.containers[0].env + content: + name: ITEMS_FILTER_CLS + value: "stac_auth_proxy.filters:opa.Opa" diff --git a/helm/tests/configmap_test.yaml b/helm/tests/configmap_test.yaml new file mode 100644 index 00000000..29c99c20 --- /dev/null +++ b/helm/tests/configmap_test.yaml @@ -0,0 +1,51 @@ +suite: test configmap +templates: + - configmap.yaml +tests: + - it: should create configmap when record mode is custom with filtersFile + set: + authorization.record.mode: "custom" + authorization.record.custom.filtersFile: "data/custom_filters.py" + asserts: + - isKind: + of: ConfigMap + - equal: + path: metadata.name + value: RELEASE-NAME-stac-auth-proxy-filters + - isNotEmpty: + path: data + + - it: should not create configmap when record mode is disabled + set: + authorization.record.mode: "disabled" + asserts: + - hasDocuments: + count: 0 + + - it: should not create configmap when record mode is opa + set: + authorization.record.mode: "opa" + authorization.record.opa.url: "http://opa:8181" + authorization.record.opa.policy: "stac/items/allow" + asserts: + - hasDocuments: + count: 0 + + - it: should not create configmap when filtersFile is empty + set: + authorization.record.mode: "custom" + authorization.record.custom.filtersFile: "" + asserts: + - hasDocuments: + count: 0 + + - it: should include proper labels + set: + authorization.record.mode: "custom" + authorization.record.custom.filtersFile: "data/custom_filters.py" + asserts: + - isSubset: + path: metadata.labels + content: + app.kubernetes.io/name: stac-auth-proxy + app.kubernetes.io/instance: RELEASE-NAME diff --git a/helm/values.yaml b/helm/values.yaml index 8bad227a..80255e2a 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -21,6 +21,41 @@ ingress: enabled: true secretName: "" # If empty, will be auto-generated as "{host}-tls" +authorization: + + # Route-level authorization + route: + # Mode: "default" (public catalog, protected writes), "custom" (use custom endpoints), "disabled" (no auth) + mode: "default" + + # Custom endpoint configurations (only used when mode: "custom") + # NOTE: Setting these REPLACES the application's default endpoints, does not extend them. + # publicEndpoints: {} + # Example: + # "^/collections$": ["GET"] + # "^/search$": ["GET", "POST"] + # "^/api.html$": ["GET"] + # "^/healthz": ["GET"] + # privateEndpoints: {} + # Example: + # "^/collections$": [["POST", "collection:create"]] + # "^/collections/([^/]+)$": [["PUT", "collection:update"], ["DELETE", "collection:delete"]] + # "^/collections/([^/]+)/items$": [["POST", "item:create"]] + + # Record-level authorization + record: + # Mode: "disabled" (no filtering), "custom" (Python filters), "opa" (Open Policy Agent) + mode: "disabled" + + # Custom filters configuration (only used when mode: "custom") + # custom: + # filtersFile: "" # Path to custom filters Python file (e.g., "data/custom_filters.py") + + # OPA configuration (only used when mode: "opa") + # opa: + # url: "http://opa:8181" + # policy: "stac/items/allow" + resources: limits: cpu: 500m @@ -81,22 +116,28 @@ env: WAIT_FOR_UPSTREAM: true HEALTHZ_PREFIX: "/healthz" OIDC_DISCOVERY_INTERNAL_URL: "" - DEFAULT_PUBLIC: false - PRIVATE_ENDPOINTS: | - { - "^/collections$": ["POST"], - "^/collections/([^/]+)$": ["PUT", "PATCH", "DELETE"], - "^/collections/([^/]+)/items$": ["POST"], - "^/collections/([^/]+)/items/([^/]+)$": ["PUT", "PATCH", "DELETE"], - "^/collections/([^/]+)/bulk_items$": ["POST"] - } - PUBLIC_ENDPOINTS: | - { - "^/api.html$": ["GET"], - "^/api$": ["GET"], - "^/docs/oauth2-redirect": ["GET"], - "^/healthz": ["GET"] - } + + # Note: DEFAULT_PUBLIC, PUBLIC_ENDPOINTS, PRIVATE_ENDPOINTS are now managed + # via authorization.route section. Authorization settings from + # authorization.route and authorization.record sections will be + # automatically merged with these env vars. Manually specified env vars + # take precedence. You can still override them here if needed + # DEFAULT_PUBLIC: false + # PRIVATE_ENDPOINTS: | + # { + # "^/collections$": ["POST"], + # "^/collections/([^/]+)$": ["PUT", "PATCH", "DELETE"], + # "^/collections/([^/]+)/items$": ["POST"], + # "^/collections/([^/]+)/items/([^/]+)$": ["PUT", "PATCH", "DELETE"], + # "^/collections/([^/]+)/bulk_items$": ["POST"] + # } + # PUBLIC_ENDPOINTS: | + # { + # "^/api.html$": ["GET"], + # "^/api$": ["GET"], + # "^/docs/oauth2-redirect": ["GET"], + # "^/healthz": ["GET"] + # } @@ -110,4 +151,4 @@ serviceAccount: name: "" # Image pull secrets to add to the service account imagePullSecrets: [] - # - name: my-registry-secret \ No newline at end of file + # - name: my-registry-secret From ad5150127ff53b40623f3510dd1f3c60739bbd27 Mon Sep 17 00:00:00 2001 From: Felix Delattre Date: Thu, 18 Dec 2025 16:01:35 +0100 Subject: [PATCH 2/2] Extended kubernetes auth documentation. --- docs/user-guide/deployment.md | 45 +---------- .../user-guide/kubernetes.md | 78 +++++++++++++++---- mkdocs.yml | 1 + 3 files changed, 64 insertions(+), 60 deletions(-) rename helm/AUTHORIZATION.md => docs/user-guide/kubernetes.md (55%) diff --git a/docs/user-guide/deployment.md b/docs/user-guide/deployment.md index 1416cc55..4a25ca8e 100644 --- a/docs/user-guide/deployment.md +++ b/docs/user-guide/deployment.md @@ -61,47 +61,4 @@ docker pull ghcr.io/developmentseed/stac-auth-proxy:v0.7.1 ## Kubernetes -The STAC Auth Proxy can be deployed to Kubernetes via the [Helm Chart available on the GitHub Container Registry (GHCR)](https://github.com/developmentseed/stac-auth-proxy/pkgs/container/stac-auth-proxy%2Fcharts%2Fstac-auth-proxy). - -### Prerequisites - -- Kubernetes 1.19+ -- Helm 3.2.0+ - -### Installation - -```bash -# Add the Helm repository -helm registry login ghcr.io - -# Install with minimal configuration -helm install stac-auth-proxy oci://ghcr.io/developmentseed/stac-auth-proxy/charts/stac-auth-proxy \ - --set env.UPSTREAM_URL=https://your-stac-api.com/stac \ - --set env.OIDC_DISCOVERY_URL=https://your-auth-server/.well-known/openid-configuration \ - --set ingress.host=stac-proxy.your-domain.com -``` - -### Configuration - -| Parameter | Description | Required | Default | -| ------------------------ | --------------------------------------------- | -------- | ------- | -| `env.UPSTREAM_URL` | URL of the STAC API to proxy | Yes | - | -| `env.OIDC_DISCOVERY_URL` | OpenID Connect discovery document URL | Yes | - | -| `env` | Environment variables passed to the container | No | `{}` | -| `ingress.enabled` | Enable ingress | No | `true` | -| `ingress.className` | Ingress class name | No | `nginx` | -| `ingress.host` | Hostname for the ingress | No | `""` | -| `ingress.tls.enabled` | Enable TLS for ingress | No | `true` | -| `replicaCount` | Number of replicas | No | `1` | - -For a complete list of values, see the [values.yaml](https://github.com/developmentseed/stac-auth-proxy/blob/main/helm/values.yaml) file. - -### Management - -```bash -# Upgrade -helm upgrade stac-auth-proxy oci://ghcr.io/developmentseed/stac-auth-proxy/charts/stac-auth-proxy - -# Uninstall -helm uninstall stac-auth-proxy -``` +See [Kubernetes deployment](kubernetes.md) for detailed instructions on deploying to Kubernetes using Helm. diff --git a/helm/AUTHORIZATION.md b/docs/user-guide/kubernetes.md similarity index 55% rename from helm/AUTHORIZATION.md rename to docs/user-guide/kubernetes.md index f4e8433c..f81efdae 100644 --- a/helm/AUTHORIZATION.md +++ b/docs/user-guide/kubernetes.md @@ -1,15 +1,50 @@ -# Authorization configuration guide +# Kubernetes Deployment + +Deploy STAC Auth Proxy to Kubernetes using the Helm chart. + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3.2.0+ + +## Installation + +```bash +helm registry login ghcr.io + +helm install stac-auth-proxy oci://ghcr.io/developmentseed/stac-auth-proxy/charts/stac-auth-proxy \ + --set env.UPSTREAM_URL=https://your-stac-api.com/stac \ + --set env.OIDC_DISCOVERY_URL=https://your-auth-server/.well-known/openid-configuration \ + --set ingress.host=stac-proxy.your-domain.com +``` + +### Configuration + +| Parameter | Description | Required | Default | +| ------------------------ | --------------------------------------------- | -------- | ------- | +| `env.UPSTREAM_URL` | URL of the STAC API to proxy | Yes | - | +| `env.OIDC_DISCOVERY_URL` | OpenID Connect discovery document URL | Yes | - | +| `env` | Environment variables passed to the container | No | `{}` | +| `ingress.enabled` | Enable ingress | No | `true` | +| `ingress.className` | Ingress class name | No | `nginx` | +| `ingress.host` | Hostname for the ingress | No | `""` | +| `ingress.tls.enabled` | Enable TLS for ingress | No | `true` | +| `replicaCount` | Number of replicas | No | `1` | + +For a complete list of values, see the [values.yaml](https://github.com/developmentseed/stac-auth-proxy/blob/main/helm/values.yaml) file. + +## Authorization The chart provides two levels of authorization: -1. **[Route-level authorization](https://developmentseed.org/stac-auth-proxy/user-guide/route-level-auth/)**: Controls which API endpoints are accessible and by whom -2. **[Record-level authorization](https://developmentseed.org/stac-auth-proxy/user-guide/record-level-auth/)**: Filters collections and items based on user permissions +1. **[Route-level authorization](route-level-auth.md)**: Controls which API endpoints are accessible and by whom +2. **[Record-level authorization](record-level-auth.md)**: Filters collections and items based on user permissions -## Route-Level Authorization +### Route-Level Authorization Configure via `authorization.route` section in `values.yaml`. -### Mode: `default` (Recommended) +#### Mode: `default` (Recommended) Public catalog with protected write operations. This is the most common configuration. @@ -21,7 +56,7 @@ authorization: This automatically sets `DEFAULT_PUBLIC=true`, making all read endpoints public while requiring authentication for write operations. -### Mode: `custom` +#### Mode: `custom` Define specific public and private endpoints with custom rules. @@ -45,7 +80,7 @@ authorization: - `privateEndpoints`: Maps regex paths to HTTP methods or `[method, scope]` tuples - Scopes define required OAuth2 scopes for the operation -### Mode: `disabled` +#### Mode: `disabled` No route-level authorization applied. @@ -55,11 +90,11 @@ authorization: mode: "disabled" ``` -## Record-Level Authorization +### Record-Level Authorization Configure via `authorization.record` section in `values.yaml`. -### Mode: `disabled` (Default) +#### Mode: `disabled` (Default) No record-level filtering applied. All collections and items are visible to authenticated users. @@ -69,7 +104,7 @@ authorization: mode: "disabled" ``` -### Mode: `custom` +#### Mode: `custom` Use Python filter classes to control visibility of collections and items. @@ -87,9 +122,9 @@ This automatically: - Sets `COLLECTIONS_FILTER_CLS=stac_auth_proxy.custom_filters:CollectionsFilter` - Sets `ITEMS_FILTER_CLS=stac_auth_proxy.custom_filters:ItemsFilter` -Review the stac-auth-proxy [documentation for more information on custom filters](https://developmentseed.org/stac-auth-proxy/user-guide/record-level-auth/#custom-filter-factories). +Review the stac-auth-proxy [documentation for more information on custom filters](record-level-auth.md#custom-filter-factories). -### Mode: `opa` +#### Mode: `opa` Use Open Policy Agent for policy-based filtering. @@ -106,9 +141,9 @@ This sets: - `ITEMS_FILTER_CLS=stac_auth_proxy.filters.opa:Opa` - `ITEMS_FILTER_ARGS='["http://opa-service:8181", "stac/items/allow"]'` -## Some configuration examples +### Configuration Examples -### Example 1: Default for public catalog, protected writes +#### Example 1: Default for public catalog, protected writes ```yaml authorization: @@ -118,7 +153,7 @@ authorization: mode: "disabled" ``` -### Example 2: Fully protected catalog +#### Example 2: Fully protected catalog ```yaml authorization: @@ -135,7 +170,7 @@ authorization: filtersFile: "data/custom_filters.py" ``` -## Direct configuration +### Direct Configuration Existing charts using `env` variables directly continue to work: @@ -148,3 +183,14 @@ env: ``` **Environment variables specified in `env` take precedence over `authorization` settings.** + +## Management + +```bash +# Upgrade +helm upgrade stac-auth-proxy oci://ghcr.io/developmentseed/stac-auth-proxy/charts/stac-auth-proxy + +# Uninstall +helm uninstall stac-auth-proxy +``` + diff --git a/mkdocs.yml b/mkdocs.yml index 9da95125..cc84e975 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,6 +35,7 @@ nav: - Route-Level Auth: user-guide/route-level-auth.md - Record-Level Auth: user-guide/record-level-auth.md - Deployment: user-guide/deployment.md + - Kubernetes: user-guide/kubernetes.md - Tips: user-guide/tips.md - Architecture: - Middleware Stack: architecture/middleware-stack.md