Commit c9dbf874 authored by Florian Kempenich's avatar Florian Kempenich
Browse files

Create new sudo user after Droplet created

parent 82f29c60
################################################
## This playbook has 3 steps:
## 1) Create Droplet on DigitalOcean & Update inventory / ssh config
## 2) Create new User account on Droplet
## 3) Install Software w/ new User account
##
##
## These steps are run on different machines w/ different users:
## 1) Create Droplet ...
## -> Runs on: Localhost
## -> as: Current user
## 2) Create new User account ...
## -> Runs on: Newly Created Droplet
## -> as: root
## 3) Install Software ...
## -> Runs on: Newly Created Droplet
## -> as: Newly Created User
#####################################################################
### STEP 1 ##
### Create Droplet on DigitalOcean & Update inventory / ssh config ##
### ##
### Host: Localhost ##
### SSH User: Current user ##
#####################################################################
# `droplet_name` need to be passed as `--extra-var` !!
# `droplet_spec_name` need to be passed as `--extra-var` !!
- hosts: localhost
# `droplet_name` need to be passed as `--extra-var` !!
# `droplet_spec_name` need to be passed as `--extra-var` !!
vars:
# Load config
do_token: "{{ lookup('file', '{{ digitalocean_token_location }}') }}"
ssh_pub_key_to_load_on_droplet: "{{ lookup('file', '{{ ssh_pub_key_to_load_on_droplet_location }}') }}"
remote_user: root
tasks:
- name: "Ensure 'droplet_name' is passed as parameter"
- name: "Ensure required parameters - via config"
assert:
that: droplet_name != ""
- name: "Ensure 'droplet_spec_name' is passed as parameter"
that:
- do_token != ""
- ssh_pub_key_name_on_digitalocean != ""
- ssh_pub_key_to_load_on_droplet != ""
- do_token != ""
- user_to_create_username != ""
- user_to_create_default_password != ""
msg: "'do_token', 'ssh_pub_key_name_on_digitalocean', 'ssh_pub_key_to_load_on_droplet', 'do_token', 'user_to_create_username' and 'user_to_create_default_password' must be set in the configuration"
- name: "Ensure required parameters - via --extra-vars"
assert:
that: droplet_spec_name != ""
that:
- droplet_name != ""
- droplet_spec_name != ""
msg: "'droplet_name' and 'droplet_spec_name' must be passed as parameters with '--extra-vars'"
- name: "Load the specs of the droplet to create"
include_role:
......@@ -22,7 +53,7 @@
vars:
droplet_spec_name: droplet_spec_name
- name: "Ensure SSH Key exists at DigitalOcean | Using key at: {{ ssh_pub_key_to_load_on_droplet_location }}"
- name: "Ensure SSH Key exists at DigitalOcean"
digital_ocean:
command: ssh
state: present
......@@ -52,7 +83,7 @@
block: |
Host {{ droplet_name }}
Hostname {{ created.droplet.ip_address }}
User root
User {{ user_to_create_username }}
- name: "Add Droplet as Ansible Host in `~/.ansible-droplet-inventory`"
blockinfile:
......@@ -60,14 +91,27 @@
state: present
create: yes
marker: "### ANSIBLE MANAGED - DigitalOcean Droplet: '{{ droplet_name }}' - {mark} #######################"
block: "{{ droplet_name }} ansible_host={{ created.droplet.ip_address }} ansible_user=root ansible_python_interpreter=/usr/bin/python3"
block: "{{ droplet_name }} ansible_host={{ created.droplet.ip_address }} ansible_user={{ user_to_create_username }} ansible_python_interpreter=/usr/bin/python3"
- name: "Refresh inventory"
meta: refresh_inventory
#####################################################################
### STEP 2 ##
### Create new User account on Droplet ##
### ##
### Host: Newly Created Droplet ##
### SSH User: root ##
#####################################################################
- hosts: "{{ droplet_name }}"
gather_facts: False
vars:
# If using `remote_user` at the same level as `hosts`, it would
# not override the `ansible_user` variable from the inventory
ansible_user: root
tasks:
- name: "Wait for Droplet available"
wait_for_connection:
......@@ -88,14 +132,48 @@
vars:
swapfile_size: "{{ droplet_specs.swap }}"
- name: "Install Glances Webserver as a service"
- name: "Create new sudo user w/ default password"
include_role:
name: glances
name: create-new-sudo-user
vars:
username: "{{ user_to_create_username }}"
default_password: "{{ user_to_create_default_password }}"
authorized_ssh_key: "{{ ssh_pub_key_to_load_on_droplet }}"
#####################################################################
### STEP 3 ##
### Install Software w/ new User account ##
### ##
### Host: Newly Created Droplet ##
### SSH User: Newly Created User ##
#####################################################################
- hosts: "{{ droplet_name }}"
gather_facts: False
vars:
# If using `remote_user` at the same level as `hosts`, it would
# not override the `ansible_user` variable from the inventory
ansible_user: "{{ user_to_create_username }}"
tasks:
# TODO: Fix Glances installation (or remove, but be sure to re-locate the daemon part!!)
# TODO: Fix Glances installation (or remove, but be sure to re-locate the daemon part!!)
# TODO: Fix Glances installation (or remove, but be sure to re-locate the daemon part!!)
# - name: "Install Glances Webserver as a service"
# include_role:
# name: glances
- name: "Enable advanced metrics on DigitalOcean"
shell: "curl -sSL https://agent.digitalocean.com/install.sh | sh"
- debug:
msg: "Droplet '{{ droplet_name }}' succesfuly created | IP = {{ ansible_default_ipv4.address }}"
msg:
- "Droplet '{{ droplet_name }}' succesfuly created"
- ""
- "IP = {{ ansible_default_ipv4.address }}"
- "User = {{ user_to_create_username }}"
- "Password = {{ user_to_create_password }}"
- ""
- "You can now ssh to the droplet with `ssh {{ droplet_name }}`"
- "Don't forget to change the default password!"
\ No newline at end of file
- hosts: localhost
vars:
# `droplet_name` need to be passed as `--extra-var` !!
do_token: "{{ lookup('file', '{{ digitalocean_token_location }}') }}"
tasks:
# `droplet_name` need to be passed as `--extra-var` !!
- name: "Ensure 'droplet_name' is passed as parameter"
- name: "Ensure required parameters - via config"
assert:
that: do_token != ""
msg: "'do_token' must be specified in the config"
- name: "Ensure required parameters - via --extra-vars"
assert:
that: droplet_name != ""
msg: "'droplet_name' must be passed as parameters with '--extra-vars'"
- name: "Delete droplet"
block:
......
- name: "Ensure required parameters provided"
assert:
that:
- username != ""
- default_password != ""
- authorized_ssh_key != ""
msg: "Please provide the required parameters!"
- name: Block w/ 'become' escalation
block:
- name: Create new sudo user
user:
name: "{{ username }}"
password: "{{ default_password|password_hash('sha512') }}"
create_home: yes
groups: sudo
update_password: on_create
- name: "Add SSH key to autorized_keys"
authorized_key:
user: "{{ username }}"
key: "{{ authorized_ssh_key }}"
state: present
become: yes
......@@ -2,6 +2,7 @@ import click
import os.path
from os import symlink
import subprocess
from glob import glob
SCRIPT_DIR = os.path.dirname(__file__)
......@@ -15,8 +16,7 @@ INVENTORY_DROPLETS_FILE = '.ansible-droplet-inventory'
CREATE_PLAYBOOK = 'create-droplet-playbook.yml'
DESTROY_PLAYBOOK = 'delete-droplet-playbook.yml'
DEFAULT_SSH_KEY = '{{ ansible_env.HOME }}/.ssh/id_rsa.pub'
# DEFAULT_DO_TOKEN = '"{{ ansible_env.HOME }}/secrets/digitalocean/token"'
DEFAULT_SSH_KEY = '~/.ssh/id_rsa.pub'
def _install_requirements_if_needed():
if not _are_requirements_installed():
......@@ -35,8 +35,8 @@ def _install_requirements():
def _set_configuration_if_needed():
if not _is_configured():
ssh_key, do_token = _ask_for_configuration()
_create_configuration_file(ssh_key, do_token)
ssh_key_path, ssh_key_name, do_token_path, user_username, user_default_pass = _ask_for_configuration()
_create_configuration_file(ssh_key_path, ssh_key_name, do_token_path, user_username, user_default_pass)
if not _has_droplet_inventory_symlink():
_create_droplet_inventory_symlink()
......@@ -45,18 +45,34 @@ def _is_configured():
return os.path.isfile(os.path.join(ANSIBLE, CONFIGURATION, CONFIGURATION_FILE))
def _ask_for_configuration():
ssh_key = click.prompt('Your ssh public key path', type=str, default=DEFAULT_SSH_KEY)
do_token = click.prompt('Your digital ocean token path', type=str)
return ssh_key, do_token
def _create_configuration_file(ssh_key, do_token):
# TODO Remove defaults (or put as constants)
ssh_key_path = click.prompt('[SSH PUBLIC KEY] - Path?', type=str, default=DEFAULT_SSH_KEY)
ssh_key_name = click.prompt('[SSH PUBLIC KEY] - Name on DigitalOcean?', type=str, default="Main SSH Key")
do_token_path = click.prompt('[Digital Ocean Token] - Path?', type=str, default="~/config-in-the-cloud/secrets/digitalocean/token")
user_username = click.prompt('[User on Droplet] - Username?', type=str, default="bonjour")
user_default_pass = click.prompt('[User on Droplet] - Default Password?', type=str, default="pass")
# user_username = click.prompt('[User on Droplet] - Username?', type=str)
# user_default_pass = click.prompt('[User on Droplet] - Default Password?', type=str)
return ssh_key_path, ssh_key_name, do_token_path, user_username, user_default_pass
def _create_configuration_file(ssh_key_path, ssh_key_name, do_token_path, user_username, user_default_pass):
if not os.path.exists(os.path.join(ANSIBLE, CONFIGURATION)):
os.makedirs(os.path.join(ANSIBLE, CONFIGURATION))
def lookup_file_format(path):
# Regarding the curly braces:
# Expected result '{{'
# But python interprets '{' in strings, so need to escape '{' with '{{'
# since expected result is '{{', we need to escape twice, hence '{{{{'
ansible_compatible_path = os.path.expanduser(path)
return "{{{{ lookup('file', '{0}') }}}}".format(ansible_compatible_path)
with open(os.path.join(ANSIBLE, CONFIGURATION, CONFIGURATION_FILE), "w+") as file:
file.write('ssh_pub_key_name_on_digitalocean: "Main SSH Key"\n')
file.write('ssh_pub_key_to_load_on_droplet_location: "{0}"\n'.format(ssh_key))
file.write('digitalocean_token_location: "{0}"\n'.format(do_token))
file.write('ssh_pub_key_name_on_digitalocean: "{0}"\n'.format(ssh_key_name))
file.write('ssh_pub_key_to_load_on_droplet: "{0}"\n'.format(lookup_file_format(ssh_key_path)))
file.write('do_token: "{0}"\n'.format(lookup_file_format(do_token_path)))
file.write('user_to_create_username: "{0}"\n'.format(user_username))
file.write('user_to_create_default_password: "{0}"\n'.format(user_default_pass))
def _has_droplet_inventory_symlink():
inventory_link = os.path.join(ANSIBLE, INVENTORY, INVENTORY_DROPLETS_LINK)
......
......@@ -2,6 +2,8 @@
ansible
# Required by the DigitalOcean ansible module
dopy==0.3.5
# To hash default password
passlib
# For the CLI
click
......@@ -30,7 +30,8 @@ setup(
install_requires=[
'ansible',
'dopy==0.3.5',
'click'
'click',
'passlib'
],
data_files=[(HOME, ['.ansible-droplet-inventory'])],
include_package_data=True,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment