getSignedUrl 給出“SigningError:元資料伺服器失敗”

getSignedUrl 給出“SigningError:元資料伺服器失敗”

我使用 Google Cloud Functions 和 HTTP 觸發器來建立 API 呼叫的端點。該端點正在使用getSignedUrlCloud Storage 套件中的功能。我想傳回一個已簽署的 URL,以便用戶端可以PUT透過該 URL 上傳檔案。

我發現此 API 的行為不一致。有時我會從該函數傳回一個 URL。然後我嘗試更新儲存桶名稱,但收到此錯誤:

{ SigningError: Failure from metadata server.
at /user_code/node_modules/@google-cloud/storage/src/file.js:1715:16
at getCredentials (/user_code/node_modules/@google-cloud/storage/node_modules/google-auto-auth/index.js:264:9)
at googleAuthClient.getCredentials (/user_code/node_modules/@google-cloud/storage/node_modules/google-auto-auth/index.js:148:11)
at process._tickDomainCallback (internal/process/next_tick.js:135:7) message: 'Failure from metadata server.' }

如果我改回儲存桶名稱,我仍然會看到此錯誤。我嘗試過不同的方法,例如從終端進行部署。這給了我同樣的錯誤。我還使用瀏覽器創建了該功能,並且開始工作。在我嘗試更新儲存桶名稱後,它停止工作。

透過谷歌搜索,我認為這是權限或 ACL 問題,但我不確定如何確認。文件說函數使用<YOUR_PROJECT_ID>@appspot.gserviceaccount.com服務帳戶運行,我可以在函數的常規選項卡中確認這一點。我可以在 IAM 中看到該服務帳戶具有Service Account Token Creator,其中顯示:

模擬服務帳戶(建立 OAuth2 存取權令牌、簽署 blob 或 JWT 等)。

的文檔getSignedUrl說:

在這些環境中,我們呼叫signBlob API 來建立簽章URL。該 API 需要https://www.googleapis.com/auth/iam或者https://www.googleapis.com/auth/cloud-platform範圍,因此請確保啟用它們。

我覺得這應該足以讓它發揮作用。我不知道如何明確檢查範圍。

sign-blob我嘗試過的唯一一件事就是從終端運行。我跑了這個:

gcloud iam service-accounts sign-blob --iam-account=<my-project-id>@appspot.gserviceaccount.com input.file output.file

我得到這個錯誤:

錯誤:(gcloud.iam.service-accounts.sign-blob) PERMISSION_DENIED:需要 iam.serviceAccounts.signBlob 權限才能對服務帳戶項目/-/serviceAccounts/ 執行此操作[電子郵件受保護]

我不知道如何檢查我的服務帳戶是否具有此權限。我嘗試在 IAM 網站、gcloud終端程式以及我的儲存桶上設定的權限中尋找它。

這是我的函數的程式碼:

const storage = require('@google-cloud/storage')();

exports.getSignedUrl = (req, res) => {

    if(req.method === 'POST') {

        // Perform any authorization checks here to assert
        // that the end user is authorized to upload.

        const myBucket = storage.bucket('my-bucket-name');
        const myFile = myBucket.file(req.body.filename);
        const contentType = req.body.contentType;

        // This link should only last 5 minutes
        const expiresAtMs = Date.now() + 300000;
        const config = {
            action: 'write',
            expires: expiresAtMs,
            contentType: contentType
        };

        myFile.getSignedUrl(config, function(err, url) {
            if (err) {
                console.error(err);
                res.status(500).end();
                return;
            }
            res.send(url);
        });
    } else {
        res.status(405).end();
    }
}

有沒有人以前看過這個,或是知道為什麼會發生這種事?或者您知道如何檢查我的服務帳戶是否具有這些權限或範圍?我覺得這可能是 GCP 中的錯誤,但很可能我遺漏了一些東西。我已經被困在這個問題上有一段時間了,如果您能提供任何幫助,我將不勝感激!

答案1

我透過將「雲端功能服務代理」角色新增至我的「App Engine 預設服務帳戶」服務帳戶來解決這個問題。

去:https://console.cloud.google.com/iam-admin/iam

找到“雲端函數服務代理”
管理角色

我在 @rscotten 評論中得到了螢幕剪輯的指導:https://github.com/googleapis/nodejs-storage/issues/150

答案2

經過一番嘗試和錯誤後,我發現這個@google-cloud/storage版本1.6.0給了我這種行為。我降級到1.5.2並開始工作。

我為此開啟了一個 GitHub 問題:https://github.com/googleapis/nodejs-storage/issues/150

相關內容