Skip to content

Instantly share code, notes, and snippets.

@perfecto25
Last active September 1, 2023 18:33
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save perfecto25/6e9a0c982fb76401f720b661f1a8a9f1 to your computer and use it in GitHub Desktop.
Save perfecto25/6e9a0c982fb76401f720b661f1a8a9f1 to your computer and use it in GitHub Desktop.
sshuttle:
pkg.installed: []
group.present:
- gid: 2024
user.present:
- fullname: sshuttle
- uid: 2024
- gid: 2024
- allow_uid_change: True
- allow_gid_change: True
- createhome: True
- shell: '/bin/bash'
- home: /home/sshuttle
## Manage SSH Keys
ssh_auth.present:
- user: sshuttle
- names:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKlQ2xxxxxxxxxxxxxxxx sshuttle
file.managed:
- names:
- /home/sshuttle/.ssh/id_ed25519:
- source: salt://{{ slspath }}/files/id_ed25519
- mode: 600
- /home/sshuttle/.ssh/id_ed25519.pub:
- source: salt://{{ slspath }}/files/id_ed25519.pub
- mode: 644
- user: sshuttle
- group: sshuttle
/etc/sshuttle:
file.directory:
- user: sshuttle
- group: sshuttle
- dirmode: 744
- makedirs: True
sshuttle_config:
file.serialize:
- name: /etc/sshuttle/config.json
- formatter: json
- create: True
- user: sshuttle
- group: sshuttle
- mode: 644
- makedirs: True
- dataset:
{{ salt['pillar.get']('sshuttle') }}
sshuttle_runscript:
file.managed:
- name: /etc/sshuttle/sshuttle.py
- source: salt://{{ slspath }}/files/sshuttle.py
- user: sshuttle
- group: sshuttle
- mode: 744
sshuttle_sudoers:
file.managed:
- name: /etc/sudoers.d/sshuttle
- source: salt://{{ slspath }}/files/sudoers
- user: root
- group: root
- mode: 644
sshuttle_service_file:
file.managed:
- name: /etc/systemd/system/sshuttle.service
- source: salt://{{ slspath }}/files/service
- user: root
- group: root
- mode: 644
sshuttle_service:
service.running:
- name: sshuttle
- enable: True
- watch:
- file: sshuttle_config
#!/usr/bin/env python
## REQUIRES MINIMUM PY VERSION 2.7
from __future__ import print_function
import os
import sys
import json
import signal
import time
import socket
import subprocess
from subprocess import CalledProcessError
import logging
import logging.handlers
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
handler = logging.handlers.SysLogHandler(address = '/dev/log')
formatter = logging.Formatter('%(module)s.%(funcName)s: %(message)s')
handler.setFormatter(formatter)
log.addHandler(handler)
conf = "/etc/sshuttle/config.json"
ssh_user = "sshuttle" ## username thats used for SSH connection
def precheck():
if len(sys.argv) < 2:
print("need to pass argument: start | stop | restart | status ")
sys.exit()
if sys.argv[1] in ["help", "-h", "--help", "h"]:
print("sshuttle.py start | stop | restart | status")
sys.exit()
if not sys.argv[1] in ["start", "stop", "restart", "status"]:
print("usage: sshuttle.py start | stop | restart | status")
sys.exit()
if not os.path.exists(conf):
print("no sshuttle config file present, exiting.")
sys.exit()
# check if sshuttle is installed
try:
subprocess.check_output(["which", "sshuttle"]).strip()
except CalledProcessError:
print("sshuttle is not installed on this host")
sys.exit()
def start():
with open(conf) as jsondata:
data = json.load(jsondata)
keys = sorted(data.keys())
for rhost in data.keys():
if ":" in rhost:
relay = rhost.split(":")[1]
else:
relay = rhost
netrange = ""
# if single network, turn into List
if not type(data[rhost]) is list:
networks = data[rhost].split()
else:
networks = data[rhost]
for network in networks:
# check if CIDR format
if "/" in network:
netrange = netrange + " " + network
else:
netrange = netrange + " " + socket.gethostbyname(network)
netrange = netrange.strip()
# build rpath
rpath = "-r {0}@{1} {2} -l listen '0.0.0.0' --ssh-cmd 'ssh -o ServerAliveInterval=60' --no-latency-control".format(ssh_user, rhost, netrange)
try:
print("starting sshuttle..")
log.info("starting sshuttle for networks: %s via %s" % (netrange, rhost))
subprocess.Popen("sshuttle {}".format(rpath), shell=True)
except CalledProcessError as err:
log.error("error running sshuttle: %s" % str(err))
# sleep to give connection time to establish SSH handshake, in case other connections use this conn as a hop
time.sleep(3)
def get_pid():
search = "ps -ef | grep '/usr/bin/python /usr/share/sshuttle/main.py /usr/bin/python -r' | grep -v grep | awk {'print $2'}"
pids = []
for line in os.popen(search):
fields = line.split()
pids.append(fields[0])
return pids
def stop():
pids = get_pid()
for pid in pids:
print("stopping sshuttle PID %s " % pid)
log.info("stopping sshuttle")
os.kill(int(pid), signal.SIGTERM)
def status():
pids = get_pid()
if pids:
print("sshuttle is running..")
else:
print("sshuttle is not running..")
if __name__ == "__main__":
precheck()
cmd = sys.argv[1].lower()
if cmd == "start":
start()
if cmd == "stop":
stop()
if cmd == "restart":
print("restarting sshuttle..")
stop()
start()
if cmd == "status":
status()
[Unit]
Description=sshuttle service
After=network.target
[Service]
User=sshuttle
Restart=always
Type=forking
WorkingDirectory=/etc/sshuttle
ExecStart=/etc/sshuttle/sshuttle.py start
ExecStop=/etc/sshuttle/sshuttle.py stop
[Install]
WantedBy=multi-user.target
#!/bin/sh
### SSHUTTLE INIT.D SERVICE SCRIPT
### REQUIRED MINIMUM Python version of 2.7
SCRIPT=/etc/sshuttle/sshuttle.py
RUNAS=sshuttle
LOGFILE=/var/log/messages
start() {
su -c "$SCRIPT start" $RUNAS >&2
}
stop() {
su -c "$SCRIPT stop" $RUNAS >&2
}
restart() {
stop
start
}
status() {
su -c "$SCRIPT status" >&2
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
esac
sshuttle ALL=(root) NOPASSWD: /usr/bin/python /usr/share/sshuttle/main.py /usr/bin/python --firewall 12*** 0
@perfecto25
Copy link
Author

can add to /home/sshuttle/.ssh/config

Host abc1
Hostname abc1.corp.com
User joe
Port 22
IdentityFile /home/joe/.ssh/id_rsa

Using passwords for ssh is not recommended , its insecure, and theres no way to store them, you have to manually enter them during ssh handshake, use keypairs instead

@linuxacademyir
Copy link

Thank you for your reply
I have already added it to config file but by questions is
How does this script know which host in config to connect to
Should I call the “Host” abc1?
Shouldn’t I add my “Host” name into script ? Or the script reads it as “Host” abc1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment