Google Cloud Storage(GCS)にファイルを直接アップロードするために使用する署名付きURLを作成しようとしています。ポリシーを利用するこのGithubの例を使用して、POSTを使用してこれを機能させました。ベストプラクティスに従って、PUTを使用するようにリファクタリングし、SignatureDoesNotMatch
エラーが発生します。
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>PUT
123456789
/mybucket/mycat.jpg</StringToSign></Error>
プログラムとGCPのサンプルPythonコードを使用して署名付きURLを作成するためのドキュメントに従って、私はこのプロセスを実行しています。
これはGoogleApp Engine(GAE)アプリで実行されているため、サービスアカウントユーザーのJSONキーファイルを取得する必要はありませんが、App IdentityServicesを使用して署名します。これがFlaskプロジェクト内の私のコードです:
google_access_id = app_identity.get_service_account_name()
expires = arrow.utcnow().replace(minutes=+10).replace(microseconds=0).timestamp
resource = '/mybucket/mycat.jpg'
args = self.get_parser.parse_args()
signature_string = 'PUT\n'
# take MD5 of file being uploaded and its content type, if provided
content_md5 = args.get('md5') or ''
content_type = args.get('contenttype') or ''
signature_string = ('PUT\n'
'{md5}\n'
'{content_type}\n'
'{expires}\n'
'{resource}\n').format(
md5=content_md5,
content_type=content_type,
expires=expires,
resource=resource)
log.debug('signature string:\n{}'.format(signature_string))
_, signature_bytes = app_identity.sign_blob(signature_string)
signature = base64.b64encode(signature_bytes)
# URL encode signature
signature = urllib.quote(signature)
media_url = 'https://storage.googleapis.com{}'.format(resource)
return dict(GoogleAccessId=google_access_id,
Expires=expires,
Signature=signature,
bucket='mybucket',
media_url='{}?GoogleAccessId={}&Expires={}&Signature={}'.format(media_url, google_access_id, expires, signature))
このlog.debug
ステートメントは、上記のGCSXMLエラー応答の署名と完全に一致する署名ファイルを出力します。それらが一致する場合、なぜアップロードできないのですか?
をgsutil
使用すると、同じGAEサービスアカウントを使用して署名付きURLを作成でき、Postmanで正常に機能します。gsutil
URLエンコードされた署名が表示されますが、独自の署名付きURLを作成する場合、どちらの方法でも問題はないようです。GCSはPUTリクエストを受け取り、表示されている署名が自分の署名と一致していても、署名が一致しないと文句を言います。ログに記録されたデバッグメッセージ。また、元の署名文字列の末尾に\ nがある場合とない場合も試しました。
編集:POST
私は、その後の例それは歌う前にBase64では、ポリシーをコードし、そして再び、それはそれに署名した後。PUT署名の作成でこのアプローチを試しましたが、違いはありませんでした
答えは、Content-Type
ヘッダーを使用する必要があることを指摘して、SOや他の場所で見つかった他の答えに非常に近いものでした。これは部分的には真実ですが、私の主な問題によって影が薄くなっています。私は、GCSに対して読み取りと書き込みができると想定した「エディター」のアクセス許可を持つデフォルトのGAEサービスアカウントに依存していました。私はそのアカウントからキーファイルを作成し、それを使用して、gsutil
この手がかりを与えました。
[email protected] does not have permissions on gs://mybucket/cat.jpg, using this link will likely result in a 403 error until at least READ permissions are granted
そこにファイルを配置しようとするとGCSからエラーが発生するのは正しかったのですが、それは404エラーではなくSignatureDoesNotMatch
、質問に示されているエラーでした。
解決策は2つの部分でした:
Content-Type
ファイルをGCSにPUTするときは、必ずヘッダーを使用してください。署名する署名文字列で指定しなくても、デフォルトでtext/plain
ヘッダーで指定する必要があります。最後に、アカウントに正しいアクセス許可を追加した後でも、IAMコンソールから新しいJSONキーファイルを作成するまで、gsutilで警告が表示されました。さらに、GSutilと古いキーファイルで作成された署名付きURLはSignatureDoesNotMatch
、IAMコンソールでアクセス許可が設定されていても機能しませんでした(エラー)。GAEで実行されているPythonコードは、更新なしで正常に機能しました。IAMで設定されたアクセス許可と、コンテンツヘッダーを一致させるだけで済みました。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加