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 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.kubeconfig
/target
/manifests
/operator/src/reference-values-in.json
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ i.e.
}
```

> 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
8 changes: 4 additions & 4 deletions operator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct ContextData {

async fn list_confidential_clusters(client: Client) -> anyhow::Result<ConfidentialCluster> {
let namespace = client.default_namespace();
info!("Listing ConfidentialClusters in namespace '{}'", namespace);
info!("Listing ConfidentialClusters in namespace '{namespace}'");
let api: Api<ConfidentialCluster> = Api::namespaced(client.clone(), namespace);
let lp = ListParams::default();
let list = api.list(&lp).await?;
Expand All @@ -39,7 +39,7 @@ async fn list_confidential_clusters(client: Client) -> anyhow::Result<Confidenti
"Found ConfidentialCluster: {}",
item.metadata.name.as_deref().unwrap_or("<no name>"),
);
return Ok(item.clone());
Ok(item.clone())
}
_ => bail!("too many confidential cluster resources defined in the namespace"),
}
Expand Down Expand Up @@ -172,8 +172,8 @@ async fn main() -> Result<()> {
.run::<_, ContextData>(reconcile, error_policy, context)
.for_each(|res| async move {
match res {
Ok(o) => info!("reconciled {:?}", o),
Err(e) => info!("reconcile failed: {:?}", e),
Ok(o) => info!("reconciled {o:?}"),
Err(e) => info!("reconcile failed: {e:?}"),
}
})
.await;
Expand Down
5 changes: 5 additions & 0 deletions operator/src/reference-values-in.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"pcr4": "fill in your expected PCR value here",
"pcr7": "fill in your expected PCR value here",
"pcr14": "fill in your expected PCR value here"
}
6 changes: 3 additions & 3 deletions operator/src/tpm.rego
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ hardware := 2 if {
}

tpm_pcrs_valid if {
input.tpm.pcrs[4] in data.reference.tpm_pcr4
input.tpm.pcrs[7] in data.reference.tpm_pcr7
input.tpm.pcrs[14] in data.reference.tpm_pcr14
lower(input.tpm.pcrs[4]) in data.reference.tpm_pcr4
lower(input.tpm.pcrs[7]) in data.reference.tpm_pcr7
lower(input.tpm.pcrs[14]) in data.reference.tpm_pcr14
}

executables := 3 if tpm_pcrs_valid
Expand Down
112 changes: 49 additions & 63 deletions operator/src/trustee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ use crate::reference_values::ReferenceValue;
const HTTPS_KEY: &str = "kbs-https-key";
const HTTPS_CERT: &str = "kbs-https-certificate";

macro_rules! info_if_exists {
($result:ident, $resource_type:literal, $resource_name:expr) => {
match $result {
Ok(_) => info!("Create {} {}", $resource_type, $resource_name),
Err(Error::Api(ae)) if ae.code == 409 => {
info!("{} {} already exists", $resource_type, $resource_name)
}
Err(e) => return Err(e.into()),
}
};
}

pub async fn generate_kbs_auth_public_key(
client: Client,
namespace: &str,
Expand Down Expand Up @@ -47,11 +59,8 @@ pub async fn generate_kbs_auth_public_key(
};

let secrets: Api<Secret> = Api::namespaced(client, namespace);
match secrets.create(&PostParams::default(), &secret).await {
Ok(s) => info!("Create secret {:?}", s.metadata.name),
Err(Error::Api(ae)) if ae.code == 409 => info!("Secret {} already exists", secret_name),
Err(e) => return Err(e.into()),
}
let create = secrets.create(&PostParams::default(), &secret).await;
info_if_exists!(create, "Secret", secret_name);

Ok(())
}
Expand All @@ -73,11 +82,8 @@ pub async fn generate_kbs_https_certificate(client: Client, namespace: &str) ->
data: Some(map),
..Default::default()
};
match secrets.create(&PostParams::default(), &secret).await {
Ok(s) => info!("Create secret {:?}", s.metadata.name),
Err(Error::Api(ae)) if ae.code == 409 => info!("Secret {name} already exists"),
Err(e) => return Err(e.into()),
}
let create = secrets.create(&PostParams::default(), &secret).await;
info_if_exists!(create, "Secret", name);
}

Ok(())
Expand Down Expand Up @@ -110,16 +116,10 @@ pub async fn generate_kbs_configurations(
..Default::default()
};

match config_maps
let create = config_maps
.create(&PostParams::default(), &config_map)
.await
{
Ok(s) => info!("Created ConfigMap {:?}", s.metadata.name),
Err(Error::Api(ae)) if ae.code == 409 => {
info!("ConfigMap {} already exists", configmap)
}
Err(e) => return Err(e.into()),
}
.await;
info_if_exists!(create, "ConfigMap", configmap);
}

Ok(())
Expand All @@ -141,14 +141,21 @@ pub async fn generate_reference_values(
);
let reference_values = reference_values_in
.iter()
.map(|(name, value)| match value {
serde_json::Value::String(_) => Ok(ReferenceValue {
version: "0.1.0".to_string(),
name: format!("tpm_{name}"),
expiration: chrono::DateTime::<chrono::Utc>::MAX_UTC,
value: serde_json::Value::Array(vec![value.clone()]),
}),
_ => Err(anyhow!("Reference values had unexpected data type")),
.map(|(name, value)| {
if let serde_json::Value::String(hex) = value
&& hex
.chars()
.all(|c| (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

On Azure, iirc, the letter are capital, so maybe it is worth to reduce value to lowercase first

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

compute-pcrs will also give lower case and this should be fixed attestation policy side. This is now included (cc @6-dehan)

{
Ok(ReferenceValue {
version: "0.1.0".to_string(),
name: format!("tpm_{name}"),
expiration: chrono::DateTime::<chrono::Utc>::MAX_UTC,
value: serde_json::Value::Array(vec![value.clone()]),
})
} else {
Err(anyhow!("Reference value '{value}' had unexpected shape"))
}
})
.collect::<Result<Vec<_>, _>>()?;
let reference_values_json = serde_json::to_string(&reference_values)?;
Expand All @@ -170,14 +177,10 @@ pub async fn generate_reference_values(
};

let config_maps: Api<ConfigMap> = Api::namespaced(client, namespace);
match config_maps
let create = config_maps
.create(&PostParams::default(), &config_map)
.await
{
Ok(s) => info!("Created ConfigMap {:?}", s.metadata.name),
Err(Error::Api(ae)) if ae.code == 409 => info!("ConfigMap {} already exists", name),
Err(e) => return Err(e.into()),
}
.await;
info_if_exists!(create, "ConfigMap", name);

Ok(())
}
Expand Down Expand Up @@ -209,11 +212,8 @@ pub async fn generate_secret(
};

let secrets: Api<Secret> = Api::namespaced(client.clone(), namespace);
match secrets.create(&PostParams::default(), &secret).await {
Ok(s) => info!("Created Secret {:?}", s.metadata.name),
Err(Error::Api(ae)) if ae.code == 409 => info!("Secret {id} already exists"),
Err(e) => return Err(e.into()),
}
let create = secrets.create(&PostParams::default(), &secret).await;
info_if_exists!(create, "Secret", id);

let kbs_configs: Api<KbsConfig> = Api::namespaced(client, namespace);

Expand All @@ -224,7 +224,7 @@ pub async fn generate_secret(
.kbs_secret_resources;
if existing_secrets.iter().any(|s| s == id) {
info!("Secret with ID {id} already present");
return Ok(())
return Ok(());
}

let path = jsonptr::PointerBuf::parse("/spec/kbsSecretResources")?;
Expand Down Expand Up @@ -273,14 +273,10 @@ pub async fn generate_resource_policy(
};

let config_maps: Api<ConfigMap> = Api::namespaced(client, namespace);
match config_maps
let create = config_maps
.create(&PostParams::default(), &config_map)
.await
{
Ok(s) => info!("Created ConfigMap {:?}", s.metadata.name),
Err(Error::Api(ae)) if ae.code == 409 => info!("ConfigMap {} already exists", name),
Err(e) => return Err(e.into()),
}
.await;
info_if_exists!(create, "ConfigMap", name);

Ok(())
}
Expand All @@ -305,14 +301,10 @@ pub async fn generate_attestation_policy(
};

let config_maps: Api<ConfigMap> = Api::namespaced(client, namespace);
match config_maps
let create = config_maps
.create(&PostParams::default(), &config_map)
.await
{
Ok(s) => info!("Created ConfigMap {:?}", s.metadata.name),
Err(Error::Api(ae)) if ae.code == 409 => info!("ConfigMap {} already exists", name),
Err(e) => return Err(e.into()),
}
.await;
info_if_exists!(create, "ConfigMap", name);

Ok(())
}
Expand Down Expand Up @@ -368,16 +360,10 @@ pub async fn generate_kbs(
};

let kbs_configs: Api<KbsConfig> = Api::namespaced(client, namespace);
match kbs_configs
let create = kbs_configs
.create(&PostParams::default(), &kbs_config)
.await
{
Ok(s) => info!("Created KbsConfig {:?}", s.metadata.name),
Err(Error::Api(ae)) if ae.code == 409 => {
info!("KbsConfig {} already exists", trustee.kbs_config_name)
}
Err(e) => return Err(e.into()),
}
.await;
info_if_exists!(create, "KbsConfig", trustee.kbs_config_name);

Ok(())
}