通过 Cloudflare Transform Rules 访问 Private BackBlaze B2 Bucket

杂谈 | 共 5092 字 | 2021/12/6 发表 | 2021/12/6 更新

写了个英文教程,需要这篇教程的应该都看得懂吧,不翻译了。

Cloudflare now offers free Transform Rules, so BackBlaze B2 users can use URL Rewrite rules to hide bucket name and provide access to private bucket.

TLDR: Create a URL Rewrite Rule and hide your bucket name. If your bucket is private, you also need to create a Cloudflare Worker, copy the code and fill in the config.

Hide Bucket Name

URL Rewrite is quite simple. In Cloudflare dashboard, choose your domain -> Rules -> Transform Rules. Create a new Rewrite URL rule. It simply matches the domain, and dynamically rewrites to concat("/file/<YOUR_BUCKET_ID>", http.request.uri.path).

url-rewrite-rule

Access Private Bucket

If you want to access your private bucket from Cloudflare. You first need to create a BackBlaze Application Key. You need the keyID and applicationKey to generate a token, which is used to access files from the private bucket.

You can read the B2 documentation about how to generate the token. We can use the token to download files from private buckets in two ways: add Authorization in request header or add Authorization param in request query. The first header option needs additional "Request Header Modification rule" and the response cannot be cached by Cloudflare, so we use the second method.

Edit the URL Rewrite rule we created to hide bucket name, in Query choose "Rewrite to", select Static and enter Authorization=<Token>.

The problem is that the token is only at most 24 hours. So I write this script to automatically create token and update the rule. You can create a Cloudflare worker to do the job and set Triggers to run every 30 minutes.

Create a Cloudflare worker. The name does not matter since we use the Trigger of the worker. Open the quick editor. Copy and paste the code.

const config = {
  // B2 config
  B2KeyID: '',
  B2AppKey: '',
  B2BucketID: '',
  // Cloudflare config
  cfDomain: '',
  cfAuthEmail: '',
  cfAuthKey: '',
  cfZoneID: '',
  cfRulesetID: '',
  cfRuleID: '',
}

addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request))
})
addEventListener('scheduled', (event) => {
  event.waitUntil(updateRule(config))
})

const getB2Token = async (config) => {
  const { B2KeyID, B2AppKey } = config
  const res = await fetch(
    'https://api.backblazeb2.com/b2api/v2/b2_authorize_account',
    {
      headers: {
        Authorization: 'Basic ' + btoa(B2KeyID + ':' + B2AppKey),
      },
    },
  )
  const data = await res.json()
  return data.authorizationToken
}

const updateRule = async (config) => {
  const b2Token = await getB2Token(config)
  const {
    B2BucketID,
    cfDomain,
    cfAuthEmail,
    cfAuthKey,
    cfZoneID,
    cfRulesetID,
    cfRuleID,
  } = config

  const res = await fetch(
    `https://api.cloudflare.com/client/v4/zones/${cfZoneID}/rulesets/${cfRulesetID}/rules/${cfRuleID}`,
    {
      method: 'PATCH',
      headers: {
        'X-Auth-Email': cfAuthEmail,
        'X-Auth-Key': cfAuthKey,
      },
      body: `{
      "description": "B2 ${B2BucketID}",
      "action": "rewrite",
      "expression": "(http.host eq \\\"${cfDomain}\\\")",
      "action_parameters": {
        "uri": {
          "path": {
            "expression": "concat(\\\"/file/${B2BucketID}\\\", http.request.uri.path)"
          },
          "query": {
            "value": "Authorization=${b2Token}"
          }
        }
      }
    }`,
    },
  )

  const data = await res.text()
  console.log(data)
  return data
}

async function handleRequest(request) {
  const data = await updateRule(config)
  return new Response(data)
}

The configs you need to fill in:

  • B2KeyID and B2AppKey by create a BackBlaze Application Key.

  • B2BucketID: Your BackBlaze B2 bucket ID.

  • cfDomain: The domain you want to access b2 from.

  • cfAuthEmail: Your Cloudflare email.

  • cfAuthKey: Your Global API Key from API Tokens.

  • cfZoneID: Your domain zone ID from the overview dashboard of your domain.

  • cfRulesetID: You need first create the URL Rewrite rule. Then use the following curl command to view all the rulesets you have. Find the ruleset with phase http_request_transform. Its id is the cfRulesetID we want.

    curl -X GET \
      -H "X-Auth-Email: <cfAuthEmail>" \
      -H "X-Auth-Key: <cfAuthKey>" \
      "https://api.cloudflare.com/client/v4/zones/<cfZoneID>/rulesets"
    
  • cfRuleID: Once you have the cfRulesetID, use the following curl command to view the rules you have in the rule set. Find the rule you created in Cloudflare dashboard, its id is the cfRuleID we want.

    curl -X GET \
      -H "X-Auth-Email: <cfAuthEmail>" \
      -H "X-Auth-Key: <cfAuthKey>" \
      "https://api.cloudflare.com/client/v4/zones/<cfZoneID>/rulesets/<cfRulesetID>"
    

Once you fill in the constants, you can by Save and Deploy and then Run.