Bookmark this page

Lab: Managing Variables and Facts

In this lab, you write and run an Ansible Playbook that uses variables, secrets, and facts.

Outcomes

  • You should be able to define variables and use facts in a playbook, as well as use variables defined in an encrypted file.

As the student user on the workstation machine, use the lab command to prepare your system for this exercise.

This command prepares your environment and ensures that all required resources are available.

The serverb.lab.example.com managed host is defined in this inventory as a member of the webserver host group. A developer has asked you to write an Ansible Playbook to automate the setup of a web server environment on serverb.lab.example.com, which controls user access to its website using basic authentication.

The files subdirectory contains the following files:

  • An httpd.conf configuration file for the Apache web service for basic authentication

  • A .htaccess file, used to control access to the web server's document root directory

  • An htpasswd file containing credentials for permitted users

[student@workstation ~]$ lab start data-review

Procedure 3.4. Instructions

  1. In the working directory, create the playbook.yml playbook. In the playbook, start creating a play to install and configure the web server hosts with an Apache HTTP Server that has basic authentication enabled. Configure the webserver host group to contain the managed hosts for the play.

    Define the following play variables:

    VariableValues
    firewall_pkg firewalld
    firewall_svc firewalld
    web_pkg httpd
    web_svc httpd
    ssl_pkg mod_ssl
    httpdconf_src files/httpd.conf
    httpdconf_dest /etc/httpd/conf/httpd.conf
    htaccess_src files/.htaccess
    secrets_dir /etc/httpd/secrets
    secrets_src files/htpasswd
    secrets_dest "{{ secrets_dir }}/htpasswd"
    web_root /var/www/html
    1. Change into the /home/student/data-review directory.

      [student@workstation ~]$ cd ~/data-review
      [student@workstation data-review]$
    2. Create the playbook.yml playbook file and edit it in a text editor. The beginning of the file should appear as follows:

      ---
      - name: install and configure webserver with basic auth
        hosts: webserver
        vars:
          firewall_pkg: firewalld
          firewall_svc: firewalld
          web_pkg: httpd
          web_svc: httpd
          ssl_pkg: mod_ssl
          httpdconf_src: files/httpd.conf
          httpdconf_dest: /etc/httpd/conf/httpd.conf
          htaccess_src: files/.htaccess
          secrets_dir: /etc/httpd/secrets
          secrets_src: files/htpasswd
          secrets_dest: "{{ secrets_dir }}/htpasswd"
          web_root: /var/www/html
  2. Add a tasks section to the play. Write a task that ensures the latest version of the necessary packages are installed. These packages are defined by the firewall_pkg, web_pkg, and ssl_pkg variables.

    1. Define the beginning of the tasks section by adding the following line to the play:

        tasks:
    2. Add the following lines to the play to define a task that uses the ansible.builtin.dnf module to install the required packages:

          - name: latest version of necessary packages installed
            ansible.builtin.dnf:
              name:
                - "{{ firewall_pkg }}"
                - "{{ web_pkg }}"
                - "{{ ssl_pkg }}"
              state: latest
  3. Add a second task to the play that ensures that the file specified by the httpdconf_src variable has been copied (with the ansible.builtin.copy module) to the location specified by the httpdconf_dest variable on the managed host. The file must be owned by the root user and the root group. Set 0644 as the file permissions.

    Add the following lines to the play to define a task that uses the ansible.builtin.copy module to copy the contents of the file defined by the httpdconf_src variable to the location specified by the httpdconf_dest variable.

        - name: configure web service
          ansible.builtin.copy:
            src: "{{ httpdconf_src }}"
            dest: "{{ httpdconf_dest }}"
            owner: root
            group: root
            mode: 0644
  4. Add a third task that uses the ansible.builtin.file module to create the directory specified by the secrets_dir variable on the managed host. This directory holds the password files used for the basic authentication of web services. The file must be owned by the apache user and the apache group. Set 0500 as the file permissions.

    Add the following lines to the play to define a task that uses the ansible.builtin.file module to create the directory defined by the secrets_dir variable.

        - name: secrets directory exists
          ansible.builtin.file:
            path: "{{ secrets_dir }}"
            state: directory
            owner: apache
            group: apache
            mode: 0500
  5. Add a fourth task that uses the ansible.builtin.copy module to add an htpasswd file, used for basic authentication of web users. The source should be defined by the secrets_src variable. The destination should be defined by the secrets_dest variable. The file must be owned by the apache user and group. Set 0400 as the file permissions.

        - name: htpasswd file exists
          ansible.builtin.copy:
            src: "{{ secrets_src }}"
            dest: "{{ secrets_dest }}"
            owner: apache
            group: apache
            mode: 0400
  6. Add a fifth task that uses the ansible.builtin.copy module to create a .htaccess file in the document root directory of the web server. Copy the file specified by the htaccess_src variable to {{ web_root }}/.htaccess. The file must be owned by the apache user and the apache group. Set 0400 as the file permissions.

    Add the following lines to the play to define a task that uses the ansible.builtin.copy module to create the .htaccess file using the file defined by the htaccess_src variable.

        - name: .htaccess file installed in docroot
          ansible.builtin.copy:
            src: "{{ htaccess_src }}"
            dest: "{{ web_root }}/.htaccess"
            owner: apache
            group: apache
            mode: 0400
  7. Add a sixth task that uses the ansible.builtin.copy module to create the web content file, index.html, in the directory specified by the web_root variable. The file should contain the message HOSTNAME (IPADDRESS) has been customized by Ansible., where HOSTNAME is the fully qualified host name of the managed host and IPADDRESS is its IPv4 IP address. Use the content option with the ansible.builtin.copy module to specify the content of the file, and Ansible facts to specify the host name and IP address.

    Add the following lines to the play to define a task that uses the ansible.builtin.copy module to create the index.html file in the directory defined by the web_root variable. Populate the file with the content specified using the ansible_facts['fqdn'] and ansible_facts['default_ipv4']['address'] Ansible facts retrieved from the managed host.

        - name: create index.html
          ansible.builtin.copy:
            content: "{{ ansible_facts['fqdn'] }} ({{ ansible_facts['default_ipv4']['address'] }}) has been customized by Ansible.\n"
            dest: "{{ web_root }}/index.html"
  8. Add a seventh task that uses the ansible.builtin.service module to enable and start the firewall service on the managed host.

    Add the following lines to the play to define a task that uses the ansible.builtin.service module to enable and start the firewall service.

        - name: firewall service enabled and started
          ansible.builtin.service:
            name: "{{ firewall_svc }}"
            state: started
            enabled: true
  9. Add an eighth task that uses the ansible.posix.firewalld module to enable access to the https service that is needed for users to access web services on the managed host. This firewall change should be permanent and should take place immediately.

    Add the following lines to the play to define a task that uses the ansible.posix.firewalld module to open the HTTPS port for the web service.

        - name: open the port for the web server
          ansible.posix.firewalld:
            service: https
            state: enabled
            immediate: true
            permanent: true
  10. Add a final task that uses the ansible.builtin.service module to enable and start the web service on the managed host for all configuration changes to take effect. The name of the web service is defined by the web_svc variable.

        - name: web service enabled and started
          ansible.builtin.service:
            name: "{{ web_svc }}"
            state: started
            enabled: true
  11. Define a second play in the playbook.yml file that uses the workstation machine as the managed host to test authentication to the web server. It does not need privilege escalation. Define a variable named web_user with the value guest.

    1. Add the following line to define the start of a second play. Note that there is no indentation.

      - name: test web server with basic auth
    2. Add the following line to indicate that the play applies to the workstation managed host.

        hosts: workstation
    3. Add the following line to disable privilege escalation.

        become: false
    4. Add the following lines to define the web_user play variable.

        vars:
          web_user: guest
  12. Add a directive to the play that adds additional variables from a variable file named vars/secret.yml. This file contains a variable named web_pass that specifies the password for the web user. You create this file later in the lab.

    Define the start of the task list.

    1. Using the vars_files keyword, add the following lines to the play to instruct Ansible to use variables found in the vars/secret.yml variable file.

        vars_files:
          - vars/secret.yml
    2. Add the following line to define the beginning of the tasks list.

        tasks:
  13. Add two tasks to the second play.

    The first task uses the ansible.builtin.uri module to request content from https://serverb.lab.example.com using basic authentication. Use the web_user and web_pass variables to authenticate to the web server. The task should verify a return HTTP status code of 200. Register the task result in a variable named auth_test.

    Note that the certificate presented by serverb is not trusted, so you need to avoid certificate validation.

    The second task uses the ansible.builtin.debug module to print the content returned from the web server, which is contained in the auth_test variable.

    1. Add the following lines to create the task for verifying the web service from the control node. Be sure to indent the first line with four spaces.

          - name: connect to web server with basic auth
            ansible.builtin.uri:
              url: https://serverb.lab.example.com
              validate_certs: no
              force_basic_auth: yes
              user: "{{ web_user }}"
              password: "{{ web_pass }}"
              return_content: yes
              status_code: 200
            register: auth_test
    2. Create the second task using the ansible.builtin.debug module. The content returned from the web server is added to the registered variable as the key content.

          - ansible.builtin.debug:
              var: auth_test.content
    3. The completed playbook should consist of the following content:

      ---
      - name: install and configure webserver with basic auth
        hosts: webserver
        vars:
          firewall_pkg: firewalld
          firewall_svc: firewalld
          web_pkg: httpd
          web_svc: httpd
          ssl_pkg: mod_ssl
          httpdconf_src: files/httpd.conf
          httpdconf_dest: /etc/httpd/conf/httpd.conf
          htaccess_src: files/.htaccess
          secrets_dir: /etc/httpd/secrets
          secrets_src: files/htpasswd
          secrets_dest: "{{ secrets_dir }}/htpasswd"
          web_root: /var/www/html
        tasks:
          - name: latest version of necessary packages installed
            ansible.builtin.dnf:
              name:
                - "{{ firewall_pkg }}"
                - "{{ web_pkg }}"
                - "{{ ssl_pkg }}"
              state: latest
      
          - name: configure web service
            ansible.builtin.copy:
              src: "{{ httpdconf_src }}"
              dest: "{{ httpdconf_dest }}"
              owner: root
              group: root
              mode: 0644
      
          - name: secrets directory exists
            ansible.builtin.file:
              path: "{{ secrets_dir }}"
              state: directory
              owner: apache
              group: apache
              mode: 0500
      
          - name: htpasswd file exists
            ansible.builtin.copy:
              src: "{{ secrets_src }}"
              dest: "{{ secrets_dest }}"
              owner: apache
              group: apache
              mode: 0400
      
          - name: .htaccess file installed in docroot
            ansible.builtin.copy:
              src: "{{ htaccess_src }}"
              dest: "{{ web_root }}/.htaccess"
              owner: apache
              group: apache
              mode: 0400
      
          - name: create index.html
            ansible.builtin.copy:
              content: "{{ ansible_facts['fqdn'] }} ({{ ansible_facts['default_ipv4']['address'] }}) has been customized by Ansible.\n"
              dest: "{{ web_root }}/index.html"
      
          - name: firewall service enable and started
            ansible.builtin.service:
              name: "{{ firewall_svc }}"
              state: started
              enabled: true
      
          - name: open the port for the web server
            ansible.posix.firewalld:
              service: https
              state: enabled
              immediate: true
              permanent: true
      
          - name: web service enabled and started
            ansible.builtin.service:
              name: "{{ web_svc }}"
              state: started
              enabled: true
      
      - name: test web server with basic auth
        hosts: workstation
        become: false
        vars:
          - web_user: guest
        vars_files:
          - vars/secret.yml
        tasks:
          - name: connect to web server with basic auth
            ansible.builtin.uri:
              url: https://serverb.lab.example.com
              validate_certs: no
              force_basic_auth: yes
              user: "{{ web_user }}"
              password: "{{ web_pass }}"
              return_content: yes
              status_code: 200
            register: auth_test
      
          - ansible.builtin.debug:
              var: auth_test.content
    4. Save and close the playbook.yml file.

  14. Create a vars/secret.yml file, encrypted with Ansible Vault. Use the password redhat to encrypt it. It should set the web_pass variable to redhat, which is the web user's password.

    1. Create a subdirectory named vars in the working directory.

      [student@workstation data-review]$ mkdir vars
    2. Create the encrypted variable file, vars/secret.yml, using Ansible Vault. Set the password for the encrypted file to redhat.

      [student@workstation data-review]$ ansible-vault create vars/secret.yml
      New Vault password: redhat
      Confirm New Vault password: redhat
    3. Add the following variable definition to the file:

      web_pass: redhat
    4. Save and close the file.

  15. Run the playbook.yml playbook. Verify that content is successfully returned from the web server, and that it matches what was configured in an earlier task.

    1. Before running the playbook, verify that its syntax is correct by running ansible-navigator with the --syntax-check option.

      Use --vault-id @prompt to be prompted for the Vault password. Enter redhat when prompted for the password.

      If it reports any errors, correct them before moving to the next step.

      You should see output similar to the following:

      [student@workstation data-review]$ ansible-navigator run -m stdout \
      > --playbook-artifact-enable false \
      > playbook.yml --syntax-check --vault-id @prompt
      Vault password (default): redhat
      
      playbook: /home/student/data-review/playbook.yml
    2. Using the ansible-navigator command, run the playbook with the --vault-id @prompt option. Enter redhat when prompted for the password.

      [student@workstation data-review]$ ansible-navigator run -m stdout \
      > --playbook-artifact-enable false \
      > playbook.yml --vault-id @prompt
      Vault password: redhat
      PLAY [Install and configure webserver with basic auth] *********************
      
      ...output omitted...
      
      TASK [connect to web server with basic auth] ***********************************
      ok: [workstation]
      
      TASK [debug] *******************************************************************
      ok: [workstation] => {
          "auth_test.content": "serverb.lab.example.com (172.25.250.11) has been customized by Ansible.\n"
      }
      
      PLAY RECAP *********************************************************************
      workstation                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
      serverb.lab.example.com    : ok=10   changed=8    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Evaluation

Run the lab grade data-review command on workstation to confirm success on this exercise. Correct any reported failures and rerun the script until successful.

[student@workstation ~]$ lab grade data-review

Finish

On the workstation machine, change to the student user home directory and use the lab command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.

[student@workstation ~]$ lab finish data-review

This concludes the section.

Revision: rh294-9.0-c95c7de