Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

peer-pods: pass policy hash via userdata #941

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
From 797a113c80c9fd3dfbd4d7b153d3de245c97044f Mon Sep 17 00:00:00 2001
From: Markus Rudy <[email protected]>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intentionally use a different e-mail address?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unintentional, that's my default and apparently I did not change it for CAA.

Date: Wed, 16 Oct 2024 16:12:19 +0200
Subject: [PATCH] measure agent-config.toml into PCR 10

---
src/cloud-api-adaptor/go.mod | 5 +++-
src/cloud-api-adaptor/go.sum | 2 ++
.../pkg/userdata/provision.go | 27 ++++++++++++++++++-
3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/src/cloud-api-adaptor/go.mod b/src/cloud-api-adaptor/go.mod
index bd419f6..011870a 100644
--- a/src/cloud-api-adaptor/go.mod
+++ b/src/cloud-api-adaptor/go.mod
@@ -1,6 +1,8 @@
module github.com/confidential-containers/cloud-api-adaptor/src/cloud-api-adaptor

-go 1.21
+go 1.22
+
+toolchain go1.23.2

require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1
@@ -52,6 +54,7 @@ require (
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
github.com/docker/docker v25.0.5+incompatible
github.com/golang-jwt/jwt/v5 v5.2.1
+ github.com/google/go-tpm v0.9.1
github.com/moby/sys/mountinfo v0.7.1
github.com/pelletier/go-toml/v2 v2.1.0
github.com/sirupsen/logrus v1.9.3
diff --git a/src/cloud-api-adaptor/go.sum b/src/cloud-api-adaptor/go.sum
index 0dd05c2..1ffa1f8 100644
--- a/src/cloud-api-adaptor/go.sum
+++ b/src/cloud-api-adaptor/go.sum
@@ -322,6 +322,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-tpm v0.9.1 h1:0pGc4X//bAlmZzMKf8iz6IsDo1nYTbYJ6FZN/rg4zdM=
+github.com/google/go-tpm v0.9.1/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
diff --git a/src/cloud-api-adaptor/pkg/userdata/provision.go b/src/cloud-api-adaptor/pkg/userdata/provision.go
index 5c3b6ca..222d509 100644
--- a/src/cloud-api-adaptor/pkg/userdata/provision.go
+++ b/src/cloud-api-adaptor/pkg/userdata/provision.go
@@ -2,6 +2,7 @@ package userdata

import (
"context"
+ "crypto/sha256"
"fmt"
"log"
"os"
@@ -12,6 +13,8 @@ import (
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-providers/aws"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-providers/azure"
"github.com/confidential-containers/cloud-api-adaptor/src/cloud-providers/docker"
+ "github.com/google/go-tpm/legacy/tpm2"
+ "github.com/google/go-tpm/tpmutil"
"gopkg.in/yaml.v2"
)

@@ -162,6 +165,7 @@ func findConfigEntry(path string, cc *CloudConfig) []byte {
type entry struct {
path string
optional bool
+ pcrIndex *int
}

func (f *entry) writeFile(cc *CloudConfig) error {
@@ -179,6 +183,10 @@ func (f *entry) writeFile(cc *CloudConfig) error {
return fmt.Errorf("failed to create directory: %w", err)
}

+ if f.pcrIndex != nil {
+ extendPCR(*f.pcrIndex, bytes)
+ }
+
err = os.WriteFile(f.path, bytes, 0644)
if err != nil {
return fmt.Errorf("failed to write file: %w", err)
@@ -189,7 +197,7 @@ func (f *entry) writeFile(cc *CloudConfig) error {

func processCloudConfig(cfg *Config, cc *CloudConfig) error {
entries := []entry{
- {path: cfg.paths.agentConfig, optional: false},
+ {path: cfg.paths.agentConfig, optional: false, pcrIndex: toPtr(10)},
{path: cfg.paths.daemonConfig, optional: false},
{path: cfg.paths.aaConfig, optional: true},
{path: cfg.paths.cdhConfig, optional: true},
Comment on lines +91 to +95
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered measuring the other files as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not using the three optional files (maybe we should even remove them), and the daemonConfig contains unpredictable network stuff (e.g. k8s node IP) - see PR description.

@@ -228,3 +236,20 @@ func ProvisionFiles(cfg *Config) error {

return nil
}
+
+func extendPCR(pcrIndex int, data []byte) error {
+ digest := sha256.Sum256(data)
+
+ handle, err := tpm2.OpenTPM()
+ if err != nil {
+ return fmt.Errorf("opening TPM device: %w", err)
+ }
+ if err := tpm2.PCRExtend(handle, tpmutil.Handle(pcrIndex), tpm2.AlgSHA256, digest[:], ""); err != nil {
+ return fmt.Errorf("extending PCR %d: %w", pcrIndex, err)
+ }
+ return nil
+}
+
+func toPtr[A any](a A) *A {
+ return &a
+}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
From 9bb45bab97264a15e36a4b9b9cd06531852d23af Mon Sep 17 00:00:00 2001
From: Markus Rudy <[email protected]>
Date: Thu, 17 Oct 2024 10:20:09 +0200
Subject: [PATCH] set policy digest in agent config

---
src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go | 2 +-
src/cloud-api-adaptor/pkg/agent/config.go | 10 +++++++++-
src/cloud-api-adaptor/pkg/util/cloud.go | 9 +++++++++
3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go b/src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go
index 5a3ab96..0a83683 100644
--- a/src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go
+++ b/src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go
@@ -239,7 +239,7 @@ func (s *cloudService) CreateVM(ctx context.Context, req *pb.CreateVMRequest) (r
logger.Printf("configure agent to use credentials file %s", SrcAuthfilePath)
}

- agentConfig, err := agent.CreateConfigFile(authFilePath)
+ agentConfig, err := agent.CreateConfigFile(authFilePath, util.GetPolicyFromAnnotation(req.Annotations))
if err != nil {
return nil, fmt.Errorf("creating agent config: %w", err)
}
diff --git a/src/cloud-api-adaptor/pkg/agent/config.go b/src/cloud-api-adaptor/pkg/agent/config.go
index 58bcc83..c0d5b58 100644
--- a/src/cloud-api-adaptor/pkg/agent/config.go
+++ b/src/cloud-api-adaptor/pkg/agent/config.go
@@ -1,6 +1,9 @@
package agent

import (
+ "crypto/sha256"
+ "encoding/hex"
+
"github.com/pelletier/go-toml/v2"
)

@@ -13,10 +16,11 @@ const (
type agentConfig struct {
ServerAddr string `toml:"server_addr"`
GuestComponentsProcs string `toml:"guest_components_procs"`
+ PolicySHA256Hex string `toml:"policy_digest_sha256_hex,omitempty"`
ImageRegistryAuth string `toml:"image_registry_auth,omitempty"`
}

-func CreateConfigFile(authJsonPath string) (string, error) {
+func CreateConfigFile(authJsonPath string, policy []byte) (string, error) {
var imageRegistryAuth string
if authJsonPath != "" {
imageRegistryAuth = "file://" + authJsonPath
@@ -27,6 +31,10 @@ func CreateConfigFile(authJsonPath string) (string, error) {
GuestComponentsProcs: GuestComponentsProcs,
ImageRegistryAuth: imageRegistryAuth,
}
+ if policy != nil {
+ digest := sha256.Sum256(policy)
+ config.PolicySHA256Hex = hex.EncodeToString(digest[:])
+ }

bytes, err := toml.Marshal(config)
if err != nil {
diff --git a/src/cloud-api-adaptor/pkg/util/cloud.go b/src/cloud-api-adaptor/pkg/util/cloud.go
index b2ba396..e317495 100644
--- a/src/cloud-api-adaptor/pkg/util/cloud.go
+++ b/src/cloud-api-adaptor/pkg/util/cloud.go
@@ -69,6 +69,15 @@ func GetCPUAndMemoryFromAnnotation(annotations map[string]string) (int64, int64)
return vcpuInt, memoryInt
}

+func GetPolicyFromAnnotation(annotations map[string]string) []byte {
+ // The policy is already base64-decoded in this annotation map.
+ policy, ok := annotations[hypannotations.Policy]
+ if !ok {
+ return nil
+ }
+ return []byte(policy)
+}
+
// Method to check if a string exists in a slice
func Contains(slice []string, s string) bool {
for _, item := range slice {
9 changes: 8 additions & 1 deletion packages/by-name/cloud-api-adaptor/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,17 @@ buildGoModule rec {
hash = "sha256-5tDG0sEiRAsb259lPui5ntR6DVHDdcXhb04UESJzHhE=";
};

patches = [
./0001-measure-agent-config.toml-into-PCR-10.patch
./0002-set-policy-digest-in-agent-config.patch
];

patchFlags = [ "-p3" ];

sourceRoot = "${src.name}/src/cloud-api-adaptor";

proxyVendor = true;
vendorHash = "sha256-kqzi7jRF3tQ4/yLkJXfZly4EvVKFb400/WXlN0WjYm8=";
vendorHash = "sha256-6FWMh2G5yM0QnhpfLS+fRfP6bpPtuGCeCvCNutog3YU=";

nativeBuildInputs = lib.optional withLibvirt pkg-config;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
From e8ad46895101639c1b7af8ff57b4e65d35040cc1 Mon Sep 17 00:00:00 2001
From: Markus Rudy <[email protected]>
Date: Thu, 17 Oct 2024 09:38:35 +0200
Subject: [PATCH] agent: read policy hash from config

---
src/agent/Cargo.lock | 4 ++++
src/agent/Cargo.toml | 1 +
src/agent/src/config.rs | 4 ++++
src/agent/src/policy.rs | 5 ++++-
4 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/agent/Cargo.lock b/src/agent/Cargo.lock
index 6c9342ddb..1bfc716d3 100644
--- a/src/agent/Cargo.lock
+++ b/src/agent/Cargo.lock
@@ -2818,6 +2818,7 @@ dependencies = [
"const_format",
"derivative",
"futures",
+ "hex",
"image-rs",
"ipnetwork",
"kata-sys-util",
@@ -6439,6 +6440,9 @@ name = "uuid"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
+dependencies = [
+ "serde",
+]

[[package]]
name = "valuable"
diff --git a/src/agent/Cargo.toml b/src/agent/Cargo.toml
index d5b3db965..44612495a 100644
--- a/src/agent/Cargo.toml
+++ b/src/agent/Cargo.toml
@@ -89,6 +89,7 @@ regorus = { version = "0.1.4", default-features = false, features = [
sha2 = { version = "0.10.6", optional = true }
sev = { version = "2.0.2", default-features = false, features = ["snp"], optional = true }
vmm-sys-util = { version = "0.11.0", optional = true }
+hex = "0.4.3"

[dev-dependencies]
tempfile = "3.1.0"
diff --git a/src/agent/src/config.rs b/src/agent/src/config.rs
index a83328440..79fb3037b 100644
--- a/src/agent/src/config.rs
+++ b/src/agent/src/config.rs
@@ -131,6 +131,8 @@ pub struct AgentConfig {
pub image_policy_file: String,
#[cfg(feature = "agent-policy")]
pub policy_file: String,
+ #[cfg(feature = "agent-policy")]
+ pub policy_digest_sha256_hex: String,
}

#[derive(Debug, Deserialize)]
@@ -235,6 +237,8 @@ impl Default for AgentConfig {
image_policy_file: String::from(""),
#[cfg(feature = "agent-policy")]
policy_file: String::from(""),
+ #[cfg(feature = "agent-policy")]
+ policy_digest_sha256_hex: String::from(""),
}
}
}
diff --git a/src/agent/src/policy.rs b/src/agent/src/policy.rs
index 2f1da9ecd..840385fc3 100644
--- a/src/agent/src/policy.rs
+++ b/src/agent/src/policy.rs
@@ -198,7 +198,10 @@ impl AgentPolicy {
}

fn verify_policy_digest(policy: &str) -> Result<()> {
- if let Ok(expected_digest) = get_tdx_mrconfigid() {
+ if !AGENT_CONFIG.policy_digest_sha256_hex.is_empty() {
+ let expected_digest = hex::decode(&AGENT_CONFIG.policy_digest_sha256_hex)?;
+ verify_sha_256(policy, expected_digest.as_slice())
+ } else if let Ok(expected_digest) = get_tdx_mrconfigid() {
info!(sl!(), "policy: TDX MrConfigId ({:?})", expected_digest);

// The MrConfigId used with TDX is longer than the host-data field used
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
From 9128834634ffb1c153eaa243d584b9d21dfcc1a8 Mon Sep 17 00:00:00 2001
From: Markus Rudy <[email protected]>
Date: Fri, 18 Oct 2024 09:58:47 +0200
Subject: [PATCH] runtime: forward policy to remote hypervisor

---
src/runtime/virtcontainers/remote.go | 1 +
1 file changed, 1 insertion(+)

diff --git a/src/runtime/virtcontainers/remote.go b/src/runtime/virtcontainers/remote.go
index 047f09fe8..e95763e44 100644
--- a/src/runtime/virtcontainers/remote.go
+++ b/src/runtime/virtcontainers/remote.go
@@ -81,6 +81,7 @@ func (rh *remoteHypervisor) CreateVM(ctx context.Context, id string, network Net
annotations[hypannotations.DefaultVCPUs] = strconv.FormatUint(uint64(hypervisorConfig.NumVCPUs()), 10)
annotations[hypannotations.DefaultMemory] = strconv.FormatUint(uint64(hypervisorConfig.MemorySize), 10)
annotations[hypannotations.Initdata] = hypervisorConfig.Initdata
+ annotations[hypannotations.Policy] = hypervisorConfig.AgentPolicy

req := &pb.CreateVMRequest{
Id: id,
3 changes: 3 additions & 0 deletions packages/by-name/kata/kata-runtime/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ buildGoModule rec {
# The patch is not sufficient for upstream, because it requires the extraRootFs content from
# our Nix packaging.
./0014-tools-don-t-clean-build-root-when-generating-rootfs.patch

./0015-agent-read-policy-hash-from-config.patch
./0016-runtime-forward-policy-to-remote-hypervisor.patch
];
};

Expand Down