NOTE: I'm not sure if this is the right place to ask this question or if I'm asking the right question. Please bear with me if I'm wrong and let me know how I can correct my question or move it to the correct StackExchange site.
I have a web server for which I only want some clients to connect to (Ubuntu host 1 & 2) and I want these clients to connect to the web server over a SSH tunnel and all other clients should be denied access to the web server.
The setup should look like this where if the Ubuntu hosts (or any other hosts) try to connect to the web server directly, they are denied access (or better yet the server doesn't respond at all) but if they connect to the server via a SSH tunnel, only then they have access to the web server
┌──────────────────────────────────────────────────────────────────────┐ │ Access Denied │ ┌───────────────────┴─┐ │ │ │ ┌───────────────────────────────┐ │ │ │ SSH Tunnel │ Web Server │ │ │ Ubuntu Host 1 ◄─────────────────────────────────┤ │ │ │ ┌────────────────┼────────────────┼───────────────────┐ │ │ │ │ │ │ Access Granted │ │ │ └─────────────────────┘ │ │ │ │ │ │ │ │ │ │ ┌─────────────────────┐ │ │ ┌─▼───────────┤ │ │ │ │ │ Access Granted │ Python │ │ │ ├────────────────┼────────────────┼─────────────────► http.server │◄─┘ │ Ubuntu Host 2 ◄────────────────┘ │ │ port=8080 │ │ │ │ │ host=0.0.0.0│◄─┐ │ │ └─────────────────┴─────────────┘ │ └───────────────────┬─┘ │ │ Access Denied │ └──────────────────────────────────────────────────────────────────────┘
I can achieve this by doing the following:
On web server (web-server.example.com):
- Run
python3 server.py
- SSH to Ubuntu machines with
ssh ubuntu-host-1.example.com -R 8080:web-server.example.com:8080
ssh ubuntu-host-2.example.com -R 8080:web-server.example.com:8080
Code in server.py (from pythonbasics.org):
# Python 3 server example
from http.server import BaseHTTPRequestHandler, HTTPServer
import time, logging, ipaddress
hostName = "0.0.0.0"
serverPort = 8080
allowed_net = ipaddress.ip_network('172.16.0.0/12')
priv_net = list(allowed_net.hosts())
class MyServer(BaseHTTPRequestHandler):
def do_GET(self):
client = ipaddress.ip_address(self.client_address[0])
if client in priv_net:
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(bytes("<html><head><title>https://pythonbasics.org</title></head>", "utf-8"))
self.wfile.write(bytes("<p>Request: %s</p>" % self.path, "utf-8"))
self.wfile.write(bytes("<p>IP: %s</p>" % self.client_address[0], "utf-8"))
self.wfile.write(bytes("<body>", "utf-8"))
self.wfile.write(bytes("<p>This is an example web server.</p>", "utf-8"))
self.wfile.write(bytes("</body></html>", "utf-8"))
else:
self.send_response(404)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(bytes("<html><head><title>https://pythonbasics.org</title></head>", "utf-8"))
self.wfile.write(bytes("<p>Request: %s</p>" % self.path, "utf-8"))
self.wfile.write(bytes("<p>IP: %s</p>" % self.client_address[0], "utf-8"))
self.wfile.write(bytes("<body>", "utf-8"))
self.wfile.write(bytes("<p>Access Denied</p>", "utf-8"))
self.wfile.write(bytes("</body></html>", "utf-8"))
if __name__ == "__main__":
webServer = HTTPServer((hostName, serverPort), MyServer)
print("Server started http://%s:%s" % (hostName, serverPort))
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
print("Server stopped.")
As you can see, in my web server code, I have to handle the case for when a client connects from outside the SSH tunnel (i.e. not a part of 172.16.0.0/12 network)
Is there a way that I can achieve this without needing the server to listen on all interfaces (0.0.0.0) but still only serve clients connected via the SSH tunnel?
NOTE: I can't open the SSH tunnel from the Ubuntu hosts to the web server. It has to be the other way around