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: email@example.com:myproject.git
~/myproject $ git push appsdeck master
# Git will execute:
~/myproject $ ssh firstname.lastname@example.org git-receive-pack myproject.git
Actually, it is possible to tell
git to use another SSH client, by setting the environment variable
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
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.
└> 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
└> 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.
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.
└> go run client.go foobar example.com:22 'ls /'
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)
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