From bcf1b7800ed6936e9f9b0ace78c3c802587a7f92 Mon Sep 17 00:00:00 2001 From: Naman Arora Date: Sun, 8 Sep 2024 17:16:59 +1000 Subject: [PATCH] Parameterize ssh path and remove old docs (#15) --- docs/HA_Proxy.md | 47 ------- docs/Variables.md | 1 + docs/Wireguard_Setup.md | 256 ---------------------------------- main.tf | 24 ++-- modules/ignition/main.tf | 2 +- modules/ignition/variables.tf | 4 + modules/proxy/main.tf | 2 +- modules/proxy/variables.tf | 4 + templates/k0s.tmpl | 4 +- terraform.tfvars.example | 1 + varaibles.tf | 5 + 11 files changed, 33 insertions(+), 317 deletions(-) delete mode 100644 docs/HA_Proxy.md delete mode 100644 docs/Wireguard_Setup.md diff --git a/docs/HA_Proxy.md b/docs/HA_Proxy.md deleted file mode 100644 index 6443d44..0000000 --- a/docs/HA_Proxy.md +++ /dev/null @@ -1,47 +0,0 @@ -# HA Proxy user setup - -It's a good idea to create a non-root user just to manage haproxy access. In this example, the user is named `wireproxy`. - -``` -# Login to the Raspberry Pi -# Install haproxy -sudo apt-get install haproxy -sudo systemctl enable haproxy -sudo systemctl start haproxy -# Run this from a user with sudo privileges -sudo EDITOR=vim visudo -%wireproxy ALL= (root) NOPASSWD: /bin/systemctl restart haproxy - -sudo addgroup wireproxy -sudo adduser --disabled-password --ingroup wireproxy wireproxy -``` - -You'll need to make sure that you're able to ssh into this user account without a password. For example, let's say the user with sudo privileges is named `ubuntu`. Follow these steps to enable passwordless SSH for `ubuntu`. - -``` -# Run this from your Client -# Change user/IP address here as needed -ssh-copy-id -i ~/.ssh/id_rsa.pub ubuntu@192.168.0.100 -``` - -Now you can either follow the same steps for the `wireproxy` user (not recommended as we don't want to give the `wireproxy` user a password) or you can copy the `~/.ssh/authorized_keys` file from the `ubuntu` user to this user. - -``` -# Login to the Raspberry Pi with user 'ubuntu' -cat ~/.ssh/authorized_keys -# Copy the value in a clipboard -sudo su wireproxy -# You're now logged in as wireproxy user -vim ~/.ssh/authorized_keys -# Paste the same key here -# Logout from the Raspberry Pi -# Make sure you're able to ssh in wireproxy user from your Client -ssh wireproxy@192.168.0.100 -``` - -Using the same example, the user `wireproxy` needs to own the files under `/etc/haproxy` - -``` -# Login to the Raspberry Pi with user 'ubuntu' -sudo chown -R wireproxy: /etc/haproxy -``` \ No newline at end of file diff --git a/docs/Variables.md b/docs/Variables.md index af890da..b2cb07a 100644 --- a/docs/Variables.md +++ b/docs/Variables.md @@ -6,6 +6,7 @@ | PROXMOX_USERNAME | User name used to login proxmox | | PROXMOX_PASSWORD | Password used to login proxmox | | PROXMOX_IP | IP address for proxmox | +| PROXMOX_SSH_KEY | Path to private SSH key used to ssh into proxmox | | DEFAULT_BRIDGE | Bridge to use when creating VMs in proxmox | | TARGET_NODE | Target node name in proxmox | | MASTER_COUNT | Number of masters to create (Should be an odd number) | diff --git a/docs/Wireguard_Setup.md b/docs/Wireguard_Setup.md deleted file mode 100644 index 9e054af..0000000 --- a/docs/Wireguard_Setup.md +++ /dev/null @@ -1,256 +0,0 @@ -# Exposing private cluster over public internet - -This guide assumes that you're using a VM in OCI - this is not required and you can use any other cloud provider with slight changes to follow this guide. -This guide also assumes that the wireguard client and server are using Ubuntu - you can change the installation commands for your distro and follow this guide. - - -## Create the VM in OCI with a .pem file for ssh access - -Make sure you're able to ssh into the VM. Then run the following commands: - -``` -sudo apt-get update -y && sudo apt-get upgrade -y -sudo apt-get dist-upgrade -y -curl -fsSL https://get.docker.com -o get-docker.sh -sh get-docker.sh -sudo apt-get install docker-compose wireguard -y -sudo reboot -``` - -## Setting up DuckDNS - -This step is only needed if you don't own a domain already. -Create an account on [DuckDNS](https://www.duckdns.org/). After logging in, you'll see your token and your list of subdomains. -Create a new subdomain and keep its value handy for the following command. - -``` -mkdir duckdns -cd duckdns -# Using DuckDNS for a subdomain - update subdomains list and token value -sudo docker run -d \ - --name=duckdns \ - -e PUID=1000 \ - -e PGID=1000 \ - -e TZ=Asia/Kolkata \ - -e SUBDOMAINS=example.duckdns.org \ - -e TOKEN=token_value \ - -e LOG_FILE=true \ - -v `pwd`:/config `#optional` \ - --restart unless-stopped \ - lscr.io/linuxserver/duckdns:latest - -# Go back to the home dir -cd .. -``` - -## Setting up Nginx Proxy Manager - -Open only port 80 and 443 on the VM subnet settings. - -Port 8080 is for managing your proxy manager (with the port mapping in this config) - by default it will have very weak creds - we'll port forward the port over SSH to configure this securely later. -``` -mkdir nginx-proxy-manager -cd nginx-proxy-manager -vim docker-compose.yml -``` - -Paste the following into the file. Update username and passwords as needed. -``` -version: "3" -services: - app: - image: 'jc21/nginx-proxy-manager:latest' - restart: unless-stopped - ports: - # These ports are in format : - - '80:80' # Public HTTP Port - - '443:443' # Public HTTPS Port - - '8080:81' # Admin Web Port - # Add any other Stream port you want to expose - # - '21:21' # FTP - environment: - DB_MYSQL_HOST: "db" - DB_MYSQL_PORT: 3306 - DB_MYSQL_USER: "username" - DB_MYSQL_PASSWORD: "password" - DB_MYSQL_NAME: "username" - # Uncomment this if IPv6 is not enabled on your host - DISABLE_IPV6: 'true' - volumes: - - ./data:/data - - ./letsencrypt:/etc/letsencrypt - depends_on: - - db - - db: - image: 'jc21/mariadb-aria:latest' - restart: unless-stopped - environment: - MYSQL_ROOT_PASSWORD: 'password' - MYSQL_DATABASE: 'username' - MYSQL_USER: 'username' - MYSQL_PASSWORD: 'password' - volumes: - - ./data/mysql:/var/lib/mysql -``` - -Deploy nginx proxy manager. -``` -sudo docker-compose up -d -``` -In case you need to restart this compose after the wireguard connection - make sure to delete the data and letsencrypt dirs. - - -SSH using -L flag to port forward 8080 -``` -ssh -L 8080:127.0.0.1:8080 ubuntu@IP -``` -In your local go to http://localhost:8080/login -Update the username and password from admin@example.com/changeme to something more secure - - - -## Setting up Wireguard - -Many cloud providers use something called CGNAT to stop wireguard traffic. -Follow the steps mentioned in this [repo](https://github.com/mochman/Bypass_CGNAT.git) to get around this. - -In the following instructions: - -Client = Raspberry Pi/VM running HAProxy - -Server = VPS in the cloud - -Assuming that you're using OCI as your cloud provider, you may have to follow the instructions below to fix some issues with the script. - -- Modify the Endpoint on the client side to use the duckdns subdomain -- Fix the public key on the client side - this will require regenerating the wg keys for both client and server as the script seems to mess up the public key on the client side - -``` -# On both client and server -wg genkey | tee privatekey | wg pubkey > publickey -``` - -- Copy the private key from file 'privatekey' and update in this file - -``` -sudo vim /etc/wireguard/wg0.conf -``` -- Copy the publickey of client and move to the config of server and also the other way around - -On client run the script mentioned below and select this option --> 2) Reload Wireguard Service. It will ask some questions regarding the config - just press enter from that point onwards to select the default config. - -``` -# Only on the client -./Oracle_Installer.sh -sudo systemctl restart wg-quick@wg0.service -``` - -- Make sure the server and client are able to ping each other -- One way to check this is to use wg show - -``` -sudo wg show -``` -- If you see anything in the 'transfer' section - then this means the VPN is working! - -If you're still having trouble, refer to the client and server configs shown below. - -``` -# Server -[Interface] -Address = 10.1.0.1/24 -SaveConfig = true -PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o br-e9809ca86b25 -j MASQUERADE; -PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o br-e9809ca86b25 -j MASQUERADE; -ListenPort = 55108 -PrivateKey = server_private_key - -[Peer] -PublicKey = client_public_key -AllowedIPs = 10.1.0.2/32 -``` - -``` -#Client -[Interface] -PrivateKey = client_private_key -Address = 10.1.0.2/24 - - -[Peer] -PublicKey = server_public_key -AllowedIPs = 0.0.0.0/0 -Endpoint = example.duckdns.org:55108 -PersistentKeepalive = 25 -``` - -## Re-using the same subdomain by using multi-path ingresses - -Let's say that you have one subdomain "example.duckdns.com" and you want to host a bunch of websites using the same subdomain. Meaning you want to have websites with paths something like this: - -- example.duckdns.com/wordpress -- example.duckdns.com/blog -- example.duckdns.com/docs -- example.duckdns.com/grafana - -In order to make this work properly, you'll need to add some annotations to rewrite the ingress path before it reaches the service endpoint in kubernetes. To do this, you need to add a rewrite-target annotation to your ingress. This annotation depends on what ingress controller you're using in your cluster. - -In case you're using the nginx ingress controller as shown in the main readme file of this repo, then you need to add the following annotation to your ingress resources. - -``` -nginx.ingress.kubernetes.io/rewrite-target: /$2 -``` - -This is re-writing the path that is present in any path that has the following syntax: - -``` -- path: /something(/|$)(.*) -``` - -Read [this](https://github.com/kubernetes/ingress-nginx/blob/main/docs/examples/rewrite/README.md) document to learn more about the nginx ingress controller's rewrite-target annotation. - -### Example Ingress - -``` -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - meta.helm.sh/release-name: longhorn - meta.helm.sh/release-namespace: longhorn-system - nginx.ingress.kubernetes.io/rewrite-target: /$2 - generation: 2 - labels: - app: longhorn-ingress - app.kubernetes.io/instance: longhorn - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: longhorn - app.kubernetes.io/version: v1.4.0 - helm.sh/chart: longhorn-1.4.0 - name: longhorn-ingress - namespace: longhorn-system -spec: - ingressClassName: nginx - rules: - - host: example.duckdns.org - http: - paths: - - backend: - service: - name: longhorn-frontend - port: - number: 80 - path: /longhorn(/|$)(.*) - pathType: ImplementationSpecific -status: - loadBalancer: - ingress: - - ip: 192.168.0.101 -``` - -Now longhorn will be accessible at `https://example.duckdns.org/longhorn/` - -## Notes - -Make sure that your IP is not being leaked by checking your subdomain in https://ipleak.net/ diff --git a/main.tf b/main.tf index 9e89fe1..d230788 100644 --- a/main.tf +++ b/main.tf @@ -46,7 +46,7 @@ resource "null_resource" "copy_qcow2_image" { connection { host = var.PROXMOX_IP user = var.PROXMOX_USERNAME - private_key = file("~/.ssh/id_rsa") + private_key = file(var.PROXMOX_SSH_KEY) } inline = [ @@ -64,7 +64,7 @@ resource "null_resource" "copy_qcow2_image" { type = "ssh" host = var.PROXMOX_IP user = var.PROXMOX_USERNAME - private_key = file("~/.ssh/id_rsa") + private_key = file(var.PROXMOX_SSH_KEY) } } } @@ -74,13 +74,13 @@ resource "null_resource" "copy_ssh_keys" { null_resource.copy_qcow2_image ] provisioner "file" { - source = "~/.ssh/id_rsa.pub" + source = join("", [var.PROXMOX_SSH_KEY, ".pub"]) destination = "/root/fcos-cluster/id_rsa.pub" connection { type = "ssh" host = var.PROXMOX_IP user = var.PROXMOX_USERNAME - private_key = file("~/.ssh/id_rsa") + private_key = file(var.PROXMOX_SSH_KEY) } } } @@ -94,7 +94,7 @@ resource "null_resource" "create_template" { connection { host = var.PROXMOX_IP user = var.PROXMOX_USERNAME - private_key = file("~/.ssh/id_rsa") + private_key = file(var.PROXMOX_SSH_KEY) } script = "${path.root}/scripts/template.sh" @@ -117,6 +117,7 @@ module "master-ignition" { proxmox_user = var.PROXMOX_USERNAME proxmox_password = var.PROXMOX_PASSWORD proxmox_host = var.PROXMOX_IP + ssh_key = join("", [var.PROXMOX_SSH_KEY, ".pub"]) count = var.MASTER_COUNT } @@ -129,6 +130,7 @@ module "worker-ignition" { proxmox_user = var.PROXMOX_USERNAME proxmox_password = var.PROXMOX_PASSWORD proxmox_host = var.PROXMOX_IP + ssh_key = join("", [var.PROXMOX_SSH_KEY, ".pub"]) count = var.WORKER_COUNT } @@ -171,6 +173,7 @@ module "proxy" { ha_proxy_user = local.ha_proxy_user DEFAULT_BRIDGE = var.DEFAULT_BRIDGE TARGET_NODE = var.TARGET_NODE + ssh_key = join("", [var.PROXMOX_SSH_KEY, ".pub"]) } @@ -201,7 +204,7 @@ resource "local_file" "haproxy_config" { type = "ssh" host = module.proxy.proxy_ipv4_address user = local.ha_proxy_user - private_key = file("~/.ssh/id_rsa") + private_key = file(var.PROXMOX_SSH_KEY) } } @@ -209,7 +212,7 @@ resource "local_file" "haproxy_config" { connection { host = module.proxy.proxy_ipv4_address user = local.ha_proxy_user - private_key = file("~/.ssh/id_rsa") + private_key = file(var.PROXMOX_SSH_KEY) } inline = [ @@ -232,9 +235,10 @@ resource "local_file" "k0sctl_config" { node_map_workers = zipmap( tolist(module.worker_domain.*.address), tolist(module.worker_domain.*.name) ), - "user" = "core", - "k0s_version" = local.k0s_version, - "ha_proxy_server" : module.proxy.proxy_ipv4_address + "user" = "core", + "k0s_version" = local.k0s_version, + "ha_proxy_server" = module.proxy.proxy_ipv4_address, + "ssh_key" = var.PROXMOX_SSH_KEY } ) filename = "k0sctl.yaml" diff --git a/modules/ignition/main.tf b/modules/ignition/main.tf index 96304f0..59198d4 100644 --- a/modules/ignition/main.tf +++ b/modules/ignition/main.tf @@ -12,7 +12,7 @@ data "template_file" "config" { template = file("${path.module}/system-units/template.yaml") vars = { domain_name = var.name - ssh_authorized_key = file("~/.ssh/id_rsa.pub") + ssh_authorized_key = file(pathexpand(var.ssh_key)) } } diff --git a/modules/ignition/variables.tf b/modules/ignition/variables.tf index cb73172..846356b 100644 --- a/modules/ignition/variables.tf +++ b/modules/ignition/variables.tf @@ -16,4 +16,8 @@ variable "proxmox_user" { variable "proxmox_password" { description = "Password used to login proxmox" type = string +} + +variable "ssh_key" { + description = "Public SSH key to be authorized" } \ No newline at end of file diff --git a/modules/proxy/main.tf b/modules/proxy/main.tf index a9244cf..ba00b52 100644 --- a/modules/proxy/main.tf +++ b/modules/proxy/main.tf @@ -8,7 +8,7 @@ terraform { } data "local_file" "ssh_public_key" { - filename = pathexpand("~/.ssh/id_rsa.pub") + filename = pathexpand(var.ssh_key) } resource "proxmox_virtual_environment_file" "cloud_config" { diff --git a/modules/proxy/variables.tf b/modules/proxy/variables.tf index fcd7c3f..126fbfc 100644 --- a/modules/proxy/variables.tf +++ b/modules/proxy/variables.tf @@ -11,4 +11,8 @@ variable "DEFAULT_BRIDGE" { variable "TARGET_NODE" { description = "Target node name in proxmox" type = string +} + +variable "ssh_key" { + description = "Public SSH key to be authorized" } \ No newline at end of file diff --git a/templates/k0s.tmpl b/templates/k0s.tmpl index 81fd877..274c238 100644 --- a/templates/k0s.tmpl +++ b/templates/k0s.tmpl @@ -9,14 +9,14 @@ spec: ssh: address: ${node_host} user: ${user} - keyPath: ~/.ssh/id_rsa + keyPath: ${ssh_key} %{endfor} %{ for node_host, node_hostname in node_map_workers ~} - role: worker ssh: address: ${node_host} user: ${user} - keyPath: ~/.ssh/id_rsa + keyPath: ${ssh_key} %{endfor} k0s: version: ${k0s_version} diff --git a/terraform.tfvars.example b/terraform.tfvars.example index 82f4fbb..5574b5f 100644 --- a/terraform.tfvars.example +++ b/terraform.tfvars.example @@ -2,6 +2,7 @@ PROXMOX_API_ENDPOINT = "https://192.168.0.103:8006/api2/json" PROXMOX_USERNAME = "root" PROXMOX_PASSWORD = "password" +PROXMOX_SSH_KEY = "~/.ssh/id_rsa" PROXMOX_IP = "192.168.0.103" DEFAULT_BRIDGE = "vmbr0" TARGET_NODE = "pve" diff --git a/varaibles.tf b/varaibles.tf index 35ded99..a615397 100644 --- a/varaibles.tf +++ b/varaibles.tf @@ -19,6 +19,11 @@ variable "PROXMOX_IP" { type = string } +variable "PROXMOX_SSH_KEY" { + description = "SSH key for proxmox host" + type = string +} + variable "DEFAULT_BRIDGE" { description = "Bridge to use when creating VMs in proxmox" type = string