Skip to content

Commit d59a563

Browse files
authored
Merge pull request #1088 from jvanz/mtlstests
feat(tests): TLS communication tests.
2 parents aa5bb78 + b583f52 commit d59a563

File tree

2 files changed

+129
-3
lines changed

2 files changed

+129
-3
lines changed

tests/common/mod.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use policy_server::{
55
};
66
use std::{
77
collections::{BTreeSet, HashMap},
8-
net::SocketAddr,
8+
net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener},
99
};
1010
use tempfile::tempdir;
1111

@@ -105,8 +105,8 @@ pub(crate) fn default_test_config() -> Config {
105105
]);
106106

107107
Config {
108-
addr: SocketAddr::from(([127, 0, 0, 1], 3001)),
109-
readiness_probe_addr: SocketAddr::from(([127, 0, 0, 1], 3002)),
108+
addr: get_available_address_with_port(),
109+
readiness_probe_addr: get_available_address_with_port(),
110110
sources: None,
111111
policies,
112112
policies_download_dir: tempdir().unwrap().into_path(),
@@ -130,6 +130,15 @@ pub(crate) fn default_test_config() -> Config {
130130
}
131131
}
132132

133+
/// Returns a random adress with an available port to use with policy server. Therefore, we can
134+
/// have multiple policy server running at the same time in async tests
135+
fn get_available_address_with_port() -> SocketAddr {
136+
TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))
137+
.expect("failed to bind to available port")
138+
.local_addr()
139+
.expect("failed to get local address")
140+
}
141+
133142
pub(crate) async fn app(config: Config) -> Router {
134143
let server = PolicyServer::new_from_config(config).await.unwrap();
135144

tests/integration_test.rs

+117
Original file line numberDiff line numberDiff line change
@@ -946,3 +946,120 @@ fn generate_tls_certs() -> (String, String, String) {
946946

947947
(ca_cert_pem, cert.pem(), key)
948948
}
949+
950+
#[cfg(target_os = "linux")]
951+
#[tokio::test(flavor = "multi_thread")]
952+
#[rstest]
953+
#[case::no_tls_config(None, None)]
954+
#[case::with_server_tls_config(Some(certificate_reload_helpers::create_cert("127.0.0.1")), None)]
955+
#[case::mtls_config(
956+
Some(certificate_reload_helpers::create_cert("127.0.0.1")),
957+
Some(certificate_reload_helpers::create_cert("127.0.0.1"))
958+
)]
959+
async fn test_tls(
960+
#[case] server_tls_data: Option<certificate_reload_helpers::TlsData>,
961+
#[case] client_tls_data: Option<certificate_reload_helpers::TlsData>,
962+
) {
963+
use certificate_reload_helpers::*;
964+
965+
setup();
966+
967+
let certs_dir = tempfile::tempdir().unwrap();
968+
let cert_file = certs_dir.path().join("policy-server.pem");
969+
let key_file = certs_dir.path().join("policy-server-key.pem");
970+
let client_ca = certs_dir.path().join("client_cert.pem");
971+
972+
let server_cert = if let Some(ref tls_data) = server_tls_data {
973+
std::fs::write(&cert_file, tls_data.cert.clone()).unwrap();
974+
std::fs::write(&key_file, tls_data.key.clone()).unwrap();
975+
tls_data.cert.clone()
976+
} else {
977+
String::new()
978+
};
979+
980+
let (client_cert, client_key) = if let Some(ref tls_data) = client_tls_data {
981+
std::fs::write(&client_ca, tls_data.cert.clone()).unwrap();
982+
(tls_data.cert.clone(), tls_data.key.clone())
983+
} else {
984+
(String::new(), String::new())
985+
};
986+
987+
let mut config = default_test_config();
988+
config.tls_config = match (server_tls_data.as_ref(), client_tls_data.as_ref()) {
989+
(None, None) => None,
990+
(Some(_), Some(_)) => Some(policy_server::config::TlsConfig {
991+
cert_file: cert_file.to_str().unwrap().to_owned(),
992+
key_file: key_file.to_str().unwrap().to_owned(),
993+
client_ca_file: Some(client_ca.to_str().unwrap().to_owned()),
994+
}),
995+
(Some(_), None) => Some(policy_server::config::TlsConfig {
996+
cert_file: cert_file.to_str().unwrap().to_owned(),
997+
key_file: key_file.to_str().unwrap().to_owned(),
998+
client_ca_file: None,
999+
}),
1000+
_ => {
1001+
panic!("Invalid test case")
1002+
}
1003+
};
1004+
1005+
let host = config.addr.ip().to_string();
1006+
let port = config.addr.port().to_string();
1007+
let readiness_probe_port = config.readiness_probe_addr.port().to_string();
1008+
1009+
tokio::spawn(async move {
1010+
let api_server = policy_server::PolicyServer::new_from_config(config)
1011+
.await
1012+
.unwrap();
1013+
api_server.run().await.unwrap();
1014+
});
1015+
1016+
// readiness probe should always return 200 no matter the tls configuration.
1017+
// The probe should run in a different server on http
1018+
let exponential_backoff = ExponentialBuilder::default()
1019+
.with_min_delay(Duration::from_secs(10))
1020+
.with_max_delay(Duration::from_secs(30))
1021+
.with_max_times(5);
1022+
1023+
let status_code = (|| async {
1024+
policy_server_is_ready(format!("{host}:{readiness_probe_port}").as_str()).await
1025+
})
1026+
.retry(exponential_backoff)
1027+
.await
1028+
.expect("policy server is not ready");
1029+
assert_eq!(status_code, reqwest::StatusCode::OK);
1030+
1031+
// Validate TLS communication
1032+
let mut builder = reqwest::Client::builder();
1033+
1034+
if server_tls_data.is_some() {
1035+
let certificate = reqwest::Certificate::from_pem(server_cert.as_bytes())
1036+
.expect("Invalid policy server certificate");
1037+
builder = builder.add_root_certificate(certificate);
1038+
}
1039+
1040+
if client_tls_data.is_some() {
1041+
let identity =
1042+
reqwest::Identity::from_pem(format!("{}\n{}", client_cert, client_key).as_bytes())
1043+
.expect("successfull pem parsing");
1044+
builder = builder.identity(identity);
1045+
};
1046+
let client = builder.build().unwrap();
1047+
1048+
let prefix = if server_tls_data.is_some() {
1049+
"https"
1050+
} else {
1051+
"http"
1052+
};
1053+
let url =
1054+
reqwest::Url::parse(&format!("{prefix}://{host}:{port}/validate/pod-privileged")).unwrap();
1055+
let response = client
1056+
.post(url)
1057+
.header(header::CONTENT_TYPE, "application/json")
1058+
.body(include_str!("data/pod_without_privileged_containers.json"))
1059+
.send()
1060+
.await;
1061+
assert_eq!(
1062+
response.expect("successfull request").status(),
1063+
reqwest::StatusCode::OK
1064+
);
1065+
}

0 commit comments

Comments
 (0)