Skip to content

Commit 3951960

Browse files
committed
kbs: Add splitapi plugin
This plugin generates credentials (keys and certificates) for both the API proxy server (required for kata-containers/kata-containers#9159 and kata-containers/kata-containers#9752) and the workload owner. This plugin also delivers the credentials to a sandbox (i.e., confidential PODs or VMs), specifically to the kata agent to initiate the SplitAPI proxy server so that a workload owner can communicate with the proxy server using a secure tunnel. The IPv4 address, name, and the ID of the sandbox must be provided in the query string to obtain the credential resources from the kbs. After receiving the credential request, the splitapi plugin will create a key pair for the server and client and sign them using the self-signed CA. The generated ca.crt, server.crt, and server.key are stored in a directory specific to the sandbox (the caller) and returned to the caller. In addition, ca.key, client.key, and client.crt are also generated and stored to that particular directory specific to the sandbox (i.e., caller). During the credential generation, a sandbox directory mapper creates a unique directory specific to the sandbox (i.e., the caller). The mapper creates the unique directory using the sandbox parameters passed in the query string. A mapping file is also maintained to store the mapping between the sandbox name and the unique directory created for the sandbox. The splitapi plugin itself is not initialized by default. To initialize it, you need to add 'splitapi' in the kbs-config.toml. Signed-off-by: Salman Ahmed <sahmed@ibm.com>
1 parent 54dd787 commit 3951960

11 files changed

Lines changed: 897 additions & 1 deletion

File tree

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ reqwest = { version = "0.12", default-features = false, features = [
5050
rstest = "0.18.1"
5151
serde = { version = "1.0", features = ["derive"] }
5252
serde_json = "1.0.132"
53+
serde_qs = "0.13.0"
5354
serde_with = { version = "1.11.0", features = ["base64", "hex"] }
5455
serial_test = "0.9.0"
5556
sha2 = "0.10"

kbs/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ scc = "2"
6262
semver = "1.0.16"
6363
serde = { workspace = true, features = ["derive"] }
6464
serde_json.workspace = true
65+
serde_qs.workspace = true
6566
strum.workspace = true
6667
thiserror.workspace = true
6768
time = { version = "0.3.23", features = ["std"] }

kbs/config/kbs-config.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ insecure_api = true
2727
name = "resource"
2828
type = "LocalFs"
2929
dir_path = "/opt/confidential-containers/kbs/repository"
30+
31+
[[plugins]]
32+
name = "splitapi"
33+
type = "CertManager"
34+
plugin_dir = "/opt/confidential-containers/kbs/plugin/splitapi"

kbs/src/plugins/implementations/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
33
// SPDX-License-Identifier: Apache-2.0
44

5+
pub mod splitapi;
56
pub mod resource;
67
pub mod sample;
78

9+
pub use splitapi::{SplitAPI, SplitAPIConfig};
810
pub use resource::{RepositoryConfig, ResourceStorage};
911
pub use sample::{Sample, SampleConfig};
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) 2024 by IBM Corporation
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
use anyhow::{Context, Result};
6+
use std::{ffi::OsString, sync::Arc};
7+
use serde::Deserialize;
8+
9+
use super::manager;
10+
11+
12+
pub const PLUGIN_NAME: &str = "splitapi";
13+
14+
15+
/// Services supported by the SplitAPI plugin
16+
#[async_trait::async_trait]
17+
pub trait SplitAPIBackend: Send + Sync {
18+
/// Generate and obtain the credential for API Proxy server
19+
async fn get_server_credential(&self, params: &SandboxParams) -> Result<Vec<u8>>;
20+
}
21+
22+
pub struct SplitAPI {
23+
pub backend: Arc<dyn SplitAPIBackend>,
24+
}
25+
26+
#[derive(Clone, Debug, Deserialize, PartialEq)]
27+
#[serde(tag = "type")]
28+
pub enum SplitAPIConfig {
29+
CertManager(manager::SplitAPIRepoDesc),
30+
}
31+
32+
impl Default for SplitAPIConfig {
33+
fn default() -> Self {
34+
Self::CertManager(manager::SplitAPIRepoDesc::default())
35+
}
36+
}
37+
38+
impl TryFrom<SplitAPIConfig> for SplitAPI {
39+
type Error = anyhow::Error;
40+
41+
fn try_from(config: SplitAPIConfig) -> anyhow::Result<Self> {
42+
match config {
43+
SplitAPIConfig::CertManager(desc) => {
44+
let backend = manager::CertManager::new(&desc)
45+
.context("Failed to initialize Resource Storage")?;
46+
Ok(Self {
47+
backend: Arc::new(backend),
48+
})
49+
}
50+
}
51+
}
52+
}
53+
54+
/// Parameters taken by the "splitapi" plugin to store the certificates
55+
/// generated for the sandbox by combining the IP address, sandbox name,
56+
/// sandbox ID to create an unique directory for the sandbox
57+
#[derive(Debug, PartialEq, serde::Deserialize)]
58+
pub struct SandboxParams {
59+
pub id: String,
60+
pub ip: String,
61+
pub name: String,
62+
}
63+
64+
impl From<&SandboxParams> for Vec<OsString> {
65+
fn from(params: &SandboxParams) -> Self {
66+
let mut v: Vec<OsString> = Vec::new();
67+
68+
v.push("-id".into());
69+
v.push((&params.id).into());
70+
v.push("-name".into());
71+
v.push((&params.name).into());
72+
v.push("-ip".into());
73+
v.push((&params.ip.to_string()).into());
74+
75+
v
76+
}
77+
}

0 commit comments

Comments
 (0)