diff --git a/src/agent/Cargo.lock b/src/agent/Cargo.lock index da5b5000f1ed..28245bf9639a 100644 --- a/src/agent/Cargo.lock +++ b/src/agent/Cargo.lock @@ -2100,6 +2100,7 @@ dependencies = [ "devicemapper", "futures", "h2", + "hex", "http", "image-rs", "ipnetwork", @@ -2129,6 +2130,7 @@ dependencies = [ "serde", "serde_json", "serial_test", + "sha2 0.10.6", "simple_asn1", "slog", "slog-scope", diff --git a/src/agent/Cargo.toml b/src/agent/Cargo.toml index e78b28f46a91..32e7972d8f76 100644 --- a/src/agent/Cargo.toml +++ b/src/agent/Cargo.toml @@ -83,6 +83,10 @@ openssl = { version = "0.10.54", features = ["vendored"], optional = true } # Image pull/decrypt image-rs = { git = "https://github.com/confidential-containers/image-rs", tag = "v0.6.0", default-features = false, features = ["kata-cc-native-tls"] } +# Policy validation +sha2 = { version = "0.10.6", optional = true } +hex = { version = "0.4.2", optional = true } + [patch.crates-io] oci-distribution = { git = "https://github.com/krustlet/oci-distribution.git", rev = "f44124c" } @@ -103,7 +107,7 @@ lto = true [features] seccomp = ["rustjail/seccomp"] standard-oci-runtime = ["rustjail/standard-oci-runtime"] -agent-policy = ["http", "openssl", "reqwest"] +agent-policy = ["hex", "http", "openssl", "reqwest", "sha2"] [[bin]] name = "kata-agent" diff --git a/src/agent/src/policy.rs b/src/agent/src/policy.rs index 0202510240fc..91437736c4e0 100644 --- a/src/agent/src/policy.rs +++ b/src/agent/src/policy.rs @@ -4,6 +4,7 @@ // use anyhow::{bail, Result}; +use sha2::{Sha256, Digest}; use serde::{Deserialize, Serialize}; use slog::Drain; use tokio::io::AsyncWriteExt; @@ -144,6 +145,8 @@ impl AgentPolicy { /// Replace the Policy in OPA. pub async fn set_policy(&mut self, policy: &str) -> Result<()> { + check_policy_hash(policy)?; + if let Some(opa_client) = &mut self.opa_client { // Delete the old rules. opa_client.delete(&self.policy_path).send().await?; @@ -265,3 +268,13 @@ fn start_opa(opa_addr: &str) -> Result<()> { } bail!("OPA binary not found in {:?}", &bin_dirs); } + +pub fn check_policy_hash(policy: &str) -> Result<()> { + let mut hasher = Sha256::new(); + hasher.update(policy.as_bytes()); + let digest = hasher.finalize(); + debug!(sl!(), "New policy hash: {}", hex::encode(digest)); + + // TODO: check that the corresponding TEE field matches this hash. + Ok(()) +} diff --git a/src/runtime/virtcontainers/clh.go b/src/runtime/virtcontainers/clh.go index 0fa88272cdff..31853a8a3cbe 100644 --- a/src/runtime/virtcontainers/clh.go +++ b/src/runtime/virtcontainers/clh.go @@ -83,7 +83,7 @@ const ( clhAPISocket = "clh-api.sock" virtioFsSocket = "virtiofsd.sock" defaultClhPath = "/usr/local/bin/cloud-hypervisor" - snpHostDataDummy = "0123456789012345678901234567890123456789012345678901234567890123" + snpZeroHostData = "0000000000000000000000000000000000000000000000000000000000000000" ) // Interface that hides the implementation of openAPI client @@ -450,7 +450,11 @@ func (clh *cloudHypervisor) enableProtection() error { } clh.vmconfig.Platform.SetSnp(true) - clh.vmconfig.Payload.SetHostData(snpHostDataDummy) + if len(clh.config.PolicyHash) > 0 { + clh.vmconfig.Payload.SetHostData(clh.config.PolicyHash) + } else { + clh.vmconfig.Payload.SetHostData(snpZeroHostData) + } return nil diff --git a/src/runtime/virtcontainers/hypervisor.go b/src/runtime/virtcontainers/hypervisor.go index 47b6805d8f77..dc39a363d418 100644 --- a/src/runtime/virtcontainers/hypervisor.go +++ b/src/runtime/virtcontainers/hypervisor.go @@ -422,6 +422,7 @@ type HypervisorConfig struct { DisableGuestSeLinux bool LegacySerial bool ColdPlugVFIO hv.PCIePort + PolicyHash string } // vcpu mapping from vcpu number to thread number diff --git a/src/runtime/virtcontainers/sandbox.go b/src/runtime/virtcontainers/sandbox.go index 1d3b729ff5b1..0b0591f90638 100644 --- a/src/runtime/virtcontainers/sandbox.go +++ b/src/runtime/virtcontainers/sandbox.go @@ -10,6 +10,8 @@ import ( "bufio" "bytes" "context" + "crypto/sha256" + "encoding/hex" "fmt" "io" "math" @@ -647,6 +649,8 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor } } + sandboxConfig.HypervisorConfig.PolicyHash = getAgentPolicyHash(sandboxConfig.AgentConfig.Policy) + // store doesn't require hypervisor to be stored immediately if err = s.hypervisor.CreateVM(ctx, s.id, s.network, &sandboxConfig.HypervisorConfig); err != nil { return nil, err @@ -2702,3 +2706,13 @@ func (s *Sandbox) resetVCPUsPinning(ctx context.Context, vCPUThreadsMap VcpuThre func (s *Sandbox) PullImage(ctx context.Context, req *image.PullImageReq) (*image.PullImageResp, error) { return s.agent.PullImage(ctx, req) } + +func getAgentPolicyHash(policy string) string { + if len(policy) == 0 { + return "" + } else { + h := sha256.New() + h.Write([]byte(policy)) + return hex.EncodeToString(h.Sum(nil)) + } +}