Skip to content
Merged
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
1,458 changes: 1,330 additions & 128 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
[workspace]
members = ["crds", "operator", "manifest-gen"]
members = ["compute-pcrs", "crds", "operator", "manifest-gen"]
resolver = "3"

[workspace.package]
edition = "2024"

[workspace.dependencies]
anyhow = "1.0.99"
clap = "4.5.41"
env_logger = "0.11.8"
k8s-openapi = { version = "0.25.0", features = ["v1_33"] }
kube = "1.1.0"
log = "0.4.27"
serde = "1.0.219"
serde_json = "1.0.141"
tokio = "1.46.1"
18 changes: 12 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
KUBECTL=kubectl

REGISTRY ?= quay.io
IMAGE=$(REGISTRY)/confidential-clusters/cocl-operator:latest
OPERATOR_IMAGE=$(REGISTRY)/confidential-clusters/cocl-operator:latest
COMPUTE_PCRS_IMAGE=$(REGISTRY)/confidential-clusters/compute-pcrs:latest

all: build tools

Expand All @@ -19,8 +20,9 @@ manifests-dir:

manifests: tools
target/debug/manifest-gen --output-dir manifests \
--image $(IMAGE) \
--trustee-namespace operators
--image $(OPERATOR_IMAGE) \
--trustee-namespace operators \
--pcrs-compute-image $(COMPUTE_PCRS_IMAGE)

cluster-up:
scripts/create-cluster-kind.sh
Expand All @@ -29,17 +31,21 @@ cluster-down:
scripts/delete-cluster-kind.sh

image: build
podman build -t $(IMAGE) -f Containerfile .
podman build -t $(OPERATOR_IMAGE) -f Containerfile .
podman build -t $(COMPUTE_PCRS_IMAGE) \
-f compute-pcrs/Containerfile \
--env K8S_OPENAPI_ENABLED_VERSION=$(K8S_VERSION) .

# TODO: remove the tls-verify, right now we are pushing only on the local registry
push: image
podman push $(IMAGE) --tls-verify=false
podman push $(OPERATOR_IMAGE) --tls-verify=false
podman push $(COMPUTE_PCRS_IMAGE) --tls-verify=false

install-trustee:
scripts/install-trustee.sh

install:
scripts/clean-cluster-kind.sh $(IMAGE)
scripts/clean-cluster-kind.sh $(OPERATOR_IMAGE) $(COMPUTE_PCRS_IMAGE)
$(KUBECTL) apply -f manifests/operator.yaml
$(KUBECTL) apply -f manifests/confidential_cluster_crd.yaml
$(KUBECTL) apply -f manifests/confidential_cluster_cr.yaml
Expand Down
23 changes: 0 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,6 @@ within the cluster.

### Quick Start

Fill the file `operator/src/reference-values-in.json` with the desired PCR values, e.g. by

```bash
$ for i in {4,7,14}; do
sudo tpm2_pcrread sha256:${i} | awk -F: '/0x/ {sub(/.*0x/, "", $2); gsub(/[^0-9A-Fa-f]/, "", $2); print tolower($2)}'
done
6401162a80170f039aabff2606d2c7b4843c592edcdc082abd66f644131d83c8
b3a56a06c03a65277d0a787fcabc1e293eaa5d6dd79398f2dda741f7b874c65d
17cdefd9548f4383b67a37a901673bf3c8ded6f619d36c8007562de1d93c81cc
```

i.e.

```json
{
"pcr4": "6401162a80170f039aabff2606d2c7b4843c592edcdc082abd66f644131d83c8",
"pcr7": "b3a56a06c03a65277d0a787fcabc1e293eaa5d6dd79398f2dda741f7b874c65d",
"pcr14": "17cdefd9548f4383b67a37a901673bf3c8ded6f619d36c8007562de1d93c81cc"
}
```

> Hint: You can stop tracking changes to this file with `git update-index --skip-worktree operator/src/reference-values-in.json`.

Create the cluster, install [trustee operator](https://github.com/confidential-containers/trustee-operator) and deploy
the operator.

Expand Down
17 changes: 17 additions & 0 deletions compute-pcrs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "compute-pcrs"
version = "0.1.0"
edition.workspace = true
description = "A cocl-operator optimized compute-pcrs interface"

[dependencies]
anyhow.workspace = true
chrono = "0.4.41"
clap = { workspace = true, features = ["derive"] }
compute-pcrs-lib = { git = "https://github.com/confidential-clusters/compute-pcrs", version = "0.1.0" }
k8s-openapi.workspace = true
kube.workspace = true
log.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
13 changes: 13 additions & 0 deletions compute-pcrs/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM ghcr.io/confidential-clusters/compute-pcrs/buildroot AS builder
WORKDIR /compute-pcrs
COPY Cargo.toml Cargo.lock .
COPY compute-pcrs compute-pcrs
# Hack: Set compute-pcrs as sole member to avoid needing to copy other crates.
# In that case, a rebuild would be triggered upon any change in those crates.
RUN sed -i 's/members =.*/members = ["compute-pcrs"]/' Cargo.toml && \
Comment on lines +5 to +7
Copy link
Contributor

Choose a reason for hiding this comment

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

cannot you copy the Cargo.toml from compute-pcrs instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, it has workspace dependencies and I prefer workspace dependencies over potentially deviating versions

git clone --depth 1 https://github.com/confidential-clusters/reference-values && \
cargo build --release -p compute-pcrs

FROM quay.io/fedora/fedora:42
COPY --from=builder /compute-pcrs/target/release/compute-pcrs /usr/local/bin
COPY --from=builder /compute-pcrs/reference-values /reference-values
108 changes: 108 additions & 0 deletions compute-pcrs/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use anyhow::Result;
use chrono::{DateTime, TimeDelta, Utc};
use clap::Parser;
use compute_pcrs_lib::*;
use k8s_openapi::api::core::v1::ConfigMap;
use kube::api::{ObjectMeta, PostParams};
use kube::{Api, Client};
use log::info;
use serde::{Serialize, Serializer};
use std::collections::BTreeMap;

fn primitive_date_time_to_str<S>(d: &DateTime<Utc>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_str(&d.format("%Y-%m-%dT%H:%M:%SZ").to_string())
}

/// Sync with Trustee
/// reference_value_provider_service::reference_value::ReferenceValue
/// (cannot import directly because its expiration doesn't serialize
/// right)
#[derive(Serialize)]
struct ReferenceValue {
pub version: String,
pub name: String,
#[serde(serialize_with = "primitive_date_time_to_str")]
pub expiration: DateTime<Utc>,
pub value: serde_json::Value,
}

#[derive(Parser)]
#[command(version, about)]
struct Args {
/// Path to the kernel modules directory
#[arg(short, long)]
kernels: String,
/// Path to the ESP directory
#[arg(short, long)]
esp: String,
/// Path to the directory storing EFIVar files
#[arg(short = 's', long)]
efivars: String,
/// Path to directory storing MokListRT, MokListTrustedRT and MokListXRT
#[arg(short, long)]
mokvars: String,
/// ConfigMap name to write to
#[arg(short, long)]
configmap: String,
/// Namespace to write ConfigMap to
#[arg(short, long)]
namespace: String,
}

#[tokio::main]
async fn main() -> Result<()> {
let args = Args::parse();

let mut pcrs: Vec<_> = [
compute_pcr4(&args.kernels, &args.esp, false, true),
compute_pcr7(Some(&args.efivars), &args.esp, true),
compute_pcr14(&args.mokvars),
]
.iter()
.map(|pcr| (format!("pcr{}", pcr.id), pcr.value.clone()))
.collect();
pcrs.push(("svn".to_string(), "1".to_string()));

let reference_values: Vec<_> = pcrs
.iter()
.map(|(name, value)| ReferenceValue {
version: "0.1.0".to_string(),
name: format!("tpm_{name}"),
expiration: Utc::now() + TimeDelta::days(365),
value: serde_json::Value::Array(vec![serde_json::Value::String(value.to_string())]),
})
.collect();
let reference_values_json = serde_json::to_string(&reference_values)?;
let data = BTreeMap::from([(
"reference-values.json".to_string(),
reference_values_json.to_string(),
)]);

let config_map = ConfigMap {
metadata: ObjectMeta {
name: Some(args.configmap.clone()),
namespace: Some(args.namespace.clone()),
..Default::default()
},
data: Some(data),
..Default::default()
};

let client = Client::try_default().await?;
let config_maps: Api<ConfigMap> = Api::namespaced(client, &args.namespace);
match config_maps
.create(&PostParams::default(), &config_map)
.await
{
Ok(_) => info!("Create ConfigMap {}", args.configmap),
Err(kube::Error::Api(ae)) if ae.code == 409 => {
info!("ConfigMap {} already exists", args.configmap)
}
Err(e) => return Err(e.into()),
}
Comment on lines +94 to +105
Copy link
Contributor

Choose a reason for hiding this comment

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

what if the config map already exists? You probably wants to retrieve its value check if it is different from the reference values, and if not then not update it. Right now, it make little sense but when we have more coreos versions to handle then the logic will become useful

Copy link
Contributor Author

Choose a reason for hiding this comment

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

as per #13, the RVs will be computed statelessly, and the config map will be overwritten. the code that I wrote for this which I momentarily refuse to delete is at Jakob-Naucke:shelved-append-rvs. I'm in favor of merging this PR first and moving on from there.


Ok(())
}
10 changes: 5 additions & 5 deletions crds/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[package]
name = "crds"
version = "0.1.0"
edition = "2024"
edition.workspace = true

[dependencies]
k8s-openapi = { version = "0.25.0", features = ["v1_33"] }
kube = { version = "1.1.0", features = ["derive"] }
k8s-openapi.workspace = true
kube = { workspace = true, features = ["derive"] }
schemars = { version = "0.8", features = ["derive"] }
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.141"
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
1 change: 1 addition & 0 deletions crds/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use serde::{Deserialize, Serialize};
)]
pub struct ConfidentialClusterSpec {
pub trustee: Trustee,
pub pcrs_compute_image: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
Expand Down
2 changes: 2 additions & 0 deletions kind/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ nodes:
extraPortMappings:
- containerPort: 31000
hostPort: 8080
featureGates:
"ImageVolume": true
14 changes: 7 additions & 7 deletions manifest-gen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[package]
name = "manifest-gen"
version = "0.1.0"
edition = "2024"
edition.workspace = true

[dependencies]
anyhow.workspace = true
env_logger.workspace = true
clap = { workspace = true, features = ["derive"] }
crds = { path = "../crds" }
anyhow = "1.0.98"
clap = { version = "4.5.41", features = ["derive"] }
kube = { version = "1.1.0", features = ["derive"] }
k8s-openapi.workspace = true
kube = { workspace = true, features = ["derive"] }
log.workspace = true
serde_yaml = "0.9"
k8s-openapi = { version = "0.25.0", features = ["v1_33"] }
log = "0.4.27"
env_logger = "0.11.8"
Loading
Loading