aoh

A tool for running Ansible playbooks with `curl <url> | python` commands
git clone https://git.ashermorgan.net/aoh/
Log | Files | Refs | README

commit ad01caecedc0faeab421ebca0f0ed8d06ca81a7b
parent e8a87e0d7d7cfdcc0c062ba5e03bcce313db9442
Author: Asher Morgan <asher@ashermorgan.net>
Date:   Sat, 29 Aug 2026 16:55:58 -0700

Update README.md

Diffstat:
MREADME.md | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 172 insertions(+), 0 deletions(-)

diff --git a/README.md b/README.md @@ -1 +1,173 @@ # Ansible-over-HTTP (AoH) + +Run an Ansible playbook with a single `curl <url> | python` command. + +More specifically, this command triggers an `ansible-playbook` run on the AoH +server, with the local client fetching execution instructions for its own tasks +over HTTP. This is especially useful for machines that are behind a NAT/firewall +(thus preventing the use of `ansible-playbook` directly), but also either run +Windows or aren't trusted with full repository access (thus preventing the use +of `ansible-pull`). For example, AoH can be used to easily install dotfiles on +new machines, anytime, anywhere. + + +## Comparison with Traditional Ansible & Ansible Pull + +| | Ansible | AoH | Ansible Pull | +| --------------------------------- | -------------------- | -------------------- | -------------------- | +| Architecture | Push | Hybrid | Pull | +| Server requirements | `ansible-playbook` | `aoh` | Any git server | +| Client requirements | `python` | `python` | `ansible-pull` | +| Controller logic execution | Server-side | Server-side | Client-side | +| Client has full repository access | No | No | Yes | +| Connection method | Usually SSH | HTTP | Local connection | +| Connection direction | Server &rarr; client | Client &rarr; server | Client &rarr; server | + + +## Setup + +1. Install python dependencies: `pip install -r requirements.txt` + +2. Create `.env`, `playbooks.yml`, and `passwords.yml` files as described below + +3. Start AoH development server: `python -m aoh` + +4. Run AoH client: `curl -s localhost:5000/run | python3 - --help` + + +## Configuration + +### Environment Variables + +AoH supports the following configuration options, specified either via +environment variables or a `.env` file. + +- `AOH_ORIGIN`: The origin of the AoH server, as referenced in the `/run.py` + script (e.g. `https://aoh.example.com:5000`). This must be set if running AoH + behind a proxy. Defaults to the origin on which requests for `/run.py` are + received. + +- `AOH_PASSWORDS_FILE`: The file containing passwords for password-protected + playbooks (see below). Defaults to `./passwords.yml`. + +- `AOH_PLAYBOOKS_DIR`: The default directory to search for playbooks in. + Defaults to the directory containing `AOH_PLAYBOOKS_FILE`. + +- `AOH_PLAYBOOKS_FILE`: The file containing playbook configuration (see below). + Defaults to `./playbooks.yml`. + + +### Playbooks + +AoH only executes playbooks that are listed in the `$AOH_PLAYBOOKS_FILE` file, +which must have the following structure: + +```yml +main.yml: # The playbook name + + # The path to the playbook, relative to $AOH_PLAYBOOKS_DIR. Defaults to the + # playbook name. + path: demo/playbook.yml + + # The path to an associated Ansible config file, if one exists. + config: demo/ansible.cfg + + # The hostname to assign to clients. If omitted or null, each client is + # assigned the hostname that it reports for itself. + host: my-aoh-host + + # The groups to assign to clients, in addition to the aoh group and any groups + # defined in inventory files. + groups: + - group1 + - group2 + + # Whether to require a password to execute the playbook. Passwords must be + # specified separately in the $AOH_PASSWORDS_FILE file (see below). Defaults + # to false. + password: true + + # Additional raw ansible-playbook options + cmdline: '--limit aoh' # only run tasks for the current client + + # Whether to print Ansible output on the client. Defaults to true. + output: true + + # The ansible-playbooks options that users are allowed to invoke. Short and + # long option forms must be specified separately. A reasonable set of safe + # options are allowed by default, see aoh/security.py. + allow_opts: + - '--become-method' + + # A list of ansible-playbook options that users are not allowed to invoke. + # This overrides the default allowed options and the options specified in + # allow_opts. Some options are always blocked, see aoh/security.py. + block_opts: + - '--list-tags' + + # Whether to allow clients to use Jinja expressions in ansible-playbook + # options. Defaults to false. + jinja: true + + # The description displayed on the playbook web page. Defaults to null, which + # disables the playbook web page. + web_description: 'Run the main.yml playbook with a single command:' +``` + + +### Playbook Passwords + +Passwords for password-protected playbooks must be specified as bcrypt hashes in +the `$AOH_PASSWORDS_FILE` file. For example: + +``` +# Require the password "hunter2" to execute the main.yml playbook +main.yml: $2a$14$LfC6Bcczc0WM.OObqgQPYeVvYa10g1Z4Z8C.eERyd.GarPmNa5/ve +``` + + +## Security + +Like both Ansible and Ansible Pull, AoH clients must trust the server and its +playbooks since they are allowed to execute arbitrary commands. Unlike both +Ansible and Ansible Pull however, AoH introduces the risk of clients influencing +command execution on the server. As just one example, if a malicious client +passed the options `--extra-var "foo={{ lookup('file', '/secret' }}"` to AoH and +the variable `foo` was used in a task run on the client, the contents of +`/secret` could be leaked to the client. + +AoH aims to minimize these security risks as much as possible while still +providing flexibility for different use cases. Below are the measures that AoH +takes, or can be configured to take, to mitigate security risks. + +- **Restricting Playbook Access:** By default, any client with access to the AoH + server can run any playbook. If access must be restricted to certain clients, + playbooks should be password-protected using the `password` playbook option + and the `$AOH_PASSWORDS_FILE` file. + +- **Blocking Ansible Options:** By default, clients are only allowed to invoke + only a small subset of reasonably safe `ansible-playbook` options. Additional + options can be allowed or blocked via the `allow_opts` and `block_opts` + playbook options. + +- **Blocking Jinja Expressions:** By default, clients-supplied + `ansible-playbook` options containing Jinja expressions are blocked. If + necessary, this protection can be disabled via the `jinja` playbook option. + +- **Hiding Ansible Output:** By default, clients receives and print all Ansible + output, including `--diff` output, `--verbose` logs, and even output from + tasks executed on other hosts. If this behavior could reveal sensitive data, + Ansible output should be hidden entirely from clients via the `output` + playbook option. + +- **Forcing Client Hostnames:** By default, the server executes tasks on clients + according to their reported hostnames. This could allow a client to receive + playbook tasks meant for other hosts. If a playbook includes sensitive tasks + for other hosts, client hostnames should be set to a safe value via the `host` + playbook option. + +- **Forcing Ansible Options:** Additional `ansible-playbook` options may be + added to every execution via the `cmdline` playbook option. For example, if + clients must not be able to trigger the execution of other hosts' tasks, then + the `--limit aoh` option should be added to `cmdline`. Consider also adding + these options to `block_opts` to prevent clients from modifying them.