This shows you the differences between two versions of the page.
scgc:laboratoare:07 [2020/04/06 20:20] darius.mihai [7. [BONUS - 10p] Ansible Commands] |
scgc:laboratoare:07 [2021/10/27 14:09] (current) maria.mihailescu |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laboratory 07. Configuration Management: Puppet, Ansible ====== | + | ====== Configuration Management: Puppet, Ansible ====== |
===== Lab Setup ===== | ===== Lab Setup ===== | ||
- | * We will be using a virtual machine in the [[http://cloud.curs.pub.ro/|faculty's cloud]]. | + | * We will be using a virtual machine in the [[http://cloud.grid.pub.ro/|faculty's cloud]]. |
- | * When creating a virtual machine follow the steps in this [[https://cloud.curs.pub.ro/about/tutorial-for-students/|tutorial]]. | + | |
* When creating a virtual machine in the Launch Instance window: | * When creating a virtual machine in the Launch Instance window: | ||
- | * For **Availability zone**, choose **CAMPUS**, **CI** or **hp** | ||
* Select **Boot from image** in **Instance Boot Source** section | * Select **Boot from image** in **Instance Boot Source** section | ||
* Select **SCGC Template** in **Image Name** section | * Select **SCGC Template** in **Image Name** section | ||
Line 31: | Line 29: | ||
===== Tasks ====== | ===== Tasks ====== | ||
- | ==== 1. [20p] Puppet Resources ==== | + | ==== 1. [10p] Puppet Resources ==== |
Puppet is a configuration management tool. In order to describe the necessary configurations, Puppet uses its own declarative language. Puppet can manage both Linux and Windows systems. | Puppet is a configuration management tool. In order to describe the necessary configurations, Puppet uses its own declarative language. Puppet can manage both Linux and Windows systems. | ||
Line 150: | Line 148: | ||
Chech the **/etc/passwd** file to see if the user was actually removed. | Chech the **/etc/passwd** file to see if the user was actually removed. | ||
- | ==== 2. [20p] Puppet Manifests ==== | + | ==== 2. [10p] Puppet Manifests ==== |
Even though we can create, modify or remove resources from the command line, using **puppet resource** commands, this is not a scalable approach and not appropriate for complex scenarios. | Even though we can create, modify or remove resources from the command line, using **puppet resource** commands, this is not a scalable approach and not appropriate for complex scenarios. | ||
Line 238: | Line 236: | ||
<note important>If it doesn't already exist, the key pair for the **student** user must be generated beforehand. | <note important>If it doesn't already exist, the key pair for the **student** user must be generated beforehand. | ||
- | Then, run the command ''ssh-add ~/.ssh.id_rsa''</note> | + | Then, run the command ''ssh-add ~/.ssh/id_rsa''</note> |
<note>Use the Puppet documentation for the resource type [[https://puppet.com/docs/puppet/5.5/types/ssh_authorized_key.html|ssh_authorized_key]].</note> | <note>Use the Puppet documentation for the resource type [[https://puppet.com/docs/puppet/5.5/types/ssh_authorized_key.html|ssh_authorized_key]].</note> | ||
Line 297: | Line 295: | ||
ensure => file, | ensure => file, | ||
mode => '0600', | mode => '0600', | ||
- | source => '/root/examples/sshd_config', | + | source => '/root/config-files/sshd_config', |
} | } | ||
service { 'sshd': | service { 'sshd': | ||
Line 439: | Line 437: | ||
} | } | ||
</code> | </code> | ||
+ | |||
+ | <note important> | ||
+ | Puppet has a modular implementation, and some functionality is provided through classes, some of which may be provided by certain modules. To use the ''%%str2bool%%'' function, you must install the ''%%puppet-module-puppetlabs-stdlib%%'' module using the ''%%apt%%'' package manager. | ||
+ | </note> | ||
+ | |||
Apply the manifest and notice the state of the NTP service. | Apply the manifest and notice the state of the NTP service. | ||
Line 461: | Line 464: | ||
</note> | </note> | ||
- | ==== 6. [BONUS - 5p] Ansible Install & Configuration ==== | + | ==== 6. [10p] Ansible Install & Configuration ==== |
Ansible is a configuration management and provisioning tool, similar to Puppet. It uses SSH to connect to servers and run the configured tasks. | Ansible is a configuration management and provisioning tool, similar to Puppet. It uses SSH to connect to servers and run the configured tasks. | ||
Line 472: | Line 475: | ||
student@scgc:~$ sudo apt install -y ansible | student@scgc:~$ sudo apt install -y ansible | ||
# Required to use password authentication. By default, ansible requires authentication through SSH keys | # Required to use password authentication. By default, ansible requires authentication through SSH keys | ||
- | student@scgc:~$ sudo apt install -y ansible | + | student@scgc:~$ sudo apt install -y sshpass |
</code> | </code> | ||
Line 534: | Line 537: | ||
* ''%%--ask-pass --user=student%%'' - SSH connection parameters: interactive password input, login as **student** user | * ''%%--ask-pass --user=student%%'' - SSH connection parameters: interactive password input, login as **student** user | ||
- | ==== 7. [BONUS - 5p] Ansible Commands ==== | + | ==== 7. [10p] Ansible Facter ==== |
Ansible has a fact gathering system similar to Puppet. To extract facts about the remote host we can use the ''%%setup%%'' module. The information is returned as Python dictionaries, where values can be strings, arrays, or other dictionaries. | Ansible has a fact gathering system similar to Puppet. To extract facts about the remote host we can use the ''%%setup%%'' module. The information is returned as Python dictionaries, where values can be strings, arrays, or other dictionaries. | ||
Line 557: | Line 560: | ||
... | ... | ||
</code> | </code> | ||
+ | |||
+ | The information in the facter, can be used in playbooks - configuration files written in YAML that act as scripts for ansible. The syntax used to expand all variables - including those created by the facter - is ''%%"{{ variable }}"%%''. For example, ''%%"{{ ansible_facts.hostname }}"%%'' will be expanded to the hostname, as identified by the facter. | ||
+ | |||
+ | |||
+ | ==== 8. [BONUS - 20p] Two-factor Authentication for SSH ==== | ||
+ | |||
+ | We plan to enable the use of two-factor authentication for SSH through the use of Google's Authenticator mobile application. To do this, we need to create a Google Authenticator configuration file on the host. To create one with sensible defaults, you can use the following commands: | ||
+ | <code bash> | ||
+ | student@scgc:~$ sudo apt install libpam-google-authenticator qrencode | ||
+ | student@scgc:~$ echo -e "y\ny\ny\nn\ny" | google-authenticator | ||
+ | </code> | ||
+ | |||
+ | The commands above will create a configuration file for the authenticator, that will generate time-based codes, will update the ''%%~/.google-authenticator%%'' file, disallow multiple users and enable rate limiting. The fourth option (the **n** in the string passed to the ''%%google-authenticator%%'' binary ) disables longer-lasting codes (this option is only useful when the phone and/or the server's time sync protocols are not working properly). For more details, consult DigitalOcean's tutorial on how to set it up [[https://www.digitalocean.com/community/tutorials/how-to-set-up-multi-factor-authentication-for-ssh-on-ubuntu-16-04|here]]. | ||
+ | |||
+ | After running the command, the terminal will display the secret key as both a large QR code, and text. Please open the Google Authenticator app on your phone, and scan the QR code or enter it manually. | ||
+ | |||
+ | We will copy the Google Authenticator's configuration file, the configuration for the SSH daemon, and the PAM configuration file for the SSH service: | ||
+ | <code bash> | ||
+ | student@scgc:~$ mkdir config-files | ||
+ | student@scgc:~$ cd config-files | ||
+ | student@scgc:~/config-files$ cp /home/student/.google_authenticator . | ||
+ | student@scgc:~/config-files$ cp /etc/pam.d/sshd . | ||
+ | student@scgc:~/config-files$ cp /etc/ssh/sshd_config . | ||
+ | </code> | ||
+ | |||
+ | <note warning> | ||
+ | The Authenticator configuration file is sensitive information! It MUST have ''%%0600%%'' permissions (only the user must be able to access it), and it is usually not a good idea to copy it to another server. From a security point of view, it is similar to copying a private SSH key to another server. Make sure you copy the configuration only to servers you trust. | ||
+ | </note> | ||
+ | |||
+ | We will use the files created above as templates to replicate on the server(s). This example will only use the ''%%10.0.0.2%%'' VM as a target machine. We must set up the configuration files to use password + the a One Time Password (OTP) generated by the authenticator. Make sure the configuration files for sshd and PAM look as below: | ||
+ | <code bash> | ||
+ | student@scgc:~/config-files$ grep -B 5 -A 3 'pam_google_authenticator.so' sshd | ||
+ | # PAM configuration for the Secure Shell service | ||
+ | |||
+ | # Standard Un*x authentication. | ||
+ | @include common-auth | ||
+ | # 2-FA authentication with Google Authenticator | ||
+ | auth required pam_google_authenticator.so | ||
+ | |||
+ | # Disallow non-root logins when /etc/nologin exists. | ||
+ | account required pam_nologin.so | ||
+ | </code> | ||
+ | The changes to the PAM configuration file above make using the Google Authenticator module mandatory. It is placed after 'common-auth', so the code will be required **after** entering the password. | ||
+ | |||
+ | <code bash> | ||
+ | student@scgc:~/config-files$ grep -B 5 -A 3 '^ChallengeResponseAuthentication' sshd_config | ||
+ | #PasswordAuthentication yes | ||
+ | #PermitEmptyPasswords no | ||
+ | |||
+ | # Change to yes to enable challenge-response passwords (beware issues with | ||
+ | # some PAM modules and threads) | ||
+ | ChallengeResponseAuthentication yes | ||
+ | AuthenticationMethods publickey keyboard-interactive | ||
+ | |||
+ | # Kerberos options | ||
+ | </code> | ||
+ | The changes to the configuration file above make using the challenge response to allow PAM to use multiple modules with challenge responses (i.e., password and authentication code in our case); the use of keyboard-interactive authentication is mandatory if more than just the password is required. | ||
+ | |||
+ | Ansible can use privilege escalation using the **become** keyword at certain tasks, or all tasks. If the user cannot run sudo with a password, the ''%%ansible_become_password%%'' variable must be set. To do this we will use a vault - a type of file that encrypts strings through a password - to store the password, instead of adding it as plain text to the playbook. To create a vault, use the following command, and write the key-value pair for the password in the file it opens using the default editor: | ||
+ | <code bash> | ||
+ | student@scgc:~/config-files$ ansible-vault create puppet.vault | ||
+ | New Vault password: # Enter vault password | ||
+ | Confirm New Vault password: # Confirm vault password | ||
+ | |||
+ | # In the opened file | ||
+ | ansible_become_password: student | ||
+ | </code> | ||
+ | |||
+ | After closing the vault, you can see that the information in it is encrypted. | ||
+ | |||
+ | To install the SSH daemon on the remote machine, and set it up for use with the Google Authenticator we will use the following playbook, saved as ''%%sshd.yaml%%'': | ||
+ | <code yaml> | ||
+ | --- | ||
+ | - hosts: remote | ||
+ | remote_user: student | ||
+ | |||
+ | tasks: | ||
+ | # include sudo password vault | ||
+ | - name: Set host variables | ||
+ | include_vars: "{{ ansible_facts.hostname }}.vault" | ||
+ | |||
+ | # Install sshd and make sure it is at the latest version using the package | ||
+ | # manager identified by ansible | ||
+ | - name: Ensure sshd is at the latest version | ||
+ | package: | ||
+ | name: openssh-server | ||
+ | state: latest | ||
+ | become: yes | ||
+ | |||
+ | # Install google authenticator module and make sure it is at the latest version | ||
+ | - name: Ensure google-authenticator is at the latest version | ||
+ | package: | ||
+ | name: libpam-google-authenticator | ||
+ | state: latest | ||
+ | become: yes | ||
+ | |||
+ | # Copy the google authenticator configuration file | ||
+ | # The file MUST be located in the user's home directory with permissions 0600 | ||
+ | - name: Copy Google Authenticator config file | ||
+ | copy: | ||
+ | src: /home/student/config-files/.google_authenticator | ||
+ | dest: /home/student/.google_authenticator | ||
+ | mode: 0600 | ||
+ | owner: student | ||
+ | group: student | ||
+ | |||
+ | # Overwrite sshd configuration file. Make sure the challenge response setting | ||
+ | # is enabled, and keyboard-interactive is a valid authentication method | ||
+ | - name: Write the sshd configuration file | ||
+ | template: | ||
+ | src: /home/student/config-files/sshd_config | ||
+ | dest: /etc/ssh/sshd_config | ||
+ | become: yes | ||
+ | notify: | ||
+ | - restart sshd | ||
+ | |||
+ | # Overwrite the PAM configuration file. Make sure that authentication through | ||
+ | # google authenticator is required | ||
+ | - name: Write the PAM configuration file | ||
+ | template: | ||
+ | src: /home/student/config-files/sshd | ||
+ | dest: /etc/pam.d/sshd | ||
+ | become: yes | ||
+ | notify: | ||
+ | - restart sshd | ||
+ | |||
+ | handlers: | ||
+ | # Handlers that are invoked when the configuration files change - | ||
+ | # restart the sshd service | ||
+ | - name: restart sshd | ||
+ | service: | ||
+ | name: sshd | ||
+ | state: restarted | ||
+ | become: yes | ||
+ | </code> | ||
+ | |||
+ | The playbook attempts to include the file named ''%%{{ ansible_facts.hostname }}.vault%%'' - which resolves to ''%%puppet.vault%%'' for the VM. To run it, we use the ''%%ansible-playbook%%'' command, with the ''%%--ask-pass%%'', to ask for the SSH authentication password, and the ''%%--ask-vault-pass%%'' to provide the decryption password for the vault. | ||
+ | <code bash> | ||
+ | student@scgc:~/config-files$ ansible-playbook --ask-vault-pass --ask-pass sshd.yml | ||
+ | SSH password: | ||
+ | Vault password: | ||
+ | |||
+ | PLAY [remote] ********************************************************************* | ||
+ | |||
+ | TASK [Gathering Facts] ************************************************************ | ||
+ | ok: [10.0.0.2] | ||
+ | |||
+ | TASK [Set host variables] ********************************************************* | ||
+ | ok: [10.0.0.2] | ||
+ | |||
+ | TASK [Ensure sshd is at the latest version] *************************************** | ||
+ | ok: [10.0.0.2] | ||
+ | |||
+ | TASK [Ensure google-authenticator is at the latest version] *********************** | ||
+ | changed: [10.0.0.2] | ||
+ | |||
+ | TASK [Copy Google Authenticator config file] ************************************** | ||
+ | changed: [10.0.0.2] | ||
+ | |||
+ | TASK [Write the sshd configuration file] ****************************************** | ||
+ | changed: [10.0.0.2] | ||
+ | |||
+ | TASK [Write the PAM configuration file] ******************************************* | ||
+ | changed: [10.0.0.2] | ||
+ | |||
+ | RUNNING HANDLER [restart sshd] **************************************************** | ||
+ | changed: [10.0.0.2] | ||
+ | | ||
+ | PLAY RECAP ************************************************************************ | ||
+ | 10.0.0.2 : ok=8 changed=5 unreachable=0 failed=0 | ||
+ | </code> | ||
+ | |||
+ | You should now be able to login using the password and the Google Authenticator. | ||
+ | <code bash> | ||
+ | student@scgc:~$ ssh student@10.0.0.2 | ||
+ | Password: | ||
+ | Verification code: | ||
+ | Password: | ||
+ | Verification code: | ||
+ | Linux puppet 4.19.0-8-amd64 #1 SMP Debian 4.19.98-1 (2020-01-26) x86_64 | ||
+ | |||
+ | The programs included with the Debian GNU/Linux system are free software; | ||
+ | the exact distribution terms for each program are described in the | ||
+ | individual files in /usr/share/doc/*/copyright. | ||
+ | |||
+ | Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent | ||
+ | permitted by applicable law. | ||
+ | student@puppet:~$ | ||
+ | </code> | ||
+ | |||
+ | <note important> | ||
+ | After adding two-factor authentication, Ansible will no longer be able to access the VM using password authentication, since the password is read by ansible before actually attempting to access the server, and ''%%sshpass%%'' is not aware it is required. | ||
+ | </note> |