web-dev-qa-db-ja.com

getSignedUrlが「SigningError:メタデータサーバーからのエラー」を返す

API呼び出しのエンドポイントを作成するために、Google Cloud FunctionsとHTTPトリガーを使用しています。このエンドポイントは、Cloud StorageパッケージのgetSignedUrl関数を使用しています。クライアントがファイルをアップロードするためにその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:サービスアカウントprojects/-/serviceAccounts/[email protected]でこの操作を実行するには、権限iam.serviceAccounts.signBlobが必要です。

サービスアカウントにこの権限があることを確認する方法がわかりません。ウェブサイトの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のバグのようですが、何か不足している可能性があります。私はしばらくこれにこだわっています。あなたの助けがあれば助かります!

4
jsambuo

試行錯誤の末、@google-cloud/storageバージョン1.6.0がこの動作を引き起こしていることがわかりました。私は1.5.2にダウングレードし、機能し始めました。

このためにGitHubの問題を公開しました: https://github.com/googleapis/nodejs-storage/issues/15

1
jsambuo

「App Engineのデフォルトのサービスアカウント」サービスアカウントに「Cloud Functionsサービスエージェント」の役割を追加することで解決しました。

移動: https://console.cloud.google.com/iam-admin/iam

"Cloud Functionsサービスエージェント"を検索
ロールの管理

@rscottenコメントでスクリーンクリップを使用してガイドを取得: https://github.com/googleapis/nodejs-storage/issues/15

11
Matjaz Hirsman