0時に寝て6時に起きた。

waf のカスタムレスポンス

メンテンナンス時にエンドユーザーがアプリケーションにアクセスできないようにしたい。いろんなやり方があるけど、どういった手段で対応するのが最もシンプルで運用も容易かを少し前から頭を悩ませていた。

当初は cloudfront のディストリビューションをアプリケーションの assets とメンテナンスページの html の2つを作って、cdk のデプロイで切り替えできないかと考えた。cloudfront はドメイン名と密接に紐付いていて、同じドメイン名を2つのディストリビューションに設定することはできないようにみえる。あらかじめそれぞれのディストリビューションを2つ作っておいて route53 で必要に応じて向き先を切り替えるといった構成はできなかった。その次に waf について調べていたら waf がルールでカスタムレスポンスを返すことができることに気付いた。

ちょうどいまエンドユーザーからのアクセスは ipSet で許可し、それ以外のネットワークからのアクセスをブロックしていた。そのルールを更新して、メンテナンス時はエンドユーザーからのリクエストのみをブロックに変更してカスタムレスポンスを返せることに気付いた。waf を管理するスタックなら cdk デプロイで1分ぐらいで更新できた。このやり方のよいところの1つに開発者の ip アドレスを許可することで開発者だけはアクセスできるようにもできる。あと具体的に cdk でカスタムレスポンスをどう実装するかのドキュメントがわかりにくい。サンプルとしてはこんな感じ。

const acl = new wafv2.CfnWebACL(this, 'MyAcl', {
  defaultAction: { block: {} },
  name: 'my-acl',
  scope: 'CLOUDFRONT',
  customResponseBodies: {
    maintenanceInProgress: {
      content: '<html lang="en">Maintenance in progress</html>',
      contentType: 'TEXT_HTML',
    },
  },
  rules: [{
    action: { 
      block: {
        customResponse: {
          responseCode: 503,
          customResponseBodyKey: 'maintenanceInProgress',
        },
      },
    },
    statement: {
      ipSetReferenceStatement: {
        arn: ipSet.attrArn,
      },
    }
  }],
});