A note: I meant to write this blog post for years. I am finally knocking this blog post off of my todo list. Hurray!
In the beginning, there was the terminal, and it was great. After networking had come around, the terminal was networked and called telnet. It was thought to be good but later realized to be a disaster when people realized it was not secure. Then there came the secure shell which was a secure wrapper around telnet. Later the features for SSH expanded into:
- Port Forwarding (used as a jump box/service)
- Proxying network traffic
- X11 forwarding
- Secure shell environment
- Key based authentication
- Secure File Transfer (SFTP)
There are a lot of different uses of SSH and how you can configure it to do some pretty extraordinary things. That is something that would be out of the scope of this blog post. A great reference on SSH can be found in this book.
One of the features that caught my attention is that it is possible to create services that are purely in the Unix environment and are incredibly secure. The attack surface is small, communication is encrypted, and that your environment is sandboxed (well as much as you make it).
Passwords are incredibly low effort to unlock a system. They tend to be short, and they can be brute forced. (Even worse, they frequently have a small space of combinations as that they are human chosen). Randomly generated keys with lots of bits were created to avoid this issue. This was added to SSH to add in passwordless login and to avoid sharing passwords as well. All of the public keys are stored in the user’s authorized_keys file.
Within the authorized_keys, each entry has the following format:
<key encryption used> <public key> <comment>
Within each line, it is possible to extend the features (shell, a command to run, environment variables, etc.) of that particular login. (See the man page for more details)
To build a secure service, use the command variable. You will see in the section labeled your first secure service for an example.
- To setup an account, you are going to need a private key. Generate that with ssh-keygen without a password. (You can use a password, but it will make automation tough)
- Add the entry into the authorized_keys file. (~/.ssh/authorized_keys) With the ssh-copy-id command (ex. ssh-copy-id –i [location of your private key] [user running the command]@[server]
- Your ~/.ssh/authorized_keys file should have entries similar to the following:
- cat ~/.ssh/authorized_keys
- ssh-rsa A……..iJu+ElF7 steven@server
- See the section Authorized Keys section for an explanation of what this means.
- Test the access to the service by sshing into the box under that user and with that key. (Sample command: ssh –i [private key] user@server
- The first time you connect to a server with SSH you are going to get a message asking if it is ok to connect to a particular box. (This is something you need to do if you are automating a process as well)
Your first service
Your first service will be an incredibly simple example. Open up your authorized_keys file that was modified from the setup section. Add in the following command in front of the ssh-rsa/dsa line for the new entry.
command="echo hello the time is `date`"
The line of the login should now look similar to the following:
command="echo hello the time is `date`" ssh-rsa A.......
Now you can make a call to the configured service as such:
ssh -i .ssh/id_sitetest steven@localhost
You will receive an output of:
hello the time is Fri Nov 11 22:28:37 CST 2016
Connection to localhost closed.
Congratulations, if you followed along with the previous instructions: you have created your first secure service. All of the input communicated to the service and coming back from the service is encrypted. You have control over the format that is output and how you are going to take in input. The beauty of this service is that a terminal is not left open, and only the command that is defined is run. Once the command is done, the session automatically closes.
How should one best develop services?
You should develop a bash script to replicate the functionality that you would like the server to perform before setting it up to run in SSH. This gives you an isolated environment to test the process and to test it before it goes live. The SSH service setup is merely a layer above the script.
How should I get input into the service?
To do this, you would need to take in input just like how you would in a bash script. I would suggest using the ‘read’ command to do this. See this guide.
A note on this: Always validate the input. Attackers are unlikely (assuming that the key is managed properly), but it never hurts to
Is it webscale?
Honestly, I do not know the answer to this question. I guess it is possible to do this via the web, and I am not sure how stable it would be with lots of concurrent users. It is at most as scalable as the SSH service and system.
Can you automate the use of these secure services?
Yes. However, when you create the key, you should never add a passphrase as that requires manual interaction. A word to the wise, keys should have a required live cycle and should be phased out periodically. Key management will be an issue in this situation.