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

image-rs: Support simple signing with X-R-S-S #372

Merged
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
7 changes: 7 additions & 0 deletions .github/workflows/image_rs_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ jobs:
cargo clippy -p image-rs --all-targets --features=kata-cc-native-tls --no-default-features -- -D warnings
cargo clippy -p image-rs --all-targets --features=enclave-cc-eaakbc-native-tls --no-default-features -- -D warnings
cargo clippy -p image-rs --all-targets --features=enclave-cc-cckbc-native-tls --no-default-features -- -D warnings
cargo clippy -p image-rs --all-targets --features=kata-cc-native-tls,signature-simple-xrss --no-default-features -- -D warnings

- name: Run cargo build
uses: actions-rs/cargo@v1
Expand All @@ -100,3 +101,9 @@ jobs:
- name: Run cargo test - kata-cc (native-tls version) with keywrap-ttrpc (default) + keywrap-jwe
run: |
sudo -E PATH=$PATH -s cargo test -p image-rs --no-default-features --features=kata-cc-native-tls,keywrap-jwe

- name: Run cargo test - kata-cc (native-tls version) with keywrap-ttrpc (default) + keywrap-jwe and with signatures from XRSS registry extension
env:
AUTH_PASSWORD: ${{ secrets.SH_ICR_API_KEY }}
run: |
sudo -E PATH=$PATH -s cargo test -p image-rs --no-default-features --features=kata-cc-native-tls,keywrap-jwe,signature-simple-xrss
57 changes: 56 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions image-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ oci-spec = "0.6.2"
ocicrypt-rs = { path = "../ocicrypt-rs", default-features = false, features = ["async-io"], optional = true }
prost = { workspace = true, optional = true }
protobuf = { workspace = true, optional = true }
reqwest = { workspace = true, features = ["json"], optional = true }
sequoia-openpgp = { version = "1.7.0", default-features = false, features = ["compression", "crypto-rust", "allow-experimental-crypto", "allow-variable-time-crypto"], optional = true }
serde = { workspace = true, features = ["serde_derive", "rc"] }
serde_json.workspace = true
Expand Down Expand Up @@ -111,6 +112,7 @@ signature-cosign-native = ["signature-cosign", "sigstore/cosign-native-tls"]
oci-distribution-rustls = ["oci-distribution/rustls-tls"]
oci-distribution-native = ["oci-distribution/native-tls"]

signature-simple-xrss = ["signature-simple", "dep:reqwest"]
signature-simple = ["signature", "sequoia-openpgp", "serde_yaml"]

snapshot-overlayfs = ["nix"]
Expand Down
53 changes: 39 additions & 14 deletions image-rs/src/signature/mechanism/simple/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ use serde::*;
use strum_macros::Display;
use strum_macros::EnumString;

#[cfg(feature = "signature-simple")]
use base64::Engine;

#[cfg(feature = "signature-simple")]
mod sigstore;
#[cfg(feature = "signature-simple")]
mod verify;
#[cfg(feature = "signature-simple-xrss")]
mod xrss;

use crate::signature::{image::Image, mechanism::Paths, policy::ref_match::PolicyReqMatchType};

Expand Down Expand Up @@ -71,9 +76,16 @@ impl SignScheme for SimpleParameters {
async fn init(&mut self, config: &Paths) -> Result<()> {
prepare_runtime_dirs(crate::config::SIG_STORE_CONFIG_DIR).await?;
self.initialize_sigstore_config().await?;
let sig_store_config_file = crate::resource::get_resource(&config.sigstore_config).await?;
let sig_store_config_file = crate::resource::get_resource(&config.sigstore_config).await;

#[cfg(feature = "signature-simple-xrss")]
if sig_store_config_file.is_err() {
// When using xrss extension a sigstore config file is optional
return Ok(());
}

let sig_store_config_file =
serde_yaml::from_slice::<sigstore::SigstoreConfig>(&sig_store_config_file)?;
serde_yaml::from_slice::<sigstore::SigstoreConfig>(&sig_store_config_file?)?;
self.sig_store_config_file
.update_self(sig_store_config_file)?;
Ok(())
Expand All @@ -86,7 +98,6 @@ impl SignScheme for SimpleParameters {

#[cfg(feature = "signature-simple")]
async fn allows_image(&self, image: &mut Image, _auth: &RegistryAuth) -> Result<()> {
use base64::Engine;
// FIXME: only support "GPGKeys" type now.
//
// refer to https://github.com/confidential-containers/image-rs/issues/14
Expand All @@ -108,7 +119,7 @@ impl SignScheme for SimpleParameters {
}
};

let sigs = self.get_signatures(image).await?;
let sigs = self.get_signatures(image, _auth).await?;
let mut reject_reasons: Vec<anyhow::Error> = Vec::new();

for sig in sigs.iter() {
Expand Down Expand Up @@ -182,22 +193,19 @@ impl SimpleParameters {
/// Set the content of sigstore config with files in
/// [`crate::config::SIG_STORE_CONFIG_DIR`]
pub async fn initialize_sigstore_config(&mut self) -> Result<()> {
// If the registry support `X-Registry-Supports-Signatures` API extension,
// try to get signatures from the registry first.
// Else, get signatures from "sigstore" according to the sigstore config file.
// (https://github.com/containers/image/issues/384)
//
// TODO: Add get signatures from registry X-R-S-S API extension.
//
// issue: https://github.com/confidential-containers/image-rs/issues/12
let sigstore_config =
sigstore::SigstoreConfig::new_from_configs(crate::config::SIG_STORE_CONFIG_DIR).await?;
self.sig_store_config_file.update_self(sigstore_config)?;

Ok(())
}

pub async fn get_signatures(&self, image: &Image) -> Result<Vec<Vec<u8>>> {
pub async fn get_signatures(
&self,
image: &Image,
_auth: &RegistryAuth,
) -> Result<Vec<Vec<u8>>> {
let mut sigs: Vec<Vec<u8>> = Vec::new();
// Get image digest (manifest digest)
let image_digest = if !image.manifest_digest.is_empty() {
image.manifest_digest.clone()
Expand All @@ -207,6 +215,22 @@ impl SimpleParameters {
bail!("Missing image digest");
};

#[cfg(feature = "signature-simple-xrss")]
{
let registry_client = xrss::RegistryClient::new();
let mut registry_sigs = registry_client
.get_signatures_from_registry(image, &image_digest, _auth)
.await?;
sigs.append(&mut registry_sigs);
if self.sig_store_config_file == sigstore::SigstoreConfig::default() {
if sigs.is_empty() {
bail!("Missing sigstore config file and no signatures in registry");
}

return Ok(sigs);
}
}

// Format the sigstore name: `image-repository@digest-algorithm=digest-value`.
let sigstore_name = sigstore::format_sigstore_name(&image.reference, image_digest);

Expand All @@ -219,7 +243,8 @@ impl SimpleParameters {
let sigstore_uri = url::Url::parse(&sigstore)
.map_err(|e| anyhow!("Failed to parse sigstore_uri: {:?}", e))?;

let sigs = sigstore::get_sigs_from_specific_sigstore(sigstore_uri).await?;
let mut sigstore_sigs = sigstore::get_sigs_from_specific_sigstore(sigstore_uri).await?;
sigs.append(&mut sigstore_sigs);

Ok(sigs)
}
Expand Down
Loading
Loading