自宅サーバーでホストしてるアプリをCloudflare Accessで保護しつつCloudflare Tunnelで公開する
外出中に録画したい時がまあまああって,わざわざVPN張るのはかなり非効率
とはいえ認証なしで公開するのはアウトだし,認証を自分で管理するのは面倒
そもそも自宅のポートを空けるのがちょっと面倒
逸般の誤家庭だとちゃんとサーバーを運用していてハードルが低いのかもしれないけど,一般の家庭なのでそこまでのやる気はない
の2つだけで実現できる
authentikとか使ってもいいけど全部Terraformで管理してる都合上Cloudflareにまとめたかった
このページに書くこと
Cloudflare Tunnelを使って自宅のポートを空けずに外部からアクセスできるようにする
Cloudflare AccessのIdPの設定
Cloudflare Accessのグループで許可されたユーザーのみCloudflare Tunnelにアクセスできるようにする
ダッシュボードからでも出来るはずだけど,Terraformで設定したのでやり方は分からない
前提
1. Cloudflare Tunnelの設定
こんな感じのコードを書いた
code:tunnel.tf
resource "cloudflare_tunnel" "epgstation" {
account_id = cloudflare_account.main.id
name = "epgstation"
secret = var.tunnel_epgstation_secret
config_src = "cloudflare"
}
resource "cloudflare_tunnel_config" "epgstation" {
account_id = cloudflare_account.main.id
tunnel_id = cloudflare_tunnel.epgstation.id
config {
ingress_rule {
hostname = "epgstation.example.com"
origin_request {}
}
ingress_rule {
service = "http_status:404"
origin_request {}
}
}
}
epgstation.example.comへのリクエストをリバースプロキシに向け,それ以外で404を返す設定
EPGStationに直接向けると/api/configが取得出来なかったのでNginxのリバースプロキシを挟んでいる
設定はローカルで管理するかCloudflareで管理するかを選べる
頻繁に変更するならローカルが便利っぽい
設定は変えないしYAML書くのもアレなのでTerraformで書いてCloudflareで管理するようにした
この辺を参照
2. ドメインのCNAMEの設定
cloudflare_tunnelにcnameが生えているのでそのまま設定
code:record.tf
resource "cloudflare_record" "cname_epgstation" {
zone_id = cloudflare_zone.main.id
name = "epgstation"
type = "CNAME"
value = cloudflare_tunnel.epgstation.cname
proxied = true
}
3. Cloudflaredの設定&Cloudflared経由で公開
4. IdPの設定
今回はGoogleを使った
GitHubとかOktaとか色々あるので好きなのを選べば良いと思う
1. 公式のドキュメントの通りにOAuth Clientを作成
2. Terraformでリソースを作成
One-time PINは元からあった?ので使うか分からないけどimportしておいた
けど一回も使っていない
client_idとかclient_secretのセンシティブな値を変数で持つのはナンセンスな気がするけど,どうせTerraform Cloudで設定してあるので妥協
Secrets Storeが公開されたら移行したい
code:access_identity_provider.tf
resource "cloudflare_access_identity_provider" "onetimepin" {
account_id = cloudflare_account.main.id
name = "One-time PIN"
type = "onetimepin"
}
resource "cloudflare_access_identity_provider" "google" {
account_id = cloudflare_account.main.id
name = "Google"
type = "google"
config {
client_id = var.idp_google_client_id
client_secret = var.idp_google_client_secret
}
}
この辺を参照
ApplyするとダッシュボードのSettings -> AuthenticationのLogin methodsにGoogleが生えている
https://gyazo.com/d0a53f1d05a1421066d2ff3231926bfa
Testからログインすると名前とメールアドレスを取得できるはず
https://gyazo.com/cd5e2bc8889f142f39a54047f1121cb5
5. Access Groupの設定
アクセスを許可する条件を設定
メールアドレスが管理者のアドレスと一致するかだけを見るようにした
code:access_group.tf
resource "cloudflare_access_group" "dtv_admin" {
account_id = cloudflare_account.main.id
name = "DTV Admin"
include {
email = [
var.admin_gmail_address
]
}
}
この辺を参照
6. Access Policyの設定
Applicationのアクセスポリシーを作成する
application_idを指定しなければ使い回し可能なポリシーになる
code:access_policy.tf
resource "cloudflare_access_policy" "dtv_admin" {
account_id = cloudflare_account.main.id
name = "DTV Admin"
decision = "allow"
include {
group = [
cloudflare_access_group.dtv_admin.id
]
}
}
7. Applicationの設定
動かすアプリケーションを作成する
ドメインはCNAMEを設定したレコードのhostnameを使う
code:access.tf
resource "cloudflare_access_application" "epgstation" {
account_id = cloudflare_account.main.id
name = "EPGStation"
domain = cloudflare_record.cname_epgstation.hostname
type = "self_hosted"
app_launcher_visible = true
allowed_idps = [
cloudflare_access_identity_provider.google.id,
]
policies = [
cloudflare_access_policy.dtv_admin.id
]
}
ログインセッションはデフォルトで24時間なので伸ばしたい場合はsession_durationで設定する
この辺を参照
7. apply
上手く動いていればログイン画面が出てくる
https://gyazo.com/507e2daf17e9b1e50993385dab676860