Replace external reachability with an owned canary
This commit is contained in:
parent
0f6825c3b9
commit
31e9ab0f2d
1 changed files with 1409 additions and 1972 deletions
|
|
@ -6,21 +6,20 @@ use lazaret_core::identity::{
|
|||
PidfsProcessAuthorityV1, PidfsProcessIdentityV1, ProcessStartTimeTicks, ReadinessFingerprint,
|
||||
};
|
||||
use lazaret_core::network::{
|
||||
DnsQueryExpectation, NetworkValidationErrorKind, ReachabilityExpectation, ReadinessExpectation,
|
||||
accept_network_readiness, canonical_readiness_identity_bytes, derive_policy,
|
||||
readiness_fingerprint, readiness_identity, validate_network_readiness_evidence,
|
||||
NetworkValidationErrorKind, ReadinessExpectation, accept_network_readiness,
|
||||
canonical_readiness_identity_bytes, derive_policy, readiness_fingerprint, readiness_identity,
|
||||
validate_network_readiness_evidence,
|
||||
};
|
||||
use lazaret_core::records::{
|
||||
AddressFamily, AddressFamilyDisposition, AddressFamilyDispositionValue, DefaultAction,
|
||||
DeniedDestinationObservation, DerivedNetworkPolicyFields, DnsObservation, IpAddress, IpNetwork,
|
||||
NetworkObservation, NetworkReachabilityProbe, NetworkReadinessAttestation,
|
||||
NetworkReadinessAttestationFields, PermittedDestinationObservation, PolicyAction,
|
||||
PolicyDelivery, PrefixRule, Resolver,
|
||||
DerivedNetworkPolicyFields, IpAddress, IpNetwork, NetworkCanaryObservation, NetworkObservation,
|
||||
NetworkReadinessAttestation, NetworkReadinessAttestationFields, PolicyAction, PolicyDelivery,
|
||||
PrefixRule, Resolver,
|
||||
};
|
||||
|
||||
type AttestationMutation = fn(&mut NetworkReadinessAttestation);
|
||||
type EvidenceMutation = fn(&mut lazaret_core::records::NetworkReadinessEvidence);
|
||||
type ProbeMutation = fn(&mut NetworkReachabilityProbe);
|
||||
type CanaryMutation = fn(&mut NetworkCanaryObservation);
|
||||
|
||||
fn repeated(value: u8) -> [u8; 32] {
|
||||
[value; 32]
|
||||
|
|
@ -107,8 +106,7 @@ struct Fixture {
|
|||
runtime_supervisor: PidfsProcessIdentityV1,
|
||||
connectivity_helper: PidfsProcessIdentityV1,
|
||||
attestation: NetworkReadinessAttestation,
|
||||
probe: NetworkReachabilityProbe,
|
||||
reachability: ReachabilityExpectation,
|
||||
canary: NetworkCanaryObservation,
|
||||
}
|
||||
|
||||
impl Fixture {
|
||||
|
|
@ -135,39 +133,34 @@ impl Fixture {
|
|||
routes_attested: true,
|
||||
},
|
||||
});
|
||||
let probe = NetworkReachabilityProbe {
|
||||
let canary = NetworkCanaryObservation {
|
||||
domain_id: DomainId::new(repeated(1)),
|
||||
generation_id: GenerationId::new(2),
|
||||
enforcement_namespace: namespace(),
|
||||
denied_destinations: vec![DeniedDestinationObservation {
|
||||
destination: IpAddress::V4([10, 1, 2, 3]),
|
||||
unreachable: true,
|
||||
}],
|
||||
permitted_destinations: vec![PermittedDestinationObservation {
|
||||
destination: IpAddress::V4([10, 20, 1, 2]),
|
||||
reachable: true,
|
||||
}],
|
||||
dns_observations: vec![DnsObservation {
|
||||
resolver: IpAddress::V4([192, 0, 2, 53]),
|
||||
query_name: "sandbox.invalid".into(),
|
||||
resolved_addresses: vec![IpAddress::V4([192, 0, 2, 10])],
|
||||
}],
|
||||
};
|
||||
let reachability = ReachabilityExpectation {
|
||||
denied_destinations: vec![IpAddress::V4([10, 1, 2, 3])],
|
||||
permitted_destinations: vec![IpAddress::V4([10, 20, 1, 2])],
|
||||
dns_queries: vec![DnsQueryExpectation {
|
||||
resolver: IpAddress::V4([192, 0, 2, 53]),
|
||||
query_name: "sandbox.invalid".into(),
|
||||
}],
|
||||
linux_policy_matches: true,
|
||||
endpoints_authenticated_before_policy: true,
|
||||
allowed_endpoint_authenticated: true,
|
||||
denied_endpoint_unreachable: true,
|
||||
imported_interface_matches: true,
|
||||
tap_present: true,
|
||||
ipv6_absent: true,
|
||||
network_capabilities_empty: true,
|
||||
route_mutation_refused: true,
|
||||
cleanup_shape_matched: true,
|
||||
responder_closed: true,
|
||||
peer_namespace_closed: true,
|
||||
host_interface_deleted: true,
|
||||
allowed_endpoint_unreachable_after_cleanup: true,
|
||||
tap_present_after_cleanup: true,
|
||||
ipv6_unchanged_after_cleanup: true,
|
||||
network_admin_dropped: true,
|
||||
};
|
||||
Self {
|
||||
policy,
|
||||
runtime_supervisor,
|
||||
connectivity_helper,
|
||||
attestation,
|
||||
probe,
|
||||
reachability,
|
||||
canary,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -188,8 +181,7 @@ impl Fixture {
|
|||
&self.policy,
|
||||
&self.expectation(),
|
||||
self.attestation.clone(),
|
||||
self.probe.clone(),
|
||||
&self.reachability,
|
||||
self.canary.clone(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
|
@ -344,8 +336,7 @@ fn every_attestation_identity_mismatch_is_refused() {
|
|||
&fixture.policy,
|
||||
&fixture.expectation(),
|
||||
attestation,
|
||||
fixture.probe.clone(),
|
||||
&fixture.reachability,
|
||||
fixture.canary.clone(),
|
||||
)
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
|
|
@ -392,13 +383,13 @@ fn every_evidence_identity_mismatch_is_refused() {
|
|||
value.readiness_fingerprint = ReadinessFingerprint::new(repeated(90));
|
||||
}),
|
||||
("probe domain", |value| {
|
||||
value.reachability_probe.domain_id = DomainId::new(repeated(91));
|
||||
value.canary_observation.domain_id = DomainId::new(repeated(91));
|
||||
}),
|
||||
("probe generation", |value| {
|
||||
value.reachability_probe.generation_id = GenerationId::new(92);
|
||||
value.canary_observation.generation_id = GenerationId::new(92);
|
||||
}),
|
||||
("probe namespace", |value| {
|
||||
value.reachability_probe.enforcement_namespace.inode = InodeId::new(93);
|
||||
value.canary_observation.enforcement_namespace.inode = InodeId::new(93);
|
||||
}),
|
||||
];
|
||||
for (name, mutate) in mutations {
|
||||
|
|
@ -409,7 +400,6 @@ fn every_evidence_identity_mismatch_is_refused() {
|
|||
&fixture.policy,
|
||||
&fixture.expectation(),
|
||||
&evidence,
|
||||
&fixture.reachability,
|
||||
)
|
||||
.is_err(),
|
||||
"accepted {name}"
|
||||
|
|
@ -418,34 +408,35 @@ fn every_evidence_identity_mismatch_is_refused() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn incomplete_or_failed_reachability_is_refused() {
|
||||
fn incomplete_or_failed_canary_is_refused() {
|
||||
let fixture = Fixture::new();
|
||||
let mutations: [(&str, ProbeMutation); 6] = [
|
||||
let mutations: [(&str, CanaryMutation); 6] = [
|
||||
("deny reached", |value| {
|
||||
value.denied_destinations[0].unreachable = false;
|
||||
value.denied_endpoint_unreachable = false;
|
||||
}),
|
||||
("permit unreachable", |value| {
|
||||
value.permitted_destinations[0].reachable = false;
|
||||
value.allowed_endpoint_authenticated = false;
|
||||
}),
|
||||
("missing deny", |value| value.denied_destinations.clear()),
|
||||
("missing permit", |value| {
|
||||
value.permitted_destinations.clear();
|
||||
("policy mismatch", |value| {
|
||||
value.linux_policy_matches = false;
|
||||
}),
|
||||
("missing DNS", |value| value.dns_observations.clear()),
|
||||
("empty DNS result", |value| {
|
||||
value.dns_observations[0].resolved_addresses.clear();
|
||||
("cleanup mismatch", |value| {
|
||||
value.cleanup_shape_matched = false;
|
||||
}),
|
||||
("capability retained", |value| {
|
||||
value.network_admin_dropped = false;
|
||||
}),
|
||||
("IPv6 present", |value| value.ipv6_absent = false),
|
||||
];
|
||||
for (name, mutate) in mutations {
|
||||
let mut probe = fixture.probe.clone();
|
||||
mutate(&mut probe);
|
||||
let mut canary = fixture.canary.clone();
|
||||
mutate(&mut canary);
|
||||
assert!(
|
||||
accept_network_readiness(
|
||||
&fixture.policy,
|
||||
&fixture.expectation(),
|
||||
fixture.attestation.clone(),
|
||||
probe,
|
||||
&fixture.reachability,
|
||||
canary,
|
||||
)
|
||||
.is_err(),
|
||||
"accepted {name}"
|
||||
|
|
@ -475,8 +466,7 @@ fn incomplete_or_malformed_attestation_is_refused() {
|
|||
&fixture.policy,
|
||||
&fixture.expectation(),
|
||||
attestation,
|
||||
fixture.probe.clone(),
|
||||
&fixture.reachability,
|
||||
fixture.canary.clone(),
|
||||
)
|
||||
.is_err(),
|
||||
"accepted {name}"
|
||||
|
|
|
|||
Loading…
Reference in a new issue