mirror of
https://github.com/warp-tech/warpgate.git
synced 2024-09-20 06:46:17 +08:00
unattended setup - fixes #409
This commit is contained in:
parent
8831d2006f
commit
f96760982c
|
@ -1,6 +1,6 @@
|
|||
use std::fs::{create_dir_all, File};
|
||||
use std::io::Write;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
|
@ -21,6 +21,7 @@ use warpgate_db_entities::{Role, User, UserRoleAssignment};
|
|||
|
||||
use crate::commands::common::{assert_interactive_terminal, is_docker};
|
||||
use crate::config::load_config;
|
||||
use crate::Commands;
|
||||
|
||||
fn prompt_endpoint(prompt: &str, default: ListenEndpoint) -> ListenEndpoint {
|
||||
loop {
|
||||
|
@ -53,7 +54,9 @@ pub(crate) async fn command(cli: &crate::Cli) -> Result<()> {
|
|||
std::process::exit(1);
|
||||
}
|
||||
|
||||
assert_interactive_terminal();
|
||||
if let Commands::Setup = cli.command {
|
||||
assert_interactive_terminal();
|
||||
}
|
||||
|
||||
let mut config_dir = cli.config.parent().unwrap_or_else(|| Path::new(&"."));
|
||||
if config_dir.as_os_str().is_empty() {
|
||||
|
@ -87,18 +90,22 @@ pub(crate) async fn command(cli: &crate::Cli) -> Result<()> {
|
|||
|
||||
// ---
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
let default_data_path = "/var/lib/warpgate".to_string();
|
||||
#[cfg(target_os = "macos")]
|
||||
let default_data_path = "/usr/local/var/lib/warpgate".to_string();
|
||||
|
||||
let data_path: String = if is_docker() {
|
||||
"/data".to_owned()
|
||||
let data_path: String = if let Commands::UnattendedSetup { data_path, .. } = &cli.command {
|
||||
data_path.to_owned()
|
||||
} else {
|
||||
dialoguer::Input::with_theme(&theme)
|
||||
.default(default_data_path)
|
||||
.with_prompt("Directory to store app data (up to a few MB) in")
|
||||
.interact_text()?
|
||||
#[cfg(target_os = "linux")]
|
||||
let default_data_path = "/var/lib/warpgate".to_string();
|
||||
#[cfg(target_os = "macos")]
|
||||
let default_data_path = "/usr/local/var/lib/warpgate".to_string();
|
||||
|
||||
if is_docker() {
|
||||
"/data".to_owned()
|
||||
} else {
|
||||
dialoguer::Input::with_theme(&theme)
|
||||
.default(default_data_path)
|
||||
.with_prompt("Directory to store app data (up to a few MB) in")
|
||||
.interact_text()?
|
||||
}
|
||||
};
|
||||
|
||||
let db_path = PathBuf::from(&data_path).join("db");
|
||||
|
@ -115,42 +122,62 @@ pub(crate) async fn command(cli: &crate::Cli) -> Result<()> {
|
|||
database_url.push_str(&db_path);
|
||||
store.database_url = Secret::new(database_url);
|
||||
|
||||
// ---
|
||||
if !is_docker() {
|
||||
store.http.listen = prompt_endpoint(
|
||||
"Endpoint to listen for HTTP connections on",
|
||||
HTTPConfig::default().listen,
|
||||
);
|
||||
|
||||
info!("You will now choose specific protocol listeners to be enabled.");
|
||||
info!("");
|
||||
info!("NB: Nothing will be exposed by default -");
|
||||
info!(" you'll set target hosts in the config file later.");
|
||||
|
||||
store.ssh.enable = dialoguer::Confirm::with_theme(&theme)
|
||||
.default(true)
|
||||
.with_prompt("Accept SSH connections?")
|
||||
.interact()?;
|
||||
|
||||
if store.ssh.enable {
|
||||
store.ssh.listen = prompt_endpoint(
|
||||
"Endpoint to listen for SSH connections on",
|
||||
SSHConfig::default().listen,
|
||||
if let Commands::UnattendedSetup { http_port, .. } = &cli.command {
|
||||
store.http.enable = true;
|
||||
store.http.listen = ListenEndpoint(SocketAddr::from(([0, 0, 0, 0], *http_port)));
|
||||
} else {
|
||||
if !is_docker() {
|
||||
store.http.listen = prompt_endpoint(
|
||||
"Endpoint to listen for HTTP connections on",
|
||||
HTTPConfig::default().listen,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
if let Commands::UnattendedSetup { ssh_port, .. } = &cli.command {
|
||||
if let Some(ssh_port) = ssh_port {
|
||||
store.ssh.enable = true;
|
||||
store.ssh.listen = ListenEndpoint(SocketAddr::from(([0, 0, 0, 0], *ssh_port)));
|
||||
}
|
||||
} else {
|
||||
if !is_docker() {
|
||||
info!("You will now choose specific protocol listeners to be enabled.");
|
||||
info!("");
|
||||
info!("NB: Nothing will be exposed by default -");
|
||||
info!(" you'll set target hosts in the config file later.");
|
||||
|
||||
store.mysql.enable = dialoguer::Confirm::with_theme(&theme)
|
||||
.default(true)
|
||||
.with_prompt("Accept MySQL connections?")
|
||||
.interact()?;
|
||||
store.ssh.enable = dialoguer::Confirm::with_theme(&theme)
|
||||
.default(true)
|
||||
.with_prompt("Accept SSH connections?")
|
||||
.interact()?;
|
||||
|
||||
if store.mysql.enable {
|
||||
store.mysql.listen = prompt_endpoint(
|
||||
"Endpoint to listen for MySQL connections on",
|
||||
MySQLConfig::default().listen,
|
||||
);
|
||||
if store.ssh.enable {
|
||||
store.ssh.listen = prompt_endpoint(
|
||||
"Endpoint to listen for SSH connections on",
|
||||
SSHConfig::default().listen,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Commands::UnattendedSetup { ssh_port, .. } = &cli.command {
|
||||
if let Some(ssh_port) = ssh_port {
|
||||
store.ssh.enable = true;
|
||||
store.ssh.listen = ListenEndpoint(SocketAddr::from(([0, 0, 0, 0], *ssh_port)));
|
||||
}
|
||||
} else {
|
||||
if !is_docker() {
|
||||
store.mysql.enable = dialoguer::Confirm::with_theme(&theme)
|
||||
.default(true)
|
||||
.with_prompt("Accept MySQL connections?")
|
||||
.interact()?;
|
||||
|
||||
if store.mysql.enable {
|
||||
store.mysql.listen = prompt_endpoint(
|
||||
"Endpoint to listen for MySQL connections on",
|
||||
MySQLConfig::default().listen,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,10 +203,17 @@ pub(crate) async fn command(cli: &crate::Cli) -> Result<()> {
|
|||
|
||||
// ---
|
||||
|
||||
store.recordings.enable = dialoguer::Confirm::with_theme(&theme)
|
||||
.default(true)
|
||||
.with_prompt("Do you want to record user sessions?")
|
||||
.interact()?;
|
||||
if let Commands::UnattendedSetup {
|
||||
record_sessions, ..
|
||||
} = &cli.command
|
||||
{
|
||||
store.recordings.enable = *record_sessions;
|
||||
} else {
|
||||
store.recordings.enable = dialoguer::Confirm::with_theme(&theme)
|
||||
.default(true)
|
||||
.with_prompt("Do you want to record user sessions?")
|
||||
.interact()?;
|
||||
}
|
||||
store.recordings.path = PathBuf::from(&data_path)
|
||||
.join("recordings")
|
||||
.to_string_lossy()
|
||||
|
@ -187,9 +221,25 @@ pub(crate) async fn command(cli: &crate::Cli) -> Result<()> {
|
|||
|
||||
// ---
|
||||
|
||||
let admin_password = dialoguer::Password::with_theme(&theme)
|
||||
.with_prompt("Set a password for the Warpgate admin user")
|
||||
.interact()?;
|
||||
let admin_password = if let Commands::UnattendedSetup { admin_password, .. } = &cli.command {
|
||||
if let Some(admin_password) = admin_password {
|
||||
admin_password.to_owned()
|
||||
} else {
|
||||
if let Ok(admin_password) = std::env::var("WARPGATE_ADMIN_PASSWORD") {
|
||||
admin_password
|
||||
} else {
|
||||
error!(
|
||||
"You must supply the admin password either through the --admin-password option"
|
||||
);
|
||||
error!("or the WARPGATE_ADMIN_PASSWORD environment variable.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dialoguer::Password::with_theme(&theme)
|
||||
.with_prompt("Set a password for the Warpgate admin user")
|
||||
.interact()?
|
||||
};
|
||||
|
||||
// ---
|
||||
|
||||
|
|
|
@ -30,9 +30,35 @@ pub struct Cli {
|
|||
}
|
||||
|
||||
#[derive(clap::Subcommand)]
|
||||
enum Commands {
|
||||
pub(crate) enum Commands {
|
||||
/// Run first-time setup and generate a config file
|
||||
Setup,
|
||||
/// Run first-time setup non-interactively
|
||||
UnattendedSetup {
|
||||
/// Directory to store data in
|
||||
#[clap(long)]
|
||||
data_path: String,
|
||||
|
||||
/// HTTP port
|
||||
#[clap(long)]
|
||||
http_port: u16,
|
||||
|
||||
/// Enable SSH and set port
|
||||
#[clap(long)]
|
||||
ssh_port: Option<u16>,
|
||||
|
||||
/// Enable MySQL and set port
|
||||
#[clap(long)]
|
||||
mysql_port: Option<u16>,
|
||||
|
||||
/// Enable session recording
|
||||
#[clap(long)]
|
||||
record_sessions: bool,
|
||||
|
||||
/// Password for the initial user (required if WARPGATE_ADMIN_PASSWORD env var is not set)
|
||||
#[clap(long)]
|
||||
admin_password: Option<String>,
|
||||
},
|
||||
/// Show Warpgate's SSH client keys
|
||||
ClientKeys,
|
||||
/// Run Warpgate
|
||||
|
@ -62,7 +88,9 @@ async fn _main() -> Result<()> {
|
|||
Commands::TestTarget { target_name } => {
|
||||
crate::commands::test_target::command(&cli, target_name).await
|
||||
}
|
||||
Commands::Setup => crate::commands::setup::command(&cli).await,
|
||||
Commands::Setup | Commands::UnattendedSetup { .. } => {
|
||||
crate::commands::setup::command(&cli).await
|
||||
}
|
||||
Commands::ClientKeys => crate::commands::client_keys::command(&cli).await,
|
||||
Commands::RecoverAccess { username } => {
|
||||
crate::commands::recover_access::command(&cli, username).await
|
||||
|
|
Loading…
Reference in a new issue