Skip to content

Files

Latest commit

 

History

History
142 lines (105 loc) · 7.21 KB

README.md

File metadata and controls

142 lines (105 loc) · 7.21 KB

sshconfig

GoDoc

This directory contains an implementation of a parser for OpenSSH's ssh_config file format.

The format and its parsing rules are slightly complicated.

Further reading:

This implementation

Implemented features:

  • All of the fields listed in the ssh_config(5) man page (and two additional Apple specific fields).
  • Partial Match directive support. Address, LocalAddress, LocalPort and RDomain are not implemented (because they require an established connection, which could be achievable later if needed).
  • Partial TOKENS expansion support. Like above, expanding some of the tokens would require an established connection to the host while parsing the config.
  • Include directive support, the parser will follow the Include directives as expected, in lexical order like the OpenSSH implementation. It will also detect circular includes.
  • Expansion of ~ and environment variables in the values for the supported fields listed on the man page.
  • Support for list modifier prefixes for fields like HostKeyAlgorithms or KexAlgorithms where you can use a + prefix to append to the default list, a - prefix to remove from the default list, or ^ to prepend to the default list.
  • Support and validation for "multistate fields" as they are called in OpenSSH's readconf.c which can act like booleans but can also contain other string values, such as yes, no, ask, always, none, etc.
  • A "strict" mode for supporting the IgnoreUnknown directive. When enabled, the parser will throw an error when it encounters an unknown directive. To enable, use the sshconfig.WithStrict() option when creating the parser.
  • The origin based value precedence is correctly implemented as described in the specification and as observed in the OpenSSH implementation.
  • Hostname canonicalization.
  • Original-like unquoting and splitting of values based on argv_split from the original C source converted to go.

Status

The parser has not been tested outside of the development environment at all yet.

If there's interest, the parser can be extracted from the rig repository and published as a separate module.

Usage

Typically you first create a parser via sshconfig.NewParser(nil) and then call Apply on it with a struct that you want to populate with the values for a given host from the system's ssh configuration files.

You can use the provided sshconfig.Config which includes all the known configuration fields or you can define a struct with a subset of the fields. The object must have the same field names as the ssh_config man page describes them and at least a "Host (string)" field must exist.

package main

import(
    "fmt"
    "github.com/k0sproject/rig/v2/sshconfig"
)

func main() {
    // this will read the configurations from the default locations.
	parser, err := sshconfig.NewParser(nil) 
    // To read from a specific file or a string, pass in an io.Reader like:
    // parser, err := sshconfig.NewParser(strings.NewReader("Host example.com\nIdentityFile ~/.ssh/id_rsa\n"))

    if err != nil {
        panic(err)
    }
    host := &sshconfig.Config{}
    if err := parser.Apply(host, "example.com"); err != nil {
        panic(err)
    }
    fmt.Println(host.IdentityFile[0])
}

There's also a sshconfig.ConfigFor shorthand for when you're not expecting to need the configuration for more than one host:

package main

import(
    "fmt"
    "github.com/k0sproject/rig/v2/sshconfig"
)

func main() {
	config, err := sshconfig.ConfigFor("example.com") 
    if err != nil {
        panic(err)
    }
    fmt.Println(config.IdentityFile[0])
}

You can output a ssh_config formatted string using sshconfig.Dump:

package main

import(
    "fmt"
    "github.com/k0sproject/rig/v2/sshconfig"
)

func main() {
	config, err := sshconfig.ConfigFor("example.com") 
    if err != nil {
        panic(err)
    }
    str, err := sshconfig.Dump(config)
    fmt.Println(str)
}

This will output something like:

Host example.com
    AddKeysToAgent no
    AddressFamily any
    BatchMode no
    ...

Alternatives

Currently there seems to exist two alternatives:

  • kevinburke/ssh_config

    This is a rather complete implementation but there are some issues with it:

    • Does not support Match directives at all.
    • Does not support Hostname canonicalization.
    • Not all of the Boolean fields listed here are actually strictly boolean. For example, ForwardAgent can be a path to agent socket or an environment variable name.
    • Not all of the default values are correct or set. In fact, the list of defaults is from 2017. The default for IdentityFile is ~/.ssh/identity which started to phase out upon the release of OpenSSH 3.0 in 2001 which started defaulting to ~/.ssh/id_dsa.
    • It does not support the list modifier prefixes for fields like HostKeyAlgorithms or KexAlgorithms where you can use + prefix to append to the existing list or - prefix to remove from the existing list.
    • When you need to know multiple settings for a given host, you need to query for each setting separately. There doesn't seem to be a function that returns a list of settings that apply to a given host alias.
    • Values need to be unquoted and expanded manually and values for comma separated list fields need to be split manually.
    • No expansion of ~/ or environment variables in the values (there's a pull request from 2021).
    • No expansion of the TOKENS (there's a pull request from 2022).
    • Doesn't seem to be actively maintained, there are open unanswered issues and unmerged pull requests from several years ago.
  • mikkeloscar/sshconfig

    This is a newer arrival. It supports a very limited subset of fields (Host, HostName, User, Port, IdentityFile, HostKeyAlgorithms, ProxyCommand, LocalForward, RemoteForward, DynamicForward, Ciphers and MACs). It implements even less features and quirks of the syntax.

Contributing

Issues and PRs are welcome. Especially ones that eliminate any of the //nolint comments.