Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed access rules for Storage not work in emulators #7946

Open
bgrand-ch opened this issue Nov 13, 2024 · 2 comments
Open

Closed access rules for Storage not work in emulators #7946

bgrand-ch opened this issue Nov 13, 2024 · 2 comments

Comments

@bgrand-ch
Copy link

bgrand-ch commented Nov 13, 2024

[REQUIRED] Environment info

firebase-tools: 13.25.0

Platform: macOS Sequioa 15.1

[REQUIRED] Test case

storage.rules minimal file with closed access:

rules_version = '2';

service firebase.storage {
  match /b/{bucket}/o {
    // Firebase Admin SDK only
    match /{file=**} {
      allow read, write: if false;
    }
  }
}

firebase.json with the following emulators settings (and other settings required for your project):

{
  "emulators": {
    "singleProjectMode": true,
    "ui": {
      "enabled": true,
      "port": 3010
    },
    "auth": {
      "port": 3011,
      "host": "localhost"
    },
    "firestore": {
      "port": 3012,
      "host": "localhost"
    },
    "database": {
      "port": 3013,
      "host": "localhost"
    },
    "storage": {
      "port": 3014,
      "host": "localhost"
    },
    "functions": {
      "port": 3015,
      "host": "localhost"
    },
    "eventarc": {
      "port": 3016,
      "host": "localhost"
    },
    "pubsub": {
      "port": 3017,
      "host": "localhost"
    },
    "hosting": {
      "port": 3018,
      "host": "localhost"
    }
  }
}

[REQUIRED] Steps to reproduce

  1. If necessary, build TypeScript Cloud Functions.
  2. Start emulators with firebase emulators:start.
  3. Upload a file to Storage emulator from Emulators UI.
  4. Get this file with firebase-admin/storage in a Cloud Function.
  5. Error ApiError: Permission denied. No READ permission.

[REQUIRED] Expected behavior

Same behaviours of closed access rules between the Cloud Storage service and the Storage emulator.

[REQUIRED] Actual behavior

Closed access rules work for Cloud Storage service in a Cloud Function with firebase-admin/storage, but not on the Storage emulator.

Logs:

{
  "user":{
    "severity":"ERROR",
    "message":"[getFile] Storage error ApiError: Permission denied. No READ permission.\n    at new ApiError (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:114:15)\n    at Util.parseHttpRespBody (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:253:38)\n    at Util.handleResp (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:193:30)\n    at /Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:583:22\n    at onResponse (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/[email protected][email protected]/node_modules/retry-request/index.js:259:7)\n    at /Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/[email protected][email protected]/node_modules/teeny-request/build/src/index.js:217:17\n    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {\n  code: 403,\n  errors: undefined,\n  response: PassThrough {\n    _readableState: ReadableState {\n      objectMode: false,\n      highWaterMark: 16384,\n      buffer: BufferList { head: null, tail: null, length: 0 },\n      length: 0,\n      pipes: [],\n      flowing: true,\n      ended: true,\n      endEmitted: true,\n      reading: false,\n      constructed: true,\n      sync: false,\n      needReadable: false,\n      emittedReadable: false,\n      readableListening: false,\n      resumeScheduled: false,\n      errorEmitted: false,\n      emitClose: true,\n      autoDestroy: true,\n      destroyed: true,\n      errored: null,\n      closed: true,\n      closeEmitted: true,\n      defaultEncoding: 'utf8',\n      awaitDrainWriters: null,\n      multiAwaitDrain: false,\n      readingMore: false,\n      dataEmitted: true,\n      decoder: null,\n      encoding: null,\n      [Symbol(kPaused)]: false\n    },\n    _events: [Object: null prototype] {\n      prefinish: [Function: prefinish],\n      error: [Array],\n      data: [Function (anonymous)],\n      end: [Function (anonymous)]\n    },\n    _eventsCount: 4,\n    _maxListeners: undefined,\n    _writableState: WritableState {\n      objectMode: false,\n      highWaterMark: 16384,\n      finalCalled: true,\n      needDrain: false,\n      ending: true,\n      ended: true,\n      finished: true,\n      destroyed: true,\n      decodeStrings: true,\n      defaultEncoding: 'utf8',\n      length: 0,\n      writing: false,\n      corked: 0,\n      sync: false,\n      bufferProcessing: false,\n      onwrite: [Function: bound onwrite],\n      writecb: null,\n      writelen: 0,\n      afterWriteTickInfo: null,\n      buffered: [],\n      bufferedIndex: 0,\n      allBuffers: true,\n      allNoop: true,\n      pendingcb: 0,\n      constructed: true,\n      prefinished: true,\n      errorEmitted: false,\n      emitClose: true,\n      autoDestroy: true,\n      errored: null,\n      closed: true,\n      closeEmitted: true,\n      [Symbol(kOnFinished)]: []\n    },\n    allowHalfOpen: true,\n    statusCode: 403,\n    statusMessage: 'Forbidden',\n    request: {\n      agent: [Agent],\n      headers: [Object],\n      href: 'http://127.0.0.1:3014/v0/b/live-display-staging.appspot.com/o/authorized-emails.json'\n    },\n    body: { error: [Object] },\n    headers: {\n      'access-control-expose-headers': 'content-type,x-firebase-storage-version,X-Goog-Upload-Size-Received,x-goog-upload-url,x-goog-upload-command,x-gupload-uploadid,x-goog-upload-header-content-length,x-goog-upload-header-content-type,x-goog-upload-protocol,x-goog-upload-status,x-goog-upload-chunk-granularity,x-goog-upload-control-url',\n      connection: 'keep-alive',\n      'content-length': '73',\n      'content-type': 'application/json; charset=utf-8',\n      date: 'Wed, 13 Nov 2024 22:02:00 GMT',\n      etag: 'W/\"49-rW1o0iNt7zW3rgr9/wz7M3rApug\"',\n      'keep-alive': 'timeout=5',\n      vary: 'Origin',\n      'x-powered-by': 'Express'\n    },\n    toJSON: [Function: toJSON],\n    [Symbol(kCapture)]: false,\n    [Symbol(kCallback)]: null\n  }\n}"
  },
  "metadata":{
    "emulator":{
      "name":"functions"
    },
    "function":{
      "name":"europe-west3-checkEmailAuthorized"
    },
    "extension":{
      
    },
    "message":"\u001b[90m> \u001b[39m {\"severity\":\"ERROR\",\"message\":\"[getFile] Storage error ApiError: Permission denied. No READ permission.\\n    at new ApiError (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:114:15)\\n    at Util.parseHttpRespBody (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:253:38)\\n    at Util.handleResp (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:193:30)\\n    at /Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:583:22\\n    at onResponse (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/[email protected][email protected]/node_modules/retry-request/index.js:259:7)\\n    at /Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/[email protected][email protected]/node_modules/teeny-request/build/src/index.js:217:17\\n    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {\\n  code: 403,\\n  errors: undefined,\\n  response: PassThrough {\\n    _readableState: ReadableState {\\n      objectMode: false,\\n      highWaterMark: 16384,\\n      buffer: BufferList { head: null, tail: null, length: 0 },\\n      length: 0,\\n      pipes: [],\\n      flowing: true,\\n      ended: true,\\n      endEmitted: true,\\n      reading: false,\\n      constructed: true,\\n      sync: false,\\n      needReadable: false,\\n      emittedReadable: false,\\n      readableListening: false,\\n      resumeScheduled: false,\\n      errorEmitted: false,\\n      emitClose: true,\\n      autoDestroy: true,\\n      destroyed: true,\\n      errored: null,\\n      closed: true,\\n      closeEmitted: true,\\n      defaultEncoding: 'utf8',\\n      awaitDrainWriters: null,\\n      multiAwaitDrain: false,\\n      readingMore: false,\\n      dataEmitted: true,\\n      decoder: null,\\n      encoding: null,\\n      [Symbol(kPaused)]: false\\n    },\\n    _events: [Object: null prototype] {\\n      prefinish: [Function: prefinish],\\n      error: [Array],\\n      data: [Function (anonymous)],\\n      end: [Function (anonymous)]\\n    },\\n    _eventsCount: 4,\\n    _maxListeners: undefined,\\n    _writableState: WritableState {\\n      objectMode: false,\\n      highWaterMark: 16384,\\n      finalCalled: true,\\n      needDrain: false,\\n      ending: true,\\n      ended: true,\\n      finished: true,\\n      destroyed: true,\\n      decodeStrings: true,\\n      defaultEncoding: 'utf8',\\n      length: 0,\\n      writing: false,\\n      corked: 0,\\n      sync: false,\\n      bufferProcessing: false,\\n      onwrite: [Function: bound onwrite],\\n      writecb: null,\\n      writelen: 0,\\n      afterWriteTickInfo: null,\\n      buffered: [],\\n      bufferedIndex: 0,\\n      allBuffers: true,\\n      allNoop: true,\\n      pendingcb: 0,\\n      constructed: true,\\n      prefinished: true,\\n      errorEmitted: false,\\n      emitClose: true,\\n      autoDestroy: true,\\n      errored: null,\\n      closed: true,\\n      closeEmitted: true,\\n      [Symbol(kOnFinished)]: []\\n    },\\n    allowHalfOpen: true,\\n    statusCode: 403,\\n    statusMessage: 'Forbidden',\\n    request: {\\n      agent: [Agent],\\n      headers: [Object],\\n      href: 'http://127.0.0.1:3014/v0/b/live-display-staging.appspot.com/o/authorized-emails.json'\\n    },\\n    body: { error: [Object] },\\n    headers: {\\n      'access-control-expose-headers': 'content-type,x-firebase-storage-version,X-Goog-Upload-Size-Received,x-goog-upload-url,x-goog-upload-command,x-gupload-uploadid,x-goog-upload-header-content-length,x-goog-upload-header-content-type,x-goog-upload-protocol,x-goog-upload-status,x-goog-upload-chunk-granularity,x-goog-upload-control-url',\\n      connection: 'keep-alive',\\n      'content-length': '73',\\n      'content-type': 'application/json; charset=utf-8',\\n      date: 'Wed, 13 Nov 2024 22:02:00 GMT',\\n      etag: 'W/\\\"49-rW1o0iNt7zW3rgr9/wz7M3rApug\\\"',\\n      'keep-alive': 'timeout=5',\\n      vary: 'Origin',\\n      'x-powered-by': 'Express'\\n    },\\n    toJSON: [Function: toJSON],\\n    [Symbol(kCapture)]: false,\\n    [Symbol(kCallback)]: null\\n  }\\n}\"}"
  }
}
@bgrand-ch
Copy link
Author

bgrand-ch commented Nov 13, 2024

@bgrand-ch bgrand-ch changed the title Storage emulator: Closed access rules with Cloud Functions does not work in the emulator Closed access rules for Storage not work in emulators Nov 13, 2024
@aalej
Copy link
Contributor

aalej commented Nov 15, 2024

Hey @bgrand-ch, thanks for the detailed report! I'm able to reproduce the behavior you mentioned. When using the emulators, the request is being denied with a Permission denied. No READ permission error. I'll mark this as reproducible and raise this to our engineering team so they can take a look.

Sharing the mcve here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants