数据库(PostgreSQL RDS/Amazon Aurora)返回大量图像文件。我们需要对 URL 进行签名。目前,用户定义的函数或视图返回记录。
我正在寻找一种直接在 SQL 中将 S3 URL 签名为用户定义函数的方法。不幸的是,除了在用户定义的函数中使用 Python 语言之外,似乎没有其他方法,并且 PostgreSQL/Aurora 不支持 python 作为过程语言。
有人知道我们可以直接对 URL 进行签名作为 PostgreSQL RDS/Amazon Aurora 中 SQL 查询的一部分吗?
是的,这是可能的,我已经做到了。
首先,让我们看看AWS SDK是如何做到的。在 JavaScript AWS SDK 中,我们调用
getSignedUrlPromise
来获取签名的 url。
import AWS from 'aws-sdk';
const s3 = new AWS.S3();
s3.getSignedUrlPromise('getObject', { Bucket, Key, Expires: 60 * 60});
从 getSignedUrlPromise 开始,到 getSignedUrl、request.presign、AWS.Signers.Presign().sign,我们可以看到
sign: function sign(request, expireTime, callback) {
request.on('build', signedUrlBuilder);
request.on('sign', signedUrlSigner);
// ...
return AWS.util.urlFormat(request.httpRequest.endpoint);
}
签名发生在 V3 的 signedUrlSigner 中
function signedUrlSigner(request) {
var auth = request.httpRequest.headers['Authorization'].split(' ');
if (auth[0] === 'AWS') {
auth = auth[1].split(':');
queryParams['Signature'] = auth.pop();
queryParams['AWSAccessKeyId'] = auth.join(':');
}
endpoint.search = AWS.util.queryParamsToString(queryParams);
}
Signature
来自headers['Authorization']
,但是Authorization
集在哪里?
它在 AWS.Signers.S3.addAuthorization
中设置 addAuthorization: function addAuthorization(credentials, date) {
var signature = this.sign(credentials.secretAccessKey, this.stringToSign());
var auth = 'AWS ' + credentials.accessKeyId + ':' + signature;
this.request.headers['Authorization'] = auth;
},
sign
函数使用sha1和base64摘要
sign: function sign(secret, string) {
return AWS.util.crypto.hmac(secret, string, 'base64', 'sha1');
}
并且
stringToSign
有点令人困惑,但在我的实验中结果是
const stringToSign = `GET\n\n\n${EXPIRES}\n/${BUCKET}/${KEY}`;
有了以上信息,我们就可以轻松编写一个postgres函数了
CREATE OR REPLACE FUNCTION image_s3_signed_url(image_row "Image")
RETURNS TEXT AS $$
DECLARE
newline text := E'\n';
method text := 'GET';
bucket text := 'my_bucket';
access_key text := 'my_access_key';
access_secret text := 'my_access_secret';
filepath text;
expires bigint;
tosign text;
raw_signature text;
encoded_signatre text;
result text;
BEGIN
filepath := image_row.filepath;
expires = EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) + 60 * 60;
tosign := method || newline || newline || newline || expires || newline || '/' || bucket || filepath;
raw_signature := encode(hmac(tosign, access_secret, 'sha1'), 'base64');
encoded_signatre := REPLACE(REPLACE(REPLACE(raw_signature, '+', '%2B'), '/', '%2F'), '=', '%3D');
result = filepath || '?AWSAccessKeyId=' || access_key || '&Expires=' || expires || '&Signature=' || encoded_signatre;
RETURN result;
END;
$$ LANGUAGE plpgsql STABLE;
数据库不是执行此类操作的地方。 您应该考虑将签名 URL 放入数据库中,或者重新考虑您的应用程序(如果不应该重新构建它)。