The second part is live: Writing a replacement to OpenSSH using Go (2/2)
SSH is a well-known protocol to access remote servers and OpenSSH is the most common implementation. This article will explain how to build a SSH server and client using Go.
In a Platform as a Service such as Appsdeck, the standard way to deploy an application is to use git push
. Underneath, git
is simply using the ssh
command. The two lines below explain the link between them:
# With appsdeck remote: git@appsdeck.eu:myproject.git
~/myproject $ git push appsdeck master
# Git will execute:
~/myproject $ ssh git@appsdeck.eu git-receive-pack myproject.git
Actually, it is possible to tell git
to use another SSH client, by setting the environment variable GIT_SSH
.
To authenticate a user to a remote server using OpenSSH Server, the user’s public SSH key has to be appended in the ~/.ssh/authorized_keys
file of the target user. If OpenSSH finds the public key in this file, the authentication is considered successful. By default, it would execute the shell of the user, defined by its account.
It is possible to execute a custom command by prepending it to the public SSH key in the authorized_keys
file:
command="ssh-handler" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAA[...]2bF26cl
In this case, instead of running the shell of the user, it will run the command “ssh-handler”. Our first prototype was using this feature to authenticate and authorize our users. However, as soon as you want to build a real distributed infrastructure, it’s not sufficient anymore. Indeed, with this method, it means that several hosts have to keep their authorized_keys
file containing all the public keys of our users in sync. That’s two problems in one : we had to find a synchronization mechanism, and, sensitive data are spread out on several machines.
That’s why we decided it was time to build something more robust and scalable by writing our own custom SSH server, which would be able to use a custom backend to identify our users and then to forward the SSH connection to another host which will actually execute the GIT operation.
We decided to write this custom SSH server with Go for different reasons. Except the fact that we had experience with the language, this official package (http://godoc.org/golang.org/x/crypto/ssh) implements everything we needed to build what we were looking for, while keeping it simple.
At Appsdeck, we are looking to respect the KISS principle. If a software is simple, it is easier to conserve readability, modularity and easy maintenance. By the way, that’s also why Go has become one of our core languages.
While the Go package implements SSH connections setup (that includes transport and crypto), you still have to understand and to use SSH applicative protocol to build your software.
To achieve this, it is important to get how SSH is working, the following RFCs define the protocol:
Anytime you need to get explanations about a method or a constant of the Go package, refering to the RFCs is pretty straightforward with a simple text search.
(RFCs 4255 and 4256 also concern SSH but are less useful in this scope)
The following code example defines a simple SSH server: https://github.com/Scalingo/go-ssh-examples/blob/master/server.go
This server only displays the kind of SSH key used for authentication (if any), accepts it, then closes the connection.
Server:
└> go run server.go
2014/12/05 15:41:27 [::1]:46428 authenticate with ssh-rsa
2014/12/05 15:41:27 Connection from [::1]:46428
Client:
└> ssh localhost -p 2222
Connection to localhost closed by remote host.
Connection to localhost closed.
As expected, our Go server succeeds to speak with OpenSSH, but then the connection is closed instantly.
https://github.com/Scalingo/go-ssh-examples/blob/master/client.go
Usage:
go run client.go <user> <server:port> <command>
This client has only one job, it connects to a server, creates a sessions, executes a command, then prints the output and disconnects.
Output:
└> go run client.go foobar example.com:22 'ls /'
Password: *********
bin
boot
conf.d
dev
etc
home
initrd.img
lib[...]
This article introduces our problematic and how to use the SSH protocol with Go. In the next article we’ll explain how we use this library to solve our real problems (Authentication, Authorization, Connection Proxying).
To be continued…
… Ready? Second part is here: Writing a replacement to OpenSSH using Go (2/2)
Links
This article was the 2nd post of the serie #FridayTechnical, see you next time!
Gopher image by Renee French (Creative Commons Attributions 3.0) Puffy - OpenSSH logo
— Léo Unbekandt, CTO @ Appsdeck
At Scalingo (with our partners) we use trackers on our website.
Some of those are mandatory for the use of our website and can't be refused.
Some others are used to measure our audience as well as to improve our relationship with you or to send you quality content and advertising.