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

Add GitHub actions and subject prefix #157

Merged
merged 3 commits into from
Jul 13, 2022
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ dns-lookup = "1.0.8"
json-patch = "0.2.6"
kube = { version = "0.73.1", default-features = false, features = ["client", "rustls-tls"] }
k8s-openapi = { version = "0.15.0", default-features = false }
kubewarden-policy-sdk = "0.6.2"
kubewarden-policy-sdk = "0.6.3"
lazy_static = "1.4.0"
policy-fetcher = { git = "https://github.com/kubewarden/policy-fetcher", tag = "v0.7.8" }
serde_json = "1.0"
Expand Down
8 changes: 3 additions & 5 deletions src/callback_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ use std::collections::HashMap;
use tokio::sync::{mpsc, oneshot};
use tracing::{debug, warn};

use crate::callback_requests::{CallbackRequest, CallbackResponse};
use crate::callback_requests::{CallbackRequest, CallbackRequestType, CallbackResponse};

use kubewarden_policy_sdk::host_capabilities::verification::{KeylessInfo, KeylessPrefixInfo};
use kubewarden_policy_sdk::host_capabilities::{
net::LookupResponse,
oci::ManifestDigestResponse,
verification::{KeylessInfo, KeylessPrefixInfo, VerificationResponse},
CallbackRequestType,
net::LookupResponse, oci::ManifestDigestResponse, verification::VerificationResponse,
};
use policy_fetcher::verify::FulcioAndRekorData;

Expand Down
140 changes: 139 additions & 1 deletion src/callback_requests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use anyhow::Result;
use kubewarden_policy_sdk::host_capabilities::CallbackRequestType;
use kubewarden_policy_sdk::host_capabilities::verification::{KeylessInfo, KeylessPrefixInfo};
use kubewarden_policy_sdk::host_capabilities::{
SigstoreVerificationInputV1, SigstoreVerificationInputV2,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tokio::sync::oneshot;

/// Holds the response to a waPC evaluation request
Expand All @@ -18,3 +23,136 @@ pub struct CallbackRequest {
/// A tokio oneshot channel over which the evaluation response has to be sent
pub response_channel: oneshot::Sender<Result<CallbackResponse>>,
}

/// Describes the different kinds of request a waPC guest can make to
/// our host.
#[derive(Serialize, Deserialize, Debug)]
pub enum CallbackRequestType {
/// Require the computation of the manifest digest of an OCI object (be
/// it an image or anything else that can be stored into an OCI registry)
OciManifestDigest {
/// String pointing to the object (e.g.: `registry.testing.lan/busybox:1.0.0`)
image: String,
},

/// Require the verification of the manifest digest of an OCI object (be
/// it an image or anything else that can be stored into an OCI registry)
/// to be signed by Sigstore, using public keys mode
SigstorePubKeyVerify {
/// String pointing to the object (e.g.: `registry.testing.lan/busybox:1.0.0`)
image: String,
/// List of PEM encoded keys that must have been used to sign the OCI object
pub_keys: Vec<String>,
/// Optional - Annotations that must have been provided by all signers when they signed the OCI artifact
annotations: Option<HashMap<String, String>>,
},

// Require the verification of the manifest digest of an OCI object to be
// signed by Sigstore, using keyless mode
SigstoreKeylessVerify {
/// String pointing to the object (e.g.: `registry.testing.lan/busybox:1.0.0`)
image: String,
/// List of keyless signatures that must be found
keyless: Vec<KeylessInfo>,
/// Optional - Annotations that must have been provided by all signers when they signed the OCI artifact
annotations: Option<HashMap<String, String>>,
},

// Require the verification of the manifest digest of an OCI object to be
// signed by Sigstore using keyless mode, where the passed subject is a URL
// prefix of the subject to match
SigstoreKeylessPrefixVerify {
/// String pointing to the object (e.g.: `registry.testing.lan/busybox:1.0.0`)
image: String,
/// List of keyless signatures that must be found
keyless_prefix: Vec<KeylessPrefixInfo>,
/// Optional - Annotations that must have been provided by all signers when they signed the OCI artifact
annotations: Option<HashMap<String, String>>,
},

// Require the verification of the manifest digest of an OCI object to be
// signed by Sigstore using keyless mode and performed in GitHub Actions
SigstoreGithubActionsVerify {
/// String pointing to the object (e.g.: `registry.testing.lan/busybox:1.0.0`)
image: String,
/// owner of the repository. E.g: octocat
owner: String,
/// Optional - Repo of the GH Action workflow that signed the artifact. E.g: example-repo
repo: Option<String>,
/// Optional - Annotations that must have been provided by all signers when they signed the OCI artifact
annotations: Option<HashMap<String, String>>,
},

/// Lookup the addresses for a given hostname via DNS
DNSLookupHost { host: String },
}

impl From<SigstoreVerificationInputV2> for CallbackRequestType {
fn from(val: SigstoreVerificationInputV2) -> Self {
match val {
SigstoreVerificationInputV2::SigstorePubKeyVerify {
image,
pub_keys,
annotations,
} => CallbackRequestType::SigstorePubKeyVerify {
image,
pub_keys,
annotations,
},
SigstoreVerificationInputV2::SigstoreKeylessVerify {
image,
keyless,
annotations,
} => CallbackRequestType::SigstoreKeylessVerify {
image,
keyless,
annotations,
},
SigstoreVerificationInputV2::SigstoreKeylessPrefixVerify {
image,
keyless_prefix,
annotations,
} => CallbackRequestType::SigstoreKeylessPrefixVerify {
image,
keyless_prefix,
annotations,
},
SigstoreVerificationInputV2::SigstoreGithubActionsVerify {
image,
owner,
repo,
annotations,
} => CallbackRequestType::SigstoreGithubActionsVerify {
image,
owner,
repo,
annotations,
},
}
}
}

impl From<SigstoreVerificationInputV1> for CallbackRequestType {
fn from(val: SigstoreVerificationInputV1) -> Self {
match val {
SigstoreVerificationInputV1::SigstorePubKeyVerify {
image,
pub_keys,
annotations,
} => CallbackRequestType::SigstorePubKeyVerify {
image,
pub_keys,
annotations,
},
SigstoreVerificationInputV1::SigstoreKeylessVerify {
image,
keyless,
annotations,
} => CallbackRequestType::SigstoreKeylessVerify {
image,
keyless,
annotations,
},
}
}
}
23 changes: 19 additions & 4 deletions src/runtimes/wapc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ use tracing::{debug, error};
pub(crate) struct Runtime<'a>(pub(crate) &'a mut wapc::WapcHost);

use crate::admission_response::AdmissionResponse;
use crate::callback_requests::{CallbackRequest, CallbackResponse};
use crate::callback_requests::{CallbackRequest, CallbackRequestType, CallbackResponse};
use crate::cluster_context::ClusterContext;
use crate::policy::Policy;
use crate::policy_evaluator::{PolicySettings, ValidateRequest};

use kubewarden_policy_sdk::host_capabilities::CallbackRequestType;
use kubewarden_policy_sdk::host_capabilities::{
SigstoreVerificationInputV1, SigstoreVerificationInputV2,
};
use kubewarden_policy_sdk::metadata::ProtocolVersion;
use kubewarden_policy_sdk::response::ValidationResponse as PolicyValidationResponse;
use kubewarden_policy_sdk::settings::SettingsValidationResponse;
Expand Down Expand Up @@ -54,9 +56,22 @@ pub(crate) fn host_callback(
}
},
"oci" => match operation {
"v1/verify" | "v2/verify" => {
let req_type: CallbackRequestType =
"v1/verify" => {
let req: SigstoreVerificationInputV1 =
serde_json::from_slice(payload.to_vec().as_ref())?;
let req_type: CallbackRequestType = req.into();
let (tx, rx) = oneshot::channel::<Result<CallbackResponse>>();
let req = CallbackRequest {
request: req_type,
response_channel: tx,
};

send_request_and_wait_for_response(policy_id, binding, operation, req, rx)
}
"v2/verify" => {
let req: SigstoreVerificationInputV2 =
serde_json::from_slice(payload.to_vec().as_ref())?;
let req_type: CallbackRequestType = req.into();
let (tx, rx) = oneshot::channel::<Result<CallbackResponse>>();
let req = CallbackRequest {
request: req_type,
Expand Down