package common
@Grapes([
@Grab('com.aestasit.infrastructure.sshoogr:sshoogr:0.9.25'),
@Grab('commons-codec:commons-codec:1.10')
])
import com.aestasit.infrastructure.ssh.DefaultSsh
class Sshoogr extends DefaultSsh { }
Rasperry Pi + SSHoogr
The idea
Well some time ago I wanted to build a mini raspberry pi mini tower to
do some proofs of concept about distributed computing. The time passed
and I didn’t do anything…until today. But the thing is attending
last GreachConf I saw sshoogr (pronounced
"sugar"). sshoogr
is a Groovy-based DSL library for working with
remote servers through SSH.
It seemed something easy to use and most importantly…fun! It may well be not as powerful as Ansible but I don’t really need that (at least at the moment) and I thought it would be nice to do some devops while using Groovy.
So steps are:
-
Installing OS
-
Initializing systems
-
Install ssh keys
-
Install Docker
OS
First of all I had to install the OS. Although many people is using Raspbian, or HypriotOS, I chose ArchlinuxARM. Among other things I liked the idea of using the same linux flavor I’m using everyday, and Arch normally is lighter than Debian distros.
To install the OS for a rpi-2
you can find a step-by-step
here. Of
course there are distros for many ARM micros.
Of course once I have install it in the first rpi-2
then clone it to
the other 3 machines.
Commons
Base script
Because I’m dealing with Groovy scripts I’m using Grapes to get sshoogr dependencies. However I don’t want to repeat the dependencies all over again in every script, so I created a base script, and I will be using it through the rest of scripts.
How to use this script in the other scripts ? Well because we are
only interested in methods within DefaultSsh
then we should add a
static import in your script:
import static common.Sudo.*
import static common.Util.*
import static common.Sshoogr.*
Common variables
At this point we can only access the rpi2
using the default
usernames and passwords. In order to avoid copy-pasting the user names
and password every time, I put all of them in the same place.
Unresolved directive in <stdin> - include::../../../../../../../sources/2016/04/sshoogr/common/secrets.groovy[indent=0]
1 | Ip of the host we’re setting |
2 | Sudo prefix |
3 | Default usernames and passwords |
4 | New credentials used to replace default ones |
5 | Path to ssh key files |
6 | A way of gaining root access through su - |
How these variables are included in the rest of scripts ? Throug
the evaluate
method:
evaluate('common/secrets.groovy' as File)
When invoking the evaluate
method, that script will be evaluated and
included in the current script scope.
Install new credentials
First time you access a machine it could be normal to access through user/password, but once you’ve entered the first time afterwards you should be accessing using a ssh key. The following script will be installing our public ssh key as an authorized key in the remote host.
/**
* 1.SSHOOGR CONFIG
*/
import static common.Sudo.*
import static common.Util.*
import static common.Sshoogr.*
(1)
options.trustUnknownHosts = true
/**
* 2.SHARED VARIABLES
*/
evaluate('common/secrets.groovy' as File)
/**
* 3.OWN VARIABLES
*/
PREFIX = "echo $RPI_ROOT_PASSWORD | su -c '"
SUFFIX = "'"
/**
* 4.CHANGE DEFAULT CREDENTIALS
*
* This step is done without online connection to avoid
* any attack at this point due the fact that machines have
* default usernames and passwords.
*/
remoteSession("$DEF_RPI_USER_TUPLE@$IP"){
prefix("echo $DEF_RPI_ROOT_PASSWORD | su -c '") {
suffix(SUFFIX){
exec "echo \"$RPI_ROOT_TUPLE\" | chpasswd -m"
}
}
prefix(PREFIX) {
suffix(SUFFIX) {
exec "pacman --noconfirm -S sudo"
}
}
prefix(PREFIX) {
suffix(SUFFIX) {
exec "useradd -m $DOCKER_USERNAME"
exec "echo \"$DOCKER_TUPLE\" | chpasswd -m"
exec "echo \"${noPasswd(DOCKER_USERNAME)}\" >> /etc/sudoers"
}
}
}
/**
* 3.INSTALL SSH KEY
*
* Once machines have been initialized, they should be accessed via
* ssh key instead of using username and password. In order to do that
* we need to install an authorized key in every one of them.
*/
AUTHORIZED_KEYS_FILE = "/home/$DOCKER_USERNAME/.ssh/authorized_keys"
DOCKER_PUBLIC_KEY = new File(SUPERVISOR_SSH_PUB_KEY)
DOCKER_PRIVATE_KEY = new File(SUPERVISOR_SSH_PRI_KEY)
DOCKER_CREDENTIALS = [keyFile: DOCKER_PRIVATE_KEY]
remoteSession("$DOCKER_TUPLE@$IP") {
exec "mkdir -p ~/.ssh"
exec "touch $AUTHORIZED_KEYS_FILE"
remoteFile(AUTHORIZED_KEYS_FILE).text = DOCKER_PUBLIC_KEY.text
}
/**
* 5.DELETE DEFAULT USER
*
*/
remoteSession("$DOCKER_USERNAME@$IP") {
keyFile = DOCKER_PRIVATE_KEY
exec "history -c"
prefix(SUDO) {
exec "userdel -fr $DEF_RPI_USER_USERNAME"
exec "pacman --noconfirm -Syu" (1)
exec "reboot now"
}
}
Because hosts at this point doesn’t have a valid ssl certification we are telling ssh to trust a server anyway. |
the --noconfirm flag should be used when you don’t want the
process to ask for confirmation.
|
Install firewall
Now it’s time to protect your machine, install the firewall, this time
I will be using ufw
:
/**
* 1.SSHOOGR CONFIG
*/
import static common.Sudo.*
import static common.Util.*
import static common.Sshoogr.*
options.trustUnknownHosts = true
/**
* 2.SHARED VARIABLES
*/
evaluate('common/secrets.groovy' as File)
DOCKER_PRIVATE_KEY = new File(SUPERVISOR_SSH_PRI_KEY)
/**
* 4.INSTALL FIREWALL
*/
remoteSession("$DOCKER_USERNAME@$IP") {
keyFile = DOCKER_PRIVATE_KEY
prefix(SUDO) {
exec "pacman --noconfirm -S ufw" (1)
exec "ufw allow ssh" (2)
exec "systemctl enable ufw" (3)
exec "systemctl start ufw" (4)
}
}
1 | Install ufw |
2 | Add ssh exception |
3 | Enable ufw on startup |
4 | Start ufw service now |
Install Docker
/**
* 1.SSHOOGR CONFIG
*/
import static common.Sudo.*
import static common.Util.*
import static common.Sshoogr.*
options.trustUnknownHosts = true
/**
* 2.SHARED VARIABLES
*/
evaluate('common/secrets.groovy' as File)
DOCKER_PRIVATE_KEY = new File(SUPERVISOR_SSH_PRI_KEY)
/**
* 3.INSTALL DOCKER
*
* Installing docker engine in all machines
*/
remoteSession("$DOCKER_USERNAME@$IP") {
keyFile = DOCKER_PRIVATE_KEY
prefix(SUDO) {
exec "pacman --noconfirm -S docker"
exec "usermod -a -G docker $DOCKER_USERNAME"
exec "systemctl enable docker"
exec "systemctl start docker"
}
exec "history -c"
}
Check it out!
You can find Sshoogr
at https://github.com/aestasit/sshoogr