-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ssh multiplexing? #20
Comments
To better understand, do you mean the ssh connection is wrapped in TLS to hide the SSH bytes (like what's described here)? Or to serve 2 services on the same port and respond based on the peeked bytes (as in #17)? If it's the latter, then you can do that by combining the layer4 app with the SSH app, as Matt said on that other issue. If it's the former, then not in its current shape, but I'm intrigued and will consider it a feature request. |
You could probably do the former with layer4 too. Just terminate TLS and proxy the bytes to the ssh server. |
What do you know, I stand corrected! I took @mholt's clue and combining this module, the layer4 app, and {"level":"info","ts":1678661484.4180212,"msg":"using provided configuration","config_file":"/Users/mohammed/projects/caddyserver/caddy-ssh/XDG_DATA_HOME/caddy/shell-tls.json","config_adapter":""}
{"level":"info","ts":1678661484.4228532,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1678661484.4248362,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00057efc0"}
{"level":"warn","ts":1678661484.5783281,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [localhost]: no OCSP server specified in certificate","identifiers":["localhost"]}
{"level":"debug","ts":1678661484.578481,"logger":"tls.cache","msg":"added certificate to cache","subjects":["localhost"],"expiration":1678703896,"managed":true,"issuer_key":"local","hash":"c66af9471a244ea6a6266a51aa6a35f7d913405c50ae75ec6e45bc68d199acda","cache_size":1,"cache_capacity":10000}
{"level":"debug","ts":1678661484.578608,"logger":"events","msg":"event","name":"cached_managed_cert","id":"f6c3a667-1bbd-4ac5-9824-987e33803642","origin":"tls","data":{"sans":["localhost"]}}
{"level":"debug","ts":1678661484.578933,"logger":"layer4","msg":"listening","address":"tcp/127.0.0.1:8443"}
{"level":"info","ts":1678661484.5807302,"msg":"serving initial configuration"}
{"level":"info","ts":1678661484.594663,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"debug","ts":1678661485.447563,"logger":"events","msg":"event","name":"tls_get_certificate","id":"a02f2148-04c3-46aa-9f1b-10cbb6c509ee","origin":"tls","data":{"client_hello":{"CipherSuites":[4866,4867,4865,49196,49200,163,159,52393,52392,52394,49327,49325,49315,49311,49245,49249,49239,49235,49195,49199,162,158,49326,49324,49314,49310,49244,49248,49238,49234,49188,49192,107,106,49267,49271,196,195,49187,49191,103,64,49266,49270,190,189,49162,49172,57,56,136,135,49161,49171,51,50,69,68,157,49313,49309,49233,156,49312,49308,49232,61,192,60,186,53,132,47,65,255],"ServerName":"localhost","SupportedCurves":[23],"SupportedPoints":"AAEC","SignatureSchemes":[1027,1283,1539,2055,2056,2057,2058,2059,2052,2053,2054,1025,1281,1537,771,769,770,1026,1282,1538],"SupportedProtos":null,"SupportedVersions":[772,771,770,769],"Conn":{"Conn":{},"Context":{"Context":{"Context":0}},"Logger":{}}}}}
{"level":"debug","ts":1678661485.449942,"logger":"tls.handshake","msg":"choosing certificate","identifier":"localhost","num_choices":1}
{"level":"debug","ts":1678661485.4534678,"logger":"tls.handshake","msg":"default certificate selection results","identifier":"localhost","subjects":["localhost"],"managed":true,"issuer_key":"local","hash":"c66af9471a244ea6a6266a51aa6a35f7d913405c50ae75ec6e45bc68d199acda"}
{"level":"debug","ts":1678661485.4534988,"logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"127.0.0.1","remote_port":"56660","subjects":["localhost"],"managed":true,"expiration":1678703896,"hash":"c66af9471a244ea6a6266a51aa6a35f7d913405c50ae75ec6e45bc68d199acda"}
{"level":"debug","ts":1678661485.5190191,"logger":"layer4.handlers.tls","msg":"terminated TLS","remote":"127.0.0.1:56660","server_name":"localhost"}
{"level":"debug","ts":1678661485.599809,"logger":"layer4.handlers.proxy","msg":"dial upstream","remote":"127.0.0.1:56660","upstream":"localhost:2012"}
{"level":"info","ts":1678661487.213503,"logger":"ssh.authentication.flows.public_key","msg":"authentication start","providers_count":1,"remote_address":"[::1]:56661","username":"mohammed","key_type":"ssh-ed25519"}
{"level":"debug","ts":1678661487.213547,"logger":"ssh.authentication.providers.public_key.os","msg":"authenticating user","username":"mohammed"}
{"level":"info","ts":1678661487.215381,"logger":"ssh.authentication.flows.public_key","msg":"authentication successful","provider":"os","user_id":"501","username":"mohammed","key_type":"ssh-ed25519"}
{"level":"info","ts":1678661487.222975,"logger":"ssh.ask.pty.allow","msg":"asking for permission","session_id":"f98b808a69889c891f56f2a78d93db24d2f7e7081c005c38f672dca99ee312d7","local_address":"[::1]:2012","client_version":"SSH-2.0-OpenSSH_9.0","user":"mohammed","terminal":"xterm-256color"}
{"level":"info","ts":1678661487.223532,"logger":"ssh.actors.shell","msg":"start pty session","term":"xterm-256color","session_id":"f98b808a69889c891f56f2a78d93db24d2f7e7081c005c38f672dca99ee312d7","remote_ip":"[::1]:56661","user":"mohammed","command":"","force_command":"zsh","force_pty":false,"window_height":47,"window_width":193}
{"level":"info","ts":1678661487.25058,"logger":"ssh.actors.shell","msg":"found user","session_id":"f98b808a69889c891f56f2a78d93db24d2f7e7081c005c38f672dca99ee312d7","user":{"username":"mohammed","password":"*","uid":501,"gid":20,"info":"Mohammed Al Sahaf","home_dir":"/Users/mohammed","shell":"/bin/zsh"}}
{"level":"info","ts":1678661487.2527208,"logger":"ssh.actors.shell","msg":"update window size","session_id":"f98b808a69889c891f56f2a78d93db24d2f7e7081c005c38f672dca99ee312d7","new_height":47,"new_width":193} Here's the config I used (of course it's adapted to some local changes that I haven't pushed yet): {
"logging": {
"logs": {
"default": {
"level": "DEBUG"
}
}
},
"apps": {
"layer4": {
"servers": {
"example": {
"listen": [
"127.0.0.1:8443"
],
"routes": [
{
"handle": [
{
"handler": "tls"
},
{
"handler": "proxy",
"upstreams": [
{"dial": ["localhost:2012"]}
]
}
]
}
]
}
}
},
"tls": {
"certificates": {
"automate": [
"localhost"
]
},
"automation": {
"policies": [
{
"issuers": [
{
"module": "internal"
}
]
}
]
}
},
"ssh": {
"grace_period": "2s",
"servers": {
"srv0": {
"address": "tcp/0.0.0.0:2000-2012",
"pty": {
"pty": "allow"
},
"configs": [
{
"config": {
"loader": "provided",
"no_client_auth": false,
"authentication": {
"public_key": {
"providers": {
"os": {}
}
}
}
}
}
],
"actors": [
{
"act": {
"action": "shell",
"force_command": "zsh"
}
}
]
}
}
}
}
} I installed
|
I'm looking for a combo of both. scenario is this:
Acceptable "halfway" solution: SNI-based, but no peeking
I think caddy l4 is a solution (that's what I was actually expecting to find, but search landed me here). Telebit is also a solution, but caddy handles load balancing too, which Telebit does not. I can't use something like That all said... the warnings of "experimental" and "read the code, don't rely on the docs" on Caddy l4 do scare me a little bit. However, I see that what I'm talking about seems to be mentioned in the README as a use case so... is there a ready-made example for either of those? |
Oh, more comments have come in that I didn't see yet. Reading now... |
FYI: I'd recommend OpenSSL |
Thanks for that sample config. That makes sense at a glance. I'll try it out tonight. |
This doesn't really have to do with Full Instructions
1. Install xcaddyDownload pushd /tmp/
curl -o ./xcaddy_0.3.2_linux_amd64.tar.gz \
-L https://github.com/caddyserver/xcaddy/releases/download/v0.3.2/xcaddy_0.3.2_linux_amd64.tar.gz
tar xvf ./xcaddy_0.3.2_linux_amd64.tar.gz
chmod a+x caddy
mv ./caddy ~/bin/caddy
popd 2. Build with layer4Needs layer4, l4tls, l4ssh, l4proxy. Using #!/bin/sh
#export XCADDY_SETCAP=1
export XCADDY_SUDO=0
export XCADDY_SKIP_CLEANUP=1
xcaddy build \
--with github.com/mholt/caddy-l4/layer4 \
--with github.com/mholt/caddy-l4/modules/l4tls \
--with github.com/mholt/caddy-l4/modules/l4ssh \
--with github.com/mholt/caddy-l4/modules/l4subroute \
--with github.com/mholt/caddy-l4/modules/l4proxy \
--with github.com/caddy-dns/duckdns 2b. How to runAssuming an caddy run --envfile ./.env --config ./config.json 3. Test 1 TLS to SSH
{
"logging": {
"logs": {
"default": {
"level": "DEBUG"
}
}
},
"apps": {
"layer4": {
"servers": {
"my-sshtls": {
"listen": ["0.0.0.0:22443"],
"routes": [
{
"handle": [
{
"handler": "tls"
},
{
"handler": "proxy",
"upstreams": [{ "dial": ["localhost:22"] }]
}
]
}
]
}
}
},
"tls": {
"certificates": {
"automate": ["localhost", "192.168.0.4"]
},
"automation": {
"policies": [
{
"issuers": [
{
"module": "internal"
}
]
}
]
}
}
}
} 4. SNI Routing to SSHI got TLS SNI matching working too!
{
"logging": {
"logs": {
"default": {
"level": "DEBUG"
}
}
},
"apps": {
"layer4": {
"servers": {
"my-sshtls": {
"listen": ["0.0.0.0:22443"],
"routes": [
{
"match": [
{
"tls": {}
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"match": [
{
"tls": {
"sni": ["ssh-example.duckdns.org"]
}
}
],
"handle": [
{
"handler": "tls"
},
{
"handler": "proxy",
"upstreams": [{ "dial": ["localhost:22"] }]
}
]
},
{
"match": [
{
"tls": {
"sni": ["web-example.duckdns.org"]
}
}
],
"handle": [
{
"handler": "tls"
},
{
"handler": "proxy",
"upstreams": [{ "dial": ["localhost:3000"] }]
}
]
}
]
}
]
}
]
}
}
},
"tls": {
"certificates": {
"automate": [
"localhost",
"192.168.0.4",
"ssh-example.duckdns.org",
"web-example.duckdns.org"
]
},
"automation": {
"policies": [
{
"subjects": ["localhost", "192.168.0.4"],
"issuers": [
{
"module": "internal"
}
]
},
{
"subjects": ["ssh-example.duckdns.org", "web-example.duckdns.org"],
"issuers": [
{
"challenges": {
"dns": {
"provider": {
"api_token": "{env.DUCKDNS_API_TOKEN}",
"name": "duckdns"
}
}
},
"module": "acme"
},
{
"challenges": {
"dns": {
"provider": {
"api_token": "{env.DUCKDNS_API_TOKEN}",
"name": "duckdns"
}
}
},
"module": "zerossl"
}
]
}
]
}
}
}
} 5. Multiplexing HTTPS and SSH
This feels a little too verbose. I wonder if there isn't a simpler way... ? {
"logging": {
"logs": {
"default": {
"level": "DEBUG"
}
}
},
"apps": {
"layer4": {
"servers": {
"my-sshttp": {
"listen": ["0.0.0.0:443"],
"routes": [
{
"match": [
{
"tls": {}
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"match": [
{
"tls": {
"sni": ["example-a.duckdns.org"]
}
}
],
"handle": [
{
"handler": "tls",
"connection_policies": [
{
"alpn": ["http/1.1"]
}
]
},
{
"handler": "subroute",
"routes": [
{
"match": [{ "ssh": {} }],
"handle": [
{
"handler": "proxy",
"upstreams": [{ "dial": ["localhost:22"] }]
}
]
},
{
"match": [
{
"http": [
{ "host": ["example-a.duckdns.org"] }
]
}
],
"handle": [
{
"handler": "proxy",
"upstreams": [{ "dial": ["localhost:3000"] }]
}
]
}
]
}
]
},
{
"match": [
{
"tls": {
"sni": ["example-b.duckdns.org"]
}
}
],
"handle": [
{
"handler": "tls",
"connection_policies": [
{
"alpn": ["http/1.1"]
}
]
},
{
"handler": "subroute",
"routes": [
{
"match": [{ "ssh": {} }],
"handle": [
{
"handler": "proxy",
"upstreams": [{ "dial": ["10.0.0.222:22"] }]
}
]
},
{
"match": [
{
"http": [
{ "host": ["example-b.duckdns.org"] }
]
}
],
"handle": [
{
"handler": "proxy",
"upstreams": [{ "dial": ["10.0.0.222:3000"] }]
}
]
}
]
}
]
}
]
}
]
}
]
}
}
},
"tls": {
"certificates": {
"automate": [
"localhost",
"192.168.0.4",
"example-a.duckdns.org",
"example-b.duckdns.org"
]
},
"automation": {
"policies": [
{
"subjects": ["localhost", "192.168.0.4"],
"issuers": [
{
"module": "internal"
}
]
},
{
"subjects": ["example-a.duckdns.org", "example-b.duckdns.org"],
"issuers": [
{
"challenges": {
"dns": {
"provider": {
"api_token": "{env.DUCKDNS_API_TOKEN}",
"name": "duckdns"
}
}
},
"module": "acme"
},
{
"challenges": {
"dns": {
"provider": {
"api_token": "{env.DUCKDNS_API_TOKEN}",
"name": "duckdns"
}
}
},
"module": "zerossl"
}
]
}
]
}
}
}
} |
I guess this is still a WIP ? Would like to try this out but it’s not merged yet into this repo ? |
There isn't any necessary work here nor are there any necessary PRs to merge. You can use TLS-terminated SSH sessions as-is using a combination of caddy-l4 and kadeessh. It's a matter of configuration, which I could include as an example on the README or the wiki. There's a working config sample by me above. I kept it open to remind myself to include the example config of this use-case somewhere handy for users. Anything specific you're missing? |
Can this be used to handle ssh over TLS with SNI routing?
The text was updated successfully, but these errors were encountered: