-
Notifications
You must be signed in to change notification settings - Fork 0
/
ansible_install.sh
347 lines (310 loc) · 13.9 KB
/
ansible_install.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#!/usr/bin/env bash
#-----------------------------------------------------
# Visit https://github.com/juanlazarde/ansible_homelab
# Licensed under the MIT License
#-----------------------------------------------------
#
# Syntax: bash ansible_install.sh [optional [-a] [-r] [-v] [-e [<filename>]] [-d <directory name>] [-h]]
#
# Normal usage; without arguments, will install ansible, scripts, and vault key.
#
# --no-ansible, -a : don't install Ansible and its dependencies.
# --no-repository, -r : don't download the repository with Ansible scripts from GitHub.
# --no-vault, -v : don't create a secret vault key.
# --encrypt, -e [filename] : tool to create a hashed ansible-encrypted variable. Optionally, save it as a file.
# -d directory name : directory where you want to install the Ansible scripts. Default: ansible_scripts.
# --help, -h : help info
#
# More info:
# - https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#installing-ansible-on-ubuntu
#
# Enable xtrace if the DEBUG environment variable is set
# DEBUG=true
[[ ${DEBUG-} =~ ^1|yes|true$ ]] && set -o xtrace # Trace the execution of the script (debug)
# A better class of script...
set -o errexit # Exit on most errors (see the manual)
set -o errtrace # Make sure any error trap is inherited
set -o nounset # Disallow expansion of unset variables
set -o pipefail # Use last non-zero exit code in a pipeline
# DESC: Script initialization.
# ARGS: $@ (optional): Arguments provided to the script.
# OUTS: default variables, directory/file related variables.
# $default_repository_dir: Directory where the repository will be installed.
# $default_vault_name: Secret vault encryption key (DO NOT SHARE THESE FILES!!! i.e. add to .gitignore).
# $default_encrypted_name: Encrypted file with the variable just encrypted.
# $default_salt_name: Salt file with salt to hash passwords.
# $salt_path: path to salt file.
# $salt: Salt to be used for hashing passwords.
#
# $install_ansible: Install ansible and the dependencies.
# $install_repository: Retrieve and expand the repository from GitHub.
# $install_vault: Create the vault key file.
# $util_encrypt: Hash and encrypt password utility.
function script_init() {
# Default variables
readonly default_repository_subdir="ansible_scripts"
readonly default_vault_name=".vault_key"
readonly default_salt_name=".vault_salt"
# Initialization
install_ansible='true'
install_repository='true'
install_vault='true'
util_encrypt='false'
# Read-only variables
readonly script_params="$*"
readonly home_dir=$(eval echo "~")
readonly orig_cwd="${PWD}"
readonly script_path="${BASH_SOURCE[0]}"
readonly script_dir="$(dirname "${script_path}")"
readonly script_name="$(basename "${script_path}")"
readonly script_name_no_ext="${script_name%.*}"
readonly vault_path="${home_dir}/${default_vault_name}"
readonly default_repository_dir="${orig_cwd}/${default_repository_subdir}"
readonly salt_path="${home_dir}/${default_salt_name}"
readonly salt="$(deal_with_salt)"
# Atlernative sources.
# readonly orig_cwd="$(cd $(dirname '${BASH_SOURCE[0]}') && pwd)"
# readonly script_name="$(basename $0)""
}
# DESC: Creating or reading salt for hashing.
# If default_salt is empty, then create one, if a file with salt exists, then use it.
# Call as: salt="$(deal_with_salt)" or salt="$(deal_with_salt '123')"
# ARGS: Optional "salt digits".
# OUTS: RETURNS salt string to be used for hashing.
function deal_with_salt() {
local default_salt="${1:-}"
[[ -n "${default_salt}" ]] && local salt=${default_salt}
[[ -z "${default_salt}" ]] && local salt=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 13 ; echo '')
[[ -f "${salt_path}" ]] && local salt=$(cat ${salt_path})
[[ ! -f "${salt_path}" ]] && printf '%s' "${salt}" > "${salt_path}" && chmod 600 "${salt_path}"
echo "${salt}"
}
# DESC: Parameter parser
# ARGS: $@ (optional): Arguments provided to the script
# OUTS: Variables indicating command-line parameters and options
# $install_ansible: if true it will install ansible
# $install_repository: if true it will install the repository of ansible scripts
# $install_vault: if true creates vault key in home folder.
# $at_least_one: if true one of the three options above was selected.
# $util_encrypt: if true none of the four variables above will be true, runs encryption func.
# $repository_dir: is the destination dir for the repository.
function parse_params() {
local param
while [[ "$#" -gt 0 ]]; do
param="${1-}"
case ${param} in
-h|--help) script_usage; exit 0 ;;
-a|--no-ansible) install_ansible='false' ;;
-r|--no-repository) install_repository='false' ;;
-v|--no-vault) install_vault='false' ;;
-d|--repository-dir) repository_dir="${2-}"; shift ;;
-e|--encrypt) util_encrypt='true'; encrypted_name="${2-}"; break ;;
*) printf '%s\n' "Invalid option '${param}'. Use --help to see the valid options" >&2; exit 1 ;;
esac
shift
done
# User must enter a valid option or combination of valid options. Exit if all options are false.
if ! (${install_ansible} || ${install_repository} || ${install_vault} || ${util_encrypt}); then
printf '%s\n' "Invalid option. Use --help to see the valid options" >&2
exit 1
fi
# If the '-e' option is selected, then all of the other options are ignored.
if ${util_encrypt}; then
printf '%s\n' "Using [-e, --encrypt] option will disable all other options."
install_ansible='false'; install_repository='false'; install_vault='false'; at_least_one='false'
else
[[ ${install_ansible} || ${install_repository} || ${install_vault} ]] && at_least_one='true'
[[ -z "${repository_dir-}" ]] && repository_dir="${default_repository_dir}"
if [[ ${install_repository} && -d "${repository_dir}" ]]; then printf "Directory '${repository_dir}' exists. Try another.\n"; exit 1; fi
fi
}
# DESC: Script usage, when -h, --help are used as an option
# ARGS: None
# OUTS: None
function script_usage() {
cat << EOF
Ansible scripts for workstations and servers.
Usage without arguments will install ansible, scripts, and vault key.
Usage: bash ${script_name} [optional [-a] [-r] [-v] [-e [<filename>]] [-d <directory name>] [-h]]
Optional arguments:
-h, --help : this help text.
-a, --no-ansible : don't install Ansible and dependencies. DEFAULT: ${install_ansible}
-r, --no-repository : don't download repository with scripts. DEFAULT: ${install_repository}
-v, --no-vault : don't create a secret vault key. DEFAULT: ${install_vault}
location:${vault_path}
-d <directory> : directory where you want to install the Ansible scripts.
location:${default_repository_dir}
-e, --encrypt <filename> : create ansible hashed and encrypted variable. DEFAULT: ${util_encrypt}
filename is optional
EOF
}
# DESC: Header.
# ARGS: $at_least_one has to be true
# OUTS: None
function header() {
! ${at_least_one} && return
printf '%s\n' "-----------------------------------" \
"Let's install some ansible scripts." \
"-----------------------------------" \
""
}
# DESC: Update apt repository of packages, if last the update was older than a day.
# ARGS: $at_least_one has to be true
# OUTS: None
function updatePackages() {
! ${at_least_one} && return
printf '%s\n' "#####################################" \
"# Updating apt repositories #" \
"#####################################"
# Skip updating if it has been less than a day.
if [[ -z "$(find -H /var/lib/apt/lists -maxdepth 0 -mtime 0)" ]]; then
printf "To install these packages, you'll need 'sudo' powers.\n"
sudo apt update
else
printf "Repositories were updated less than a day ago.\n"
fi
printf "\n"
}
# DESC: Install Ansible and dependencies.
# ARGS: $install_ansible has to be true
# OUTS: None
function installAnsible() {
! ${install_ansible} && return
printf '%s\n' "#####################################" \
"# Installing Ansible & dependencies #" \
"#####################################"
sudo apt install -y software-properties-common
sudo apt-add-repository --yes ppa:ansible/ansible
sudo apt update
sudo apt install -y ansible
sudo apt install -y openssh-client
sudo apt install -y sshpass
printf "\n"
}
# DESC: Checks if a package is installed, i.e. whois as mkpasswd is part of the package
# ARGS: "package" name
# OUTS: None
function checkPackage() {
dpkg -s "${1}" &> /dev/null
if [ $? -ne 0 ]; then
printf "%s\n" "I will need sudo priviledge to install ${1}."
sudo apt install -y "${1}"
printf "\n"
fi
}
# DESC: Download the repository with Ansible scripts from GitHub.
# ARGS: $install_repository has to be true
# OUTS: None
function getAnsibleScripts() {
! ${install_repository} && return
printf '%s\n' "#####################################" \
"# Getting ansible scripts #" \
"#####################################"
checkPackage "git"
git clone https://github.com/juanlazarde/ansible_homelab.git "${repository_dir}"
printf "\nAnsible scripts installed in '$repository_dir'\n"
}
# DESC: Create secret Ansible vault file and salt for hashing, using mkpasswd.
# ARGS: $install_vault has to be true
# OUTS: None
function createVault() {
! ${install_vault} && return
printf '%s\n' "#####################################" \
"# Create secret vault key #" \
"#####################################"
checkPackage "whois"
printf "Enter the secret password for the vault. It will be hashed.\n"
set -C # don't overwrite file
mkpasswd --method=sha-512 --salt=${salt} | tr -d '\n' > ${vault_path}
chmod 600 ${vault_path}
set +C
printf '%s\n' "Remember your password. Otherwise, delete the vault key file, and run this script again." \
"If you don't want to install ansible and the script, use options '-a -r' to skip." \
"Secret key stored here '${vault_path}'" \
"Secret salt stored here '${salt_path}'" \
""
}
# DESC: Next step instructions.
# ARGS: $at_least_one has to be true
# OUTS: None
function nextSteps() {
! ${at_least_one} && return
cat << EOF
#####################################"
# Next steps #"
#####################################"
1. Get into the ansible directory:"
$ cd ${repository_dir}"
2. Edit ansible.cfg"
3. Edit hosts.yml"
4. Create hashed & encrypted variables with '${script_name} -e'"
5. Confirm connection to hosts:"
$ ansible all -m ping"
6. Run workstation script:"
$ bash workstation_setup.sh"
7. Run SSH deployment to hosts"
$ bash deploy_ansible_ssh.sh"
8. Run remote host plays:"
$ bash sever_setup.sh"
EOF
}
# DESC: Encryption utility for ansible variables.
# ARGS: $util_encrypt has to be true
# OUTS: None
function ansibleEncrypt() {
! ${util_encrypt} && return
printf '%s\n' "#####################################" \
"# Encryption with Ansible vault #" \
"#####################################" \
"" \
"* Must have installed 'mkpasswd' part of the 'whois' pkg, 'ansible', and 'sed'" \
"* Encryption key location: ${vault_path}" \
"* Encryption salt location: ${salt_path}" \
"* If you want the output in a file, type:" \
" $ bash ${script_name} -e encrypted_text.txt" \
""
# Check that mkpasswd is installed (part of whois)
checkPackage "whois"
# Check that the Ansible Vault key was created.
if [ -f "${vault_path}" ]; then
# Password request, hashing and encrypting. Depending on existance of file name after '-e' it will save or show.
printf "Enter your password here. It will be hashed and encrypted. Remember the password.\n"
if [[ -z "${encrypted_name:-}" ]]; then
mkpasswd --method=sha-512 --salt=${salt} | \
tr -d '\n' | \
ansible-vault encrypt --vault-password-file ${vault_path} | \
sed '/$ANSIBLE/i \!vault |'
else
mkpasswd --method=sha-512 --salt=${salt} | \
tr -d '\n' | \
ansible-vault encrypt --vault-password-file ${vault_path} | \
sed '/$ANSIBLE/i \!vault |' \
> "${encrypted_name}"
printf "\nSaved encrypted text to ${encrypted_name}"
fi
# To Decrypt and check that everything is ok:
# ansible localhost -m ansible.builtin.debug -a var="test" -e "@test.yml" --vault-password-file ~/.vault_key
else
printf "\nSecret Ansible Vault key is not available (i.e. not created)." \
"Run 'bash ${script_name} -a -r'. This will create ${vault_path}"
fi
printf "\n"
}
# DESC: Main control flow
# ARGS: $@ (optional): Arguments provided to the script
# OUTS: None
function main() {
script_init
parse_params "$@"
header
updatePackages
installAnsible
getAnsibleScripts
createVault
nextSteps
ansibleEncrypt
}
# Invoke main with args
main "$@"
# Approach for Bash: https://github.com/ralish/bash-script-template/blob/main/template.sh
# Reference for Bash: https://www.cheatsheet.wtf/bash/