mirror of https://github.com/linkerd/linkerd2.git
policy: Cleanup policy response labels (#6722)
Policy controller API responses include a set of labels. These labels are to be used in proxy m$etrics to indicate why traffic is permitted to a pod. This permits metrics to be associated with `Server` and ServerAuthorization` resources (i.e. for `stat`). This change updates the response API to include a `name` label referencing the server's name. When the policy is derived from a default configuration (and not a `Server` instance), the name takes the form 'default:<policy>'. This change also updates authorization labels. Defaults are encoded as servers are, otherwise the authorization's name is set as a label. The `tls` and `authn` labels have been removed, as they're redundant with other labels that are already present.
This commit is contained in:
parent
154ad9a228
commit
49f4af6e6b
|
@ -23,6 +23,7 @@ pub type InboundServerStream = Pin<Box<dyn Stream<Item = InboundServer> + Send +
|
||||||
/// Inbound server configuration.
|
/// Inbound server configuration.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct InboundServer {
|
pub struct InboundServer {
|
||||||
|
pub name: String,
|
||||||
pub protocol: ProxyProtocol,
|
pub protocol: ProxyProtocol,
|
||||||
pub authorizations: HashMap<String, ClientAuthorization>,
|
pub authorizations: HashMap<String, ClientAuthorization>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use linkerd_policy_controller_core::{
|
||||||
ClientAuthentication, ClientAuthorization, DiscoverInboundServer, IdentityMatch, InboundServer,
|
ClientAuthentication, ClientAuthorization, DiscoverInboundServer, IdentityMatch, InboundServer,
|
||||||
InboundServerStream, IpNet, NetworkMatch, ProxyProtocol,
|
InboundServerStream, IpNet, NetworkMatch, ProxyProtocol,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::sync::Arc;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -20,12 +20,6 @@ pub struct Server<T> {
|
||||||
cluster_networks: Arc<[IpNet]>,
|
cluster_networks: Arc<[IpNet]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Labels {
|
|
||||||
authn: bool,
|
|
||||||
tls: bool,
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
// === impl Server ===
|
// === impl Server ===
|
||||||
|
|
||||||
impl<T> Server<T>
|
impl<T> Server<T>
|
||||||
|
@ -200,9 +194,15 @@ fn to_server(srv: &InboundServer, cluster_networks: &[IpNet]) -> proto::Server {
|
||||||
.collect();
|
.collect();
|
||||||
trace!(?authorizations);
|
trace!(?authorizations);
|
||||||
|
|
||||||
|
let labels = vec![("name".to_string(), srv.name.to_string())]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
trace!(?labels);
|
||||||
|
|
||||||
proto::Server {
|
proto::Server {
|
||||||
protocol: Some(protocol),
|
protocol: Some(protocol),
|
||||||
authorizations,
|
authorizations,
|
||||||
|
labels,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,104 +233,62 @@ fn to_authz(
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
match authentication {
|
let labels = vec![("name".to_string(), name.to_string())]
|
||||||
ClientAuthentication::Unauthenticated => {
|
.into_iter()
|
||||||
let labels = Labels {
|
.collect();
|
||||||
authn: false,
|
|
||||||
tls: false,
|
|
||||||
name: name.to_string(),
|
|
||||||
};
|
|
||||||
proto::Authz {
|
|
||||||
networks,
|
|
||||||
labels: labels.into(),
|
|
||||||
authentication: Some(proto::Authn {
|
|
||||||
permit: Some(proto::authn::Permit::Unauthenticated(
|
|
||||||
proto::authn::PermitUnauthenticated {},
|
|
||||||
)),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientAuthentication::TlsUnauthenticated => {
|
let authn = match authentication {
|
||||||
let labels = Labels {
|
ClientAuthentication::Unauthenticated => proto::Authn {
|
||||||
authn: false,
|
permit: Some(proto::authn::Permit::Unauthenticated(
|
||||||
tls: true,
|
proto::authn::PermitUnauthenticated {},
|
||||||
name: name.to_string(),
|
)),
|
||||||
};
|
},
|
||||||
proto::Authz {
|
|
||||||
networks,
|
ClientAuthentication::TlsUnauthenticated => proto::Authn {
|
||||||
labels: labels.into(),
|
permit: Some(proto::authn::Permit::MeshTls(proto::authn::PermitMeshTls {
|
||||||
authentication: Some(proto::Authn {
|
clients: Some(proto::authn::permit_mesh_tls::Clients::Unauthenticated(
|
||||||
permit: Some(proto::authn::Permit::MeshTls(proto::authn::PermitMeshTls {
|
proto::authn::PermitUnauthenticated {},
|
||||||
clients: Some(proto::authn::permit_mesh_tls::Clients::Unauthenticated(
|
)),
|
||||||
proto::authn::PermitUnauthenticated {},
|
})),
|
||||||
)),
|
},
|
||||||
})),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authenticated connections must have TLS and apply to all
|
// Authenticated connections must have TLS and apply to all
|
||||||
// networks.
|
// networks.
|
||||||
ClientAuthentication::TlsAuthenticated(identities) => {
|
ClientAuthentication::TlsAuthenticated(identities) => {
|
||||||
let labels = Labels {
|
let suffixes = identities
|
||||||
authn: true,
|
.iter()
|
||||||
tls: true,
|
.filter_map(|i| match i {
|
||||||
name: name.to_string(),
|
IdentityMatch::Suffix(s) => Some(proto::IdentitySuffix { parts: s.to_vec() }),
|
||||||
};
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let authn = {
|
let identities = identities
|
||||||
let suffixes = identities
|
.iter()
|
||||||
.iter()
|
.filter_map(|i| match i {
|
||||||
.filter_map(|i| match i {
|
IdentityMatch::Name(n) => Some(proto::Identity {
|
||||||
IdentityMatch::Suffix(s) => {
|
name: n.to_string(),
|
||||||
Some(proto::IdentitySuffix { parts: s.to_vec() })
|
}),
|
||||||
}
|
_ => None,
|
||||||
_ => None,
|
})
|
||||||
})
|
.collect();
|
||||||
.collect();
|
|
||||||
|
|
||||||
let identities = identities
|
proto::Authn {
|
||||||
.iter()
|
permit: Some(proto::authn::Permit::MeshTls(proto::authn::PermitMeshTls {
|
||||||
.filter_map(|i| match i {
|
clients: Some(proto::authn::permit_mesh_tls::Clients::Identities(
|
||||||
IdentityMatch::Name(n) => Some(proto::Identity {
|
proto::authn::permit_mesh_tls::PermitClientIdentities {
|
||||||
name: n.to_string(),
|
identities,
|
||||||
}),
|
suffixes,
|
||||||
_ => None,
|
},
|
||||||
})
|
)),
|
||||||
.collect();
|
})),
|
||||||
|
|
||||||
proto::Authn {
|
|
||||||
permit: Some(proto::authn::Permit::MeshTls(proto::authn::PermitMeshTls {
|
|
||||||
clients: Some(proto::authn::permit_mesh_tls::Clients::Identities(
|
|
||||||
proto::authn::permit_mesh_tls::PermitClientIdentities {
|
|
||||||
identities,
|
|
||||||
suffixes,
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
proto::Authz {
|
|
||||||
networks,
|
|
||||||
labels: labels.into(),
|
|
||||||
authentication: Some(authn),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
proto::Authz {
|
||||||
// === impl Labels ===
|
networks,
|
||||||
|
labels,
|
||||||
impl From<Labels> for HashMap<String, String> {
|
authentication: Some(authn),
|
||||||
fn from(labels: Labels) -> HashMap<String, String> {
|
|
||||||
vec![
|
|
||||||
("authn".to_string(), labels.authn.to_string()),
|
|
||||||
("tls".to_string(), labels.tls.to_string()),
|
|
||||||
("name".to_string(), labels.name),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,6 +171,7 @@ impl DefaultPolicyWatches {
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultPolicy::Deny => InboundServer {
|
DefaultPolicy::Deny => InboundServer {
|
||||||
|
name: "default:deny".to_string(),
|
||||||
protocol,
|
protocol,
|
||||||
authorizations: Default::default(),
|
authorizations: Default::default(),
|
||||||
},
|
},
|
||||||
|
@ -218,6 +219,7 @@ impl DefaultPolicyWatches {
|
||||||
};
|
};
|
||||||
|
|
||||||
InboundServer {
|
InboundServer {
|
||||||
|
name: name.clone(),
|
||||||
protocol,
|
protocol,
|
||||||
authorizations: Some((name, authz)).into_iter().collect(),
|
authorizations: Some((name, authz)).into_iter().collect(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,7 @@ impl SrvIndex {
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
debug!(authzs = ?authzs.keys());
|
debug!(authzs = ?authzs.keys());
|
||||||
let (tx, rx) = watch::channel(InboundServer {
|
let (tx, rx) = watch::channel(InboundServer {
|
||||||
|
name: entry.key().clone(),
|
||||||
protocol: protocol.clone(),
|
protocol: protocol.clone(),
|
||||||
authorizations: authzs.clone(),
|
authorizations: authzs.clone(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -40,15 +40,13 @@ async fn incrementally_configure_server() {
|
||||||
);
|
);
|
||||||
idx.apply_pod(pod.clone()).unwrap();
|
idx.apply_pod(pod.clone()).unwrap();
|
||||||
|
|
||||||
|
let default = DefaultPolicy::Allow {
|
||||||
|
authenticated_only: false,
|
||||||
|
cluster_only: true,
|
||||||
|
};
|
||||||
let default_config = InboundServer {
|
let default_config = InboundServer {
|
||||||
authorizations: mk_default_policy(
|
name: format!("default:{}", default),
|
||||||
DefaultPolicy::Allow {
|
authorizations: mk_default_policy(default, cluster_net, kubelet_ip),
|
||||||
authenticated_only: false,
|
|
||||||
cluster_only: true,
|
|
||||||
},
|
|
||||||
cluster_net,
|
|
||||||
kubelet_ip,
|
|
||||||
),
|
|
||||||
protocol: ProxyProtocol::Detect {
|
protocol: ProxyProtocol::Detect {
|
||||||
timeout: detect_timeout,
|
timeout: detect_timeout,
|
||||||
},
|
},
|
||||||
|
@ -77,6 +75,7 @@ async fn incrementally_configure_server() {
|
||||||
// Check that the watch has been updated to reflect the above change and that this change _only_
|
// Check that the watch has been updated to reflect the above change and that this change _only_
|
||||||
// applies to the correct port.
|
// applies to the correct port.
|
||||||
let basic_config = InboundServer {
|
let basic_config = InboundServer {
|
||||||
|
name: "srv-0".into(),
|
||||||
protocol: ProxyProtocol::Http1,
|
protocol: ProxyProtocol::Http1,
|
||||||
authorizations: vec![healthcheck_authz(kubelet_ip)].into_iter().collect(),
|
authorizations: vec![healthcheck_authz(kubelet_ip)].into_iter().collect(),
|
||||||
};
|
};
|
||||||
|
@ -103,6 +102,7 @@ async fn incrementally_configure_server() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
time::timeout(time::Duration::from_secs(1), rx.next()).await,
|
time::timeout(time::Duration::from_secs(1), rx.next()).await,
|
||||||
Ok(Some(InboundServer {
|
Ok(Some(InboundServer {
|
||||||
|
name: "srv-0".into(),
|
||||||
protocol: ProxyProtocol::Http1,
|
protocol: ProxyProtocol::Http1,
|
||||||
authorizations: vec![
|
authorizations: vec![
|
||||||
(
|
(
|
||||||
|
@ -150,13 +150,14 @@ fn server_update_deselects_pod() {
|
||||||
(ips.next().unwrap(), ips.next().unwrap())
|
(ips.next().unwrap(), ips.next().unwrap())
|
||||||
};
|
};
|
||||||
let detect_timeout = time::Duration::from_secs(1);
|
let detect_timeout = time::Duration::from_secs(1);
|
||||||
|
let default = DefaultPolicy::Allow {
|
||||||
|
authenticated_only: false,
|
||||||
|
cluster_only: true,
|
||||||
|
};
|
||||||
let (lookup_rx, mut idx) = Index::new(
|
let (lookup_rx, mut idx) = Index::new(
|
||||||
vec![cluster_net],
|
vec![cluster_net],
|
||||||
"cluster.example.com".into(),
|
"cluster.example.com".into(),
|
||||||
DefaultPolicy::Allow {
|
default,
|
||||||
authenticated_only: false,
|
|
||||||
cluster_only: true,
|
|
||||||
},
|
|
||||||
detect_timeout,
|
detect_timeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -182,6 +183,7 @@ fn server_update_deselects_pod() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
port2222.get(),
|
port2222.get(),
|
||||||
InboundServer {
|
InboundServer {
|
||||||
|
name: "srv-0".into(),
|
||||||
protocol: ProxyProtocol::Http2,
|
protocol: ProxyProtocol::Http2,
|
||||||
authorizations: vec![healthcheck_authz(kubelet_ip)].into_iter().collect(),
|
authorizations: vec![healthcheck_authz(kubelet_ip)].into_iter().collect(),
|
||||||
}
|
}
|
||||||
|
@ -195,14 +197,8 @@ fn server_update_deselects_pod() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
port2222.get(),
|
port2222.get(),
|
||||||
InboundServer {
|
InboundServer {
|
||||||
authorizations: mk_default_policy(
|
name: format!("default:{}", default),
|
||||||
DefaultPolicy::Allow {
|
authorizations: mk_default_policy(default, cluster_net, kubelet_ip),
|
||||||
authenticated_only: false,
|
|
||||||
cluster_only: true,
|
|
||||||
},
|
|
||||||
cluster_net,
|
|
||||||
kubelet_ip
|
|
||||||
),
|
|
||||||
protocol: ProxyProtocol::Detect {
|
protocol: ProxyProtocol::Detect {
|
||||||
timeout: detect_timeout,
|
timeout: detect_timeout,
|
||||||
},
|
},
|
||||||
|
@ -243,6 +239,7 @@ fn default_policy_global() {
|
||||||
idx.reset_pods(vec![p]).unwrap();
|
idx.reset_pods(vec![p]).unwrap();
|
||||||
|
|
||||||
let config = InboundServer {
|
let config = InboundServer {
|
||||||
|
name: format!("default:{}", default),
|
||||||
authorizations: mk_default_policy(*default, cluster_net, kubelet_ip),
|
authorizations: mk_default_policy(*default, cluster_net, kubelet_ip),
|
||||||
protocol: ProxyProtocol::Detect {
|
protocol: ProxyProtocol::Detect {
|
||||||
timeout: detect_timeout,
|
timeout: detect_timeout,
|
||||||
|
@ -300,6 +297,7 @@ fn default_policy_annotated() {
|
||||||
idx.reset_pods(vec![p]).unwrap();
|
idx.reset_pods(vec![p]).unwrap();
|
||||||
|
|
||||||
let config = InboundServer {
|
let config = InboundServer {
|
||||||
|
name: format!("default:{}", default),
|
||||||
authorizations: mk_default_policy(*default, cluster_net, kubelet_ip),
|
authorizations: mk_default_policy(*default, cluster_net, kubelet_ip),
|
||||||
protocol: ProxyProtocol::Detect {
|
protocol: ProxyProtocol::Detect {
|
||||||
timeout: detect_timeout,
|
timeout: detect_timeout,
|
||||||
|
@ -323,13 +321,14 @@ fn default_policy_annotated_invalid() {
|
||||||
};
|
};
|
||||||
let detect_timeout = time::Duration::from_secs(1);
|
let detect_timeout = time::Duration::from_secs(1);
|
||||||
|
|
||||||
|
let default = DefaultPolicy::Allow {
|
||||||
|
authenticated_only: false,
|
||||||
|
cluster_only: false,
|
||||||
|
};
|
||||||
let (lookup_rx, mut idx) = Index::new(
|
let (lookup_rx, mut idx) = Index::new(
|
||||||
vec![cluster_net],
|
vec![cluster_net],
|
||||||
"cluster.example.com".into(),
|
"cluster.example.com".into(),
|
||||||
DefaultPolicy::Allow {
|
default,
|
||||||
authenticated_only: false,
|
|
||||||
cluster_only: false,
|
|
||||||
},
|
|
||||||
detect_timeout,
|
detect_timeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -353,6 +352,7 @@ fn default_policy_annotated_invalid() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
port2222.get(),
|
port2222.get(),
|
||||||
InboundServer {
|
InboundServer {
|
||||||
|
name: format!("default:{}", default),
|
||||||
authorizations: mk_default_policy(
|
authorizations: mk_default_policy(
|
||||||
DefaultPolicy::Allow {
|
DefaultPolicy::Allow {
|
||||||
authenticated_only: false,
|
authenticated_only: false,
|
||||||
|
@ -400,6 +400,7 @@ fn opaque_annotated() {
|
||||||
idx.reset_pods(vec![p]).unwrap();
|
idx.reset_pods(vec![p]).unwrap();
|
||||||
|
|
||||||
let config = InboundServer {
|
let config = InboundServer {
|
||||||
|
name: format!("default:{}", default),
|
||||||
authorizations: mk_default_policy(*default, cluster_net, kubelet_ip),
|
authorizations: mk_default_policy(*default, cluster_net, kubelet_ip),
|
||||||
protocol: ProxyProtocol::Opaque,
|
protocol: ProxyProtocol::Opaque,
|
||||||
};
|
};
|
||||||
|
@ -444,21 +445,21 @@ fn authenticated_annotated() {
|
||||||
);
|
);
|
||||||
idx.reset_pods(vec![p]).unwrap();
|
idx.reset_pods(vec![p]).unwrap();
|
||||||
|
|
||||||
let config = InboundServer {
|
let config = {
|
||||||
authorizations: mk_default_policy(
|
let policy = match *default {
|
||||||
match *default {
|
DefaultPolicy::Allow { cluster_only, .. } => DefaultPolicy::Allow {
|
||||||
DefaultPolicy::Allow { cluster_only, .. } => DefaultPolicy::Allow {
|
cluster_only,
|
||||||
cluster_only,
|
authenticated_only: true,
|
||||||
authenticated_only: true,
|
|
||||||
},
|
|
||||||
DefaultPolicy::Deny => DefaultPolicy::Deny,
|
|
||||||
},
|
},
|
||||||
cluster_net,
|
DefaultPolicy::Deny => DefaultPolicy::Deny,
|
||||||
kubelet_ip,
|
};
|
||||||
),
|
InboundServer {
|
||||||
protocol: ProxyProtocol::Detect {
|
name: format!("default:{}", policy),
|
||||||
timeout: detect_timeout,
|
authorizations: mk_default_policy(policy, cluster_net, kubelet_ip),
|
||||||
},
|
protocol: ProxyProtocol::Detect {
|
||||||
|
timeout: detect_timeout,
|
||||||
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let port2222 = lookup_rx
|
let port2222 = lookup_rx
|
||||||
|
|
Loading…
Reference in New Issue