- Ansible - Using ansible playbooks and inventories for provisioning
- docker-compose / docker : Mutable containers are bad, but I'm using docker to simplify environment creation for the purpose of this example
- In this example Ansible is used by a master server which provisions a target environment.
- Secrets management (for the ssh_pass key) is simplified to use docker secrets sourced from a plain text file. We assume that a real implementation would use an encrypted store like vault or ansible vault
- docker-compose wth support for compose file > v3.3
- Tested with docker-compose 1.21 on Linux running Docker Engine 19.03.2
- Make sure 4222 is free with
lsof -i :4222
The provisioned ssh server's 22 is forwarded to local 4222.
- Top Level - docker-compose orchastration to run the example
- target-ssh-server - An ubuntu 16.04 container with a local ansible playbook customising several layers to a BASELINE image
- ansible-master - An alpine container with ansible installed and inventories + roles to harden ssh, setup firewalls, set motd and test motd.
-
git checkout branch-with-keys
- OR use
ssh-keygen
and create a key WITHOUT a passphrase (see Other Notes below for justification)- Copy the public key to
target-ssh-server/public-key/management-key.pub
- Copy the private (identity) to `ansible-master/keys/management-key-cert
- Copy the public key to
- OR use
-
Run
docker-compose up --build
-
To manually connect to the server
ssh -o StrictHostChecking=no -o IdentitiesOnly=yes -p 4222 -i ./ansible-master/keys/management-key-cert ansible@localhost
- I would have liked to use inspec to test the final state, but decided on just validating motd on the server using an assert. From a risk-based perspective the connection to the server and content of /etc/motd suggest that this is a reasonable validation; although far from complete.
- Experienced issues with ansible utilising sshpass for ssh identity password's. These connections were hanging, so I went for private keys without paswswords.
- If this were the real world it would imply better key management would be required. Obviously, adding this to git is illadvised. Other than for a fun exercise like this.
- Needed to provision iptables and kernel dependencies, as well as passing
cap_add: NET_ADMIN
to the Docker engine to enable the container to manage iptables. - Due to issues with ssh_pass hangs, I had to use identity keys without passphrases. We'll assume that these are provided outside of the application. Given the use of containers I did not want to force a user to exec on a container in order to answer a password prompt.
In the real world we'd want our container image to be immutable and bake the runtime state into another layer of the container image.
Note that while this uses containers - these are only for convenience. Container images should be immutable I considered using docker commit, ansible-container, packer or something else; but that is beyond the objective of the exercise.
[top level playbook]
- target_ssh_server: local playbook to bring up to a cattle base-line
- ansible-master:
- copy: motd
- role:
- motd - using a custom version rather than one from galaxy galaxy for demonstration purposes
- harden-ssh
- validate_motd
- vars: message_to_validate