Skip to content

api: list-zones: do not send auth header#90

Merged
natalie-o-perret merged 1 commit into
masterfrom
fix/list-zones-no-iam-check
Jun 16, 2026
Merged

api: list-zones: do not send auth header#90
natalie-o-perret merged 1 commit into
masterfrom
fix/list-zones-no-iam-check

Conversation

@natalie-o-perret

@natalie-o-perret natalie-o-perret commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

/zone is public but the server enforces IAM on authenticated requests, so a DBaaS-only key gets 403 for no reason.

In _call_operation, when the operation is list-zones, the request is sent via a plain requests.request without credentials. No IAM check fires and all zones come back.

Snippet used to verify:

from exoscale.api.v2 import Client

client = Client(key=key, secret=secret, zone="ch-gva-2")
result = client.list_zones()
zones = result["zones"]
print(f"ok: {len(zones)} zones")
for z in zones:
    print(f"  - {z['name']}")

Before (master, DBaaS-only key):

exoscale.api.exceptions.ExoscaleAPIAuthException: Authentication error 403: {"message":"Invalid request signature"}

After (this branch, same key):

ok: 8 zones
  - ch-gva-2
  - ch-dk-2
  - at-vie-1
  - de-fra-1
  - bg-sof-1
  - de-muc-1
  - at-vie-2
  - hr-zag-1

Related: exoscale/egoscale#767, exoscale/exoscale-sdk-java#14


Note

AI-assisted.

The /zone endpoint enforces IAM policies on authenticated requests,
causing 403 for restricted keys (e.g. DBaaS-only) even though the
endpoint returns public data.

Skip credentials for list-zones so the call always succeeds.
natalie-o-perret added a commit to exoscale/egoscale that referenced this pull request Jun 15, 2026
# Description

`/zones` is public but the server enforces IAM on authenticated
requests, so a DBaaS-only key gets 403 for no reason.

`RequestTmpl` now has a `SkipAuth bool` field. When set, the generated
function skips `signRequest` and sends no `Authorization` header.
Operations opt in via `x-skip-auth: true` in the spec, so the guard
survives future regenerations.

**Snippet used to verify:**

```go
package main

import (
"context"
"fmt"
"os"

v3 "github.com/exoscale/egoscale/v3"
"github.com/exoscale/egoscale/v3/credentials"
)

func main() {
	creds := credentials.NewStaticCredentials(os.Getenv("EXO_KEY"), os.Getenv("EXO_SECRET"))
	client, _ := v3.NewClient(creds)
	zones, err := client.ListZones(context.Background())
	if err != nil {
		fmt.Fprintln(os.Stderr, "error:", err)
		os.Exit(1)
	}
	fmt.Printf("ok: %d zones\n", len(zones.Zones))
}
```

Or with the CLI (DBaaS-only profile, using any command that triggers a
zone switch):

```
# before fix
$ exo dbaas update --valkey-ip-filter 1.2.3.4/32 valkey-test-fix -z de-muc-1
error: unable to create client: switch client zone v3: get zone api endpoint: list zones: ListZones: http response: Forbidden: Forbidden by role policy for compute

# after fix
$ exo dbaas update --valkey-ip-filter 1.2.3.4/32 valkey-test-fix -z de-muc-1
 ✔  Updating DBaaS Valkey service "valkey-test-fix"  0s
```

**Go before** (master, DBaaS-only key):
```
error: ListZones: http response: Forbidden: Invalid request signature
```

**Go after** (this branch, same key):
```
ok: 8 zones
  - ch-gva-2
  - ch-dk-2
  - at-vie-1
  - de-fra-1
  - bg-sof-1
  - de-muc-1
  - at-vie-2
  - hr-zag-1
```

Related: exoscale/python-exoscale#90, exoscale/exoscale-sdk-java#14

## Checklist
(For exoscale contributors)
- [x] Changelog updated (under Unreleased block)

---

> [!NOTE]
> AI-assisted.
@natalie-o-perret natalie-o-perret marked this pull request as ready for review June 15, 2026 15:45
@natalie-o-perret natalie-o-perret requested a review from a team June 15, 2026 15:45
natalie-o-perret added a commit to exoscale/exoscale-sdk-java that referenced this pull request Jun 15, 2026
The /zone endpoint enforces IAM policies on authenticated requests,
causing 403 for restricted keys (e.g. DBaaS-only) even though the
endpoint returns public data.

Add x-skip-auth to the list-zones operation in the spec. The
api.mustache template wraps the signing block in a
{{^vendorExtensions.x-skip-auth}} guard, so the generated
listZonesRequestBuilder omits the Authorization header.

The update workflow injects the extension after fetching the spec,
so the guard survives future automated spec updates. pom.xml now
reads the local api/openapi.yaml instead of fetching the spec at
build time, consistent with the workflow change.

Same fix applied to the Go SDK: exoscale/egoscale#767
Same fix applied to the Python SDK: exoscale/python-exoscale#90

Refs: #14
natalie-o-perret added a commit to exoscale/exoscale-sdk-java that referenced this pull request Jun 15, 2026
The /zone endpoint enforces IAM policies on authenticated requests,
causing 403 for restricted keys (e.g. DBaaS-only) even though the
endpoint returns public data.

Add x-skip-auth to the list-zones operation in the spec. The
api.mustache template wraps the signing block in a
{{^vendorExtensions.x-skip-auth}} guard, so the generated
listZonesRequestBuilder omits the Authorization header.

The update workflow injects the extension after fetching the spec,
so the guard survives future automated spec updates. pom.xml now
reads the local api/openapi.yaml instead of fetching the spec at
build time, consistent with the workflow change.

Same fix applied to the Go SDK: exoscale/egoscale#767
Same fix applied to the Python SDK: exoscale/python-exoscale#90

Refs: #14
@natalie-o-perret natalie-o-perret merged commit 066ccd1 into master Jun 16, 2026
6 checks passed
@natalie-o-perret natalie-o-perret deleted the fix/list-zones-no-iam-check branch June 16, 2026 11:00
natalie-o-perret added a commit to exoscale/exoscale-sdk-java that referenced this pull request Jun 16, 2026
`/zone` is public but the server enforces IAM on authenticated requests,
so a DBaaS-only key gets 403 for no reason.

The `api.mustache` template wraps the signing block in a
`{{^vendorExtensions.x-skip-auth}}` guard, so the generated
`listZonesRequestBuilder` sends no `Authorization` header.

The update workflow injects the extension after fetching the upstream
spec, so the guard survives future automated spec updates.

**Snippet used to verify:**

```java
import com.exoscale.sdk.api.ExoscaleApi;
import com.exoscale.sdk.client.ApiClient;
import com.exoscale.sdk.client.Credentials;
import com.exoscale.sdk.model.ListZones200Response;
import com.exoscale.sdk.model.Zone;

Credentials creds = new Credentials(key, secret);
ApiClient apiClient = new ApiClient(creds);
apiClient.updateBaseUri("https://api-ch-gva-2.exoscale.com/v2");

ExoscaleApi api = new ExoscaleApi(apiClient);
ListZones200Response resp = api.listZones();
System.out.printf("ok: %d zones%n", resp.getZones().size());
for (Zone z : resp.getZones()) {
    System.out.printf("  - %s%n", z.getName());
}
```

**Before** (main, DBaaS-only key):
```
error 403: {"message":"Invalid request signature"}
```

**After** (this branch, same key):
```
ok: 8 zones
  - ch-gva-2
  - ch-dk-2
  - at-vie-1
  - de-fra-1
  - bg-sof-1
  - de-muc-1
  - at-vie-2
  - hr-zag-1
```

Related: exoscale/egoscale#767, exoscale/python-exoscale#90

---

> [!NOTE]
> AI-assisted.

Co-authored-by: natalie-o-perret <natalie-o-perret@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants