Commit 8ed0b8e
Move REST catalog credentials to USER MAPPING, add catalogs.conf
Until now an iceberg_catalog server carried its own client_id /
client_secret on the SERVER row. That gave every role on the
cluster the same credentials and forced operators to recreate the
server when secrets rotated. Move credentials to per-user state
and add a platform-provided file as a middle layer.
Credential resolution (lowest to highest priority):
1. pg_lake_iceberg.rest_catalog_* GUC defaults
2. iceberg_catalog SERVER options (non-secret only)
3. $PGDATA/catalogs.conf (user-created servers only)
4. pg_user_mapping options (user-created servers only)
The built-in pg_lake_rest_catalog (catalog='rest') stops after step 2
on purpose: its credentials live exclusively in the GUCs so the
built-in stays a single, global, instance-wide configuration with no
hidden per-user view. CREATE/ALTER USER MAPPING is rejected against
all three built-in long names; catalogs.conf is also ignored for the
built-in 'rest' catalog.
Notable pieces:
* iceberg_catalog_option_descs[] now carries a CATALOG_OPT_CTX_*
bitmask per option. The same table drives the validator, the
per-context "Valid options are: ..." hint, and the option->struct
applier. client_id / client_secret are USER MAPPING-only; scope is
accepted on both, with the USER MAPPING value winning because it is
applied last during resolution.
* RestCatalogOptions gains a umid field; the token cache key is now
(serverOid, umid) so different SET ROLEs in the same backend each
get their own user mapping's credentials. A USERMAPPINGOID syscache
callback invalidates cached tokens on CREATE/ALTER/DROP USER MAPPING.
* ValidateRestCatalogOptions now performs an early auth-type-aware
credentials check at resolution time:
- client_secret is always required
- client_id is required unless rest_auth_type='horizon'
Missing credentials surface as "no credentials found for REST
catalog ..." with ERRCODE_FDW_OPTION_NAME_NOT_FOUND. The per-field
checks inside FetchRestCatalogAccessToken are kept as defense in
depth and now carry the same errcode.
* New ProcessUtility handler RedactRestCatalogUserMappingSecrets
scrubs client_id / client_secret from queryString in place on
CREATE/ALTER USER MAPPING for any iceberg_catalog server (built-in
long names included). Handles plain '', E'', and U&'' literal
forms with their escape rules. Registered after the DDL validator
so it runs first (the handler list is prepend-LIFO), ensuring the
failing built-in-server path never leaks secrets into the ereport
context. DDL itself reads option values from DefElem->arg, so
pg_user_mapping still stores plaintext credentials -- only the
query string surfaces (pg_stat_statements, log_min_duration_statement,
ereport context) see the redacted form.
* New PGC_SIGHUP GUC pg_lake_iceberg.catalogs_conf_path lets
operators point at an absolute path; the default is the relative
'catalogs.conf' resolved against DataDir.
Tests:
* test_iceberg_catalog_server.py picks up the user-mapping DDL
surface (per-context option lists and hints, valid/invalid options
on each side, FOR CURRENT_USER with all three options,
per-role mappings on the same server, dependency-driven rejections,
built-in long-name blocks), the redaction handler (CREATE/ALTER,
'' escape, E'' escape, scope preservation, non-iceberg FDW skip,
built-in-rejection-after-redaction, plaintext storage preservation),
and credential resolution via catalogs.conf (file-only success,
USER MAPPING wins over the file, no-credentials-anywhere error,
scope from the file, absolute catalogs_conf_path, built-in
ignores the file).
* test_modify_iceberg_rest_table.py: client_id / client_secret are
dropped from the server-option-overrides-GUC parametrization (they
no longer belong on SERVER), and a new parametrized
test_user_mapping_credential_overrides_guc covers the same
resolution-order direction with USER MAPPING in step 4.
* test_writable_iceberg_common.py: the shared fixture for the writable
user-created REST server now puts credentials on a PUBLIC user
mapping, and drops the server with CASCADE to sweep up the mapping.
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: sfc-gh-npuka <naisila.puka@snowflake.com>1 parent 87dbbc1 commit 8ed0b8e
7 files changed
Lines changed: 2317 additions & 165 deletions
File tree
- pg_lake_iceberg
- include/pg_lake/rest_catalog
- src
- rest_catalog
- pg_lake_table/tests/pytests
Lines changed: 27 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
40 | 41 | | |
41 | 42 | | |
42 | | - | |
43 | | - | |
| 43 | + | |
44 | 44 | | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
50 | 60 | | |
51 | 61 | | |
52 | 62 | | |
53 | 63 | | |
54 | 64 | | |
55 | 65 | | |
| 66 | + | |
| 67 | + | |
56 | 68 | | |
57 | 69 | | |
58 | 70 | | |
| |||
138 | 150 | | |
139 | 151 | | |
140 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
9 | 21 | | |
10 | 22 | | |
11 | | - | |
12 | | - | |
13 | | - | |
14 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
15 | 27 | | |
16 | 28 | | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
17 | 38 | | |
18 | 39 | | |
19 | 40 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
321 | 321 | | |
322 | 322 | | |
323 | 323 | | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
324 | 334 | | |
325 | 335 | | |
326 | 336 | | |
| |||
335 | 345 | | |
336 | 346 | | |
337 | 347 | | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
338 | 356 | | |
339 | 357 | | |
340 | 358 | | |
| |||
0 commit comments