Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bb06d9b
feat: initial, untested implementation
pjhartzell Oct 13, 2025
83cdb90
tests: WIP, not all running
pjhartzell Oct 14, 2025
c969b9c
refactor: second iteration of initial implementation
pjhartzell Oct 14, 2025
4237b52
refactor: use app.local state, sundry fixups, working tests
pjhartzell Oct 16, 2025
e4b1c2a
docs: update openapi.yaml to reflect asset proxy endpoints
pjhartzell Oct 16, 2025
b0ae7d5
docs: update README
pjhartzell Oct 16, 2025
a09d37a
chore: update CHANGELOG
pjhartzell Oct 16, 2025
ac302f9
review: move appInstance initialization out of function scope so it o…
pjhartzell Oct 22, 2025
4802a72
review: initialize assetProxy outside function so it runs during lamb…
pjhartzell Oct 22, 2025
40632c8
review: move from v2 to v3 of AWS SDK
pjhartzell Oct 22, 2025
b76f0e4
review: remove unnecessary S3 client caching in AssetProxy
pjhartzell Oct 22, 2025
8d3c10f
review: 403 t0 404 when asset proxy is disabled
pjhartzell Oct 22, 2025
dad9234
review: remove redundant asset proxy isEnabled check
pjhartzell Oct 22, 2025
f8ae55e
review: significant refactor to improve bucket caching and region det…
pjhartzell Oct 24, 2025
9dc923f
docs: update docs
pjhartzell Oct 24, 2025
517a5d4
docs: minor README update and logging improvement in asset-proxy.js
pjhartzell Oct 28, 2025
3e96a02
review: remove commented code
pjhartzell Oct 28, 2025
3dec688
review: pull asset proxy bucket management into its own class
pjhartzell Oct 29, 2025
1126949
chore: update CHANGELOG
pjhartzell Oct 29, 2025
cad05dc
refactor: extract AssetBuckets class from asset-proxy.js
pjhartzell Oct 29, 2025
6863bad
review: correct requester pay information in README
pjhartzell Oct 30, 2025
eab7890
fix: correct errors revealed by testing a deployment
pjhartzell Oct 31, 2025
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
19 changes: 17 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Asset proxying for generating pre-signed S3 URLs through proxy endpoints `GET
/collections/{collectionId}/items/{itemId}/assets/{assetKey}` and `GET
/collections/{collectionId}/assets/{assetKey}`.
- Environment variables `ASSET_PROXY_BUCKET_OPTION`, `ASSET_PROXY_BUCKET_LIST`, and
`ASSET_PROXY_URL_EXPIRY` to configure asset proxying.

### Changed

- When asset proxying is enabled, when a STAC Item or Collection is served, asset S3 hrefs
are replaced with proxy endpoint URLs and the original S3 URLs are preserved in
`alternate.s3.href` using the Alternate Assets Extension.

## [4.4.0] - 2025-09-10

## Changed
Expand Down Expand Up @@ -579,8 +595,7 @@ Initial release, forked from [sat-api](https://github.com/sat-utils/sat-api/tree

Compliant with STAC 0.9.0

<!-- [unreleased]: https://github.com/stac-utils/stac-api/compare/v3.6.0...main -->

[unreleased]: https://github.com/stac-utils/stac-server/compare/v4.4.0...main
[4.4.0]: https://github.com/stac-utils/stac-api/compare/v4.3.0...v4.4.0
[4.3.0]: https://github.com/stac-utils/stac-api/compare/v4.2.0...v4.3.0
[4.2.0]: https://github.com/stac-utils/stac-api/compare/v4.1.0...v4.2.0
Expand Down
140 changes: 140 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
- [Filter Extension](#filter-extension)
- [Query Extension](#query-extension)
- [Aggregation](#aggregation)
- [Asset Proxy](#asset-proxy)
- [Collections and filter parameters for authorization](#collections-and-filter-parameters-for-authorization)
- [Collections](#collections)
- [CQL2 Filter](#cql2-filter)
Expand Down Expand Up @@ -617,6 +618,9 @@ There are some settings that should be reviewed and updated as needeed in the se
| ENABLE_INGEST_ACTION_TRUNCATE | Enables support for ingest action "truncate". | none (not enabled) |
| ENABLE_RESPONSE_COMPRESSION | Enables response compression. Set to 'false' to disable. | enabled |
| ITEMS_MAX_LIMIT | The maximum limit for the number of items returned from the /search and /collections/{collection_id}/items endpoints. It is recommended that this be set to 100. There is an absolute max limit of 10000 for this. | 10000 |
| ASSET_PROXY_BUCKET_OPTION | Control which S3 buckets are proxied through the API. Options: `NONE` (disabled), `ALL` (all S3 assets), `ALL_BUCKETS_IN_ACCOUNT` (all buckets in AWS account), `LIST` (specific buckets only). | NONE |
| ASSET_PROXY_BUCKET_LIST | Comma-separated list of S3 bucket names to proxy. Required when `ASSET_PROXY_BUCKET_OPTION` is `LIST`. | |
| ASSET_PROXY_URL_EXPIRY | Pre-signed URL expiry time in seconds for proxied assets. | 300 |

Additionally, the credential for OpenSearch must be configured, as decribed in the
section [Populating and accessing credentials](#populating-and-accessing-credentials).
Expand Down Expand Up @@ -1124,6 +1128,138 @@ Available aggregations are:
- geometry_geohash_grid_frequency ([geohash grid](https://opensearch.org/docs/latest/aggregations/bucket/geohash-grid/) on Item.geometry)
- geometry_geotile_grid_frequency ([geotile grid](https://opensearch.org/docs/latest/aggregations/bucket/geotile-grid/) on Item.geometry)

## Asset Proxy

The Asset Proxy feature enables stac-server to proxy access to S3 assets through the STAC
API by generating pre-signed URLs. Only assets with S3 URIs (`s3://` prefix) are proxied;
other URL schemes are ignored. When the Asset Proxy feature is enabled, asset `href`
values pointing to S3 are replaced with proxy endpoint URLs when an Item or Collection is
served, while the original S3 URLs are preserved in the `alternate.s3.href` field using
the [Alternate Assets Extension](https://github.com/stac-extensions/alternate-assets).
Subsequent GET requests to the proxy endpoint URLs are redirected to pre-signed S3 URLS
for download. Note that the AWS account that stac-server is running under must have
permission to access the S3 buckets containing the assets and that the stac-server AWS
account will be charged for the S3 egress, regardless of whether the bucket is a
"Requester Pays" bucket or not (the stac-server AWS account is the requester when
generating the pre-signed URL).

### Configuration

Asset proxying uses three environment variables:

- **`ASSET_PROXY_BUCKET_OPTION` -** Specifies one of four modes to control which S3 buckets are proxied.

- **NONE** (default): Asset proxy is disabled. All asset hrefs are returned unchanged.
- **ALL**: Proxy all S3 assets regardless of which bucket they are in.
- **ALL_BUCKETS_IN_ACCOUNT**: Proxy assets from any S3 bucket accessible to the AWS account credentials. The list of buckets is fetched at Lambda startup.
- **LIST**: Only proxy assets from specific buckets listed in `ASSET_PROXY_BUCKET_LIST`.

- **`ASSET_PROXY_BUCKET_LIST`** — Comma-separated list of bucket names (required only when the `ASSET_PROXY_BUCKET_OPTION` environment variable is set to `LIST`)

```yaml
ASSET_PROXY_BUCKET_OPTION: "LIST"
ASSET_PROXY_BUCKET_LIST: "my-bucket-1,my-bucket-2,my-bucket-3"
```

- **`ASSET_PROXY_URL_EXPIRY`** — Pre-signed URL expiry in seconds (default: `300`)

### Endpoints

When asset proxying is enabled, two endpoints are available for accessing proxied assets:

- `GET /collections/{collectionId}/items/{itemId}/assets/{assetKey}` - Redirects (HTTP 302) to a pre-signed S3 URL for an item asset
- `GET /collections/{collectionId}/assets/{assetKey}` - Redirects (HTTP 302) to a pre-signed S3 URL for a collection asset

### IAM Permissions

For the Asset Proxy feature to generate pre-signed URLs, the API and ingest Lambdas must be assigned permissions for the S3 buckets containing the assets. Add the following to the IAM role statements in your `serverless.yml` file, adjusting the resources as needed:

For the `LIST` mode, you can specify the buckets listed in `ASSET_PROXY_BUCKET_LIST`:

```yaml
- Effect: Allow
Action:
- s3:GetObject
Resource:
- "arn:aws:s3:::my-bucket-1/*"
- "arn:aws:s3:::my-bucket-2/*"
- Effect: Allow
Action:
- s3:HeadBucket
Resource:
- "arn:aws:s3:::my-bucket-1"
- "arn:aws:s3:::my-bucket-2"
```

For the `ALL` mode, use wildcards:

```yaml
- Effect: Allow
Action:
- s3:GetObject
Resource: "arn:aws:s3:::*/*"
- Effect: Allow
Action:
- s3:HeadBucket
Resource: "arn:aws:s3:::*"
```

When using `ALL_BUCKETS_IN_ACCOUNT` mode, the Lambda also needs permission to list buckets:

```yaml
- Effect: Allow
Action:
- s3:GetObject
Resource: "arn:aws:s3:::*/*"
- Effect: Allow
Action:
- s3:HeadBucket
Resource: "arn:aws:s3:::*"
- Effect: Allow
Action:
- s3:ListAllMyBuckets
Resource: "*"
```

### Asset Transformation

When asset proxying is enabled and an asset's `href` points to an S3 URL, the asset is transformed as follows:

**Original asset:**
```json
{
"thumbnail": {
"href": "s3://my-bucket/path/to/thumbnail.png",
"type": "image/png",
"roles": ["thumbnail"]
}
}
```

**Transformed asset:**
```json
{
"thumbnail": {
"href": "https://api.example.com/collections/my-collection/items/my-item/assets/thumbnail",
"type": "image/png",
"roles": ["thumbnail"],
"alternate": {
"s3": {
"href": "s3://my-bucket/path/to/thumbnail.png"
}
}
}
}
```

The item or collection will also have the Alternate Assets Extension added to its `stac_extensions` array:

```json
"stac_extensions": [
"https://stac-extensions.github.io/alternate-assets/v1.2.0/schema.json"
]
```

## Collections and filter parameters for authorization

One key concern in stac-server is how to restrict user's access to items. These
Expand Down Expand Up @@ -1160,6 +1296,8 @@ The endpoints this applies to are:
- /collections/:collectionId/items
- /collections/:collectionId/items/:itemId
- /collections/:collectionId/items/:itemId/thumbnail
- /collections/:collectionId/items/:itemId/assets/:assetKey
- /collections/:collectionId/assets/:assetKey
- /search
- /aggregate

Expand Down Expand Up @@ -1187,6 +1325,8 @@ The endpoints this applies to are:
- /collections/:collectionId/items
- /collections/:collectionId/items/:itemId
- /collections/:collectionId/items/:itemId/thumbnail
- /collections/:collectionId/items/:itemId/assets/:assetKey
- /collections/:collectionId/assets/:assetKey
- /search
- /aggregate

Expand Down
4 changes: 4 additions & 0 deletions serverless.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ provider:
STAC_API_URL: "https://some-stac-server.example.com"
CORS_ORIGIN: "https://ui.example.com"
CORS_CREDENTIALS: true
# Asset Proxy Environment Variables
# ASSET_PROXY_BUCKET_OPTION: "NONE" # Options: NONE, ALL, ALL_BUCKETS_IN_ACCOUNT, LIST
# ASSET_PROXY_BUCKET_LIST: "bucket1,bucket2,bucket3" # Required only when ASSET_PROXY_BUCKET_OPTION is LIST
# ASSET_PROXY_URL_EXPIRY: 300 # Pre-signed URL expiry in seconds (default: 300)
iam:
role:
statements:
Expand Down
Loading