Skip to content

Commit

Permalink
Move TLS parameters out of application config
Browse files Browse the repository at this point in the history
  • Loading branch information
tiziano88 committed May 21, 2020
1 parent 5a81037 commit 3ab065a
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 137 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

9 changes: 1 addition & 8 deletions oak/proto/application.proto
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,6 @@ message GrpcServerConfiguration {
// The endpoint address for the gRPC server to listen on.
// `address` is represented as an "ip_address:tcp_port" string.
string address = 1;
// Loaded private RSA key file used by a gRPC server pseudo-Node.
string grpc_tls_private_key = 2;
// Loaded PEM encoded X.509 TLS certificate file used by a gRPC server pseudo-Node.
string grpc_tls_certificate = 3;
}

// GrpcClientConfiguration describes the configuration of a gRPC client
Expand All @@ -94,12 +90,9 @@ message GrpcClientConfiguration {
// The URI component of a gRPC server endpoint. Must contain the "Host" element.
// https://docs.rs/tonic/0.2.1/tonic/transport/struct.Uri.html
string uri = 1;
// Loaded PEM encoded X.509 TLS root certificate file used to authenticate an external gRPC
// service.
string root_tls_certificate = 2;
// The endpoint address of the external gRPC service.
// `address` is represented as an "ip_address:tcp_port" string.
string address = 3;
string address = 2;
}

// RoughtimeClientConfiguration describes the configuration of a Roughtime
Expand Down
4 changes: 4 additions & 0 deletions oak/server/rust/oak_loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ anyhow = "*"
log = "*"
oak_runtime = "=0.1.0"
prost = "*"
rustls = "*"
signal-hook = "*"
simple_logger = "*"
structopt = "*"
# Using an old version that is supported by `cargo-raze`:
# https://github.com/google/cargo-raze/issues/41#issuecomment-592274128
tonic = { version = "=0.1.1", features = ["tls"] }

[dev-dependencies]
maplit = "*"
60 changes: 32 additions & 28 deletions oak/server/rust/oak_loader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,12 @@ use std::{
},
};
use structopt::StructOpt;
use tonic::transport::{Certificate, Identity};

#[cfg(test)]
mod tests;

use oak_runtime::proto::oak::application::{
node_configuration::ConfigType::{GrpcClientConfig, GrpcServerConfig},
ConfigMap,
};
use oak_runtime::proto::oak::application::ConfigMap;

#[derive(StructOpt, Clone, Debug)]
#[structopt(about = "Oak Loader")]
Expand Down Expand Up @@ -133,6 +131,18 @@ pub fn parse_config_map(config_files: &[ConfigEntry]) -> anyhow::Result<ConfigMa
})
}

/// Check the correctness of a PEM encoded TLS certificate.
fn load_certificate(certificate: &str) -> anyhow::Result<Certificate> {
use rustls::internal::pemfile::certs;

let mut cursor = std::io::Cursor::new(certificate);
// `rustls` doesn't specify certificate parsing errors:
// https://docs.rs/rustls/0.17.0/rustls/internal/pemfile/fn.certs.html
certs(&mut cursor).map_err(|()| anyhow!("could not parse TLS certificate"))?;

Ok(Certificate::from_pem(certificate))
}

fn main() -> anyhow::Result<()> {
if cfg!(feature = "oak_debug") {
simple_logger::init_by_env();
Expand All @@ -150,45 +160,39 @@ fn main() -> anyhow::Result<()> {

// Load application configuration.
let app_config_data = read_file(&opt.application)?;
let mut app_config = ApplicationConfiguration::decode(app_config_data.as_ref())?;
let application_configuration = ApplicationConfiguration::decode(app_config_data.as_ref())?;

// Assign a TLS identity to all gRPC server and client nodes in the application configuration.
let grpc_tls_private_key = read_to_string(&opt.grpc_tls_private_key)?;
let grpc_tls_certificate = read_to_string(&opt.grpc_tls_certificate)?;
let root_tls_certificate = read_to_string(&opt.root_tls_certificate)?;
for node in &mut app_config.node_configs {
if let Some(GrpcServerConfig(ref mut grpc_server_config)) = node.config_type {
grpc_server_config.grpc_tls_private_key = grpc_tls_private_key.clone();
grpc_server_config.grpc_tls_certificate = grpc_tls_certificate.clone();
} else if let Some(GrpcClientConfig(ref mut grpc_client_config)) = node.config_type {
grpc_client_config.root_tls_certificate = root_tls_certificate.clone();
}
}

// Create Runtime config.
#[cfg(feature = "oak_debug")]
let runtime_config = oak_runtime::RuntimeConfiguration {
metrics_port: if opt.no_metrics {
None
} else {
let runtime_configuration = oak_runtime::RuntimeConfiguration {
metrics_port: if cfg!(feature = "oak_debug") && !opt.no_metrics {
Some(opt.metrics_port)
},
introspect_port: if opt.no_introspect {
None
} else {
None
},
introspect_port: if cfg!(feature = "oak_debug") && !opt.no_introspect {
Some(opt.introspect_port)
} else {
None
},
};
#[cfg(not(feature = "oak_debug"))]
let runtime_config = oak_runtime::RuntimeConfiguration {
metrics_port: None,
introspect_port: None,
let grpc_configuration = oak_runtime::GrpcConfiguration {
grpc_server_tls_identity: Identity::from_pem(grpc_tls_certificate, grpc_tls_private_key),
grpc_client_root_tls_certificate: load_certificate(&root_tls_certificate)?,
};

// Start the Runtime from the given config.
info!("starting Runtime, config {:?}", runtime_config);
let (runtime, initial_handle) = configure_and_run(app_config, runtime_config)
.map_err(|status| anyhow!("status {:?}", status))?;
info!("starting Runtime, config {:?}", runtime_configuration);
let (runtime, initial_handle) = configure_and_run(
application_configuration,
runtime_configuration,
grpc_configuration,
)
.map_err(|status| anyhow!("status {:?}", status))?;
info!(
"initial node {:?} with write handle {:?}",
runtime.node_id, initial_handle
Expand Down
73 changes: 31 additions & 42 deletions oak/server/rust/oak_runtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

use crate::{
node,
node::{check_uri, load_certificate, load_wasm},
node::{check_uri, load_wasm},
proto::oak::application::{
node_configuration::ConfigType, ApplicationConfiguration, GrpcClientConfiguration,
GrpcServerConfiguration, LogConfiguration, NodeConfiguration, RoughtimeClientConfiguration,
Expand All @@ -28,7 +28,6 @@ use itertools::Itertools;
use log::error;
use oak_abi::OakStatus;
use std::collections::HashMap;
use tonic::transport::Identity;

/// Create an application configuration.
///
Expand Down Expand Up @@ -89,43 +88,32 @@ pub fn from_protobuf(
return Err(OakStatus::ErrInvalidArgs);
}
Some(ConfigType::LogConfig(_)) => node::Configuration::LogNode,
Some(ConfigType::GrpcServerConfig(GrpcServerConfiguration {
address,
grpc_tls_private_key,
grpc_tls_certificate,
})) => node::Configuration::GrpcServerNode {
address: address.parse().map_err(|error| {
error!("Incorrect gRPC server address: {:?}", error);
OakStatus::ErrInvalidArgs
})?,
tls_identity: Identity::from_pem(grpc_tls_certificate, grpc_tls_private_key),
},
Some(ConfigType::GrpcClientConfig(GrpcClientConfiguration {
uri,
root_tls_certificate,
address,
})) => node::Configuration::GrpcClientNode {
uri: uri
.parse()
.map_err(|error| {
error!("Error parsing URI {}: {:?}", uri, error);
Some(ConfigType::GrpcServerConfig(GrpcServerConfiguration { address })) => {
node::Configuration::GrpcServerNode {
address: address.parse().map_err(|error| {
error!("Incorrect gRPC server address: {:?}", error);
OakStatus::ErrInvalidArgs
})
.and_then(|uri| match check_uri(&uri) {
Ok(_) => Ok(uri),
Err(error) => {
error!("Incorrect URI {}: {:?}", uri, error);
Err(OakStatus::ErrInvalidArgs)
}
})?,
root_tls_certificate: load_certificate(root_tls_certificate).map_err(
|error| {
error!("Error loading root certificate: {:?}", error);
OakStatus::ErrInvalidArgs
},
)?,
address: address.to_string(),
},
}
}
Some(ConfigType::GrpcClientConfig(GrpcClientConfiguration { uri, address })) => {
node::Configuration::GrpcClientNode {
uri: uri
.parse()
.map_err(|error| {
error!("Error parsing URI {}: {:?}", uri, error);
OakStatus::ErrInvalidArgs
})
.and_then(|uri| match check_uri(&uri) {
Ok(_) => Ok(uri),
Err(error) => {
error!("Incorrect URI {}: {:?}", uri, error);
Err(OakStatus::ErrInvalidArgs)
}
})?,
address: address.to_string(),
}
}
Some(ConfigType::WasmConfig(WebAssemblyConfiguration { module_bytes, .. })) => {
load_wasm(&module_bytes).map_err(|error| {
error!("Error loading Wasm module: {}", error);
Expand All @@ -151,11 +139,12 @@ pub fn from_protobuf(
/// passing the write [`oak_abi::Handle`] into the runtime will enable messages to be read
/// back out from the [`RuntimeProxy`].
pub fn configure_and_run(
app_config: ApplicationConfiguration,
runtime_config: crate::RuntimeConfiguration,
application_configuration: ApplicationConfiguration,
runtime_configuration: crate::RuntimeConfiguration,
grpc_configuration: crate::GrpcConfiguration,
) -> Result<(RuntimeProxy, oak_abi::Handle), OakStatus> {
let configuration = from_protobuf(app_config)?;
let proxy = RuntimeProxy::create_runtime(configuration);
let handle = proxy.start_runtime(runtime_config)?;
let configuration = from_protobuf(application_configuration)?;
let proxy = RuntimeProxy::create_runtime(configuration, grpc_configuration);
let handle = proxy.start_runtime(runtime_configuration)?;
Ok((proxy, handle))
}
20 changes: 12 additions & 8 deletions oak/server/rust/oak_runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ pub mod metrics;
pub mod node;
pub mod runtime;

pub use config::{application_configuration, configure_and_run};
use tonic::transport::{Certificate, Identity};

pub use config::{application_configuration, configure_and_run};
pub use message::NodeMessage;
pub use runtime::{NodeId, RuntimeProxy};

Expand All @@ -46,11 +47,14 @@ pub struct RuntimeConfiguration {
pub introspect_port: Option<u16>,
}

impl Default for RuntimeConfiguration {
fn default() -> Self {
RuntimeConfiguration {
metrics_port: None,
introspect_port: None,
}
}
/// Configuration options related to gRPC pseudo-Nodes.
///
/// `Debug` is intentionally not implemented in order to avoid accidentally logging secrets.
pub struct GrpcConfiguration {
/// TLS identity to use for all gRPC Server Nodes.
pub grpc_server_tls_identity: Identity,

/// Root TLS certificate to use for all gRPC Client Nodes.
// TODO(#999): Remove user-configurable root CA.
pub grpc_client_root_tls_certificate: Certificate,
}
50 changes: 17 additions & 33 deletions oak/server/rust/oak_runtime/src/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
// limitations under the License.
//

use crate::runtime::RuntimeProxy;
use crate::{runtime::RuntimeProxy, GrpcConfiguration};
use log::debug;
use std::{
net::{AddrParseError, SocketAddr},
string::String,
sync::Arc,
};
use tokio::sync::oneshot;
use tonic::transport::{Certificate, Identity, Uri};
use tonic::transport::Uri;

pub mod external;
mod grpc;
Expand Down Expand Up @@ -57,14 +57,12 @@ pub enum Configuration {
/// a TLS identity that consists of a private RSA key and an X.509 TLS certificate.
GrpcServerNode {
address: SocketAddr,
tls_identity: Identity,
},

/// The configuration for a gRPC server pseudo-Node that contains a URI and an X.509 root TLS
/// certificate.
GrpcClientNode {
uri: Uri,
root_tls_certificate: Certificate,
address: String,
},

Expand Down Expand Up @@ -148,18 +146,6 @@ pub fn check_uri(uri: &Uri) -> Result<(), ConfigurationError> {
.ok_or(ConfigurationError::NoHostElement)
}

/// Check the correctness of a PEM encoded TLS certificate.
pub fn load_certificate(certitiface: &str) -> Result<Certificate, ConfigurationError> {
use rustls::internal::pemfile::certs;

let mut cursor = std::io::Cursor::new(certitiface);
// `rustls` doesn't specify certificate parsing errors:
// https://docs.rs/rustls/0.17.0/rustls/internal/pemfile/fn.certs.html
certs(&mut cursor).map_err(|_| ConfigurationError::CertificateParsingError)?;

Ok(Certificate::from_pem(certitiface))
}

impl Configuration {
/// Creates a new Node instance corresponding to the [`Configuration`].
///
Expand All @@ -169,30 +155,28 @@ impl Configuration {
node_name: &str, // Used for pretty debugging
config_name: &str,
entrypoint: String,
grpc_configuration: &GrpcConfiguration,
) -> Option<Box<dyn Node + Send>> {
debug!(
"create_node('{}': '{}'.'{}')",
node_name, config_name, entrypoint
);
match self {
Configuration::LogNode => Some(Box::new(logger::LogNode::new(node_name))),
Configuration::GrpcServerNode {
address,
tls_identity,
} => Some(Box::new(grpc::server::GrpcServerNode::new(
node_name,
*address,
tls_identity.clone(),
))),
Configuration::GrpcClientNode {
uri,
root_tls_certificate,
address: _,
} => Some(Box::new(grpc::client::GrpcClientNode::new(
node_name,
uri.clone(),
root_tls_certificate.clone(),
))),
Configuration::GrpcServerNode { address } => {
Some(Box::new(grpc::server::GrpcServerNode::new(
node_name,
*address,
grpc_configuration.grpc_server_tls_identity.clone(),
)))
}
Configuration::GrpcClientNode { uri, address: _ } => {
Some(Box::new(grpc::client::GrpcClientNode::new(
node_name,
uri.clone(),
grpc_configuration.grpc_client_root_tls_certificate.clone(),
)))
}
Configuration::WasmNode { module } => {
match wasm::WasmNode::new(node_name, module.clone(), entrypoint) {
Some(node) => Some(Box::new(node)),
Expand Down
Loading

0 comments on commit 3ab065a

Please sign in to comment.