Skip to content

Commit 88ce4b3

Browse files
committed
fix: add ip whitelist to tunnels (#930)
<!-- Please make sure there is an issue that this PR is correlated to. --> Fixes RVTEE-71 ## Changes <!-- If there are frontend changes, please include screenshots. -->
1 parent 8b551f4 commit 88ce4b3

File tree

8 files changed

+113
-18
lines changed

8 files changed

+113
-18
lines changed

infra/tf/k8s_infra/traefik_tunnel.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ resource "helm_release" "traefik_tunnel" {
102102
enabled = true
103103
options = "ingress-tunnel"
104104
}
105+
106+
# Created in svc/api/traefik-provider/src/route/tunnel.rs
107+
middlewares = [
108+
"tunnel-ip-allowlist@http"
109+
]
105110
}
106111
}
107112

@@ -138,6 +143,11 @@ resource "helm_release" "traefik_tunnel" {
138143
}
139144
} : null
140145

146+
additionalArguments = [
147+
"--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"]}",
148+
"--providers.http.pollInterval=2.5s",
149+
]
150+
141151
logs = {
142152
# general = {
143153
# level = "DEBUG"

infra/tf/tls/tunnel_server.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ resource "tls_locally_signed_cert" "locally_signed_tunnel_server" {
1919
ca_key_algorithm = "RSA"
2020
ca_private_key_pem = tls_private_key.root_ca.private_key_pem
2121
ca_cert_pem = tls_self_signed_cert.root_ca.cert_pem
22-
22+
2323
validity_period_hours = 8760 # 1 year
2424

2525
allowed_uses = [

svc/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

svc/api/traefik-provider/Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,20 @@ util-cdn = { package = "rivet-util-cdn", path = "../../pkg/cdn/util" }
3737
util-job = { package = "rivet-util-job", path = "../../pkg/job/util" }
3838
uuid = { version = "1", features = ["v4"] }
3939

40+
cluster-server-list = { path = "../../pkg/cluster/ops/server-list" }
41+
4042
[dev-dependencies]
4143
rivet-connection = { path = "../../../lib/connection" }
4244
rivet-route = { path = "../../../lib/smithy-output/api-traefik-provider/rust" }
4345
base64 = "0.13"
4446
reqwest = "0.11"
4547

46-
cdn-namespace-domain-create = { path = "../../pkg/cdn/ops/namespace-domain-create" }
4748
cdn-namespace-auth-user-update = { path = "../../pkg/cdn/ops/namespace-auth-user-update" }
48-
faker-game = { path = "../../pkg/faker/ops/game" }
49+
cdn-namespace-domain-create = { path = "../../pkg/cdn/ops/namespace-domain-create" }
4950
faker-cdn-site = { path = "../../pkg/faker/ops/cdn-site" }
51+
faker-game = { path = "../../pkg/faker/ops/game" }
5052
faker-game-namespace = { path = "../../pkg/faker/ops/game-namespace" }
51-
faker-job-run = { path = "../../pkg/faker/ops/job-run" }
5253
faker-game-version = { path = "../../pkg/faker/ops/game-version" }
54+
faker-job-run = { path = "../../pkg/faker/ops/job-run" }
5355
faker-region = { path = "../../pkg/faker/ops/region" }
5456
game-get = { path = "../../pkg/game/ops/get" }

svc/api/traefik-provider/src/route/core.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ pub async fn config(
3131
) -> GlobalResult<types::TraefikConfigResponseNullified> {
3232
ctx.auth().token(&token).await?;
3333

34+
let mut config = types::TraefikConfigResponse::default();
35+
3436
// Fetch configs and catch any errors
35-
let config = build_cdn(&ctx).await?;
37+
build_cdn(&ctx, &mut config).await?;
3638

3739
// tracing::info!(
3840
// http_services = ?config.http.services.len(),
@@ -47,6 +49,13 @@ pub async fn config(
4749
// "traefik config"
4850
// );
4951

52+
tracing::info!(
53+
services = ?config.http.services.len(),
54+
routers = config.http.routers.len(),
55+
middlewares = ?config.http.middlewares.len(),
56+
"cdn traefik config"
57+
);
58+
5059
Ok(types::TraefikConfigResponseNullified {
5160
http: config.http.nullified(),
5261
tcp: config.tcp.nullified(),
@@ -56,16 +65,18 @@ pub async fn config(
5665

5766
/// Builds configuration for CDN routes.
5867
#[tracing::instrument(skip(ctx))]
59-
pub async fn build_cdn(ctx: &Ctx<Auth>) -> GlobalResult<types::TraefikConfigResponse> {
60-
let mut config = types::TraefikConfigResponse::default();
68+
pub async fn build_cdn(
69+
ctx: &Ctx<Auth>,
70+
config: &mut types::TraefikConfigResponse,
71+
) -> GlobalResult<()> {
6172
let s3_client = s3_util::Client::from_env("bucket-cdn").await?;
6273

6374
let redis_cdn = ctx.op_ctx().redis_cdn().await?;
6475
let cdn_fetch = fetch_cdn(redis_cdn).await?;
6576

6677
// Process namespaces
6778
for ns in &cdn_fetch {
68-
let register_res = register_namespace(ns, &mut config, &s3_client);
79+
let register_res = register_namespace(ns, config, &s3_client);
6980
match register_res {
7081
Ok(_) => {}
7182
Err(err) => tracing::error!(?err, ?ns, "failed to register namespace route"),
@@ -149,14 +160,7 @@ pub async fn build_cdn(ctx: &Ctx<Auth>) -> GlobalResult<types::TraefikConfigResp
149160
},
150161
);
151162

152-
tracing::info!(
153-
services = ?config.http.services.len(),
154-
routers = config.http.routers.len(),
155-
middlewares = ?config.http.middlewares.len(),
156-
"cdn traefik config"
157-
);
158-
159-
Ok(config)
163+
Ok(())
160164
}
161165

162166
#[tracing::instrument(skip(redis_cdn))]

svc/api/traefik-provider/src/route/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use hyper::{Body, Request, Response};
33

44
pub mod core;
55
pub mod game_guard;
6+
pub mod tunnel;
67

78
pub async fn handle(
89
shared_client: chirp_client::SharedClientHandle,
@@ -26,6 +27,13 @@ define_router! {
2627
opt_auth: true,
2728
),
2829
},
30+
"config" / "tunnel": {
31+
GET: tunnel::config(
32+
query: tunnel::ConfigQuery,
33+
internal_endpoint: true,
34+
opt_auth: true,
35+
),
36+
},
2937
"config" / "game-guard": {
3038
GET: game_guard::config(
3139
query: game_guard::ConfigQuery,
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use api_helper::{anchor::WatchIndexQuery, ctx::Ctx};
2+
use proto::backend;
3+
use rivet_operation::prelude::*;
4+
use serde::{Deserialize, Serialize};
5+
6+
use crate::{auth::Auth, types};
7+
8+
#[derive(Debug, Serialize, Deserialize)]
9+
#[serde(deny_unknown_fields)]
10+
pub struct ConfigQuery {
11+
token: String,
12+
}
13+
14+
#[tracing::instrument(skip(ctx))]
15+
pub async fn config(
16+
ctx: Ctx<Auth>,
17+
_watch_index: WatchIndexQuery,
18+
ConfigQuery { token }: ConfigQuery,
19+
) -> GlobalResult<types::TraefikConfigResponseNullified> {
20+
ctx.auth().token(&token).await?;
21+
22+
let mut config = types::TraefikConfigResponse::default();
23+
24+
build_ip_allowlist(&ctx, &mut config).await?;
25+
26+
tracing::info!(
27+
services = ?config.tcp.services.len(),
28+
routers = config.tcp.routers.len(),
29+
middlewares = ?config.tcp.middlewares.len(),
30+
"tunnel traefik config"
31+
);
32+
33+
Ok(types::TraefikConfigResponseNullified {
34+
http: config.http.nullified(),
35+
tcp: config.tcp.nullified(),
36+
udp: config.udp.nullified(),
37+
})
38+
}
39+
40+
/// Builds configuration for GG edge node routes.
41+
#[tracing::instrument(skip(ctx))]
42+
pub async fn build_ip_allowlist(
43+
ctx: &Ctx<Auth>,
44+
config: &mut types::TraefikConfigResponse,
45+
) -> GlobalResult<()> {
46+
let servers_res = op!([ctx] cluster_server_list {
47+
filter: Some(backend::cluster::ServerFilter {
48+
pool_types: vec![backend::cluster::PoolType::Gg as i32],
49+
..Default::default()
50+
}),
51+
include_destroyed: false,
52+
})
53+
.await?;
54+
55+
let public_ips = servers_res
56+
.servers
57+
.iter()
58+
.filter_map(|server| server.public_ip.clone())
59+
.collect::<Vec<_>>();
60+
61+
config.tcp.middlewares.insert(
62+
"tunnel-ip-allowlist".to_owned(),
63+
types::TraefikMiddlewareHttp::IpAllowList {
64+
source_range: public_ips,
65+
ip_strategy: None,
66+
},
67+
);
68+
69+
Ok(())
70+
}

svc/api/traefik-provider/src/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ pub struct TraefikTlsDomain {
160160
pub enum TraefikMiddlewareHttp {
161161
#[serde(rename = "chain", rename_all = "camelCase")]
162162
Chain { middlewares: Vec<String> },
163-
#[serde(rename = "ipWhiteList", rename_all = "camelCase")]
164-
IpWhiteList {
163+
#[serde(rename = "ipAllowList", rename_all = "camelCase")]
164+
IpAllowList {
165165
source_range: Vec<String>,
166166
#[serde(skip_serializing_if = "Option::is_none")]
167167
ip_strategy: Option<IpStrategy>,

0 commit comments

Comments
 (0)