Skip to content

Commit 4024ce1

Browse files
authored
gateway: Ensure proper outbound metadata (#715)
The gateway has two deficiencies: * Using the outbound proxy port for the outbound original dst leads to the incorrect port being used in the `l5d-dst-canonical` header. Now, we instead use the proper port with an unroutable IP address. * Because the source cluster's outbound proxy strips `Host` headers, there's no `Host` present on gatewayed HTTP/1 requests. Now, the `Host` header is updated on all gatewayed HTTP/1 requests.
1 parent 2335076 commit 4024ce1

File tree

5 files changed

+31
-19
lines changed

5 files changed

+31
-19
lines changed

linkerd/app/gateway/src/config.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use linkerd2_app_core::{
44
};
55
use linkerd2_app_inbound::endpoint as inbound;
66
use linkerd2_app_outbound::endpoint as outbound;
7-
use std::net::SocketAddr;
7+
use tracing::info_span;
88

99
#[derive(Clone, Debug, Default)]
1010
pub struct Config {
@@ -19,7 +19,6 @@ impl Config {
1919
self,
2020
outbound: O,
2121
profiles: P,
22-
default_addr: SocketAddr,
2322
local_id: tls::PeerIdentity,
2423
) -> impl svc::NewService<
2524
inbound::Target,
@@ -45,13 +44,14 @@ impl Config {
4544
S::Error: Into<Error>,
4645
S::Future: Send + 'static,
4746
{
48-
svc::stack(MakeGateway::new(outbound, default_addr, local_id))
47+
svc::stack(MakeGateway::new(outbound, local_id))
4948
.check_new_service::<super::make::Target, http::Request<http::boxed::Payload>>()
5049
.push(profiles::discover::layer(
5150
profiles,
5251
Allow(self.allow_discovery),
5352
))
5453
.check_new_service::<inbound::Target, http::Request<http::boxed::Payload>>()
54+
.instrument(|_: &inbound::Target| info_span!("gateway"))
5555
.into_inner()
5656
}
5757
}

linkerd/app/gateway/src/gateway.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ pub(crate) enum Gateway<O> {
1212
BadDomain(dns::Name),
1313
Outbound {
1414
outbound: O,
15-
forwarded_header: http::header::HeaderValue,
1615
local_identity: identity::Name,
16+
host_header: http::header::HeaderValue,
17+
forwarded_header: http::header::HeaderValue,
1718
},
1819
}
1920

@@ -24,13 +25,16 @@ impl<O> Gateway<O> {
2425
source_identity: identity::Name,
2526
local_identity: identity::Name,
2627
) -> Self {
28+
let host = dst.as_http_authority().to_string();
2729
let fwd = format!(
2830
"by={};for={};host={};proto=https",
29-
local_identity, source_identity, dst
31+
local_identity, source_identity, host
3032
);
3133
Gateway::Outbound {
3234
outbound,
3335
local_identity,
36+
host_header: http::header::HeaderValue::from_str(&host)
37+
.expect("Host header value must be valid"),
3438
forwarded_header: http::header::HeaderValue::from_str(&fwd)
3539
.expect("Forwarded header value must be valid"),
3640
}
@@ -63,6 +67,7 @@ where
6367
Self::Outbound {
6468
ref mut outbound,
6569
ref local_identity,
70+
ref host_header,
6671
ref forwarded_header,
6772
} => {
6873
// Check forwarded headers to see if this request has already
@@ -86,6 +91,16 @@ where
8691
.headers_mut()
8792
.append(http::header::FORWARDED, forwarded_header.clone());
8893

94+
// If we're forwarding HTTP/1 requests, the old `Host` header
95+
// was stripped on the peer's outbound proxy. But the request
96+
// should have an updated `Host` header now that it's being
97+
// routed in the cluster.
98+
if let ::http::Version::HTTP_11 | ::http::Version::HTTP_10 = request.version() {
99+
request
100+
.headers_mut()
101+
.insert(http::header::HOST, host_header.clone());
102+
}
103+
89104
tracing::debug!(
90105
headers = ?request.headers(),
91106
"Passing request to outbound"

linkerd/app/gateway/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ mod test {
144144
Config { allow_discovery }.build(
145145
move |_: _| outbound.clone(),
146146
profiles,
147-
([127, 0, 0, 1], 4140).into(),
148147
tls::PeerIdentity::Some(identity::Name::from(
149148
dns::Name::try_from("gateway.id.test".as_bytes()).unwrap(),
150149
)),

linkerd/app/gateway/src/make.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,17 @@ use super::gateway::Gateway;
22
use linkerd2_app_core::{profiles, svc, transport::tls, NameAddr};
33
use linkerd2_app_inbound::endpoint as inbound;
44
use linkerd2_app_outbound::endpoint as outbound;
5-
use std::net::SocketAddr;
5+
use tracing::debug;
66

77
#[derive(Clone, Debug)]
88
pub(crate) struct MakeGateway<O> {
99
outbound: O,
10-
default_addr: SocketAddr,
1110
local_id: tls::PeerIdentity,
1211
}
1312

1413
impl<O> MakeGateway<O> {
15-
pub fn new(outbound: O, default_addr: SocketAddr, local_id: tls::PeerIdentity) -> Self {
16-
Self {
17-
outbound,
18-
default_addr,
19-
local_id,
20-
}
14+
pub fn new(outbound: O, local_id: tls::PeerIdentity) -> Self {
15+
Self { outbound, local_id }
2116
}
2217
}
2318

@@ -50,12 +45,16 @@ where
5045
},
5146
};
5247

53-
// Create an outbound target using the resolved IP & name.
54-
let svc = self.outbound.new_service(outbound::HttpLogical {
48+
// Create an outbound target using the resolved name and an address
49+
// including the original port. We don't know the IP of the target, so
50+
// we use an unroutable one.
51+
let target = outbound::HttpLogical {
5552
profile,
56-
orig_dst: self.default_addr,
5753
protocol: http_version,
58-
});
54+
orig_dst: ([0, 0, 0, 0], dst.port()).into(),
55+
};
56+
debug!(?target, "Creating outbound service");
57+
let svc = self.outbound.new_service(target);
5958

6059
Gateway::new(svc, dst, source_id, local_id)
6160
}

linkerd/app/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ impl Config {
170170
let http_gateway = gateway.build(
171171
outbound_http,
172172
dst.profiles.clone(),
173-
outbound_addr,
174173
local_identity.as_ref().map(|l| l.name().clone()),
175174
);
176175

0 commit comments

Comments
 (0)