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

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

私は、HTTP トリガーで Google Cloud Functions を使用して、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 の問題だと思っています。しかし、それをどのように確認すればよいかわかりません。ドキュメントには、関数はサービス アカウントを使用して実行されると書かれており、関数の [全般] タブで確認できます。IAM で、このサービス アカウントには があり、次のように<YOUR_PROJECT_ID>@appspot.gserviceaccount.com表示されていることがわかります。Service Account Token Creator

サービス アカウントを偽装します (OAuth2 アクセス トークンの作成、BLOB または JWT への署名など​​)。

のドキュメントには次のようにgetSignedUrl書かれています:

これらの環境では、signBlob APIを呼び出して署名付きURLを作成します。このAPIでは、https://www.googleapis.com/auth/iamまたはクラウドプラットフォームスコープなので、必ず有効にしてください。

これで動作するには十分だと思います。スコープを明示的にチェックする方法がわかりません。

私が試した唯一の他のことは、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: サービス アカウント プロジェクト/-/serviceAccounts/ でこの操作を実行するには、権限 iam.serviceAccounts.signBlob が必要です[メールアドレス]

サービス アカウントにこの権限があるかどうかを確認する方法がわかりません。Web サイトの 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 デフォルト サービス アカウント」サービス アカウントに「Cloud Functions サービス エージェント」ロールを追加することで解決しました。

次の場所に移動します:https://console.cloud.google.com/iam-admin/iam

「Cloud Functions サービスエージェント」を見つける
役割を管理する

@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

関連情報