type holyshared = Engineer<mixed>

技術的なことなど色々

R2のファイルアップロード用の署名付きURL

R2の署名付きURLが利用できるか調べていました。
S3互換と言いつつ、使えないものもあるだろうと思っていましたが最低限のAPIが揃っているので困ることはなさそうです。

今回はask-sdkのv3を使用しました。 v2まではS3Client単体で作成できたみたいですが、パッケージが分割されていて必要なものだけでインストールすればOKぽいです。

R2の利用方法

R2を利用するには、Cloudflareにログインして、R2を有効にする必要があります。
R2を有効にした後は、R2のAPIトークンとバケットを作成します。

また、アカウントIDも必要になるのでダッシュポードに掲載されているAccount IDをメモしておきます。

署名付きURLを発行する

署名付きURLを発行するには下記のコードを利用します。
S3Clientのオプションにクレデンシャルとリージョンを指定してクライアントを初期化します。

その後はgetSignedUrl関数を利用してPutObjectに対しての署名付きURLを作成します。
署名の有効期限はexpiresInで指定すればOKのようです。

const s3 = require('@aws-sdk/client-s3')
const presigner = require('@aws-sdk/s3-request-presigner')

const accountId = process.env.R2_ACCOUNT_ID || 'example'
const bucket = process.env.R2_BUCKET || 'example'

const client = new s3.S3Client({
  credentials: {
    accessKeyId: process.env.R2_ACCESS_KEY,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
  },
  region: 'auto',
  endpoint: `https://${accountId}.r2.cloudflarestorage.com`
})

exports.presignedURL = {
  async of(path) {
    const command = new s3.PutObjectCommand({
      Bucket: bucket,
      Key: path,
      ContentType: "image/jpeg",
    })
    return presigner.getSignedUrl(client, command, { expiresIn: 3600 });
  }
}

署名付きURLにファイルをアップロードする

署名付きURLにPUTでファイルを指定すると、ファイルをアップロードできます。
Content-Typeヘッダーは指定しておいた方がよさそうです。

curl -XPUT -H "content-type:image/jpeg" --data-binary @example.jpg [URL]

気になったところ

署名付きURLにはX-Amz-CredentialにAccessKeyIdが含まれるので、S3の場合はセキュリティのために署名付きURLを作成する際はAWS Security Token Serviceで一時的なクレデンシャルを作成し、署名付きURLを作成していました。

この方法の場合、X-Amz-Credentialが一時的なクレデンシャルのものになるので安心でした。
R2の場合はこの方法が取れないので、URLの期限をできるだけ短くするなどしか対策が取れないかもしれないです。

最後に

今回の具体的なコードはここにおいて置いました。 github.com