mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-11-02 08:04:37 +08:00
fix(mxc): reject expiring credential snapshots
Fail sandbox creation for expiring static provider credentials because MXC has no live refresh channel, while retaining request-time dynamic token grants and documenting recreation requirements. Signed-off-by: Akber Raza <akberr@nvidia.com>
This commit is contained in:
@@ -109,6 +109,8 @@ activity, and correlation-vector links remain available for five seconds so
|
||||
already in-flight ETW records can arrive, but retired PID evidence cannot resolve
|
||||
them. Records without matching generation evidence remain unattributed.
|
||||
|
||||
The MXC credential handoff is also fixed at sandbox creation. The gateway rejects expiring static provider credentials because the in-process MXC driver has no live credential-refresh channel. Dynamic token grants remain request-time operations in the host proxy. Recreate the sandbox after rotating or revoking a non-expiring static credential.
|
||||
|
||||
## Prerequisites (live runs)
|
||||
|
||||
- Windows 11 Insider build ≥ 26300.8553
|
||||
|
||||
@@ -3340,6 +3340,7 @@ pub(super) async fn resolve_sandbox_create_runtime_inputs(
|
||||
provider_environment.credential_expires_at_ms.remove(&key);
|
||||
provider_environment.static_credential_keys.remove(&key);
|
||||
}
|
||||
validate_create_time_provider_credential_lifetimes(sandbox_id, &provider_environment)?;
|
||||
|
||||
let provider_credentials = if provider_records.is_empty() {
|
||||
None
|
||||
@@ -3373,6 +3374,33 @@ pub(super) async fn resolve_sandbox_create_runtime_inputs(
|
||||
))
|
||||
}
|
||||
|
||||
fn validate_create_time_provider_credential_lifetimes(
|
||||
sandbox_id: &str,
|
||||
provider_environment: &super::provider::ProviderEnvironment,
|
||||
) -> Result<(), Status> {
|
||||
let mut expiring_static_keys = provider_environment
|
||||
.static_credential_keys
|
||||
.iter()
|
||||
.filter(|key| {
|
||||
provider_environment
|
||||
.credential_expires_at_ms
|
||||
.get(*key)
|
||||
.is_some_and(|expires_at_ms| *expires_at_ms > 0)
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
expiring_static_keys.sort();
|
||||
|
||||
if expiring_static_keys.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Status::failed_precondition(format!(
|
||||
"compute driver cannot refresh expiring provider credentials for running sandbox '{sandbox_id}'; recreate the sandbox with non-expiring credentials (expiring keys: {})",
|
||||
expiring_static_keys.join(", ")
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn handle_get_sandbox_provider_environment(
|
||||
state: &Arc<ServerState>,
|
||||
request: Request<GetSandboxProviderEnvironmentRequest>,
|
||||
@@ -7417,6 +7445,7 @@ mod tests {
|
||||
use crate::auth::principal::{
|
||||
Principal, SandboxIdentitySource, SandboxPrincipal, UserPrincipal,
|
||||
};
|
||||
use crate::grpc::provider::ProviderEnvironment;
|
||||
use crate::grpc::test_support::{authed_request, test_server_state};
|
||||
use crate::persistence::test_store;
|
||||
use std::collections::HashMap;
|
||||
@@ -11767,6 +11796,41 @@ mod tests {
|
||||
assert_eq!(v2_env.get("GITHUB_TOKEN"), Some(&"ghp-test".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_time_provider_credentials_reject_expiring_static_values() {
|
||||
let provider_environment = ProviderEnvironment {
|
||||
credential_expires_at_ms: HashMap::from([
|
||||
("B_TOKEN".to_string(), 20_000),
|
||||
("A_TOKEN".to_string(), 10_000),
|
||||
("NON_SECRET".to_string(), 30_000),
|
||||
]),
|
||||
static_credential_keys: HashSet::from(["A_TOKEN".to_string(), "B_TOKEN".to_string()]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let error = validate_create_time_provider_credential_lifetimes(
|
||||
"sandbox-expiring",
|
||||
&provider_environment,
|
||||
)
|
||||
.expect_err("expiring static credentials must fail closed");
|
||||
|
||||
assert_eq!(error.code(), Code::FailedPrecondition);
|
||||
assert!(error.message().contains("A_TOKEN, B_TOKEN"));
|
||||
assert!(!error.message().contains("NON_SECRET"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_time_provider_credentials_allow_non_expiring_static_values() {
|
||||
let provider_environment = ProviderEnvironment {
|
||||
credential_expires_at_ms: HashMap::from([("STATIC_TOKEN".to_string(), 0)]),
|
||||
static_credential_keys: HashSet::from(["STATIC_TOKEN".to_string()]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
validate_create_time_provider_credential_lifetimes("sandbox-static", &provider_environment)
|
||||
.expect("non-expiring static credentials are supported");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn provider_environment_withholds_static_credentials_from_legacy_supervisors() {
|
||||
use openshell_core::proto::GetSandboxProviderEnvironmentRequest;
|
||||
|
||||
@@ -914,7 +914,7 @@ OpenShell sends no override and Podman applies its runtime-selected profile.
|
||||
Set `Unconfined` explicitly only when the deployment requires the supervisor's
|
||||
mount setup to bypass that profile.
|
||||
|
||||
Attached provider credentials require this governed-egress path. The gateway gives MXC only revision-scoped environment placeholders and keeps real values in the host proxy's endpoint-bound resolver. Provider keys override matching `agent_env` entries case-insensitively. Sandbox creation fails when attached provider material exists but `egress_proxy` is disabled. MXC takes its provider snapshot at creation; recreate the sandbox after attaching, detaching, or rotating a provider.
|
||||
Attached provider credentials require this governed-egress path. The gateway gives MXC only revision-scoped environment placeholders and keeps real values in the host proxy's endpoint-bound resolver. Provider keys override matching sandbox environment entries case-insensitively. Sandbox creation fails when attached provider material exists but `egress_proxy` is disabled. MXC takes its static provider snapshot at creation and rejects credentials with an expiration timestamp because it has no live refresh channel. Dynamic token grants continue to mint credentials per request in the host proxy. Recreate the sandbox after attaching, detaching, rotating, or revoking a non-expiring static provider credential.
|
||||
|
||||
### MicroVM
|
||||
|
||||
|
||||
Reference in New Issue
Block a user