2020-06-07

Terraform RegistryのModuleを使ってHasuraを立てる

Terraformの素振りのため、公開されているModuleを使ってAWS ECSクラスター上にHasuraを立ててみました.
Auth0での認証認可まで疎通確認できたので手順を共有します.

概要

Hasura について軽く説明をすると, これはPostgreSQLをバックエンドとしてAPIを自動生成してくれるGraphQLサーバーです. DBスキーマからとりうるCRUD操作をAPI越しに一通り行うことができるようにしてくれます. また、ロールベースの権限付与の仕組みをサポートしており、 Auth0 といったOAuthサービスプロバイダーと組み合わせることで、Hasura外部のサービスで認証を行ったユーザの認可から, ロールに許されたAPI操作を割り振ることができます。
Hasuraのサービスを稼働させるためにはHerokuが推奨されていますが、あえてAWSで立てようとするなら docker hubに提供されているDockerイメージ とデータストアであるPostgreSQLを構築する必要から、ECSを使うのが自然な選択肢になるかと思います. ちょうどTerraformでAWSの環境構築をする練習りをしたかったこともあり Hasuraを立てるのがお題として手頃そうでした.
一方、Terraform Registryを”hasura”で検索してみると3件ほどマッチしました。 このうちメンテナンスされておりdownload数の多い Rayraegah/hasura/aws があります. ライセンスのところに Gordon Johnston により提案されたAWSアーキテクチャを採用しているとあります, おそらく以下の記事のことと見られます.

Deploying Hasura on AWS with Fargate, RDS and Terraform - DEV

今回はこちらをお借りしてTerraformを素振りさせてもらいました.

事前準備

今回の手順を行うにあたって必要な準備は以下の通りです:

  • Terraform 0.12 の実行環境
  • AWSアカウント
    • IAMユーザ
    • Route53で管理されているドメイン
  • Auth0アカウント
  • GraphiQL.app の実行環境
    • macos Homebrewであれば brew cask install graphiql しておく

この記事ではそれぞれのセットアップについては述べません.

Auth0の設定

まず, Auth0について Hasuraの公式ドキュメント を参考に事前にSingle Page Applicationを用意しておきます. Hasuraの認証認可の仕組みをこちらで整えることになります. 手順の通りなのですが, ハマりどころとして2点補足しておきます.

一つ目はRulesです. “Configure Auth0 Rules & Callback URLs”の手順にてJWTカスタムクレームを埋め込むためのスニペットが2通り記載されています. 厳密にはどちらでも構いませんが, この手順では前者のauth0.js向けのスニペットを入力してください. 2つ目は OIDC Conformantを無効にする ということです. “Test auth0 login and generate sample JWTs for testing” の手順でid_tokenを取得しますが, これを無効にしておかないとコールバック時にエラーとなります.

TerraformのApply

手元の実行環境のお好きなディレクトリ配下に, Terraformのapplyのためmoduleの呼び出しを行う main.tf および変数定義を行う terraform.tfvars を用意しました.
gistに貼ってありますが、それぞれ以下の通りです:

まず, main.tf:

variable "domain" {}
variable "hasura_admin_secret" {}
variable "rds_password" {}
variable "hasura_jwt_secret_key" {}

module "hasura" {
  source                         = "Rayraegah/hasura/aws"
  version                        = "3.0.2"
  domain                         = var.domain
  hasura_version_tag             = "v1.2.1"
  hasura_admin_secret            = var.hasura_admin_secret
  hasura_jwt_secret_key          = var.hasura_jwt_secret_key
  hasura_jwt_secret_algo         = "RS256"
  rds_db_name                    = "hasura"
  rds_instance                   = "db.t3.small"
  rds_username                   = "hasura"
  rds_password                   = var.rds_password
  create_iam_service_linked_role = false
}

provider "aws" {
  region = "ap-northeast-1"
}

module “hasura”になるべくdefault値を使ったうえで必要な変数定義をしています. 秘密情報にしたかったものはvariableに切り出してtfvarsにて記述することにしました. defaultを上書きした変数は3箇所あります. 1つ目は hasura_version_tag , これは単純に執筆時点の最新版を使いたかったためです. 2つ目は hasura_jwt_secret_algo , こちらにはHS256 または RS256が選べますが, Auth0で使用するのは後者のため設定しました. 最後にcreate_iam_service_linked_role, これはAWSのアカウント上で初めてECSを作成したときに勝手に作られる service_linked_role の有無についてです. 私の環境では以前にECSクラスターを作ったことがあるためfalseにしましたが, この操作が初めての場合defaultのtrueとしておきましょう.

次に, terraform.tfvars:

domain                = "example.com"
hasura_admin_secret   = "Password"
rds_password          = "Password"
hasura_jwt_secret_key = <<EOF
-----BEGIN CERTIFICATE-----
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxx
-----END CERTIFICATE-----
EOF

これにはvariableで定義した変数を指定しています. 1つ目の domain にはRoute53で管理しているdomainを指定してください. 続く hasura_admin_secret rds_password には, 前者はHasura管理画面の、 後者はRDSのパスワードになります. 最後の hasura_jwt_secret_key には先のAuth0の設定後に得られる公開鍵情報を入力します. https://<your-auth0-domain>.auth0.com/pem にアクセスすることで取得できます.

以上で設定が完了です. 作業したディレクトリ上で terraform init, terraform plan, terraform apply を実行しましょう.

Hasuraコンソールにログインする

上記が無事成功したことを確認するために, ブラウザから https://hasura.<あなたのdomain> にアクセスしましょう. Hasuraのパスワード入力画面が出ますので, hasura_admin_secret を入力してください.
Hasuraの管理画面が開くはずです.

Hasuraのコンソール画面から, テーブル定義およびそれのuserへのpermissionをしたとします. コンソール上でポチポチ操作するだけでOKで, これによりDBマイグレーションなどのメタデータ設定が簡単に行えます. 私の環境では usersposts テーブルを一対多の関係で定義、user ロールにそれぞれのテーブルへのSELECT権限の付与を行いました.

GraphQL APIの操作

これまでの設定がうまくいったことを確認するために, GraphQL APIを触ってみたいと思います. 手順としてはGraphiQL.app を起動します. アプリが起動したら GraphQL Endpointhttps://hasura.<あなたのdomain>/v1/graphql を入力します. 次に Edit HTTP Headers をクリックし, Add Header からHeader nameにAuthorization, Header valueに Bearer <id_token> を入力します. このid_tokenは “Test auth0 login and generate sample JWTs for testing”で取得したものになります. これでトップ画面に戻るとうまくいった場合Document Explorer > ROOT TYPES に利用可能なqueryがリストアップされます. これでHasuraから認証認可を踏まえたGraphQLのndpointが得られました.

後始末

満足できるまで確認ができたら, 課金対象ですので AWSリソース を削除しましょう. ただし, 安全のためaws_db_instanceのlife_cycleが prevent_destroy = true となっているため, 単にterraform destroy をしても成功しません. workaroundとして, main.tf 中のmodule定義をすべてコメントアウトして terraform apply を行ってから terraform destroy をすることでリソースの削除に成功します.

まとめ

以上で, terraformのmoduleを使わせてもらったAWSでのhasuraの構築の素振りを行いました. 素振りをやろうとした当初はイチからtfファイルを書く気持ちでいたのですが, 先人の肩を借りて手数少なく実施することができました. まじまじとregistryに公開されているmoduleを読むのは初めてでしたが, ためになります.