-
Notifications
You must be signed in to change notification settings - Fork 63
[nexus] Add HTTPS support, plumbing x509 certificates #1500
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
Changes from 9 commits
1f843f1
920ad13
494a6f1
3ede000
0104f49
1cf097a
b58e10a
2926fe0
edea7b9
8137419
eb1ea85
95c10a0
6502c44
0f0afbb
31a93ea
cf4864b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,6 +53,13 @@ This script requires Omicron be uninstalled, e.g., with `pfexec | |
| that is not the case. The script will then remove the file-based vdevs and the | ||
| VNICs created by `create_virtual_hardware.sh`. | ||
|
|
||
| === Make me a certificate! | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there an analogous change for
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is not, because the implementation within Nexus checks for the existence of the certificate files before deciding whether or not to launch the HTTPS server. For the simulated server, they won't exist, so only the HTTP server will be launched. I definitely think this would be required before moving to "HTTPS only", but considered this PR an intermediate step.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mentioned in the other comment, but that doesn't seem like the right behavior. It seems like in production, if they don't exist, that should be a fatal error. And in development, if they do exist, we should start the HTTP server. If this were part of configuration, then whoever's running Nexus can express their intent. (I'm not saying we have to do all that in this PR, but if we decide that is what we want, then I think this behavior is not really an intermediate step.) |
||
|
|
||
| Nexus's external interface will typically be served using public-facing x.509 | ||
| certificate. While we are still configuring the mechanism to integrate this real | ||
| certificate into the package system, `./tools/create_self_signed_cert.sh` can be | ||
| used to generate an equivalent self-signed certificate. | ||
|
Comment on lines
+58
to
+61
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO(me): I wonder if I can fix #1398 and make this easier at the same time?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See: #1528. We're gonna need to grab / insert certs from somewhere. I've updating the packaging hints to make this more obvious if an error is encountered. |
||
|
|
||
| == Deploying Omicron | ||
|
|
||
| The control plane repository contains a packaging tool which bundles binaries | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,8 @@ pub use crucible_agent_client; | |
| use external_api::http_entrypoints::external_api; | ||
| use internal_api::http_entrypoints::internal_api; | ||
| use slog::Logger; | ||
| use std::net::SocketAddr; | ||
| use std::path::PathBuf; | ||
| use std::sync::Arc; | ||
|
|
||
| #[macro_use] | ||
|
|
@@ -71,7 +73,9 @@ pub fn run_openapi_internal() -> Result<(), String> { | |
| pub struct Server { | ||
| /// shared state used by API request handlers | ||
| pub apictx: Arc<ServerContext>, | ||
| /// dropshot server for external API | ||
| /// dropshot server for external API (encrypted) | ||
| pub https_server_external: Option<dropshot::HttpServer<Arc<ServerContext>>>, | ||
| /// dropshot server for external API (unencrypted) | ||
| pub http_server_external: dropshot::HttpServer<Arc<ServerContext>>, | ||
| /// dropshot server for internal API | ||
| pub http_server_internal: dropshot::HttpServer<Arc<ServerContext>>, | ||
|
|
@@ -92,26 +96,98 @@ impl Server { | |
| ServerContext::new(config.deployment.rack_id, ctxlog, &config) | ||
| .await?; | ||
|
|
||
| let http_server_starter_external = dropshot::HttpServerStarter::new( | ||
| &config.deployment.dropshot_external, | ||
| external_api(), | ||
| Arc::clone(&apictx), | ||
| &log.new(o!("component" => "dropshot_external")), | ||
| ) | ||
| .map_err(|error| format!("initializing external server: {}", error))?; | ||
|
|
||
| // Determine port choices | ||
|
|
||
| let (external_http_port, external_https_port, internal_http_port) = | ||
| match config.deployment.port_picker { | ||
| omicron_common::nexus_config::PortPicker::NexusChoice => { | ||
| (80, 443, omicron_common::address::NEXUS_INTERNAL_PORT) | ||
| } | ||
| omicron_common::nexus_config::PortPicker::Zero => (0, 0, 0), | ||
| }; | ||
|
|
||
| // Launch the internal server. | ||
|
|
||
| let dropshot_internal_config = dropshot::ConfigDropshot { | ||
| bind_address: SocketAddr::new( | ||
| config.deployment.internal_ip, | ||
| internal_http_port, | ||
| ), | ||
| request_body_max_bytes: 1048576, | ||
| ..Default::default() | ||
| }; | ||
| let http_server_starter_internal = dropshot::HttpServerStarter::new( | ||
| &config.deployment.dropshot_internal, | ||
| &dropshot_internal_config, | ||
| internal_api(), | ||
| Arc::clone(&apictx), | ||
| &log.new(o!("component" => "dropshot_internal")), | ||
| ) | ||
| .map_err(|error| format!("initializing internal server: {}", error))?; | ||
| let http_server_internal = http_server_starter_internal.start(); | ||
|
|
||
| // Launch the external server(s). | ||
| // | ||
| // - The HTTP server is unconditionally started. | ||
| // - The HTTPS server is started if the necessary certificate files | ||
| // exist. | ||
| // | ||
| // TODO: Consider changing this disposition, making "HTTPS" the default, | ||
| // and returning an error if the certificates don't exist. Doing so | ||
| // would be the more secure long-term plan, but would make gradual | ||
| // deployment of this feature more difficult. | ||
|
|
||
| let cert_file = PathBuf::from("/var/nexus/certs/cert.pem"); | ||
|
||
| let key_file = PathBuf::from("/var/nexus/certs/key.pem"); | ||
|
|
||
| let https_server_external = if cert_file.exists() && key_file.exists() { | ||
| let dropshot_external_https_config = dropshot::ConfigDropshot { | ||
| bind_address: SocketAddr::new( | ||
| config.deployment.external_ip, | ||
| external_https_port, | ||
| ), | ||
| request_body_max_bytes: 1048576, | ||
| tls: Some(dropshot::ConfigTls { cert_file, key_file }), | ||
| }; | ||
| let https_server_starter_external = | ||
| dropshot::HttpServerStarter::new( | ||
| &dropshot_external_https_config, | ||
| external_api(), | ||
| Arc::clone(&apictx), | ||
| &log.new( | ||
| o!("component" => "dropshot_external (encrypted)"), | ||
| ), | ||
| ) | ||
| .map_err(|error| { | ||
| format!("initializing external server: {}", error) | ||
| })?; | ||
| Some(https_server_starter_external.start()) | ||
| } else { | ||
| None | ||
| }; | ||
|
|
||
| let dropshot_external_http_config = dropshot::ConfigDropshot { | ||
| bind_address: SocketAddr::new( | ||
| config.deployment.external_ip, | ||
| external_http_port, | ||
| ), | ||
| request_body_max_bytes: 1048576, | ||
| tls: None, | ||
| }; | ||
| let http_server_starter_external = dropshot::HttpServerStarter::new( | ||
| &dropshot_external_http_config, | ||
| external_api(), | ||
| Arc::clone(&apictx), | ||
| &log.new(o!("component" => "dropshot_external (unencrypted)")), | ||
| ) | ||
| .map_err(|error| format!("initializing external server: {}", error))?; | ||
| let http_server_external = http_server_starter_external.start(); | ||
| let http_server_internal = http_server_starter_internal.start(); | ||
|
|
||
| Ok(Server { apictx, http_server_external, http_server_internal }) | ||
| Ok(Server { | ||
| apictx, | ||
| https_server_external, | ||
| http_server_external, | ||
| http_server_internal, | ||
| }) | ||
| } | ||
|
|
||
| /// Wait for the given server to shut down | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.