Skip to content

Commit 47e40b9

Browse files
authored
Merge pull request #1959 from fermyon/address-checks-mysql-postgres
Add address checks for mysql and postgres
2 parents ed4e13f + 2692d57 commit 47e40b9

File tree

17 files changed

+268
-124
lines changed

17 files changed

+268
-124
lines changed

Cargo.lock

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/manifest/src/schema/v2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ pub struct Component {
102102
/// `allowed_http_hosts = ["example.com"]`
103103
#[serde(default, skip_serializing_if = "Vec::is_empty")]
104104
pub allowed_http_hosts: Vec<String>,
105-
/// `allowed_outbound_hosts = ["myredishost.com"]`
105+
/// `allowed_outbound_hosts = ["myredishost.com:6379"]`
106106
#[serde(default, skip_serializing_if = "is_none_or_empty")]
107107
pub allowed_outbound_hosts: Option<Vec<String>>,
108108
/// `key_value_stores = ["default"]`

crates/outbound-mysql/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ mysql_async = { version = "0.32.2", default-features = false, features = [
1616
] }
1717
# Removing default features for mysql_common to remove flate2/zlib feature
1818
mysql_common = { version = "0.30.6", default-features = false }
19+
spin-app = { path = "../app" }
1920
spin-core = { path = "../core" }
21+
spin-outbound-networking = { path = "../outbound-networking" }
2022
spin-world = { path = "../world" }
2123
table = { path = "../table" }
2224
tokio = { version = "1", features = ["rt-multi-thread"] }

crates/outbound-mysql/src/lib.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use anyhow::Result;
1+
use anyhow::{Context, Result};
22
use mysql_async::{consts::ColumnType, from_value_opt, prelude::*, Opts, OptsBuilder, SslOpts};
3+
use spin_app::DynamicHostComponent;
34
use spin_core::wasmtime::component::Resource;
45
use spin_core::{async_trait, HostComponent};
56
use spin_world::v1::mysql as v1;
@@ -12,6 +13,7 @@ use url::Url;
1213
/// A simple implementation to support outbound mysql connection
1314
#[derive(Default)]
1415
pub struct OutboundMysql {
16+
allowed_hosts: Option<spin_outbound_networking::AllowedHosts>,
1517
pub connections: table::Table<mysql_async::Conn>,
1618
}
1719

@@ -24,6 +26,10 @@ impl OutboundMysql {
2426
.get_mut(connection.rep())
2527
.ok_or_else(|| v2::Error::ConnectionFailed("no connection found".into()))
2628
}
29+
30+
fn is_address_allowed(&self, address: &str, default: bool) -> bool {
31+
spin_outbound_networking::check_address(address, "mysql", &self.allowed_hosts, default)
32+
}
2733
}
2834

2935
impl HostComponent for OutboundMysql {
@@ -42,11 +48,33 @@ impl HostComponent for OutboundMysql {
4248
}
4349
}
4450

51+
impl DynamicHostComponent for OutboundMysql {
52+
fn update_data(
53+
&self,
54+
data: &mut Self::Data,
55+
component: &spin_app::AppComponent,
56+
) -> anyhow::Result<()> {
57+
let hosts = component
58+
.get_metadata(spin_outbound_networking::ALLOWED_HOSTS_KEY)?
59+
.unwrap_or_default();
60+
data.allowed_hosts = hosts
61+
.map(|h| spin_outbound_networking::AllowedHosts::parse(&h[..]))
62+
.transpose()
63+
.context("`allowed_outbound_hosts` contained an invalid url")?;
64+
Ok(())
65+
}
66+
}
67+
4568
impl v2::Host for OutboundMysql {}
4669

4770
#[async_trait]
4871
impl v2::HostConnection for OutboundMysql {
4972
async fn open(&mut self, address: String) -> Result<Result<Resource<Connection>, v2::Error>> {
73+
if !self.is_address_allowed(&address, false) {
74+
return Ok(Err(v2::Error::ConnectionFailed(format!(
75+
"address {address} is not permitted"
76+
))));
77+
}
5078
Ok(async {
5179
self.connections
5280
.push(
@@ -125,6 +153,11 @@ impl v2::HostConnection for OutboundMysql {
125153
/// Delegate a function call to the v2::HostConnection implementation
126154
macro_rules! delegate {
127155
($self:ident.$name:ident($address:expr, $($arg:expr),*)) => {{
156+
if !$self.is_address_allowed(&$address, true) {
157+
return Ok(Err(v1::MysqlError::ConnectionFailed(format!(
158+
"address {} is not permitted", $address
159+
))));
160+
}
128161
let connection = match <Self as v2::HostConnection>::open($self, $address).await? {
129162
Ok(c) => c,
130163
Err(e) => return Ok(Err(e.into())),

crates/outbound-networking/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ edition.workspace = true
66

77
[dependencies]
88
anyhow = "1.0"
9+
spin-locked-app = { path = "../locked-app" }
10+
terminal = { path = "../terminal" }
911
url = "2.4.1"

0 commit comments

Comments
 (0)