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 vm ( in my case)
  • Some hosts with docker installed: could be a flavor of ubuntu, debian, centos, coreos (depending of your taste and needs)
  • Firewall: 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, firewall, container)

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. Nowdays 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 get, 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 of 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, only need ssh access
  • Deployed code is stored in a repo, saved on github/bitbucket
  • presence of ansible vault, in order to store secret/password/key, encrypted in the repo


  • deploy container (via ansible docker module)
  • Create vm and firewall rules (via cloud provider plugin, in our case cloudstack)
  • Upgrade/migrate containers versions
  • Execute administrative tasks on server: apt-get update, dist-upgrade, clean file, backups, ...

With docker and ansible, your can redeploy all your infra, in another cloud within minutes:

  • Containers hold the code and can be moved easily from hosts to hosts while ansible can build hosts and firewalls, and deploy/customize containers.
  • When using this setup, every changes in the code and migration are subject to a destroy and rebuild of the container (that how docker works). So you learn quickly that all servers can be rebuild easily if one fails.

2. Security by isolation & control

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

2.1. Firewall

Critical components (like the DB) should be segregated and only have minimal access from the outside. With security groups we only allow 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 dont 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.2 Bastion

This host acts as the only ssh access door to all our infra (on all other server we block port ssh ports). 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. Each of these configs needs to restart ssh in order to be applied:

sudo service ssh restart

Change ssh port default port 22 to 32123:

nano /etc/ssh/sshd_config
Port: 32123

Allow only pub-key access, and so disable ssh password login (if you don't use 2fa)

nano /etc/ssh/sshd_config
PasswordAuthentication  yes

Activate 2fa (google authentificator)

sudo apt-get install libpam-google-authenticat

Configure shh to use google auth

auth required nullok
#@include common-auth    

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

Create user account on serve

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

And setup 2fa:

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     <-- and uncommment the auto-update you want
dpkg-reconfigure -fnoninteractive unattended-upgrades  <-- bug: update doesnt applied...

2.3 Monitor ssh connections with ELK

As Bastion is now locked, we control the flux of access from this point only. It makes then lot of sense to monitor ssh logs. With elk, you can create dashboard to differentiate successful and denied access. Have a look to this post to setup elk:


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