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

test/nanocld: ssl self signed #826

Merged
merged 7 commits into from
Jan 31, 2024
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
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This section tell which versions are currently being supported with security upd

| Version | Supported |
| ------- | ------------------ |
| 0.10.x | :white_check_mark: |
| 0.13.x | :white_check_mark: |

## Reporting a Vulnerability

Expand Down
2 changes: 1 addition & 1 deletion bin/nanocl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ dialoguer = "0.11"
termios = "0.3"
liquid = { version = "0.26", features = ["stdlib"] }
regex = "1.10"
nanocld_client = { version = "0.13", features = ["tokio"] }
nanocld_client = { version = "0.13", features = ["tokio", "openssl"] }
nanocl_error = { version = "0.2", features = [
"io",
"tokio",
Expand Down
1 change: 1 addition & 0 deletions bin/nanocl/src/commands/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
"Nanocl".into(),
ContextEndpoint {
host: format!("unix://{home_dir}/.nanocl/run/nanocl.sock"),
ssl: None,

Check warning on line 172 in bin/nanocl/src/commands/install.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocl/src/commands/install.rs#L172

Added line #L172 was not covered by tests
},
);
map
Expand Down
7 changes: 3 additions & 4 deletions bin/nanocl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ fn create_cli_config(cli_args: &Cli) -> IoResult<CliConfig> {
}
}
}
let endpoint = context.endpoints.get("Nanocl").unwrap();
#[allow(unused)]
let mut host = cli_args
.host
.clone()
.unwrap_or(context.endpoints.get("Nanocl").unwrap().host.clone());
let mut host = cli_args.host.clone().unwrap_or(endpoint.host.clone());
#[cfg(any(feature = "dev", feature = "test"))]
{
if context.name == "default" {
Expand All @@ -44,6 +42,7 @@ fn create_cli_config(cli_args: &Cli) -> IoResult<CliConfig> {
}
let client = NanocldClient::connect_to(&ConnectOpts {
url: host.clone(),
ssl: endpoint.ssl.clone(),
..Default::default()
});
Ok(CliConfig {
Expand Down
5 changes: 5 additions & 0 deletions bin/nanocl/src/models/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use tabled::Tabled;
use clap::{Parser, Subcommand};
use serde::{Serialize, Deserialize};

use nanocld_client::stubs::system::SslConfig;

/// `nanocl context` available arguments
#[derive(Parser)]
pub struct ContextArg {
Expand Down Expand Up @@ -34,6 +36,8 @@ pub enum ContextCommand {
#[serde(rename_all = "PascalCase")]
pub struct ContextEndpoint {
pub host: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub ssl: Option<SslConfig>,
}

/// A context metadata definition
Expand Down Expand Up @@ -67,6 +71,7 @@ impl std::default::Default for Context {
ContextEndpoint {
host: std::env::var("NANOCL_HOST")
.unwrap_or("unix:///run/nanocl/nanocl.sock".into()),
ssl: None,
},
);
map
Expand Down
3 changes: 2 additions & 1 deletion bin/nanocld/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ release = []
clap = { version = "4.4", features = ["derive"] }
clap_mangen = { version = "0.2" }
nanocl_utils = { version = "0.4", features = ["build_tools"] }
nanocl_stubs = { version = "0.13", features = ["clap"] }

[dev-dependencies]
serde_yaml = "0.9"
Expand Down Expand Up @@ -79,7 +80,7 @@ chrono = { version = "0.4", default-features = false, features = [
jsonschema = { version = "0.17", default-features = false }
nanocld_client = { version = "0.13", features = ["tokio"] }
metrsd_client = "0.5"
nanocl_stubs = { version = "0.13", features = ["serde"] }
nanocl_stubs = { version = "0.13", features = ["serde", "clap"] }
nanocl_utils = { version = "0.4", features = ["unix", "ntex", "logger"] }
utoipa = { version = "4.2", features = ["yaml"], optional = true }
notify = "6.1"
Expand Down
14 changes: 3 additions & 11 deletions bin/nanocld/specs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2854,17 +2854,9 @@ components:
format: int32
description: Group id
minimum: 0
cert:
type: string
description: Certificate path
nullable: true
cert_key:
type: string
description: Certificate key path
nullable: true
cert_ca:
type: string
description: Ca certificate path
ssl:
allOf:
- $ref: '#/components/schemas/SslConfig'
nullable: true
DeviceMapping:
type: object
Expand Down
18 changes: 6 additions & 12 deletions bin/nanocld/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use clap::Parser;

use nanocl_stubs::system::SslConfig;

/// Nanocl Daemon - Self Sufficient Orchestrator
#[derive(Debug, Clone, Parser)]
#[command(name = "Nanocl")]
Expand Down Expand Up @@ -34,15 +36,9 @@ pub struct Cli {
/// Group id
#[clap(long, default_value = "0")]
pub gid: u32,
/// Optional certificate path
#[clap(long)]
pub cert: Option<String>,
/// Optional certificate key path
#[clap(long)]
pub cert_key: Option<String>,
/// Optional ca certificate path
#[clap(long)]
pub cert_ca: Option<String>,
/// Optional ssl options
#[clap(flatten)]
pub ssl: Option<SslConfig>,
}

impl Default for Cli {
Expand All @@ -57,9 +53,7 @@ impl Default for Cli {
nodes: vec![],
advertise_addr: None,
gid: 0,
cert: None,
cert_key: None,
cert_ca: None,
ssl: None,
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions bin/nanocld/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ fn gen_daemon_conf(
advertise_addr,
nodes: args.nodes.clone(),
conf_dir: args.conf_dir.clone(),
cert: args.cert.clone(),
cert_key: args.cert_key.clone(),
cert_ca: args.cert_ca.clone(),
ssl: args.ssl.clone(),
})
}

Expand Down
78 changes: 74 additions & 4 deletions bin/nanocld/src/utils/server.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use ntex::web;
use ntex_cors::Cors;
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod, SslVerifyMode};

use nanocl_utils::ntex::middlewares;

Expand Down Expand Up @@ -50,10 +50,11 @@ pub async fn gen(
};
} else if host.starts_with("tcp://") {
let addr = host.replace("tcp://", "");
if let Some(cert) = config.cert.clone() {
if let Some(ssl) = config.ssl.clone() {
log::debug!("server::gen: {addr}: with ssl");
let cert_key = config.cert_key.clone().unwrap();
let cert_ca = config.cert_ca.clone().unwrap();
let cert = ssl.cert.clone().unwrap();
let cert_key = ssl.cert_key.clone().unwrap();
let cert_ca = ssl.cert_ca.clone().unwrap();
server = match server.bind_openssl(&addr, {
let mut builder =
SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
Expand All @@ -62,6 +63,9 @@ pub async fn gen(
.unwrap();
builder.set_certificate_chain_file(cert).unwrap();
builder.set_ca_file(cert_ca).expect("Failed to set ca file");
builder.set_verify(
SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT,
);
builder
}) {
Err(err) => {
Expand Down Expand Up @@ -108,6 +112,9 @@ pub async fn gen(
#[cfg(test)]
mod tests {
use clap::Parser;
use nanocl_stubs::system::BinaryInfo;
use ntex::http::{client::Connector, StatusCode};
use openssl::ssl::SslConnector;

use super::*;

Expand Down Expand Up @@ -180,4 +187,67 @@ mod tests {
let args = init_test_config(vec!["nanocl", "-H", "not_valid"]);
assert_config_err(args).await;
}

#[ntex::test]
async fn ssl_valid_client() {
let args = init_test_config(vec![
"nanocl",
"-H",
"tcp://0.0.0.0:6443",
"--cert",
"../../tests/server.crt",
"--cert-key",
"../../tests/server.key",
"--cert-ca",
"../../tests/ca.crt",
]);
assert_config_ok(args).await;
// Configure SSL/TLS settings
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
builder.set_verify(SslVerifyMode::NONE);
builder
.set_certificate_file("../../tests/client.crt", SslFiletype::PEM)
.unwrap();
builder
.set_private_key_file("../../tests/client.key", SslFiletype::PEM)
.unwrap();
let client = ntex::http::client::Client::build()
.connector(Connector::default().openssl(builder.build()).finish())
.finish();
let mut res = client
.get("https://0.0.0.0:6443/v0.13/version")
.send()
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
let version = res.json::<BinaryInfo>().await.unwrap();
assert_eq!(version.version, vars::VERSION);
}

#[ntex::test]
async fn ssl_wrong_client() {
let args = init_test_config(vec![
"nanocl",
"-H",
"tcp://0.0.0.0:4443",
"--cert",
"../../tests/server.crt",
"--cert-key",
"../../tests/server.key",
"--cert-ca",
"../../tests/ca.crt",
]);
assert_config_ok(args).await;
// Configure SSL/TLS settings
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
builder.set_verify(SslVerifyMode::NONE);
let client = ntex::http::client::Client::build()
.connector(Connector::default().openssl(builder.build()).finish())
.finish();
let res = client
.get("https://0.0.0.0:4443/v0.13/version")
.send()
.await;
assert!(res.is_err());
}
}
3 changes: 2 additions & 1 deletion bin/ncproxy/src/subsystem/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::sync::Arc;

use nanocl_error::io::IoResult;

use nanocld_client::{ConnectOpts, NanocldClient};
use nanocld_client::NanocldClient;

use crate::{
cli::Cli,
Expand All @@ -16,6 +16,7 @@ pub async fn init(cli: &Cli) -> IoResult<SystemStateRef> {
let mut client = NanocldClient::connect_with_unix_default();
#[cfg(any(feature = "dev", feature = "test"))]
{
use nanocld_client::ConnectOpts;
client = NanocldClient::connect_to(&ConnectOpts {
url: "http://nanocl.internal:8585".into(),
..Default::default()
Expand Down
2 changes: 2 additions & 0 deletions crates/nanocl_stubs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ default = ["serde"]
serde = ["dep:serde", "uuid/serde", "chrono/serde"]
utoipa = ["dep:utoipa"]
schemars = ["dep:schemars", "bollard-next/schemars"]
clap = ["dep:clap"]
test = []

[dependencies]
Expand All @@ -30,3 +31,4 @@ chrono = { version = "0.4", default-features = false, features = [
serde = { version = "1.0", features = ["derive"], optional = true }
utoipa = { version = "4", features = ["uuid", "chrono"], optional = true }
schemars = { version = "0.8", features = ["uuid1", "chrono"], optional = true }
clap = { version = "4.4", features = ["derive", "cargo"], optional = true }
14 changes: 5 additions & 9 deletions crates/nanocl_stubs/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};

use super::system::SslConfig;

/// Configuration of the daemon
/// It is used to configure the daemon
#[derive(Debug, Clone)]
Expand All @@ -27,12 +29,8 @@ pub struct DaemonConfig {
pub conf_dir: String,
/// Group id
pub gid: u32,
/// Certificate path
pub cert: Option<String>,
/// Certificate key path
pub cert_key: Option<String>,
/// Ca certificate path
pub cert_ca: Option<String>,
/// Optional ssl configuration
pub ssl: Option<SslConfig>,
}

/// Configuration File of the daemon
Expand Down Expand Up @@ -64,9 +62,7 @@ impl Default for DaemonConfig {
gateway: String::default(),
nodes: Vec::default(),
advertise_addr: String::default(),
cert: None,
cert_key: None,
cert_ca: None,
ssl: None,
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions crates/nanocl_stubs/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,33 @@

use crate::config::DaemonConfig;

#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

Check warning on line 13 in crates/nanocl_stubs/src/system.rs

View check run for this annotation

Codecov / codecov/patch

crates/nanocl_stubs/src/system.rs#L13

Added line #L13 was not covered by tests
#[cfg_attr(feature = "serde", serde(rename_all = "PascalCase"))]
#[cfg_attr(feature = "clap", derive(clap::Parser))]

Check warning on line 15 in crates/nanocl_stubs/src/system.rs

View check run for this annotation

Codecov / codecov/patch

crates/nanocl_stubs/src/system.rs#L15

Added line #L15 was not covered by tests
pub struct SslConfig {
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "Option::is_none")
)]
#[cfg_attr(feature = "clap", clap(long))]
pub cert: Option<String>,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "Option::is_none")
)]
#[cfg_attr(feature = "clap", clap(long))]
pub cert_key: Option<String>,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "Option::is_none")
)]
#[cfg_attr(feature = "clap", clap(long))]
pub cert_ca: Option<String>,
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
Expand Down
Loading
Loading