Differences

This shows you the differences between two versions of the page.

Link to this comparison view

scgc:laboratoare:07 [2020/04/06 14:45]
darius.mihai [3. [20p] Resource Dependency]
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 - 20p] 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.
  
-On the **SAISP VM** we are going to install ​and configure ​Ansible.+As opposed ​to Puppet, where each host manages its own data (services, users, files, etc.), ​and can optionally connect to a remote host to retrieve manifest files for configuration, ​Ansible ​is used to push the configuration from a central system to other hosts. An advantage of Ansible is that it does not require a specific service daemon to be installed before being able to configure the hosts. Operation is achieved through Python scripts for remote Linux hosts, or Powershell scripts for remote Windows hosts.
  
-<​code>​ +On the **SCGC VM** we are going to install and configure Ansible. 
-student@saisp:~$ sudo apt-add-repository -y ppa:​ansible/​ansible + 
-student@saisp:~$ sudo apt-get update +<​code ​bash
-student@saisp:~$ sudo apt-get install -y ansible+student@scgc:~$ sudo apt update 
 +student@scgc:~$ sudo apt install ​-y ansible 
 +# Required to use password authentication. By default, ansible requires authentication through SSH keys 
 +student@scgc:~$ sudo apt install -y sshpass
 </​code>​ </​code>​
  
 Check that the package was successfully installed by running the command: Check that the package was successfully installed by running the command:
 <​code>​ <​code>​
-student@saisp:~/saisp$ ansible --version +student@scgc:~/scgc$ ansible --version 
-ansible 2.5.0+ansible 2.5.1
   config file = /​etc/​ansible/​ansible.cfg   config file = /​etc/​ansible/​ansible.cfg
   configured module search path = [u'/​home/​student/​.ansible/​plugins/​modules',​ u'/​usr/​share/​ansible/​plugins/​modules'​]   configured module search path = [u'/​home/​student/​.ansible/​plugins/​modules',​ u'/​usr/​share/​ansible/​plugins/​modules'​]
   ansible python module location = /​usr/​lib/​python2.7/​dist-packages/​ansible   ansible python module location = /​usr/​lib/​python2.7/​dist-packages/​ansible
   executable location = /​usr/​bin/​ansible   executable location = /​usr/​bin/​ansible
-  python version = 2.7.(default, ​Mar 22 201422:59:56) [GCC 4.8.2]+  python version = 2.7.17 (default, ​Nov  7 201910:07:09) [GCC 7.4.0]
 </​code>​ </​code>​
  
Line 486: Line 492:
 Ansible has a default inventory file used to define which servers it will be managing. After installation,​ there'​s an example one you can reference at **/​etc/​ansible/​hosts** (initially fully commented out). Ansible has a default inventory file used to define which servers it will be managing. After installation,​ there'​s an example one you can reference at **/​etc/​ansible/​hosts** (initially fully commented out).
  
-We are going to add 2 **labels** to the hosts file. One containing the local address, named **thishost** and another one of the previously used VM, named **remote**+We are going to add 2 **labels** to the hosts file. One containing the local address, named **thishost** and another one of the previously used VM, named **remote**.
  
 <​code>​ <​code>​
-student@saisp:~$ cat /​etc/​ansible/​hosts | grep -A 5 thishost+student@scgc:~$ cat /​etc/​ansible/​hosts | grep -A 5 thishost
 -- --
 -- --
Line 501: Line 507:
 </​code>​ </​code>​
  
-=== Running Commands ​===+=== Testing hosts availability ​===
 Let's start running Tasks against a server. Let's start running Tasks against a server.
  
 Running against localhost: Running against localhost:
 <​code>​ <​code>​
-student@saisp:~$ ansible --connection=local ​thishost ​-m ping+student@scgc:~$ ansible ​thishost ​--connection=local -m ping
 127.0.0.1 | SUCCESS => { 127.0.0.1 | SUCCESS => {
     "​changed":​ false, ​     "​changed":​ false, ​
Line 515: Line 521:
 Running against the remote VM: Running against the remote VM:
 <​code>​ <​code>​
-student@saisp:~$ ansible --ask-pass --user=root remote -m ping+student@scgc:~$ ansible --ask-pass --user=student ​remote -m ping
 SSH password: ​ SSH password: ​
 10.0.0.2 | SUCCESS => { 10.0.0.2 | SUCCESS => {
Line 526: Line 532:
  
 Let's cover these commands: Let's cover these commands:
-  * ''​remote'',​ ''​local''​ - Use the servers defined under this label in the hosts inventory file +  * ''​thishost'',​ ''​remote''​ - Use the servers defined under this label in the hosts inventory file. The ''​%%all%%'' ​argument can be used to run the ruleset on all defined hosts.
-  * ''​-m ping'' ​- Use the "​ping"​ module, which simply runs the ping command and returns the results+
   * ''​%%--connection=local%%''​ - Run commands on the local server, not over SSH   * ''​%%--connection=local%%''​ - Run commands on the local server, not over SSH
-  * ''​%%--ask-pass --user=root%%''​ - SSH connection parameters: interactive password input, login as **root** user+  ​* ''​-m ping''​ - Use the "​ping"​ module, which checks if the host can be accessed. Using ''​%%ping%%''​ with ''​%%--connection=local%%''​ does not make sense, as the option is used when running commands on the host that is issuing commands. It normally attempts to connect to the host via SSH. 
 +  ​* ''​%%--ask-pass --user=student%%''​ - SSH connection parameters: interactive password input, login as **student** user
  
 +==== 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.
  
 +<​code>​
 +student@scgc:​~$ ansible --ask-pass --user=student remote -m setup
 +SSH password:
 +10.0.0.2 | SUCCESS => {
 +    "​ansible_facts":​ {
 +        "​ansible_all_ipv4_addresses":​ [
 +            "​10.0.0.2"​
 +        ], 
 +        "​ansible_all_ipv6_addresses":​ [
 +            "​fe80::​5054:​ff:​fe12:​3451"​
 +        ], 
 +        "​ansible_apparmor":​ {
 +            "​status":​ "​enabled"​
 +        }, 
 +        "​ansible_architecture":​ "​x86_64", ​
 +        "​ansible_bios_date":​ "​04/​01/​2014", ​
 +        "​ansible_bios_version":​ "​1.10.2-1ubuntu1", ​
 +...
 +</​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>​
scgc/laboratoare/07.1586173538.txt.gz · Last modified: 2020/04/06 14:45 by darius.mihai
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0