Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

basic sandwich #789

Merged
merged 3 commits into from
Mar 14, 2024
Merged

basic sandwich #789

merged 3 commits into from
Mar 14, 2024

Conversation

stevenctl
Copy link
Contributor

@stevenctl stevenctl commented Jan 24, 2024

When the Waypoint is captured, zTunnel sees the connection address as the Waypoint's address and the HBONE address as the actual destination.

This impl currently uses that to detect whether the current connection is part of a sandwich, and verifies that the HBONE target actually references the connection address as a Waypoint. Instead of sending traffic to the HBONE target, we send it to the connection address.

Depends on #832 so the relevant commits are: https://github.com/istio/ztunnel/pull/789/files/b5af5ac0fb7e71805ee6f5b9fe56e8010511dead..a17e43e3488a4567c4c84eaae0638bf09d045c4d

@stevenctl stevenctl requested a review from a team as a code owner January 24, 2024 20:41
@istio-policy-bot
Copy link

😊 Welcome @stevenctl! This is either your first contribution to the Istio ztunnel repo, or it's been
a while since you've been here.

You can learn more about the Istio working groups, Code of Conduct, and contribution guidelines
by referring to Contributing to Istio.

Thanks for contributing!

Courtesy of your friendly welcome wagon.

@istio-testing istio-testing added do-not-merge/work-in-progress Block merging of a PR because it isn't ready yet. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jan 24, 2024
src/proxy/inbound.rs Outdated Show resolved Hide resolved
@stevenctl stevenctl mentioned this pull request Jan 29, 2024
9 tasks
Copy link
Contributor

@ilrudie ilrudie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

direction seems good

match Builder::with_addresses(
Version::Two | Command::Proxy,
Protocol::Stream, proxy_protocol).
write_tlv(0xD0, id.as_bytes()).unwrap().
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is write_tlv infallible in this context?

Comment on lines 224 to 259
if let Err(e) = super::copy_hbone(
&mut upgraded,
&mut stream,
&metrics,
transferred_bytes,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So even if we fail to write proxy proto headers for some reason we're going to try to press forward and I suppose it's up to the gateway to decide if that's ok or not. Would it be better to fail fast in zt or do we think most of the time this would be recoverable at the gateway somehow?

Comment on lines 305 to 314
if addr.is_err() {
info!("Sending 400, {:?}", addr.err());
return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Empty::new())
.unwrap());
}

let addr: SocketAddr = addr.unwrap();
if addr.ip() != conn.dst.ip() {
info!("Sending 400, ip mismatch {addr} != {}", conn.dst);
return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Empty::new())
.unwrap());
}
// Orig has 15008, swap with the real port
let conn = Connection { dst: addr, ..conn };
let dst_network_addr = NetworkAddress {
network: conn.dst_network.to_string(), // dst must be on our network
address: addr.ip(),
};
let Some((upstream, upstream_service)) =
state.fetch_workload_services(&dst_network_addr).await
else {
info!(%conn, "unknown destination");
return Ok(Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Empty::new())
.unwrap());
};
let has_waypoint = upstream.waypoint.is_some();
let from_waypoint = Self::check_waypoint(state.clone(), &upstream, &conn).await;
let from_gateway = Self::check_gateway(state.clone(), &upstream, &conn).await;
let addr: SocketAddr = addr.unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitty: this looks a bit odd. I think you can let addr = match addr{...} and it works Ok so long as arms that won't result in the desired type return.

src/proxy/inbound.rs Outdated Show resolved Hide resolved
@istio-testing istio-testing added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jan 31, 2024
src/state/service.rs Outdated Show resolved Hide resolved
@hzxuzhonghu
Copy link
Member

@stevenctl Is there a proposal, i missed the context

@istio-testing istio-testing added the needs-rebase Indicates a PR needs to be rebased before being merged label Feb 5, 2024
@istio-testing istio-testing removed the needs-rebase Indicates a PR needs to be rebased before being merged label Feb 5, 2024
@stevenctl stevenctl force-pushed the sandwich branch 2 times, most recently from 7c64261 to 28b50e7 Compare February 5, 2024 22:56
@stevenctl
Copy link
Contributor Author

@hzxuzhonghu

See this doc (primarily the propagating L4 info section) and istio/istio#48362

The goal is to provide alternative Waypoint implementations with an option other than supporting CONNECT.

@istio-testing istio-testing added the needs-rebase Indicates a PR needs to be rebased before being merged label Feb 25, 2024
@stevenctl stevenctl requested a review from a team as a code owner March 11, 2024 22:15
@istio-policy-bot istio-policy-bot added the lifecycle/stale Indicates a PR or issue hasn't been manipulated by an Istio team member for a while label Mar 11, 2024
@istio-testing istio-testing added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Mar 11, 2024
@stevenctl stevenctl changed the title wip: sandwich: send proxy protocol basic sandwich implementation Mar 11, 2024
@istio-testing istio-testing removed the do-not-merge/work-in-progress Block merging of a PR because it isn't ready yet. label Mar 11, 2024
tests/namespaced.rs Outdated Show resolved Hide resolved
@istio-policy-bot istio-policy-bot removed the lifecycle/stale Indicates a PR or issue hasn't been manipulated by an Istio team member for a while label Mar 11, 2024
) {
(_, Ok(None)) => {} // workload doesn't have a waypoint; this is fine
(true, _) => {} // we already traversed the waypoint
(false, Ok(Some(waypoint_us))) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this branch (and the one for to Service) we're using the port WDS GatewayAddress sends us.

let waypoint_socket_address = SocketAddr::new(waypoint_ip, waypoint_us.port);

Right now, the CP happens to send us 15008 which happens to be what the ztunnel listens on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the CP going to be smart and send the zTunnel address, or do we need to be smart and use pi.hbone_port?

Copy link
Contributor

@bleggett bleggett Mar 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now as per the protocol 15008 is "the" HBONE port and we assume that in other spots, I suspect.

For this I would suggest maybe splitting the difference and taking what CP sends us, but explicitly checking here that waypoint_us.port == pi.hbone_port and throwing an error if not. If we wish to intentionally change that behavior in all of ambient later, we can actually remove the check.

@stevenctl
Copy link
Contributor Author

cc @bleggett

@istio-testing istio-testing added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed needs-rebase Indicates a PR needs to be rebased before being merged size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Mar 12, 2024
Makefile.core.mk Outdated
@@ -11,6 +11,9 @@ endif
test:
RUST_BACKTRACE=1 cargo test --benches --tests --bins $(FEATURES)

test.root:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: +1 on adding RUST_BACKTRACE here too, but without #821 this will just cause make test.root to hang for people (unless they explicitly set BUILD_WITH_CONTAINER=0 - which is not the default)

src/proxy.rs Outdated Show resolved Hide resolved
@stevenctl stevenctl changed the title basic sandwich implementation basic sandwich Mar 13, 2024
Copy link
Contributor

@ilrudie ilrudie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. couple comments/questions

Comment on lines +311 to +317
let from_waypoint = proxy::check_from_waypoint(
pi.state.clone(),
&upstream,
conn.src_identity.as_ref(),
&conn.src_ip,
)
.await;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't change anything just yet but not sure we need the check anymore per discussions around svc-addressed vs wl-addressed traffic. A user may have a waypoint for their service but still allow workload addressed without a waypoint and this would be considered valid so either inbound must take this type of configuration into account or elide checks that outbound ztunnel routing was correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I just don't want to take an opinion on that in this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#851

created this so I/we don't forget to circle back around on it until a user files a report that things don't work like we said they do

src/proxy/inbound.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@ilrudie ilrudie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

Copy link
Member

@howardjohn howardjohn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, all comments are theoretical future improvements so good to go ahead

return Some(None);
};

// Validate that the HBONE target references the Waypoint we're connecting to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not 100% sure we will want to be this strict forever... but I cannot think of any concrete reasons why not to, and its easier to loosen later. So LGTm

src_ip: &IpAddr,
) -> bool {
let is_waypoint = |wl: &Workload| {
Some(wl.identity()).as_ref() == src_identity && wl.workload_ips.contains(src_ip)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long term it would be nice to have a method more reliable than source IP. That being said, since its node-local it would be quite strange for this check to not work somehow.

@istio-testing istio-testing merged commit 9b7bf7a into istio:master Mar 14, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants