Skip to content
Draft
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
150 changes: 150 additions & 0 deletions helm/AUTHORIZATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Authorization configuration guide
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we push this into the docs directory to publish at developmentseed.org/stac-auth-proxy?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a bit out of context. We could move it into the docs but frame it as helm/kubernetes setup and include this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from the repo, is there anywhere else that this information would be surfaced?

I'd ideally like for people to be able to think about this tool as a packaged product rather than just a codebase, hence my view that docs should be available outside of the repo

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from the repo, is there anywhere else that this information would be surfaced?

I'd ideally like for people to be able to think about this tool as a packaged product rather than just a codebase, hence my view that docs should be available outside of the repo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to move it to the docs. Perhaps good to bring in #117 first? After that I can combine README and AUTHORIZATION into one file in the docs.


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.**
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 }}
11 changes: 11 additions & 0 deletions helm/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +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 }}
volumeMounts:
{{- include "stac-auth-proxy.authorizationVolumeMounts" . | nindent 12 }}
{{- with .Values.extraVolumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
{{- include "stac-auth-proxy.authorizationVolumes" . | nindent 8 }}
{{- with .Values.extraVolumes }}
{{- toYaml . | nindent 8 }}
{{- end }}

{{- with .Values.nodeSelector }}
nodeSelector:
Expand Down
Loading
Loading