Skip to content
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

Add YAML config example #19

Merged
merged 4 commits into from Apr 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 20 additions & 11 deletions README.md
Expand Up @@ -80,29 +80,38 @@ Please note that the sftp and scp clients bundled with openssh cannot use normal
Using a "ssh -W" ProxyCommand circumvents this limitation, both for ssh and sftp/scp, and also bypasses the interactive server selection, as the client will inform sshmux of the wanted target directly. If the target is permitted, the user will be connected. This also provides more protection for the paranoid, as the connection to the final host is encrypted end-to-end, rather than being plaintext in the memory of sshmux.

# Configuration
sshmuxd requires 3 things:
* An authorized_keys-style file ("authkeys"), with the public key of all permitted users. Do note that the comment after the public key will be used as name of the user internally (this does not affect usernames over SSH, though).
* A private key for the server to use ("hostkey").
* A JSON configuration file named sshdmuxd.json in one of the following places:
sshmuxd requires a configuration file named sshmuxd.json/.yml in one of the following places:
- Working dir
- $HOME/.sshmuxd/
- /etc/sshmuxd/
- or pass the path on command line using --config filename.json

The format of the file is as follows (note that, due to the presence of comments, this is not actually a valid JSON file. Remove comments before use, or refer to sshmuxd.json)
The format of the file is as follows (note that, due to the presence of comments, this is not actually a valid JSON file. Remove comments before use, or refer to sshmuxd.json).
You can also use YAML, see sshmuxd.yml for an example.

```
{
// Listening address as given directly to net.Listen.
"address": ":22",

// Private key to use for built-in SSH server.
"hostkey": "hostkey",
// Private key to use for built-in SSH server. Make sure you replace all newlines with \n
"hostkey": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIJEDt/lHs7jSUNEMbX+Swp6xa8ZiamPFoYsTZgP+We8DoAoGCCqGSM49\nAwEHoUQDQgAEUvK6aRbBnFVsXvpJ9bwUDEI3c/phJAIsjk2dA+YNiFVQq20Xkefl\nFqPJeBriA2EMGkU2AmKGFK45PwRjKI10bA==\n-----END EC PRIVATE KEY-----",

// Authorized keys to use for authenticating users. An important note
// is that the comment (the part after the key itself in an entry)
// will be used as name for the user internally.
"authkeys": "authkeys",
// Authorized keys to use for authenticating users.
"users": [
{
"publicKey": "AAAAC3NzaC1lZDI1NTE5AAAAIG5AnPTKFnstV0y4n9m4Qo624wEkQKdVKz0HTrsGmecs",
"name": "me"
},
{
"publicKey": "AAAAC3NzaC1lZDI1NTE5AAAAINg6gWZLnH5gwLeDlw/URtvYgKmlFiiXHmra6oYObfBz",
"name": "boss"
},
{
"publicKey": "AAAAB3NzaC1yc2EAAAADAQABAAACAQDEmICmR4ZD175AlaWnLrMlHnNTu9MqZplgkj2MZOoX4gODbzlRUcI4MquehcZ3evF7o9GjAMLRVN16fkDBx6YH7tFfQFxsSSfIToXHW0L8k06HW5eoLEo6nZ/mBI7tq98XQ4qWC71n+/O59bGP2mFph1LR4G2m9DApW4I/JVTLqWh0dkQbNV5RrPn9h+nJ0dNUumubUU2uTyd9u6UjCc+Hg9ScqNc3fheNoeS72ihu/33G/O+xwUc0nX+0ngRsUkakGgk5IiU4Lx4xofqMRiKKcQNHajo9tLGKLv11EaMEOdMDVJiTf/JGFyEMofM0tPqJjLXXwtTqgFx/8y5PIiZsuepaouNBWZ3T/Sp8OUZsim67Tllvc7qFZ6zzdMXLD5aKLtqkRgDvP9NuGlHVbq2cdkrCToIjsz5PZo+KvNV6V+Tzy13QKkwkHmabMOMRiR5MH4Jt80lJeOce1Se9e57rHhJ8DmxhEmqNSCIYegrX6hW+8XMRDdmL8OS7US9v7dwpjB+lehDidH2xd3rTzEbR+EeFZJ47L+jSSO+GDYRRB7IffnVf2JAwKCAQu13w8TJwLKBwKUHqcbb/vnofHz6geLweIM03Rbi4e87zdMgeghbM0ys6hAg/ZMwUkpUn89OGtGBE5cmjPYXEdbJcd8EF3LTmEf/POdaJ1qc/ObHbUw==",
"name": "granny"
}
],

// The list of remote hosts that can be used through this proxy.
"hosts": [
Expand Down
82 changes: 43 additions & 39 deletions main.go
Expand Up @@ -2,10 +2,10 @@ package main

import (
"bytes"
"encoding/base64"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net"

Expand All @@ -21,43 +21,36 @@ type Host struct {
NoAuth bool `json:"noAuth"`
}

type User struct {
PublicKey string `json:"publicKey"`
Name string `json:"name"`
}

var configFile = flag.String("config", "", "User-supplied configuration file to use")

func parseAuthFile(filename string) ([]*sshmux.User, error) {
func parseUsers() ([]*sshmux.User, error) {
var users []*sshmux.User

authFile, err := ioutil.ReadFile(filename)
us := make([]User, 0)
err := viper.UnmarshalKey("users", &us)
if err != nil {
return nil, err
}

// Parse authfile as authorized_key

for len(authFile) > 0 {
switch authFile[0] {
case '\n', '\r', '\t', ' ':
authFile = authFile[1:]
continue
for _, u := range us {
encoded, err := base64.StdEncoding.DecodeString(u.PublicKey)
if err != nil {
return nil, errors.New("Could not decode key: " + u.Name)
}

var (
pk ssh.PublicKey
comment string
)

pk, comment, _, authFile, err = ssh.ParseAuthorizedKey(authFile)
pk, err := ssh.ParsePublicKey([]byte(encoded))
if err != nil {
return nil, err
return nil, errors.New(err.Error() + " for " + u.Name)
}

u := &sshmux.User{
PublicKey: pk,
Name: comment,
Name: u.Name,
}

users = append(users, u)
}

return users, nil
}

Expand Down Expand Up @@ -86,32 +79,43 @@ func main() {
panic(fmt.Errorf("Error parsing the config file hosts list: %s\n", err))
}

users, err := parseUsers()
if err != nil {
panic(fmt.Errorf("Error parsing the config file hosts list: %s\n", err))
}

hostSigner, err := ssh.ParsePrivateKey([]byte(viper.GetString("hostkey")))
if err != nil {
panic(err)
}

viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
log.Println("Config file changed:", e.Name)
err = viper.UnmarshalKey("hosts", &hosts)
nh := make([]Host, 0)
err = viper.UnmarshalKey("hosts", &nh)
if err != nil {
log.Printf("Error parsing the config file hosts list: %s\n"+
"Keeping current host list", err)
} else {
hosts = nh
log.Printf("New hosts list: %+v\n", hosts)
}
})

hostPrivateKey, err := ioutil.ReadFile(viper.GetString("hostkey"))
if err != nil {
panic(err)
}

hostSigner, err := ssh.ParsePrivateKey(hostPrivateKey)
if err != nil {
panic(err)
}
if u, err := parseUsers(); err != nil {
log.Printf("Error parsing the config file users list: %s\n"+
"Keeping current users list", err)
} else {
users = u
}
h, err := ssh.ParsePrivateKey([]byte(viper.GetString("hostkey")))
if err != nil {
log.Printf("Error parsing the config file hostkey: %s\n"+
"Keeping current hostkey", err)
} else {
hostSigner = h
}

users, err := parseAuthFile(viper.GetString("authkeys"))
if err != nil {
panic(err)
}
})

hasDefaults := false
for _, h := range hosts {
Expand Down
18 changes: 15 additions & 3 deletions sshmuxd.json
@@ -1,7 +1,20 @@
{
"address": ":22",
"hostkey": "hostkey",
"authkeys": "authkeys",
"hostkey": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIJEDt/lHs7jSUNEMbX+Swp6xa8ZiamPFoYsTZgP+We8DoAoGCCqGSM49\nAwEHoUQDQgAEUvK6aRbBnFVsXvpJ9bwUDEI3c/phJAIsjk2dA+YNiFVQq20Xkefl\nFqPJeBriA2EMGkU2AmKGFK45PwRjKI10bA==\n-----END EC PRIVATE KEY-----",
"users": [
{
"publicKey": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPoWImSrY0Rt33Rg97HkDS3r7mdcFn5EJUv/dxiRWD9aPQUm8wp7buZDhpjb32Dt2PjKnNB6PrNOj7ORDFYEhRg=",
"name": "me"
},
{
"publicKey": "AAAAC3NzaC1lZDI1NTE5AAAAINg6gWZLnH5gwLeDlw/URtvYgKmlFiiXHmra6oYObfBz",
"name": "boss"
},
{
"publicKey": "AAAAB3NzaC1yc2EAAAADAQABAAACAQDEmICmR4ZD175AlaWnLrMlHnNTu9MqZplgkj2MZOoX4gODbzlRUcI4MquehcZ3evF7o9GjAMLRVN16fkDBx6YH7tFfQFxsSSfIToXHW0L8k06HW5eoLEo6nZ/mBI7tq98XQ4qWC71n+/O59bGP2mFph1LR4G2m9DApW4I/JVTLqWh0dkQbNV5RrPn9h+nJ0dNUumubUU2uTyd9u6UjCc+Hg9ScqNc3fheNoeS72ihu/33G/O+xwUc0nX+0ngRsUkakGgk5IiU4Lx4xofqMRiKKcQNHajo9tLGKLv11EaMEOdMDVJiTf/JGFyEMofM0tPqJjLXXwtTqgFx/8y5PIiZsuepaouNBWZ3T/Sp8OUZsim67Tllvc7qFZ6zzdMXLD5aKLtqkRgDvP9NuGlHVbq2cdkrCToIjsz5PZo+KvNV6V+Tzy13QKkwkHmabMOMRiR5MH4Jt80lJeOce1Se9e57rHhJ8DmxhEmqNSCIYegrX6hW+8XMRDdmL8OS7US9v7dwpjB+lehDidH2xd3rTzEbR+EeFZJ47L+jSSO+GDYRRB7IffnVf2JAwKCAQu13w8TJwLKBwKUHqcbb/vnofHz6geLweIM03Rbi4e87zdMgeghbM0ys6hAg/ZMwUkpUn89OGtGBE5cmjPYXEdbJcd8EF3LTmEf/POdaJ1qc/ObHbUw==",
"name": "granny"
}
],
"hosts": [
{
"address": "ssh1.example.com:22",
Expand All @@ -17,4 +30,3 @@
}
]
}

23 changes: 23 additions & 0 deletions sshmuxd.yml
@@ -0,0 +1,23 @@
address: :22
hostkey: |
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJEDt/lHs7jSUNEMbX+Swp6xa8ZiamPFoYsTZgP+We8DoAoGCCqGSM49
AwEHoUQDQgAEUvK6aRbBnFVsXvpJ9bwUDEI3c/phJAIsjk2dA+YNiFVQq20Xkefl
FqPJeBriA2EMGkU2AmKGFK45PwRjKI10bA==
-----END EC PRIVATE KEY-----

users:
- publicKey: "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPoWImSrY0Rt33Rg97HkDS3r7mdcFn5EJUv/dxiRWD9aPQUm8wp7buZDhpjb32Dt2PjKnNB6PrNOj7ORDFYEhRg="
name: "me"
- publicKey: "AAAAC3NzaC1lZDI1NTE5AAAAINg6gWZLnH5gwLeDlw/URtvYgKmlFiiXHmra6oYObfBz"
name: "boss"
- publicKey: "AAAAB3NzaC1yc2EAAAADAQABAAACAQDEmICmR4ZD175AlaWnLrMlHnNTu9MqZplgkj2MZOoX4gODbzlRUcI4MquehcZ3evF7o9GjAMLRVN16fkDBx6YH7tFfQFxsSSfIToXHW0L8k06HW5eoLEo6nZ/mBI7tq98XQ4qWC71n+/O59bGP2mFph1LR4G2m9DApW4I/JVTLqWh0dkQbNV5RrPn9h+nJ0dNUumubUU2uTyd9u6UjCc+Hg9ScqNc3fheNoeS72ihu/33G/O+xwUc0nX+0ngRsUkakGgk5IiU4Lx4xofqMRiKKcQNHajo9tLGKLv11EaMEOdMDVJiTf/JGFyEMofM0tPqJjLXXwtTqgFx/8y5PIiZsuepaouNBWZ3T/Sp8OUZsim67Tllvc7qFZ6zzdMXLD5aKLtqkRgDvP9NuGlHVbq2cdkrCToIjsz5PZo+KvNV6V+Tzy13QKkwkHmabMOMRiR5MH4Jt80lJeOce1Se9e57rHhJ8DmxhEmqNSCIYegrX6hW+8XMRDdmL8OS7US9v7dwpjB+lehDidH2xd3rTzEbR+EeFZJ47L+jSSO+GDYRRB7IffnVf2JAwKCAQu13w8TJwLKBwKUHqcbb/vnofHz6geLweIM03Rbi4e87zdMgeghbM0ys6hAg/ZMwUkpUn89OGtGBE5cmjPYXEdbJcd8EF3LTmEf/POdaJ1qc/ObHbUw=="
name: "granny"

hosts:
- address: ssh1.example.com:22
users: [ "me", "boss", "granny" ]
- address: public.example.com:22
noAuth: true
- address: secret.example.com:22
users: [ "me" ]