From 85d81ec7697cf505381d85adb79356655067142f Mon Sep 17 00:00:00 2001 From: Ethan Paul Date: Sun, 5 Sep 2021 22:54:48 -0400 Subject: [PATCH] Add initial provisioning playbook --- inventory.yaml | 3 +- playbooks/files | 1 + playbooks/provision.yml | 155 +++++++++++++++++++++++++ playbooks/templates | 1 + resources/global.sh | 34 ++++++ resources/motd.j2 | 11 ++ resources/remote-requirements.txt | 28 +++++ resources/wheel-group-no-sudo-password | 1 + 8 files changed, 232 insertions(+), 2 deletions(-) create mode 120000 playbooks/files create mode 100644 playbooks/provision.yml create mode 120000 playbooks/templates create mode 100644 resources/global.sh create mode 100644 resources/motd.j2 create mode 100644 resources/remote-requirements.txt create mode 100644 resources/wheel-group-no-sudo-password diff --git a/inventory.yaml b/inventory.yaml index 043ef80..9200f46 100644 --- a/inventory.yaml +++ b/inventory.yaml @@ -3,9 +3,8 @@ all: vars: skylab_state_dir: /var/run/skylab skylab_ansible_venv: "{{ skylab_state_dir }}/ansible-runtime" - skylab_secrets_repository: git@vcs.enp.one:skylab/skylab-ansible-secrets.git + skylab_pip_version: 19.3.1 ansible_user: ansible - ansible_python_interpreter: "{{ skylab_ansible_venv }}/bin/python" ansible_ssh_common_args: "-o ControlMaster=auto -o ControlPersist=60s -o ForwardAgent=yes" en2: diff --git a/playbooks/files b/playbooks/files new file mode 120000 index 0000000..35a4f7a --- /dev/null +++ b/playbooks/files @@ -0,0 +1 @@ +../resources \ No newline at end of file diff --git a/playbooks/provision.yml b/playbooks/provision.yml new file mode 100644 index 0000000..645f088 --- /dev/null +++ b/playbooks/provision.yml @@ -0,0 +1,155 @@ +--- +- name: Bootstrap remote ansible environment + hosts: all + tags: + - always + tasks: + - name: Install CentOS 8 python bindings + when: ansible_distribution == "Rocky" + become: true + ansible.builtin.dnf: + state: present + name: + - python3-libselinux + - python3-policycoreutils + - python3-firewall + + - name: Create state directory + become: true + ansible.builtin.file: + path: "{{ skylab_state_dir }}" + state: directory + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: 0755 + + - name: Create bootstrap virtualenv + ansible.builtin.command: + cmd: "{{ ansible_python_interpeter | default(discovered_interpreter_python) }} -m venv {{ skylab_ansible_venv }} --system-site-packages" + creates: "{{ skylab_ansible_venv }}/bin/python" + + - name: Pin bootstrap virtualenv pip + ansible.builtin.pip: + executable: "{{ skylab_ansible_venv }}/bin/pip" + name: pip + state: present + version: "{{ skylab_pip_version }}" + + - name: Copy requirements file to remote + ansible.builtin.copy: + src: remote-requirements.txt + dest: "{{ skylab_ansible_venv }}/requirements.txt" + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: 0644 + + - name: Install remote requirements + ansible.builtin.pip: + executable: "{{ skylab_ansible_venv }}/bin/pip" + requirements: "{{ skylab_ansible_venv }}/requirements.txt" + state: present + +- name: Configure common server settings + hosts: all + tasks: + - name: Set hostname + become: true + ansible.builtin.hostname: + name: "{{ inventory_hostname }}" + use: systemd + + - name: Install EPEL repository config + when: ansible_distribution == "Rocky" + become: true + ansible.builtin.yum_repository: + name: epel + description: Extra Packages for Enterprise Linux + baseurl: https://download.fedoraproject.org/pub/epel/$releasever{{ '/Everything' if ansible_distribution_major_version == '8' else '' }}/$basearch/ + + - name: Install EPEL GPG key + when: ansible_distribution == "Rocky" + become: true + ansible.builtin.rpm_key: + state: present + key: https://archive.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-{{ ansible_distribution_major_version }} + + - name: Disable sudo password for WHEEL group + when: ansible_distribution == "Rocky" or ansible_distribution == "CentOS" + become: true + ansible.builtin.copy: + src: wheel-group-no-sudo-password + dest: /etc/sudoers.d/30-wheel + owner: root + group: "{{ ansible_user }}" + mode: 0644 + + - name: Install global bash config + become: true + ansible.builtin.copy: + src: global.sh + dest: /etc/profile.d/ZZ-skylab-global.sh + owner: root + group: "{{ ansible_user }}" + mode: 0644 + +- name: Configure SSH + hosts: all + handlers: + - name: restart-sshd + become: true + ansible.builtin.systemd: + name: sshd + state: restarted + tasks: + - name: Disable root auth + become: true + ansible.builtin.replace: + path: /etc/ssh/sshd_config + regexp: "^.*PermitRootLogin (yes|no).*$" + replace: "PermitRootLogin no" + notify: [restart-sshd] + + - name: Disable password auth + become: true + ansible.builtin.replace: + path: /etc/ssh/sshd_config + regexp: "^.*PasswordAuthentication (yes|no).*$" + replace: "PasswordAuthentication no" + notify: [restart-sshd] + + - name: Disable challenge response auth + become: true + ansible.builtin.replace: + path: /etc/ssh/sshd_config + regexp: "^.*ChallengeResponseAuthentication (yes|no).*$" + replace: "ChallengeResponseAuthentication no" + notify: [restart-sshd] + + - name: Disable GSSAPI auth + become: true + ansible.builtin.replace: + path: /etc/ssh/sshd_config + regexp: "^.*GSSAPIAuthentication (yes|no).*$" + replace: "GSSAPIAuthentication no" + notify: [restart-sshd] + + - name: Disable dynamic MOTD on debian systems + when: ansible_os_family == "Debian" + ansible.builtin.replace: + path: /etc/pam.d/sshd + regexp: "^session optional pam_motd.so motd=/run/motd.dynamic" + replace: "#session optional pam_motd.so motd=/run/motd.dynamic" + + - name: Disable Cockpit activation message on Rocky + when: ansible_distribution == "Rocky" + become: true + ansible.builtin.file: + path: /etc/motd.d/cockpit + state: absent + + - name: Copy MOTD to remote + become: true + ansible.builtin.template: + src: motd.j2 + dest: /etc/motd + mode: 0644 diff --git a/playbooks/templates b/playbooks/templates new file mode 120000 index 0000000..35a4f7a --- /dev/null +++ b/playbooks/templates @@ -0,0 +1 @@ +../resources \ No newline at end of file diff --git a/resources/global.sh b/resources/global.sh new file mode 100644 index 0000000..76ffc60 --- /dev/null +++ b/resources/global.sh @@ -0,0 +1,34 @@ +function _parse_git_branch() { + git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/' +} + +export PS1="\[\e[0;97m\]\[\e[37m\e[1m\]\u\[\e[1;94m\]@\[\e[94m\]\H\[\e[0;33m\]\$(_parse_git_branch) \[\e[37m\]\w\[\e[33m\] \[\e[0;97m\]$\[\e[0m\] " +export rc=/home/$USERNAME/.bashrc +export VIRTUALENV_DIR=/home/$USERNAME/.venvs + +random() { + if [[ $# -eq 0 ]]; then + num=32 + else + num=$1 + fi + cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $num | head -n 1 +} + +function up() { cd $(eval printf '../'%.0s {1..$1}); } + +function pipin() { pip freeze | grep $1; } + +alias bk='cd -' +alias fuck='sudo $(history -p \!\!)' +alias ls='ls -lshF --color --group-directories-first --time-style=long-iso' +alias version='uname -orp && lsb_release -a | grep Description' +alias activate='source ./bin/activate' +alias cls='clear' +alias ls='/usr/bin/ls -lshF --color --group-directories-first --time-style=long-iso' +alias gmtime='/usr/bin/date -u --iso-8601=seconds' +alias date='/usr/bin/date --iso-8601=seconds' +alias whatismyip='curl https://icanhazip.com/' +alias uuid="python3 -c 'import uuid; print(uuid.uuid4());'" +alias epoch="python3 -c 'import time; print(time.time());'" +alias uptime="command uptime --pretty" diff --git a/resources/motd.j2 b/resources/motd.j2 new file mode 100644 index 0000000..11436df --- /dev/null +++ b/resources/motd.j2 @@ -0,0 +1,11 @@ + + ///////// /// /// /// /// /// /////// ////// + /// /// /// /// /// /// /// /// /// /// + /// //////// /////// /// ///////// /////// + //////// /// /// /// /// /// /// /// /// + /// /// /// ///// /// /// /// /////// + /// /// + ///////// ================== ///////// ================ + + > {{ skylab_description }} @{{ skylab_location }} + {{ '' }} diff --git a/resources/remote-requirements.txt b/resources/remote-requirements.txt new file mode 100644 index 0000000..999d5d0 --- /dev/null +++ b/resources/remote-requirements.txt @@ -0,0 +1,28 @@ +attrs==21.2.0; python_version >= "3.4" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.4" +bcrypt==3.2.0; python_version >= "3.6" +certifi==2021.5.30; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" +cffi==1.14.6; python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0") +charset-normalizer==2.0.4; python_full_version >= "3.6.0" and python_version >= "3.6" +colorama==0.4.4; python_version >= "3.4" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.4" and python_full_version >= "3.5.0" +cryptography==3.4.8; python_version >= "3.6" +distro==1.6.0; python_version >= "3.4" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.4" +docker-compose==1.29.2; python_version >= "3.4" +docker==5.0.2; python_version >= "3.6" +dockerpty==0.4.1; python_version >= "3.4" +docopt==0.6.2; python_version >= "3.4" +idna==3.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" +jsondiff==1.3.0 +jsonschema==3.2.0; python_version >= "3.4" +paramiko==2.7.2; python_version >= "3.6" +pycparser==2.20; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" +pynacl==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" +pyrsistent==0.18.0; python_version >= "3.6" +python-dotenv==0.19.0; python_version >= "3.5" +pywin32==227; sys_platform == "win32" and python_version >= "3.6" +pyyaml==5.4.1; python_version >= "3.4" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.4" +requests==2.26.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" +selinux==0.2.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") +six==1.16.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" +texttable==1.6.4; python_version >= "3.4" +urllib3==1.26.6; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.6" +websocket-client==0.59.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" diff --git a/resources/wheel-group-no-sudo-password b/resources/wheel-group-no-sudo-password new file mode 100644 index 0000000..7c499c2 --- /dev/null +++ b/resources/wheel-group-no-sudo-password @@ -0,0 +1 @@ +%wheel ALL=(ALL) NOPASSWD: ALL