API key allowlist syntax for listing and unlocking datasets

Hi all,

I’m trying to create a limited API key in SCALE 24.04, specifically one that can only read the list of datasets and unlock them.

I’m using curl (and the REST API) to do the calls, not the Websocket API.

I know that with the CLI I can put restrictions on keys (api_key | TrueNAS Documentation Hub), but any time I try to put one on my key curl starts returning 403 errors.

I know the key is correct because It works it if I update the settings to allow all calls.

auth api_key> update id=2 allowlist=[{"method":"*","resource":"*"}]

These are the combinations of resources I tried to use as restrictions:

auth api_key> update id=2 allowlist=[{"method":"POST","resource":"pool.dataset.unlock"}, {"method":"GET","resource":"pool.dataset"}]
auth api_key> update id=2 allowlist=[{"method":"POST","resource":"pool.dataset.unlock"}, {"method":"CALL","resource":"pool.dataset"}]
auth api_key> update id=2 allowlist=[{"method":"POST","resource":"pool.dataset.unlock"}, {"method":"CALL","resource":"pool.dataset"}, {"method":"GET"}]
auth api_key> update id=2 allowlist=[{"method":"POST","resource":"pool.dataset.unlock"}, {"method":"GET","resource":"pool.dataset"}]
auth api_key> update id=2 allowlist=[{"method":"POST","resource":"pool.dataset.unlock"}, {"method":"CALL","resource":"pool.dataset"}]
auth api_key> update id=2 allowlist=[{"method":"GET","resource":"pool"}, {"method":"GET","resource":"pool.dataset"}]
auth api_key> update id=2 allowlist=[{"method":"GET","resource":"pool"}, {"method":"CALL","resource":"pool.dataset"}]
auth api_key> update id=2 allowlist=[{"method":"GET","resource":"pool"}, {"method":"SUBSCRIBE","resource":"pool.dataset"}]
auth api_key> update id=2 allowlist=[{"method":"GET","resource":"pool"}, {"method":"GET","resource":"pool.dataset.*"}]
auth api_key> update id=2 allowlist=[{"method":"GET","resource":"pool"}, {"method":"GET","resource":"pool.dataset."}]                                                                 
auth api_key> update id=2 allowlist=[{"method":"GET","resource":"pool"}, {"method":"*","resource":"pool.dataset.*"}]
auth api_key> update id=2 allowlist=[{"method":"GET","resource":"pool"}, {"method":"*","resource":"pool.dataset.details"}]
auth api_key> update id=2 allowlist=[{"method":"GET","resource":"pool"}, {"method":"*","resource":"pool.dataset.query"}]

I’m aware some of these won’t result in unlock powers, but right now I’d be ok understanding why I can’t even get it to list datasets, and once I figured out the correct combination of resources I can move on to trying remote unlocks.

I also thought I got it right by allowing pool.dataset.* or pool.dataset.query but they’re not working :frowning:

An example from one of many attempts

$  curl -k -H "Accept: application/json" -H "Authorization: Bearer $APIKEY" -X GET -D - "https://192.168.44.88/api/v2.0/pool/dataset"
HTTP/2 403 
server: nginx
date: Sun, 09 Jun 2024 15:41:09 GMT
content-type: application/octet-stream
content-length: 0
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
permissions-policy: geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()
referrer-policy: strict-origin
x-frame-options: SAMEORIGIN

returned this in logs (I beautified it)

Jun  9 17:41:09 Redacted TNAUDIT_MIDDLEWARE[1177]: @cee:{
    "TNAUDIT": {
        "aid": "aee06fbe-3af1-4b50-af6d-340bfad42e42",
        "vers": {
            "major": 0,
            "minor": 1
        },
        "addr": "127.0.0.1",
        "user": "root",
        "sess": null,
        "time": "2024-06-09 15:41:09.598362",
        "svc": "MIDDLEWARE",
        "svc_data": "{\"vers\": {\"major\": 0, \"minor\": 1}, \"origin\": \"192.168.44.11\", \"protocol\": \"REST\", \"credentials\": {\"credentials\": \"API_KEY\", \"credentials_data\": {\"api_key\": {\"id\": 2, \"name\": \"Redacted\"}}}}",
        "event": "AUTHENTICATION",
        "event_data": "{\"credentials\": {\"credentials\": \"API_KEY\", \"credentials_data\": {\"api_key\": \"Redacted\"}}, \"error\": null}",
        "success": true
    }:
}

Why does it have error: null and success: true if the call failed?!

Does anyone know what I’m doing wrong?

Thanks!

Closing the loop here:

  • limited API keys did not work at all with the REST API
  • the REST API has been discontinued in TrueNAS 25 (see API Reference | TrueNAS Documentation Hub)
  • they worked with the websocket API, using the command below
  • limited API keys created like this have been discontinued in TrueNAS >= 25 in favor of limited accounts with user-linked API keys.

From the documentation (bold is mine)

Existing API keys created via the TrueNAS API (not UI or TrueCommand) that specify an allow list with white-listed API methods are revoked upon upgrade because there is no clean way to migrate to the new system. Administrators should create a service account (a user account for this particular purpose), define desired access rights for this service account, generate a new user-linked API key, and distribute it to the API client.

For TrueNAS < 25, this command allowed me to limit an API key to only lock and unlock datasets

midclt call api_key.update <KEY_ID> '{"allowlist": [{"method": "GET","resource": "pool"},{"method": "*","resource": "pool.dataset.unlock"},{"method": "*", "resource": "pool.dataset.lock"}]}'