Your 3-tier secure platform with Docker & bastion

December 01, 2016 in #3-tier #security #docker #bastion #ansible #devops | | | Share on Google+


Enjoy the DevOps trend with this efficient & secure architecture to run your Docker web platform in the cloud

Ever wanted to migrate your 3-tier platform to the Cloud and take advantage of Docker? To get an efficient and secure architecture to start building your project, you will need:

  • A cloud provider where you can deploy some VMs ( in my case)
  • Some hosts with Docker installed: could be a flavor of Ubuntu, Debian, CentOS, CoreOS (depending of your taste and needs)
  • Firewall: this could be some security groups from your Cloud provider, or local firewall with ufw (uncomplicated firewall)
  • A Bastion: SSH gateway and deployment server
  • Ansible: to deploy everything (VM, firewalls, containers)

Below is a diagram representing a 3-tier architecture that I use in prod, with example of front / app / DB which can be adapted to your needs.


1. Fast deployment with Ansible & Docker

1.1. Docker

Docker permit to deploy a packaged application with ease. You can be sure that wherever you deploy Nginx (for example), it will behave the same on every host. Nowadays you can find docker image of all the popular apps, and if missing, you can create your own one in few steps.

1.2. Ansible

To deploy these public docker images, Ansible will gives us all the flexibility to download, customize and run the containers, locally or on remote host.

Ansible tools will be installed on Bastion, because this server will have the access key to all servers. More on Bastion below.


  • Declarative actions: you can run and rerun a deploy, only changes will be applied, you are then sure of the state of you infra
  • No agent needed; you only need SSH access
  • Deployed code is stored in a repo, saved in Github/Bitbucket
  • Presence of Ansible Vault, in order to store secret/password/key, encrypted in the repo

Available features:

  • Deploy containers (via Ansible docker module)
  • Create VMs and firewall rules (via Cloud provider plugin, in our case CloudStack)
  • Upgrade/migrate containers versions
  • Execute administrative tasks on servers: apt-get update, dist-upgrade, clean file, backups, ...

With Docker and Ansible, you can redeploy all your infra, in another Cloud within minutes:

  • Containers hold the code and can be moved easily between hosts, while Ansible can build these new hosts and firewalls, and deploy/customize containers.
  • When using this setup, every change in the code is subject to a container destroy & rebuild (that's how docker works). So you learn quickly that nearly all servers can be rebuild easily if one fails (except permanent data like DBs).

2. Security by isolation & control

The most important aspect is the segregation with security groups (firewalls) and the presence of bastion, which filtered access.

2.1 Bastion

This host acts as the only SSH access door to all our infra (on all other servers, we block port SSH ports access from the outside). We will activate high security on that host (2FA, pubkey-only access, access monitoring) so we can closely control admin access and outside world attacks.

Below are commands to secure SSH connection on your Bastion. Always keep a console open somewhere in case of a bad config.

Create an SSH user

Create a user account Greg on the server

sudo useradd -d /home/greg -m greg

Add his public key

mkdir /home/greg/.ssh
echo "greg_public_key" >> /home/greg/.ssh/authorized_keys

User greg then Log in remotely via his private key:

ssh greg@zeus_ip -i greg_private_key

Secure SSH access

Change ssh port default port 22 to 32123

nano /etc/ssh/sshd_config
Port: 32123

Allow only pubkey access, and so disable SSH password login (if you don't use 2FA)

nano /etc/ssh/sshd_config
PasswordAuthentication  no

Restart SSH to apply settings

sudo service ssh restart

From another console, try to connect

ssh greg@zeus_ip -i greg_private_key -p 32123

Activate 2FA (Google Authenticator)

sudo apt-get install libpam-google-authenticat

Configure SSH to use Google Auth

auth required nullok
#@include common-auth    

nano /etc/ssh/sshd_config
ChallengeResponseAuthentication yes
PasswordAuthentication  yes
AuthenticationMethods publickey,keyboard-interactive

sudo service ssh restart

And setup 2FA for Greg:

ssh greg@zeus_ip -i greg_private_key -p 32123

Option: Time based: yes On phone, Open google authentificator app > option > setup new account > scan qr code Backup in a save place all secret keys and scrash code Then yes to all setup questions asked!

Activate automatic upgrades to not miss any security updates of OpenSSH:

nano /etc/apt/apt.conf.d/50unattended-upgrades
dpkg-reconfigure -fnoninteractive unattended-upgrades 

2.2. Firewall

Critical components (like the DB) should be segregated and only have minimal access from/to the outside. With security groups we only allow only known flows and components to talk together.

One more step (not represented here) could be to set all outbound to deny by default, and open only specific access to the outside.

Uncomplicated firewall

Install "uncomplicated firewall" if you don't have any Cloud integrated firewall

sudo apt-get install ufw
sudo ufw status
sudo ufw delault allow outgoing
sudo ufw default deny incoming
sudo ufw limit 32123/tcp   <-- limit permit to stop consecutive failed SSH connection ;-)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp 
sudo ufw delete 22/tcp   <-- we don't need SSH on 22 anymore
sudo ufw status verbose
sudo ufw enable

And try to connect from another console (don't close the first console before all is working fine!)

2.3 Monitor SSH connections with ELK

As bastion is now locked, we control the connections from this point only. It makes then lot of sense to monitor SSH logs. With ELK, you can create a dashboard to differentiate successful and denied accesses. Have a look to this post to setup ELK.


Thank you for reading :-) See you in the next post!

December 01, 2016 in #3-tier #security #docker #bastion #ansible #devops | | | Share on Google+