diff --git a/infra/tf/k8s_infra/traefik_tunnel.tf b/infra/tf/k8s_infra/traefik_tunnel.tf index f179d458e..1999cfa68 100644 --- a/infra/tf/k8s_infra/traefik_tunnel.tf +++ b/infra/tf/k8s_infra/traefik_tunnel.tf @@ -102,6 +102,11 @@ resource "helm_release" "traefik_tunnel" { enabled = true options = "ingress-tunnel" } + + # Created in svc/api/traefik-provider/src/route/tunnel.rs + middlewares = [ + "tunnel-ip-allowlist@http" + ] } } @@ -138,6 +143,11 @@ resource "helm_release" "traefik_tunnel" { } } : null + additionalArguments = [ + "--providers.http.endpoint=http://rivet-api-internal-monolith.rivet-service.svc.cluster.local/traefik-provider/config/tunnel?token=${module.traefik_secrets.values["rivet/api_traefik_provider/token"]}", + "--providers.http.pollInterval=2.5s", + ] + logs = { # general = { # level = "DEBUG" diff --git a/infra/tf/tls/tunnel_server.tf b/infra/tf/tls/tunnel_server.tf index b54927dfe..70a55e517 100644 --- a/infra/tf/tls/tunnel_server.tf +++ b/infra/tf/tls/tunnel_server.tf @@ -19,7 +19,7 @@ resource "tls_locally_signed_cert" "locally_signed_tunnel_server" { ca_key_algorithm = "RSA" ca_private_key_pem = tls_private_key.root_ca.private_key_pem ca_cert_pem = tls_self_signed_cert.root_ca.cert_pem - + validity_period_hours = 8760 # 1 year allowed_uses = [ diff --git a/svc/Cargo.lock b/svc/Cargo.lock index 90a7ee52f..8b93bfe1f 100644 --- a/svc/Cargo.lock +++ b/svc/Cargo.lock @@ -859,6 +859,7 @@ dependencies = [ "cdn-namespace-domain-create", "chirp-client", "chrono", + "cluster-server-list", "faker-cdn-site", "faker-game", "faker-game-namespace", diff --git a/svc/api/traefik-provider/Cargo.toml b/svc/api/traefik-provider/Cargo.toml index ecac1578f..69708ac00 100644 --- a/svc/api/traefik-provider/Cargo.toml +++ b/svc/api/traefik-provider/Cargo.toml @@ -37,18 +37,20 @@ util-cdn = { package = "rivet-util-cdn", path = "../../pkg/cdn/util" } util-job = { package = "rivet-util-job", path = "../../pkg/job/util" } uuid = { version = "1", features = ["v4"] } +cluster-server-list = { path = "../../pkg/cluster/ops/server-list" } + [dev-dependencies] rivet-connection = { path = "../../../lib/connection" } rivet-route = { path = "../../../lib/smithy-output/api-traefik-provider/rust" } base64 = "0.13" reqwest = "0.11" -cdn-namespace-domain-create = { path = "../../pkg/cdn/ops/namespace-domain-create" } cdn-namespace-auth-user-update = { path = "../../pkg/cdn/ops/namespace-auth-user-update" } -faker-game = { path = "../../pkg/faker/ops/game" } +cdn-namespace-domain-create = { path = "../../pkg/cdn/ops/namespace-domain-create" } faker-cdn-site = { path = "../../pkg/faker/ops/cdn-site" } +faker-game = { path = "../../pkg/faker/ops/game" } faker-game-namespace = { path = "../../pkg/faker/ops/game-namespace" } -faker-job-run = { path = "../../pkg/faker/ops/job-run" } faker-game-version = { path = "../../pkg/faker/ops/game-version" } +faker-job-run = { path = "../../pkg/faker/ops/job-run" } faker-region = { path = "../../pkg/faker/ops/region" } game-get = { path = "../../pkg/game/ops/get" } diff --git a/svc/api/traefik-provider/src/route/core.rs b/svc/api/traefik-provider/src/route/core.rs index eddedfccc..0f65eb2de 100644 --- a/svc/api/traefik-provider/src/route/core.rs +++ b/svc/api/traefik-provider/src/route/core.rs @@ -31,8 +31,10 @@ pub async fn config( ) -> GlobalResult { ctx.auth().token(&token).await?; + let mut config = types::TraefikConfigResponse::default(); + // Fetch configs and catch any errors - let config = build_cdn(&ctx).await?; + build_cdn(&ctx, &mut config).await?; // tracing::info!( // http_services = ?config.http.services.len(), @@ -47,6 +49,13 @@ pub async fn config( // "traefik config" // ); + tracing::info!( + services = ?config.http.services.len(), + routers = config.http.routers.len(), + middlewares = ?config.http.middlewares.len(), + "cdn traefik config" + ); + Ok(types::TraefikConfigResponseNullified { http: config.http.nullified(), tcp: config.tcp.nullified(), @@ -56,8 +65,10 @@ pub async fn config( /// Builds configuration for CDN routes. #[tracing::instrument(skip(ctx))] -pub async fn build_cdn(ctx: &Ctx) -> GlobalResult { - let mut config = types::TraefikConfigResponse::default(); +pub async fn build_cdn( + ctx: &Ctx, + config: &mut types::TraefikConfigResponse, +) -> GlobalResult<()> { let s3_client = s3_util::Client::from_env("bucket-cdn").await?; let redis_cdn = ctx.op_ctx().redis_cdn().await?; @@ -65,7 +76,7 @@ pub async fn build_cdn(ctx: &Ctx) -> GlobalResult {} Err(err) => tracing::error!(?err, ?ns, "failed to register namespace route"), @@ -149,14 +160,7 @@ pub async fn build_cdn(ctx: &Ctx) -> GlobalResult, + _watch_index: WatchIndexQuery, + ConfigQuery { token }: ConfigQuery, +) -> GlobalResult { + ctx.auth().token(&token).await?; + + let mut config = types::TraefikConfigResponse::default(); + + build_ip_allowlist(&ctx, &mut config).await?; + + tracing::info!( + services = ?config.tcp.services.len(), + routers = config.tcp.routers.len(), + middlewares = ?config.tcp.middlewares.len(), + "tunnel traefik config" + ); + + Ok(types::TraefikConfigResponseNullified { + http: config.http.nullified(), + tcp: config.tcp.nullified(), + udp: config.udp.nullified(), + }) +} + +/// Builds configuration for GG edge node routes. +#[tracing::instrument(skip(ctx))] +pub async fn build_ip_allowlist( + ctx: &Ctx, + config: &mut types::TraefikConfigResponse, +) -> GlobalResult<()> { + let servers_res = op!([ctx] cluster_server_list { + filter: Some(backend::cluster::ServerFilter { + pool_types: vec![backend::cluster::PoolType::Gg as i32], + ..Default::default() + }), + include_destroyed: false, + }) + .await?; + + let public_ips = servers_res + .servers + .iter() + .filter_map(|server| server.public_ip.clone()) + .collect::>(); + + config.tcp.middlewares.insert( + "tunnel-ip-allowlist".to_owned(), + types::TraefikMiddlewareHttp::IpAllowList { + source_range: public_ips, + ip_strategy: None, + }, + ); + + Ok(()) +} diff --git a/svc/api/traefik-provider/src/types.rs b/svc/api/traefik-provider/src/types.rs index 8a5350c44..b8c744b39 100644 --- a/svc/api/traefik-provider/src/types.rs +++ b/svc/api/traefik-provider/src/types.rs @@ -160,8 +160,8 @@ pub struct TraefikTlsDomain { pub enum TraefikMiddlewareHttp { #[serde(rename = "chain", rename_all = "camelCase")] Chain { middlewares: Vec }, - #[serde(rename = "ipWhiteList", rename_all = "camelCase")] - IpWhiteList { + #[serde(rename = "ipAllowList", rename_all = "camelCase")] + IpAllowList { source_range: Vec, #[serde(skip_serializing_if = "Option::is_none")] ip_strategy: Option,