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

Expand tests to account for audit access policy #12847

Merged
merged 1 commit into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion policy-controller/k8s/index/src/inbound/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ struct TestConfig {
_tracing: tracing::subscriber::DefaultGuard,
}

const DEFAULTS: [DefaultPolicy; 5] = [
const DEFAULTS: [DefaultPolicy; 6] = [
DefaultPolicy::Deny,
DefaultPolicy::Allow {
authenticated_only: true,
Expand All @@ -63,6 +63,7 @@ const DEFAULTS: [DefaultPolicy; 5] = [
authenticated_only: false,
cluster_only: true,
},
DefaultPolicy::Audit,
];

pub fn mk_pod_with_containers(
Expand Down Expand Up @@ -121,6 +122,7 @@ fn mk_server(
port,
selector: k8s::policy::server::Selector::Pod(pod_labels.into_iter().collect()),
proxy_protocol,
access_policy: None,
},
}
}
Expand Down Expand Up @@ -177,6 +179,13 @@ fn mk_default_policy(
networks: cluster_nets,
},
)),
DefaultPolicy::Audit => Some((
AuthorizationRef::Default("audit"),
ClientAuthorization {
authentication: ClientAuthentication::Unauthenticated,
networks: all_nets,
},
)),
}
.into_iter()
.collect()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ fn authenticated_annotated() {
authenticated_only: true,
},
DefaultPolicy::Deny => DefaultPolicy::Deny,
DefaultPolicy::Audit => DefaultPolicy::Audit,
};
InboundServer {
reference: ServerRef::Default(policy.as_str()),
Expand Down
1 change: 1 addition & 0 deletions policy-controller/k8s/status/src/tests/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ fn make_server(
port,
selector: linkerd_k8s_api::server::Selector::Pod(pod_labels.into_iter().collect()),
proxy_protocol,
access_policy: None,
},
}
}
3 changes: 2 additions & 1 deletion policy-test/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub fn pod(ns: &str) -> k8s::Pod {
}
}

pub fn server(ns: &str) -> k8s::policy::Server {
pub fn server(ns: &str, access_policy: Option<String>) -> k8s::policy::Server {
k8s::policy::Server {
metadata: k8s::ObjectMeta {
namespace: Some(ns.to_string()),
Expand All @@ -46,6 +46,7 @@ pub fn server(ns: &str) -> k8s::policy::Server {
)))),
port: k8s::policy::server::Port::Name("http".to_string()),
proxy_protocol: Some(k8s::policy::server::ProxyProtocol::Http1),
access_policy,
},
}
}
Expand Down
23 changes: 23 additions & 0 deletions policy-test/tests/admit_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ async fn accepts_valid() {
selector: Selector::Pod(api::labels::Selector::default()),
port: Port::Number(80.try_into().unwrap()),
proxy_protocol: None,
access_policy: None,
},
})
.await;
Expand All @@ -34,6 +35,7 @@ async fn accepts_server_updates() {
selector: Selector::Pod(api::labels::Selector::from_iter(Some(("app", "test")))),
port: Port::Number(80.try_into().unwrap()),
proxy_protocol: None,
access_policy: None,
},
};

Expand All @@ -60,6 +62,7 @@ async fn rejects_identitical_pod_selector() {
selector: Selector::Pod(api::labels::Selector::from_iter(Some(("app", "test")))),
port: Port::Number(80.try_into().unwrap()),
proxy_protocol: None,
access_policy: None,
};

let api = kube::Api::namespaced(client, &ns);
Expand Down Expand Up @@ -106,6 +109,7 @@ async fn rejects_all_pods_selected() {
selector: Selector::Pod(api::labels::Selector::from_iter(Some(("app", "test")))),
port: Port::Number(80.try_into().unwrap()),
proxy_protocol: Some(ProxyProtocol::Http2),
access_policy: None,
},
};
api.create(&kube::api::PostParams::default(), &test0)
Expand All @@ -123,6 +127,7 @@ async fn rejects_all_pods_selected() {
port: Port::Number(80.try_into().unwrap()),
// proxy protocol doesn't factor into the selection
proxy_protocol: Some(ProxyProtocol::Http1),
access_policy: None,
},
};
api.create(&kube::api::PostParams::default(), &test1)
Expand Down Expand Up @@ -179,3 +184,21 @@ async fn rejects_invalid_proxy_protocol() {
})
.await;
}

#[tokio::test(flavor = "current_thread")]
async fn rejects_invalid_access_policy() {
admission::rejects(|ns| Server {
metadata: api::ObjectMeta {
namespace: Some(ns),
name: Some("test".to_string()),
..Default::default()
},
spec: ServerSpec {
selector: Selector::Pod(api::labels::Selector::default()),
port: Port::Number(80.try_into().unwrap()),
proxy_protocol: None,
access_policy: Some("foobar".to_string()),
},
})
.await;
}
123 changes: 123 additions & 0 deletions policy-test/tests/e2e_audit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use kube::{Client, ResourceExt};
use linkerd_policy_controller_k8s_api as k8s;
use linkerd_policy_test::{create, create_ready_pod, curl, web, with_temp_ns, LinkerdInject};

#[tokio::test(flavor = "current_thread")]
async fn server_audit() {
with_temp_ns(|client, ns| async move {
// Create a server with no policy that should block traffic to the associated pod
let srv = create(&client, web::server(&ns, None)).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))
);

// All requests should fail
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_ne!(injected_status, 0, "injected curl must fail");
assert_ne!(uninjected_status, 0, "uninjected curl must fail");

// Patch the server with accessPolicy audit
let patch = serde_json::json!({
"spec": {
"accessPolicy": "audit",
}
});
let patch = k8s::Patch::Merge(patch);
let api = k8s::Api::<k8s::policy::Server>::namespaced(client.clone(), &ns);
api.patch(&srv.name_unchecked(), &k8s::PatchParams::default(), &patch)
.await
.expect("failed to patch server");

// All requests should succeed
let (injected, uninjected) = tokio::join!(
curl.run("curl-audit-injected", "http://web", LinkerdInject::Enabled),
curl.run(
"curl-audit-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 contact web");
assert_eq!(uninjected_status, 0, "uninjected curl must contact web");
})
.await;
}

#[tokio::test(flavor = "current_thread")]
async fn ns_audit() {
with_temp_ns(|client, ns| async move {
change_access_policy(client.clone(), &ns, "cluster-authenticated").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))
);

// Unmeshed requests should fail
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 contact web");
assert_ne!(uninjected_status, 0, "uninjected curl must fail");

change_access_policy(client.clone(), &ns, "audit").await;

// Recreate pod for it to pick the new default policy
let api = kube::Api::<k8s::api::core::v1::Pod>::namespaced(client.clone(), &ns);
kube::runtime::wait::delete::delete_and_finalize(
api,
"web",
&kube::api::DeleteParams::foreground(),
)
.await
.expect("web pod must be deleted");

create_ready_pod(&client, web::pod(&ns)).await;

// All requests should work
let (injected, uninjected) = tokio::join!(
curl.run("curl-audit-injected", "http://web", LinkerdInject::Enabled),
curl.run(
"curl-audit-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 contact web");
assert_eq!(uninjected_status, 0, "uninject curl must contact web");
})
.await;
}

async fn change_access_policy(client: Client, ns: &str, policy: &str) {
let api = k8s::Api::<k8s::Namespace>::all(client.clone());
let patch = serde_json::json!({
"metadata": {
"annotations": {
"config.linkerd.io/default-inbound-policy": policy,
}
}
});
let patch = k8s::Patch::Merge(patch);
api.patch(ns, &k8s::PatchParams::default(), &patch)
.await
.expect("failed to patch namespace");
}
16 changes: 8 additions & 8 deletions policy-test/tests/e2e_authorization_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async fn meshtls() {
//
// The policy requires that all connections are authenticated with MeshTLS.
let (srv, all_mtls) = tokio::join!(
create(&client, web::server(&ns)),
create(&client, web::server(&ns, None)),
create(&client, all_authenticated(&ns))
);
create(
Expand Down Expand Up @@ -60,7 +60,7 @@ async fn targets_route() {
//
// The policy requires that all connections are authenticated with MeshTLS.
let (srv, all_mtls) = tokio::join!(
create(&client, web::server(&ns)),
create(&client, web::server(&ns, None)),
create(&client, all_authenticated(&ns)),
);
// Create a route which matches the /allowed path.
Expand Down Expand Up @@ -171,7 +171,7 @@ async fn targets_namespace() {
//
// The policy requires that all connections are authenticated with MeshTLS.
let (_srv, all_mtls) = tokio::join!(
create(&client, web::server(&ns)),
create(&client, web::server(&ns, None)),
create(&client, all_authenticated(&ns))
);
create(
Expand Down Expand Up @@ -220,7 +220,7 @@ async fn meshtls_namespace() {
// The policy requires that all connections are authenticated with MeshTLS
// and come from service accounts in the given namespace.
let (srv, mtls_ns) = tokio::join!(
create(&client, web::server(&ns)),
create(&client, web::server(&ns, None)),
create(&client, ns_authenticated(&ns))
);
create(
Expand Down Expand Up @@ -277,7 +277,7 @@ async fn network() {
// Once we know the IP of the (blocked) pod, create an web
// authorization policy that permits connections from this pod.
let (srv, allow_ips) = tokio::join!(
create(&client, web::server(&ns)),
create(&client, web::server(&ns, None)),
create(&client, allow_ips(&ns, Some(blessed_ip)))
);
create(
Expand Down Expand Up @@ -351,7 +351,7 @@ async fn both() {
// Once we know the IP of the (blocked) pod, create an web
// authorization policy that permits connections from this pod.
let (srv, allow_ips, all_mtls) = tokio::join!(
create(&client, web::server(&ns)),
create(&client, web::server(&ns, None)),
create(
&client,
allow_ips(&ns, vec![blessed_injected_ip, blessed_uninjected_ip]),
Expand Down Expand Up @@ -451,7 +451,7 @@ async fn either() {
// Once we know the IP of the (blocked) pod, create an web
// authorization policy that permits connections from this pod.
let (srv, allow_ips, all_mtls) = tokio::join!(
create(&client, web::server(&ns)),
create(&client, web::server(&ns, None)),
create(&client, allow_ips(&ns, vec![blessed_uninjected_ip])),
create(&client, all_authenticated(&ns))
);
Expand Down Expand Up @@ -528,7 +528,7 @@ async fn either() {
async fn empty_authentications() {
with_temp_ns(|client, ns| async move {
// Create a policy that does not require any authentications.
let srv = create(&client, web::server(&ns)).await;
let srv = create(&client, web::server(&ns, None)).await;
create(
&client,
authz_policy(&ns, "web", LocalTargetRef::from_resource(&srv), None),
Expand Down
8 changes: 4 additions & 4 deletions policy-test/tests/e2e_server_authorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use linkerd_policy_test::{
#[tokio::test(flavor = "current_thread")]
async fn meshtls() {
with_temp_ns(|client, ns| async move {
let srv = create(&client, web::server(&ns)).await;
let srv = create(&client, web::server(&ns, None)).await;

create(
&client,
Expand Down Expand Up @@ -66,7 +66,7 @@ async fn network() {

// 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)).await;
let srv = create(&client, web::server(&ns, None)).await;
create(
&client,
server_authz(
Expand Down Expand Up @@ -143,7 +143,7 @@ async fn both() {

// 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)).await;
let srv = create(&client, web::server(&ns, None)).await;
create(
&client,
server_authz(
Expand Down Expand Up @@ -243,7 +243,7 @@ async fn either() {

// 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)).await;
let srv = create(&client, web::server(&ns, None)).await;
tokio::join!(
create(
&client,
Expand Down
Loading
Loading