From 4a0ce5fa6807569155e248be209d258f42fbdff5 Mon Sep 17 00:00:00 2001 From: Dan Mihai Date: Fri, 11 Aug 2023 01:03:00 +0000 Subject: [PATCH 1/5] runtime: add policy hash in HypervisorConfig Add the hash of the agent policy in the HypervisorConfig. For confidential containers, the hypervisor might need to attach that information to the Guest VM - useful for remote attestation, to establish trust in the policy. Signed-off-by: Dan Mihai --- src/runtime/virtcontainers/hypervisor.go | 1 + src/runtime/virtcontainers/sandbox.go | 15 +++++++++++++++ 2 files changed, 16 insertions(+) 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..93f511e649cb 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,10 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor } } + if sandboxConfig.HypervisorConfig.PolicyHash, err = getAgentPolicyHash(sandboxConfig.AgentConfig.Policy); err != nil { + return nil, err + } + // 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 +2708,12 @@ 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, error) { + if len(policy) == 0 { + return "", nil + } + h := sha256.New() + h.Write([]byte(policy)) + return hex.EncodeToString(h.Sum(nil)), nil +} From d83c163f4e4c675e38352a473a07d7a14107a9e0 Mon Sep 17 00:00:00 2001 From: Dan Mihai Date: Fri, 11 Aug 2023 16:08:17 +0000 Subject: [PATCH 2/5] runtime: minor policy hash clean-up Signed-off-by: Dan Mihai --- src/runtime/virtcontainers/sandbox.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/runtime/virtcontainers/sandbox.go b/src/runtime/virtcontainers/sandbox.go index 93f511e649cb..0b0591f90638 100644 --- a/src/runtime/virtcontainers/sandbox.go +++ b/src/runtime/virtcontainers/sandbox.go @@ -649,9 +649,7 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor } } - if sandboxConfig.HypervisorConfig.PolicyHash, err = getAgentPolicyHash(sandboxConfig.AgentConfig.Policy); err != nil { - return nil, err - } + 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 { @@ -2709,11 +2707,12 @@ func (s *Sandbox) PullImage(ctx context.Context, req *image.PullImageReq) (*imag return s.agent.PullImage(ctx, req) } -func getAgentPolicyHash(policy string) (string, error) { +func getAgentPolicyHash(policy string) string { if len(policy) == 0 { - return "", nil + return "" + } else { + h := sha256.New() + h.Write([]byte(policy)) + return hex.EncodeToString(h.Sum(nil)) } - h := sha256.New() - h.Write([]byte(policy)) - return hex.EncodeToString(h.Sum(nil)), nil } From ed712f00fee55f79de3a96516861dee3dc4c0f6e Mon Sep 17 00:00:00 2001 From: Dan Mihai Date: Fri, 11 Aug 2023 17:38:12 +0000 Subject: [PATCH 3/5] agent: compute hash for new policy documents Signed-off-by: Dan Mihai --- src/agent/Cargo.lock | 3 ++- src/agent/Cargo.toml | 15 +++++++++------ src/agent/src/policy.rs | 13 +++++++++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/agent/Cargo.lock b/src/agent/Cargo.lock index dbcade0aeab1..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", @@ -2114,7 +2115,6 @@ dependencies = [ "nix 0.24.3", "oci", "openssl", - "openssl-src", "opentelemetry", "proc-mounts", "procfs 0.12.0", @@ -2130,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 331c3728c0e2..3bac85e08029 100644 --- a/src/agent/Cargo.toml +++ b/src/agent/Cargo.toml @@ -74,17 +74,20 @@ serde = { version = "1.0.129", features = ["derive"] } toml = "0.5.8" clap = { version = "3.0.1", features = ["derive"] } -# "vendored" feature for openssl is required by musl build -openssl = "0.10.54" -openssl-src = "111.26.0" # OPA requests -http = "0.2.8" -reqwest = { version = "0.11.14" } +http = { version = "0.2.8", optional = true } +reqwest = { version = "0.11.14", optional = true } +# "vendored" feature for openssl is required by musl build +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" } @@ -105,7 +108,7 @@ lto = true [features] seccomp = ["rustjail/seccomp"] standard-oci-runtime = ["rustjail/standard-oci-runtime"] -security-policy = [] +security-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 a0d8805255c6..f1a71144d14f 100644 --- a/src/agent/src/policy.rs +++ b/src/agent/src/policy.rs @@ -5,6 +5,7 @@ use anyhow::{anyhow, Result}; use reqwest::Client; +use sha2::{Sha256, Digest}; use serde::{Deserialize, Serialize}; use tokio::io::AsyncWriteExt; use tokio::time::{sleep, Duration}; @@ -106,6 +107,8 @@ impl AgentPolicy { /// Replace the Policy in OPA. pub async fn set_policy(&mut self, policy: &str) -> Result<()> { + check_policy_hash(policy)?; + // Delete the old rules. self.opa_client .delete(&self.policy_path) @@ -195,3 +198,13 @@ impl AgentPolicy { } } } + +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(()) +} From 827b7a3a4a1af15bb340342627cea0c3aceb4bf3 Mon Sep 17 00:00:00 2001 From: Dan Mihai Date: Wed, 23 Aug 2023 00:11:45 +0000 Subject: [PATCH 4/5] runtime: set the policy hash in SNP HOST_DATA Set the value of the policy hash in the SNP HOST_DATA field of the Guest VM. Signed-off-by: Dan Mihai --- src/runtime/virtcontainers/clh.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 From b827d3abbfe85b51deaec5988a3c5af560f724fa Mon Sep 17 00:00:00 2001 From: Dan Mihai Date: Wed, 23 Aug 2023 00:15:21 +0000 Subject: [PATCH 5/5] agent: fix incorrect merge Signed-off-by: Dan Mihai --- src/agent/Cargo.toml | 6 +----- src/agent/src/policy.rs | 13 +++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/agent/Cargo.toml b/src/agent/Cargo.toml index 7a0a2f05640b..32e7972d8f76 100644 --- a/src/agent/Cargo.toml +++ b/src/agent/Cargo.toml @@ -107,11 +107,7 @@ lto = true [features] seccomp = ["rustjail/seccomp"] standard-oci-runtime = ["rustjail/standard-oci-runtime"] -<<<<<<< HEAD -security-policy = ["hex", "http", "openssl", "reqwest", "sha2"] -======= -agent-policy = ["http", "openssl", "reqwest"] ->>>>>>> cc-msft-prototypes +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(()) +}