Skip to content

Commit

Permalink
Feat supporting Token distribution and verification
Browse files Browse the repository at this point in the history
Fixed: #20

Signed-off-by: Jiale Zhang <[email protected]>
  • Loading branch information
jialez0 committed Apr 20, 2023
1 parent ca725e3 commit 3d9a914
Show file tree
Hide file tree
Showing 14 changed files with 518 additions and 264 deletions.
22 changes: 22 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 config/kbs-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"repository_description": {
"dir_path": "/opt/confidential-containers/kbs/repository"
},
"attestation_token_type": "Simple",
"as_addr": "http://as:50004"
}
1 change: 1 addition & 0 deletions src/api_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ lazy_static = "1.4.0"
log.workspace = true
prost = { version = "0.11", optional = true }
rand = "0.8.5"
rcgen = "0.10.0"
rsa = "0.7.2"
rustls = { version = "0.20.8", optional = true }
rustls-pemfile = { version = "1.0.2", optional = true }
Expand Down
6 changes: 6 additions & 0 deletions src/api_server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: Apache-2.0

use crate::resource::RepositoryType;
use crate::token::AttestationTokenBrokerType;
use anyhow::anyhow;
use serde::Deserialize;
use serde_json::Value;
Expand All @@ -21,6 +22,9 @@ pub struct Config {
/// Various to repository type.
pub repository_description: Option<Value>,

/// Attestation Token type
pub attestation_token_type: AttestationTokenBrokerType,

/// OPTIONAL
/// Remote Attestation Service address.
/// Only used in remote AS mode.
Expand All @@ -40,6 +44,7 @@ impl Default for Config {
Config {
repository_type: RepositoryType::LocalFs,
repository_description: None,
attestation_token_type: AttestationTokenBrokerType::Simple,
as_addr: None,
as_config_file_path: None,
}
Expand All @@ -53,6 +58,7 @@ impl TryFrom<&Path> for Config {
/// "repository_description": {
/// "dir_path": "/opt/confidential-containers/kbs/repository"
/// },
/// "attestation_token_type": "Simple"
/// # Only used in Remote Attestation-Service mode
/// "as_addr": "http://127.0.0.1:50004",
/// # Only used in Native Attestation-Service mode
Expand Down
177 changes: 177 additions & 0 deletions src/api_server/src/http/attestation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// Copyright (c) 2022 by Rivos Inc.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use super::*;

macro_rules! unauthorized {
($error_type: ident, $reason: expr) => {
return HttpResponse::Unauthorized()
.json(kbs_error_info(ErrorInformationType::$error_type, $reason))
};
}

macro_rules! internal {
($reason: expr) => {
return HttpResponse::InternalServerError()
.message_body(BoxBody::new($reason))
.unwrap()
};
}

macro_rules! bail_option_internal {
($option: expr, $reason: expr) => {
match $option {
Some(inner) => inner,
None => {
return HttpResponse::InternalServerError()
.message_body(BoxBody::new($reason))
.unwrap()
}
}
};
}

macro_rules! bail_error_internal {
($error: expr) => {
match $error {
Ok(inner) => inner,
Err(e) => {
return HttpResponse::InternalServerError()
.message_body(BoxBody::new(e.to_string()))
.unwrap()
}
}
};
}

/// GET /attestation-results
pub(crate) async fn get_attestation_token(
request: HttpRequest,
token_broker: web::Data<Arc<RwLock<dyn AttestationTokenBroker + Send + Sync>>>,
map: web::Data<SessionMap<'_>>,
) -> HttpResponse {
let cookie = match request.cookie(KBS_SESSION_ID) {
None => {
log::error!("Missing KBS cookie");
unauthorized!(MissingCookie, "");
}
Some(c) => c,
};

let session_map = map.sessions.read().await;
let locked_session = match session_map.get(cookie.value()) {
None => {
log::error!("Invalid KBS cookie {}", cookie.value());
unauthorized!(InvalidCookie, cookie.value());
}
Some(ls) => ls,
};

let session = locked_session.lock().await;

log::info!("Cookie {} request to get Attestation Token", session.id());

if !session.is_authenticated() {
log::error!("UnAuthenticated KBS cookie {}", cookie.value());
unauthorized!(UnAuthenticatedCookie, cookie.value());
}

if session.is_expired() {
log::error!("Expired KBS cookie {}", cookie.value());
unauthorized!(ExpiredCookie, cookie.value());
}

let attestation_results = bail_option_internal!(
session.attestation_results(),
format!("no attestation results generated")
);
let token_claims = bail_error_internal!(serde_json::to_value(&attestation_results));

let token = match token_broker.read().await.issue(token_claims) {
Ok(token) => token,
Err(e) => internal!(format!("Issue Attestation Token failed: {e}")),
};

match session.to_jwe(token.into_bytes()) {
Ok(response) => HttpResponse::Ok()
.content_type("application/json")
.body(serde_json::to_string(&response).unwrap()),
Err(e) => internal!(format!("Generate Confidential Response failed: {e}")),
}
}

/// GET /resource/{repository}/{type}/{tag}
/// GET /resource/{type}/{tag}
pub(crate) async fn get_resource(
request: HttpRequest,
repository: web::Data<Arc<RwLock<dyn Repository + Send + Sync>>>,
map: web::Data<SessionMap<'_>>,
) -> HttpResponse {
let cookie = match request.cookie(KBS_SESSION_ID) {
None => {
log::error!("Missing KBS cookie");
unauthorized!(MissingCookie, "");
}
Some(c) => c,
};

let session_map = map.sessions.read().await;
let locked_session = match session_map.get(cookie.value()) {
None => {
log::error!("Invalid KBS cookie {}", cookie.value());
unauthorized!(InvalidCookie, cookie.value());
}
Some(ls) => ls,
};

let session = locked_session.lock().await;

log::info!("Cookie {} request to get resource", session.id());

if !session.is_authenticated() {
log::error!("UnAuthenticated KBS cookie {}", cookie.value());
unauthorized!(UnAuthenticatedCookie, cookie.value());
}

if session.is_expired() {
log::error!("Expired KBS cookie {}", cookie.value());
unauthorized!(ExpiredCookie, cookie.value());
}

let resource_description = ResourceDesc {
repository_name: request
.match_info()
.get("repository")
.unwrap_or("default")
.to_string(),
resource_type: request.match_info().get("type").unwrap().to_string(),
resource_tag: request.match_info().get("tag").unwrap().to_string(),
};

log::info!("Resource description: {:?}", &resource_description);

if session.tee_public_key().is_none() {
internal!(format!("TEE Pubkey not found"));
}

let resource_byte = match repository
.read()
.await
.read_secret_resource(resource_description)
.await
{
Ok(byte) => byte,
Err(e) => internal!(format!(
"Read secret resource from repository failed: {:?}",
e
)),
};

match session.to_jwe(resource_byte) {
Ok(response) => HttpResponse::Ok()
.content_type("application/json")
.body(serde_json::to_string(&response).unwrap()),
Err(e) => internal!(format!("Generate Confidential Response failed: {e}")),
}
}
Loading

0 comments on commit 3d9a914

Please sign in to comment.