Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
discopatrick committed Jul 9, 2016
2 parents 55cdbf5 + 2ce2f65 commit 7919367
Show file tree
Hide file tree
Showing 16 changed files with 176 additions and 12 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.vagrant
*.retry
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Ansible "Proof of Concepts" project

An ansible project that solves and documents some of the issues I've faced while using ansible, vagrant local vms, and remote servers together.

Keeping these examples in a simple, isolated project lets me refer to known working examples, in case I ever have issues while working in more complex projects.

## Inventory

See hosts/README.md for notes specific to inventory files.

## Playbooks

### vagrant.yml

This is a near-empty playbook that vagrant runs by default on `vagrant up`. We don't really want a playbook to be run automatically (we want to choose from one of the below playbooks), however, using the vagrant ansible provisioner requires that you choose a playbook, so we just give it this dummy playbook to keep it happy. You may ask "then why use the ansible provisioner at all?" - because we want it to auto-generate an inventory file for us.

### remote-admin-user.yml

A playbook to add an 'admin' user to your remote machine, so you don't have to use root.

Most vagrant boxes come with a default 'vagrant' user with passwordless sudo. On the other hand, most remote VPS's come with root access only. It's better to run things as a standard user, and only elevate to root when necessary.

In this playbook, the very first role is to add the admin user - this is done while logging in as root (set as `remote_user` at task level in the admin_user role, to override the playbook level setting described below). This only needs to be done on remote machines though, so the 'development group' is excluded from this role.

Any roles or tasks beyond this should use the standard user. This is set at playbook level as `remote_user`. This in turn is set via a group_var called `my_remote_user` - because the user will be different depending on the environment ('vagrant' on the development box, 'admin' elsewhere).
26 changes: 14 additions & 12 deletions Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Vagrant.configure(2) do |config|
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.

# disable vagrant-vbguest plugin
if Vagrant.has_plugin?("vagrant-vbguest")
config.vbguest.no_install = true
end

# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
config.vm.box = "ubuntu/trusty64"
Expand All @@ -33,11 +38,8 @@ Vagrant.configure(2) do |config|
# your network.
# config.vm.network "public_network"

# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
# disables the default synced folder - not used in this project
config.vm.synced_folder ".", "/vagrant", disabled: true

# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
Expand All @@ -61,11 +63,11 @@ Vagrant.configure(2) do |config|
# push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
# end

# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
# config.vm.provision "shell", inline: <<-SHELL
# sudo apt-get update
# sudo apt-get install -y apache2
# SHELL
config.vm.provision "ansible" do |ansible|
ansible.playbook = "playbooks/vagrant.yml"
ansible.groups = {
'development' => ['default']
}
end

end
8 changes: 8 additions & 0 deletions ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[defaults]
inventory = ./hosts
inventory_ignore_extensions = .md, .txt

# by default, playbooks look for a 'roles' dir in the same directory.
# thus, if your playbooks are in a subdirectory of their own, specify
# the roles dir here:
roles_path = ./roles
5 changes: 5 additions & 0 deletions group_vars/development.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---

# this actually gets overriden by ansible_ssh_user in the inventory,
# but should be defined here regardless, to avoid an undefined variable error
my_remote_user: vagrant
3 changes: 3 additions & 0 deletions group_vars/staging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---

my_remote_user: admin
1 change: 1 addition & 0 deletions hosts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_staging
47 changes: 47 additions & 0 deletions hosts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Inventory

Note: this file would normally be parsed as an inventory file! However, we have ignored .md files in ansible.cfg

## Why is the _development inventory file a symlink?

When you provision a vagrant machine with ansible, an inventory file is automatically generated at .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory. This is the inventory file that is used by `vagrant provision` and `vagrant ssh` to connect to the box.

When we come to add more environments like staging and production, it would be useful to have the details in this file replicated in our hosts directory. Then we can tell ansible.cfg to look in this one directory for connection information to all our hosts. In the interest of keeping things DRY, rather than duplicating this file, we add a symlink to it's original location. This way, it will stay updated if the details of the box ever change, or if we add multiple boxes.

By default, the vagrant_ansible_inventory doesn't add the hosts to any groups. However, you can add each box to as many groups you wish within the provisioner configuration in the Vagrantfile, like this:

```
ansible.groups = {
'development' => ['default']
}
```

We can then reference the 'development' group in our playbooks.

## Why are some inventory file names prefixed with underscores?

This is a workaround for a problem. The contents of the hosts directory are processed in alphabetical order. This means that if you had inventory files 'a' and 'b', and in 'a' you tried to reference a group name that is defined in 'b', you would get an error like: `"Section [mysection:children] includes undefined group: mygroup"`

To work around this, we make sure all groups are defined first (hence adding the underscore to make them first alphabetically).

## What is the insecure_ssh inventory file?

(The insecure_ssh file is based on a solution found here: http://stackoverflow.com/a/35564773/3293805)

This file adds a nested inventory group that allows us to disable strict host key checking for a group of servers. Strict host key checking is how SSH determines whether the machine you're connecting to is the machine you really think it is, by checking its 'fingerprint'.

But why would we want to disable this?

Disabling string host key checking is particularly useful for the development group, the server for which (in this project) is built on vagrant. If you do a `vagrant destroy` followed by a `vagrant up`, you will have a brand new machine with a brand new 'fingerprint', but with the same IP address of 127.0.0.1. Thus, the next time you run the ansible-playbook command, the connection will fail, and you'll see an error message like:

> WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
In fact, nothing nasty is happening, we've just rebuilt our machine. By disabling strict host key checking, we allow ansible to continue to connect to the machine.

Disabling string host key checking can also be useful if you test your playbooks against a remote host, and you occasionally rebuild that host (e.g. on AWS or Digital Ocean). For this reason, this project also disables strict host key checking for the 'staging' group.

To disable strict host key checking for a group, add the group name under `[insecure_ssh:children]` in the 'insecure_ssh' file. This should not be done on production, or indeed any server you plan to deploy sensitive information to (which might include staging). Use at your own risk.

Note:
* Running `vagrant provision` after rebuilding your vagrant machine does not throw up the above warning, so disabling strict host key checking is only necessary if you're trying to run ansible directly, e.g. via `ansible-playbook`. Likewise, `vagrant ssh` does not throw up the warning.
* Disabling strict host key checking in ansible does not have an effect when SSH'ing into the machine using the ssh command - you will see the above warning. A workaround in this case is to remove the old 'fingerprint' from your ~/.ssh/known_hosts file. Look for the IP address of the machine, and remove that line from the file.
1 change: 1 addition & 0 deletions hosts/_development
5 changes: 5 additions & 0 deletions hosts/_staging.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# rename this file to _staging, uncomment the lines below,
# and add your own staging hostname

#[staging]
#your_staging_hostname_or_ip
6 changes: 6 additions & 0 deletions hosts/insecure_ssh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[insecure_ssh:children]
development
staging

[insecure_ssh:vars]
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
8 changes: 8 additions & 0 deletions playbooks/remote-admin-user.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
- hosts: all
gather_facts: no
remote_user: "{{ my_remote_user }}"

roles:
- { role: admin_user, when: "'development' not in group_names" }
- { role: remote_user_test, tags: ['remote_user_test'] }
4 changes: 4 additions & 0 deletions playbooks/vagrant.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---

- hosts: all
gather_facts: no
28 changes: 28 additions & 0 deletions roles/admin_user/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---

- name: create admin group
remote_user: "{{ admin_user_role_remote_user }}"
group:
name: admin

- name: Allow admin group to have passwordless sudo
remote_user: "{{ admin_user_role_remote_user }}"
lineinfile:
dest: /etc/sudoers
state: present
regexp: '^%admin'
line: '%admin ALL=(ALL) NOPASSWD: ALL'

- name: create admin user in admin group
remote_user: "{{ admin_user_role_remote_user }}"
user:
name: admin
groups: admin
append: yes
shell: /bin/bash

- name: add ssh public key for admin user
remote_user: "{{ admin_user_role_remote_user }}"
authorized_key:
user: admin
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
3 changes: 3 additions & 0 deletions roles/admin_user/vars/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---

admin_user_role_remote_user: root
17 changes: 17 additions & 0 deletions roles/remote_user_test/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---

- name: get current username
command: id -u -n
register: user_name

- name: print home directory
command: echo $HOME
register: user_home

- name: print username and home dir
debug:
msg: "user: {{ user_name.stdout }} --- home: {{ user_home.stdout }}"

- name: test sudo pwd
become: yes
command: pwd

0 comments on commit 7919367

Please sign in to comment.