kawabatas技術ブログ

試してみたことを書いていきます

Firebase で公開したサイトに IP でアクセス制限をかける

概要

Firebase Hosting で公開した一部のページに特定のIPからのみアクセス可能にしたいという要望を実現したときのメモ。

実装

IP制限をかけたいページへアクセスがあると、Cloud functions の関数を実行し、動的にhtmlを生成して返す。

ほぼほぼこちらの記事通りにした。

今は Hack 的な実装が必要だが、いずれ Firebase 側が対応してくれる気がする。

フォルダ構成(ピックアップ)

├── firebase.json
├── functions
│   ├── index.js
│   ├── package.json
│   └── templates
│       ├── 403.html
│       ├── foo.html
└── public
   ├── index.html

firebase.json

{
  "hosting": {
    "public": "public",
    "rewrites": [
      {
        "source": "/foo.html", "function": "ipfilter"
      }
    ],
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  },
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint"
    ],
    "source": "functions"
  }
}

function/index.js

const functions = require('firebase-functions');
const requestIp = require('request-ip');
const ipRangeCheck = require('ip-range-check');
const is = require('is_js');
const fs = require('fs');
const url = require('url');
 const allowIps = [
  'xx.xx.xx.xx/xx',// 許可するIPアドレス
  '127.0.0.1',// ローカル開発環境
]

exports.ipfilter = functions.https.onRequest((request, response) => {
  // request.headers['x-forwarded-for']に appengine の ip が入っていたため変更した。https://github.com/pbojinov/request-ip/blob/master/src/index.js#L48
  const clientIp = is.ip(request.headers['fastly-client-ip']) ? request.headers['fastly-client-ip'] : requestIp.getClientIp(request);
  let filename = url.parse(request.url).pathname;

  const isAllowed = ipRangeCheck(clientIp, allowIps);
  const statusCode = isAllowed ? 200 : 403;
  if (!isAllowed) { filename = '/403.html'; }

  const html = fs.readFileSync(`./templates${filename}`).toString();

  response.status(statusCode).send(html);
});