Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 1 addition & 44 deletions docs/user-guide/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
196 changes: 196 additions & 0 deletions docs/user-guide/kubernetes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# 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](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

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](record-level-auth.md#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"]'`

### 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.**

## 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
```

27 changes: 27 additions & 0 deletions helm/data/custom_filters.py
Original file line number Diff line number Diff line change
@@ -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"
73 changes: 73 additions & 0 deletions helm/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -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 -}}
11 changes: 11 additions & 0 deletions helm/templates/configmap.yaml
Original file line number Diff line number Diff line change
@@ -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 }}
12 changes: 7 additions & 5 deletions helm/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
Loading
Loading