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 splitapi resource plugin #585

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
12 changes: 12 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ reqwest = { version = "0.12", default-features = false, features = [
rstest = "0.18.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.132"
serde_qs = "0.13.0"
serde_with = { version = "1.11.0", features = ["base64", "hex"] }
serial_test = { version = "3.2.0", features = ["async"] }
sha2 = "0.10"
Expand Down
5 changes: 5 additions & 0 deletions kbs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ aliyun = ["kms/aliyun"]
# Use pkcs11 resource backend to store secrets in an HSM
pkcs11 = ["cryptoki"]

# Use SplitAPI plugin to provide credentials for sandbox (pods) to initiate API proxy server
splitapi-plugin = []

[dependencies]
actix = "0.13.5"
actix-web = { workspace = true, features = ["openssl"] }
Expand Down Expand Up @@ -63,7 +66,9 @@ scc = "2"
semver = "1.0.16"
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
serde_qs.workspace = true
strum.workspace = true
tempfile.workspace = true
thiserror.workspace = true
time = { version = "0.3.23", features = ["std"] }
tokio.workspace = true
Expand Down
5 changes: 5 additions & 0 deletions kbs/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
AS_TYPE ?= coco-as
ALIYUN ?= false
SPLITAPI_PLUGIN ?= false

BUILD_ARCH := $(shell uname -m)
ARCH ?= $(shell uname -m)
Expand Down Expand Up @@ -48,6 +49,10 @@ ifeq ($(ALIYUN), true)
FEATURES += aliyun
endif

ifeq ($(SPLITAPI_PLUGIN), true)
FEATURES += splitapi-plugin
endif

ifndef CLI_FEATURES
ifdef ATTESTER
CLI_FEATURES = "sample_only,$(ATTESTER)"
Expand Down
2 changes: 1 addition & 1 deletion kbs/config/kbs-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ insecure_api = true
[[plugins]]
name = "resource"
type = "LocalFs"
dir_path = "/opt/confidential-containers/kbs/repository"
dir_path = "/opt/confidential-containers/kbs/repository"
4 changes: 4 additions & 0 deletions kbs/src/plugins/implementations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

pub mod resource;
pub mod sample;
#[cfg(feature = "splitapi-plugin")]
pub mod splitapi;

pub use resource::{RepositoryConfig, ResourceStorage};
pub use sample::{Sample, SampleConfig};
#[cfg(feature = "splitapi-plugin")]
pub use splitapi::{SplitAPI, SplitAPIConfig};
83 changes: 83 additions & 0 deletions kbs/src/plugins/implementations/splitapi/backend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) 2025 by IBM Corporation
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use serde::Deserialize;
use std::{path::PathBuf, sync::Arc};

use super::generator::CertificateDetails;
use super::manager;

pub const CREDENTIALS_BLOB_FILE: &str = "certificates.json";

/// Services supported by the SplitAPI plugin
#[async_trait::async_trait]
pub trait SplitAPIBackend: Send + Sync {
/// Returns credentials for API Proxy server, generates if not exist
async fn get_server_credential(&self, params: &SandboxParams) -> Result<Vec<u8>>;
}

pub struct SplitAPI {
pub backend: Arc<dyn SplitAPIBackend>,
}

#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(tag = "type")]
pub struct SplitAPIConfig {
pub plugin_dir: String,
#[serde(default)]
pub credential_blob_filename: String,
#[serde(default)]
pub certificate_details: CertificateDetails,
}

impl Default for SplitAPIConfig {
fn default() -> Self {
Self {
plugin_dir: String::from(""),
credential_blob_filename: CREDENTIALS_BLOB_FILE.into(),
certificate_details: CertificateDetails::default(),
}
}
}

impl TryFrom<SplitAPIConfig> for SplitAPI {
type Error = anyhow::Error;

fn try_from(config: SplitAPIConfig) -> anyhow::Result<Self> {
let backend = manager::CertManager::new(
PathBuf::from(&config.plugin_dir),
config.credential_blob_filename,
&config.certificate_details,
)?;

Ok(Self {
backend: Arc::new(backend),
})
}
}

/// Parameters for the credential request
///
/// These parameters are provided in the request via URL query string.
/// Parameters taken by the "splitapi" plugin to generate a unique key
/// for a sandbox store and retrieve credentials specific to the sandbox.
#[derive(Debug, PartialEq, serde::Deserialize)]
pub struct SandboxParams {
/// Required: ID of a sandbox or pod
pub id: String,
// Required: IP of a sandbox or pod
pub ip: String,
// Required: name of a sandbox or pod
pub name: String,
}

impl TryFrom<&str> for SandboxParams {
type Error = anyhow::Error;

fn try_from(query: &str) -> Result<Self> {
let params: SandboxParams = serde_qs::from_str(query)?;
Ok(params)
}
}
Loading