Ansible has documentation for most topics. The purpose of this document is to link some places to get started, and explain how NCAE Cyber Games utilizes Ansible. Any questions regarding Ansible should first be searched within the online Ansible Documentation, then Google, and finally brought to NCAE Cyber Games if still unanswered. We can be reached at:
- Email: bdavis@c2games.org
- Discord: https://discord.gg/H2jwMxt
From Wikipedia:
Ansible is an open-source software provisioning, configuration management, and application-deployment tool enabling infrastructure as code. It runs on many Unix-like systems, and can configure both Unix-like systems as well as Microsoft Windows.
Each NCAE Cyber Games Challenge Submission is written as an Ansible Role. Ansible is used to make submitting a challenge as simple as possible, while allowing the NCAE Cyber Games team to automate the modification and deployment of challenges.
An Ansible role is a set of tasks, variables, handlers, and other information used to configure a host for a certain purpose. Roles are normally used to configure a host to run a particular service, such as an OpenSSH Server. In short, a role is everything Ansible needs, wrapped up into a standalone directory (although roles may depend on other roles).
Resources to Get Started
The Ansible documentation has several resources for getting started. Recommended places to start include:
Important Terminology
What are Plays and Playbooks?
Playbooks are a list of Plays, which are a list of tasks. The infrastructure-examples repository has a predefined playbook named playbook.yml
.
More information: https://docs.ansible.com/ansible/2.4/playbooks_intro.html#playbook-language-example
What are Tasks?
At a basic level, a task is nothing more than a call to an ansible module
Tasks can be thought of as commands, or another single ‘task’ to be performed on the remote system. Examples of tasks include adding/removing a user, ensuring a value is in a configuration file, installing/removing a package, or restarting a service.
Tasks call modules, which do the actual work on the remote system. There are many modules built in to Ansible, and they can usually be found by searching the internet with your favorite search engine. For example, searching for "ansible add user" should bring you to the user module.
Each Ansible task is defined within Yaml, where the indentation of the line changes it’s meaning. At the base level, each task defines the name of the current task, and the module to be used. Take adding a user for example:
- name: "Ensure the user 'bob' exists"
user:
name: "bob"
password: "{{ bobs_password | password_hash('sha256') }}"
update_password: always
Here, the name attribute is set to the string "Ensure the user ‘bob’ exists", and the user
module is being used.
The user module also has several options specified, which are indented two more spaces than the name
attribute and user
module definition. The options available are defined in the Ansible User Module Documentation.
How do I use variables?
In the example above for adding the user "bob", some curly braces {{ }}
can be found in the password field. These curly braces represent a variable in Ansible.
Variables can be defined in several places, but it’s recommended to defined them within your role, either in defaults/main.yml
or vars/main.yml
.
More information on variables is available here:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#simple-variables
In the above example, a pipe character (|
) can also be found within the curly braces. This represents passing the data to a Jinja filter. This is an advanced usage of variable, and more information can be found here:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#playbooks-filters
What are Handlers?
Handlers are operations to be run once, after all tasks are complete. For example, you may want to restart a service if a task updates the configuration of that service, but not if the configuration is unchanged. You may also have several tasks that could update the service configuration, and the service only needs to be restarted once.
Handlers within roles are defined in handlers/main.yml
, and are defined in the same manner as tasks. Handlers are used by adding the notify
keyword to any module, which will notify the handler if it needs to run when the Play is finished.
An example can be found in the ssh_authorized_keys
role:
# ssh_authorized_keys/handlers/main.yml
- name: Restart SSH
ansible.builtin.service:
name: sshd
state: restarted
# ssh_authorized_keys/tasks/main.yaml
- name: Allow Root Login
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin.*'
line: "PermitRootLogin yes"
notify:
- Restart SSH
Examples
Several examples are included in the roles/
directory of the the infrastructure-examples repository. The repository can be downloaded using the download button in Gitlab, next to the "Clone" button.
Included Examples:
- The
ssh_authorized_keys
role will install an SSH public key onto the system, and allow root to SSH with password authentication (no SSH key required). - The
manatee_bank_web_app
role will install git/apache on a system and clone down a vulnerable web application.
These examples can be executed by first ensuring they are included in the playbook.yml
playbook:
tasks:
- include_role:
name: ssh_authorized_keys
- include_role:
name: manatee_bank_web_app
Then run the following Ansible command, with the IP(s) of your test machines substituted:
# single host - note the tailing comma!
ansible-playbook -i 10.1.10.17, playbook.yml
# multiple hosts
ansible-playbook -i 10.1.10.17,10.1.10.18 playbook.yml
If a playbook is successful, you should see a footer similar to this at the end of the output. Watch
out for ok=xxx
to be non-zero, and failed=xxx
to be zero.
PLAY RECAP *******************************************************************************************************
10.1.11.28 : ok=6 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Don’t forget to restore your VM to it’s initial snapshot after running the examples!