mirror of https://github.com/linkerd/linkerd2.git
358 lines
12 KiB
Rust
358 lines
12 KiB
Rust
use linkerd_policy_controller_k8s_api::{
|
|
self as k8s, policy::server_authorization::Client as ClientAuthz, ResourceExt,
|
|
};
|
|
use linkerd_policy_test::{
|
|
await_condition, create, create_ready_pod, curl, endpoints_ready, web, with_temp_ns,
|
|
LinkerdInject,
|
|
};
|
|
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn meshtls() {
|
|
with_temp_ns(|client, ns| async move {
|
|
let srv = create(&client, web::server(&ns, None)).await;
|
|
|
|
create(
|
|
&client,
|
|
server_authz(
|
|
&ns,
|
|
"web",
|
|
&srv,
|
|
ClientAuthz {
|
|
mesh_tls: Some(k8s::policy::server_authorization::MeshTls {
|
|
identities: Some(vec!["*".to_string()]),
|
|
..Default::default()
|
|
}),
|
|
..Default::default()
|
|
},
|
|
),
|
|
)
|
|
.await;
|
|
|
|
// Create the web pod and wait for it to be ready.
|
|
tokio::join!(
|
|
create(&client, web::service(&ns)),
|
|
create_ready_pod(&client, web::pod(&ns))
|
|
);
|
|
|
|
await_condition(&client, &ns, "web", endpoints_ready).await;
|
|
|
|
let curl = curl::Runner::init(&client, &ns).await;
|
|
let (injected, uninjected) = tokio::join!(
|
|
curl.run("curl-injected", "http://web", LinkerdInject::Enabled),
|
|
curl.run("curl-uninjected", "http://web", LinkerdInject::Disabled),
|
|
);
|
|
let (injected_status, uninjected_status) =
|
|
tokio::join!(injected.exit_code(), uninjected.exit_code());
|
|
assert_eq!(injected_status, 0, "injected curl must succeed");
|
|
assert_eq!(uninjected_status, 22, "uninjected curl must fail");
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn network() {
|
|
with_temp_ns(|client, ns| async move {
|
|
let curl = curl::Runner::init(&client, &ns).await;
|
|
|
|
// Create a lock that prevents `curl` pods from running. This allows us
|
|
// to create a curl pod so that its IP can be obtained to be used in an
|
|
// authorization policy.
|
|
curl.create_lock().await;
|
|
|
|
// Create a curl pod and wait for it to get an IP.
|
|
let blessed = curl
|
|
.run("curl-blessed", "http://web", LinkerdInject::Disabled)
|
|
.await;
|
|
let blessed_ip = blessed.ip().await;
|
|
tracing::debug!(curl.blessed.ip = %blessed_ip);
|
|
|
|
// Once we know the IP of the (blocked) pod, create an web
|
|
// authorization policy that permits connections from this pod.
|
|
let srv = create(&client, web::server(&ns, None)).await;
|
|
create(
|
|
&client,
|
|
server_authz(
|
|
&ns,
|
|
"web",
|
|
&srv,
|
|
ClientAuthz {
|
|
networks: Some(vec![k8s::policy::Network {
|
|
cidr: blessed_ip.into(),
|
|
except: None,
|
|
}]),
|
|
unauthenticated: true,
|
|
..Default::default()
|
|
},
|
|
),
|
|
)
|
|
.await;
|
|
|
|
// Start web with the policy.
|
|
tokio::join!(
|
|
create(&client, web::service(&ns)),
|
|
create_ready_pod(&client, web::pod(&ns))
|
|
);
|
|
|
|
await_condition(&client, &ns, "web", endpoints_ready).await;
|
|
|
|
// Once the web pod is ready, delete the `curl-lock` configmap to
|
|
// unblock curl from running.
|
|
curl.delete_lock().await;
|
|
tracing::info!("unblocked curl");
|
|
|
|
// The blessed pod should be able to connect to the web pod.
|
|
let status = blessed.exit_code().await;
|
|
assert_eq!(status, 0, "blessed curl must succeed");
|
|
|
|
// Create another curl pod that is not included in the authorization. It
|
|
// should fail to connect to the web pod.
|
|
let status = curl
|
|
.run("curl-cursed", "http://web", LinkerdInject::Disabled)
|
|
.await
|
|
.exit_code()
|
|
.await;
|
|
assert_eq!(status, 22, "cursed curl must fail");
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn both() {
|
|
with_temp_ns(|client, ns| async move {
|
|
let curl = curl::Runner::init(&client, &ns).await;
|
|
|
|
// Create a lock that prevents `curl` pods from running. This allows us
|
|
// to create a curl pod so that its IP can be obtained to be used in an
|
|
// authorization policy.
|
|
curl.create_lock().await;
|
|
|
|
let (blessed_injected, blessed_uninjected) = tokio::join!(
|
|
curl.run(
|
|
"curl-blessed-injected",
|
|
"http://web",
|
|
LinkerdInject::Enabled,
|
|
),
|
|
curl.run(
|
|
"curl-blessed-uninjected",
|
|
"http://web",
|
|
LinkerdInject::Disabled,
|
|
)
|
|
);
|
|
let (blessed_injected_ip, blessed_uninjected_ip) =
|
|
tokio::join!(blessed_injected.ip(), blessed_uninjected.ip(),);
|
|
tracing::debug!(curl.blessed.injected.ip = ?blessed_injected_ip);
|
|
tracing::debug!(curl.blessed.uninjected.ip = ?blessed_uninjected_ip);
|
|
|
|
// Once we know the IP of the (blocked) pod, create an web
|
|
// authorization policy that permits connections from this pod.
|
|
let srv = create(&client, web::server(&ns, None)).await;
|
|
create(
|
|
&client,
|
|
server_authz(
|
|
&ns,
|
|
"web",
|
|
&srv,
|
|
ClientAuthz {
|
|
networks: Some(vec![
|
|
k8s::policy::Network {
|
|
cidr: blessed_injected_ip.into(),
|
|
except: None,
|
|
},
|
|
k8s::policy::Network {
|
|
cidr: blessed_uninjected_ip.into(),
|
|
except: None,
|
|
},
|
|
]),
|
|
mesh_tls: Some(k8s::policy::server_authorization::MeshTls {
|
|
identities: Some(vec!["*".to_string()]),
|
|
..Default::default()
|
|
}),
|
|
..Default::default()
|
|
},
|
|
),
|
|
)
|
|
.await;
|
|
|
|
// Start web with the policy.
|
|
tokio::join!(
|
|
create(&client, web::service(&ns)),
|
|
create_ready_pod(&client, web::pod(&ns))
|
|
);
|
|
|
|
await_condition(&client, &ns, "web", endpoints_ready).await;
|
|
|
|
// Once the web pod is ready, delete the `curl-lock` configmap to
|
|
// unblock curl from running.
|
|
curl.delete_lock().await;
|
|
tracing::info!("unblocked curl");
|
|
|
|
let (blessed_injected_status, blessed_uninjected_status) =
|
|
tokio::join!(blessed_injected.exit_code(), blessed_uninjected.exit_code());
|
|
// The blessed and injected pod should be able to connect to the web pod.
|
|
assert_eq!(
|
|
blessed_injected_status, 0,
|
|
"blessed injected curl must succeed"
|
|
);
|
|
// The blessed and uninjected pod should NOT be able to connect to the web pod.
|
|
assert_eq!(
|
|
blessed_uninjected_status, 22,
|
|
"blessed uninjected curl must fail"
|
|
);
|
|
|
|
let (cursed_injected, cursed_uninjected) = tokio::join!(
|
|
curl.run("curl-cursed-injected", "http://web", LinkerdInject::Enabled,),
|
|
curl.run(
|
|
"curl-cursed-uninjected",
|
|
"http://web",
|
|
LinkerdInject::Disabled,
|
|
)
|
|
);
|
|
let (cursed_injected_status, cursed_uninjected_status) =
|
|
tokio::join!(cursed_injected.exit_code(), cursed_uninjected.exit_code(),);
|
|
assert_eq!(cursed_injected_status, 22, "cursed injected curl must fail");
|
|
assert_eq!(
|
|
cursed_uninjected_status, 22,
|
|
"cursed uninjected curl must fail"
|
|
);
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn either() {
|
|
with_temp_ns(|client, ns| async move {
|
|
let curl = curl::Runner::init(&client, &ns).await;
|
|
|
|
tracing::info!("Blocking curl");
|
|
curl.create_lock().await;
|
|
|
|
let (blessed_injected, blessed_uninjected) = tokio::join!(
|
|
curl.run(
|
|
"curl-blessed-injected",
|
|
"http://web",
|
|
LinkerdInject::Enabled,
|
|
),
|
|
curl.run(
|
|
"curl-blessed-uninjected",
|
|
"http://web",
|
|
LinkerdInject::Disabled,
|
|
)
|
|
);
|
|
let (blessed_injected_ip, blessed_uninjected_ip) =
|
|
tokio::join!(blessed_injected.ip(), blessed_uninjected.ip());
|
|
tracing::debug!(curl.blessed.injected.ip = ?blessed_injected_ip);
|
|
tracing::debug!(curl.blessed.uninjected.ip = ?blessed_uninjected_ip);
|
|
|
|
// Once we know the IP of the (blocked) pod, create an web
|
|
// authorization policy that permits connections from this pod.
|
|
let srv = create(&client, web::server(&ns, None)).await;
|
|
tokio::join!(
|
|
create(
|
|
&client,
|
|
server_authz(
|
|
&ns,
|
|
"web-from-ip",
|
|
&srv,
|
|
ClientAuthz {
|
|
unauthenticated: true,
|
|
networks: Some(vec![
|
|
k8s::policy::Network {
|
|
cidr: blessed_injected_ip.into(),
|
|
except: None,
|
|
},
|
|
k8s::policy::Network {
|
|
cidr: blessed_uninjected_ip.into(),
|
|
except: None,
|
|
},
|
|
]),
|
|
..Default::default()
|
|
},
|
|
)
|
|
),
|
|
create(
|
|
&client,
|
|
server_authz(
|
|
&ns,
|
|
"web-from-id",
|
|
&srv,
|
|
ClientAuthz {
|
|
mesh_tls: Some(k8s::policy::server_authorization::MeshTls {
|
|
identities: Some(vec!["*".to_string()]),
|
|
..Default::default()
|
|
}),
|
|
..Default::default()
|
|
},
|
|
)
|
|
),
|
|
);
|
|
|
|
// Start web with the policy.
|
|
tokio::join!(
|
|
create(&client, web::service(&ns)),
|
|
create_ready_pod(&client, web::pod(&ns)),
|
|
);
|
|
|
|
await_condition(&client, &ns, "web", endpoints_ready).await;
|
|
|
|
// Once the web pod is ready, delete the `curl-lock` configmap to
|
|
// unblock curl from running.
|
|
curl.delete_lock().await;
|
|
tracing::info!("unblocked curl");
|
|
|
|
let (blessed_injected_status, blessed_uninjected_status) =
|
|
tokio::join!(blessed_injected.exit_code(), blessed_uninjected.exit_code());
|
|
assert_eq!(
|
|
blessed_injected_status, 0,
|
|
"blessed injected curl must succeed"
|
|
);
|
|
assert_eq!(
|
|
blessed_uninjected_status, 0,
|
|
"blessed uninjected curl must succeed"
|
|
);
|
|
|
|
let (cursed_injected, cursed_uninjected) = tokio::join!(
|
|
curl.run("curl-cursed-injected", "http://web", LinkerdInject::Enabled,),
|
|
curl.run(
|
|
"curl-cursed-uninjected",
|
|
"http://web",
|
|
LinkerdInject::Disabled,
|
|
),
|
|
);
|
|
let (cursed_injected_status, cursed_uninjected_status) =
|
|
tokio::join!(cursed_injected.exit_code(), cursed_uninjected.exit_code());
|
|
assert_eq!(
|
|
cursed_injected_status, 0,
|
|
"cursed injected curl must succeed"
|
|
);
|
|
assert_eq!(
|
|
cursed_uninjected_status, 22,
|
|
"cursed uninjected curl must fail"
|
|
);
|
|
})
|
|
.await;
|
|
}
|
|
|
|
// === helpers ===
|
|
|
|
fn server_authz(
|
|
ns: &str,
|
|
name: &str,
|
|
target: &k8s::policy::Server,
|
|
client: ClientAuthz,
|
|
) -> k8s::policy::ServerAuthorization {
|
|
k8s::policy::ServerAuthorization {
|
|
metadata: k8s::ObjectMeta {
|
|
namespace: Some(ns.to_string()),
|
|
name: Some(name.to_string()),
|
|
..Default::default()
|
|
},
|
|
spec: k8s::policy::ServerAuthorizationSpec {
|
|
server: k8s::policy::server_authorization::Server {
|
|
name: Some(target.name_unchecked()),
|
|
selector: None,
|
|
},
|
|
client,
|
|
},
|
|
}
|
|
}
|