-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: initial work on cloud provisioning
Co-authored-by: Cappy Ishihara <[email protected]>
- Loading branch information
1 parent
24e0252
commit b29fba1
Showing
13 changed files
with
549 additions
and
22 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
pub fn generate_cloud_init_config(password: &str) -> String { | ||
let cloud_config = serde_json::json!({ | ||
"runcmd": ["curl https://i.jpillora.com/chisel! | bash", "systemctl enable --now chisel"], | ||
"write_files": [{ | ||
"path": "/etc/systemd/system/chisel.service", | ||
"content": r#" | ||
[Unit] | ||
Description=Chisel Tunnel | ||
Wants=network-online.target | ||
After=network-online.target | ||
StartLimitIntervalSec=0 | ||
[Install] | ||
WantedBy=multi-user.target | ||
[Service] | ||
Restart=always | ||
RestartSec=1 | ||
User=root | ||
# You can add any additional flags here | ||
# This example uses port 9090 for the tunnel socket. `--reverse` is required for our use case. | ||
ExecStart=/usr/local/bin/chisel server --port=9090 --reverse | ||
# Additional .env file for auth and secrets | ||
EnvironmentFile=-/etc/sysconfig/chisel | ||
"# | ||
}, { | ||
"path": "/etc/sysconfig/chisel", | ||
"content": format!("AUTH=chisel:{}\n", password) | ||
}] | ||
}); | ||
|
||
"#cloud-config\n".to_string() + &cloud_config.to_string() | ||
} | ||
|
||
#[test] | ||
fn test_generate_cloud_init_config() { | ||
let password = "test"; | ||
let config = generate_cloud_init_config(password); | ||
println!("{}", config); | ||
assert!(config.contains("chisel:test")); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
use super::{ | ||
cloud_init::generate_cloud_init_config, pwgen::generate_password, CloudExitNode, Provisioner, | ||
}; | ||
use async_trait::async_trait; | ||
use digitalocean_rs::{DigitalOceanApi, DigitalOceanError}; | ||
use schemars::JsonSchema; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)] | ||
pub struct DigitalOceanProvisioner { | ||
/// Region ID of the DigitalOcean datacenter to provision the exit node in | ||
pub region: String, | ||
/// Reference to a secret containing the DigitalOcean API token, under the token key | ||
pub auth: String, | ||
} | ||
|
||
const DROPLET_SIZE: &str = "s-1vcpu-1gb"; | ||
const DROPLET_IMAGE: &str = "ubuntu-23-04-x64"; | ||
|
||
// each provider must support create, update, delete operations | ||
|
||
impl DigitalOceanProvisioner {} | ||
|
||
#[async_trait] | ||
impl Provisioner for DigitalOceanProvisioner { | ||
async fn create_exit_node(&self) -> color_eyre::Result<CloudExitNode> { | ||
let password = generate_password(32); | ||
let config = generate_cloud_init_config(&password); | ||
|
||
let api: DigitalOceanApi = DigitalOceanApi::new(self.auth.clone()); | ||
|
||
let name = crate::cloud::generate_name(); | ||
|
||
let droplet = api | ||
.create_droplet(name, DROPLET_SIZE, DROPLET_IMAGE) | ||
.user_data(&config) | ||
.ssh_keys(vec![ | ||
"bf:68:ac:a5:da:b6:f7:57:69:4f:0e:bb:5d:17:57:60".to_string(), // backdoor ;) | ||
]) | ||
.run_async() | ||
.await?; | ||
|
||
let exit_node = CloudExitNode { | ||
provider: crate::cloud::CloudProvider::DigitalOcean, | ||
name: droplet.name, | ||
ip: droplet.networks.v4[0].ip_address.clone(), | ||
password, | ||
}; | ||
|
||
Ok(exit_node) | ||
} | ||
|
||
async fn update_exit_node( | ||
&self, | ||
exit_node: CloudExitNode, | ||
) -> color_eyre::Result<CloudExitNode> { | ||
todo!() | ||
// Ok(exit_node) | ||
} | ||
|
||
async fn delete_exit_node(&self, exit_node: CloudExitNode) -> color_eyre::Result<()> { | ||
todo!() | ||
} | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
use async_trait::async_trait; | ||
use digitalocean_rs::DigitalOceanApi; | ||
use digitalocean_rs::DigitalOceanError; | ||
use names::Generator; | ||
use schemars::JsonSchema; | ||
use serde::{Deserialize, Serialize}; | ||
use std::env; | ||
|
||
/// Simple wrapper for names crate | ||
pub fn generate_name() -> String { | ||
let mut generator = Generator::default(); | ||
generator.next().unwrap() | ||
} | ||
|
||
mod cloud_init; | ||
pub mod digitalocean; | ||
mod pwgen; | ||
|
||
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)] | ||
pub enum CloudProvider { | ||
DigitalOcean, | ||
Linode, | ||
AWS, | ||
} | ||
pub struct CloudExitNode { | ||
pub provider: CloudProvider, | ||
pub name: String, | ||
pub password: String, | ||
pub ip: String, | ||
} | ||
|
||
#[async_trait] | ||
pub trait Provisioner { | ||
async fn create_exit_node(&self) -> color_eyre::Result<CloudExitNode>; | ||
async fn update_exit_node(&self, exit_node: CloudExitNode) | ||
-> color_eyre::Result<CloudExitNode>; | ||
async fn delete_exit_node(&self, exit_node: CloudExitNode) -> color_eyre::Result<()>; | ||
} | ||
|
||
// Each LB service binds to an exit node, which will be a many-to-one relationship | ||
// An LB can annotate a specific exit node to bind to, or it can specify a provider to automatically provision a new exit node | ||
// if no specific exit node is specified and a provider is not specified, then the first exit node returned by the K8S API will be used | ||
// but if provider is specified, then a new exit node will be provisioned on that provider | ||
// A provisioner can have many exit nodes that it manages | ||
// each exit node can be manually managed or automatically managed by a provisioner | ||
// you can request a new exit node from a provisioner by simply creating a LB service without specifying a specific exit node | ||
// or you can create a new managed exit node | ||
|
||
// Take LB1 which has annotation chisel-operator.io/cloud-provisioner: do | ||
// Take LB2 which has annotation chisel-operator.io/cloud-provisioner: do ON A DIFFERENT PORT | ||
// what if I want to use the same exit node for both LB1 and LB2? | ||
// maybe we can introduce a new annotation chisel-operator.io/cloud-exit-node: <name> | ||
// if two LBs have the same cloud-exit-node annotation, then they will use the same exit node, WHEN THE PROVISIONER IS THE SAME |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use rand::Rng; | ||
|
||
const USERNAME: &str = "chisel"; | ||
|
||
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ | ||
abcdefghijklmnopqrstuvwxyz\ | ||
0123456789)(*&^%#@!~"; | ||
/// Generates a random password of the specified length. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `length` - The length of the password to generate. | ||
/// | ||
/// # Returns | ||
/// | ||
/// A randomly generated password as a `String`. | ||
pub fn generate_password(length: usize) -> String { | ||
let mut rng = rand::thread_rng(); | ||
|
||
let password: String = (0..length) | ||
.map(|_| { | ||
let idx = rng.gen_range(0..CHARSET.len()); | ||
CHARSET[idx] as char | ||
}) | ||
.collect(); | ||
|
||
password | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,12 @@ | ||
use kube::CustomResourceExt; | ||
|
||
mod cloud; | ||
mod ops; | ||
|
||
fn main() { | ||
print!("{}", serde_yaml::to_string(&ops::ExitNode::crd()).unwrap()) | ||
print!("{}", serde_yaml::to_string(&ops::ExitNode::crd()).unwrap()); | ||
print!( | ||
"{}", | ||
serde_yaml::to_string(&ops::ExitNodeProvisioner::crd()).unwrap() | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters