commit 7c389a36d85db0d58bf9d247a4d339ed06b9d058
parent d7a87b37fed078f370a7e8e5f26e6b4490ff8d89
Author: Asher Morgan <asher@ashermorgan.net>
Date: Tue, 18 Aug 2026 19:43:58 -0700
Pass client hostname and restrict AoH connection
Diffstat:
7 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/aoh/connection_plugins/aoh.py b/aoh/connection_plugins/aoh.py
@@ -44,6 +44,13 @@ class Connection(ConnectionBase):
if not self._connected:
AOH_DIR = self.get_option('aoh_dir')
+ with open(f'{AOH_DIR}/hostname', 'r') as f:
+ hostname = f.readline().strip()
+ if hostname != self._play_context.remote_addr:
+ raise AnsibleError('Attempted to connect to an AoH runner '
+ 'belonging to a different host '
+ f'({hostname})')
+
display.vvv(f'ESTABLISH CONNECTION TO AOH RUNNER {AOH_DIR}',
host=self._play_context.remote_addr)
diff --git a/aoh/install.py b/aoh/install.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import base64
+import platform
import subprocess
import sys
import time
@@ -51,6 +52,7 @@ def fetch(args):
def main():
res = requests.post(f'{API}/runners/', json={
+ 'host': platform.node() or 'aoh_node',
'playbook': sys.argv[1] if len(sys.argv) >= 2 else 'main',
'args': ' '.join(sys.argv[2:]),
})
diff --git a/aoh/runner.py b/aoh/runner.py
@@ -14,7 +14,7 @@ class AoHError(Exception):
class AoHRunner:
- def __init__(self, config, playbook, args):
+ def __init__(self, config, playbook, host, args):
self.id = str(uuid4())
self._dir = tempfile.mkdtemp()
self._LOGS_PATH = f'{self._dir}/artifacts/{self.id}/stdout'
@@ -27,6 +27,16 @@ class AoHRunner:
self._runner = None
try:
+ # Create hostname file so connection plugin can verify hosts
+ with open(f'{self._dir}/hostname', 'w') as f:
+ f.write(f'{host}\n')
+
+ # Set ansible_connection=aoh for the client host only. Note that we
+ # don't use ansible-runners inventory directory because that will
+ # shadow user inventory files.
+ with open(f'{self._dir}/inventory.ini', 'w') as f:
+ f.write(f'[aoh]\n{host} ansible_connection=aoh')
+
self._start_runner(config, playbook, args)
# We assume that ansible-runner will eventually create its log file
@@ -60,16 +70,22 @@ class AoHRunner:
x for x in raw_config.split('\n')
if x.startswith('DEFAULT_CONNECTION_PLUGIN_PATH')
).split('= ')[1])
+ inventory = eval(next(
+ x for x in raw_config.split('\n')
+ if x.startswith('DEFAULT_HOST_LIST')
+ ).split('= ')[1])
env = {
'ANSIBLE_CONNECTION_PLUGINS': ':'.join(
[_CONNECTION_PLUGIN_DIR] + connection_plugins
),
'ANSIBLE_CONFIG': config,
+ 'ANSIBLE_INVENTORY': ','.join(
+ [f'{self._dir}/inventory.ini'] + inventory
+ ),
}
vars = {
'ansible_aoh_dir': self._dir,
- 'ansible_connection': 'aoh',
}
self._thread, self._runner = ansible_runner.run_async(
diff --git a/aoh/server.py b/aoh/server.py
@@ -70,7 +70,7 @@ def job_new():
return { 'err': f"Playbook not found: {request.json['playbook']}" }, 400
runner = AoHRunner(playbook['config'], playbook['playbook'],
- request.json['args'])
+ request.json['host'], request.json['args'])
_DATA[runner.id] = runner
session['runner'] = runner.id
diff --git a/demo/ansible.cfg b/demo/ansible.cfg
@@ -1,2 +0,0 @@
-[defaults]
-inventory = inventory.yml
diff --git a/demo/inventory.yml b/demo/inventory.yml
@@ -1,3 +0,0 @@
-all:
- hosts:
- myhost:
diff --git a/demo/playbook.yml b/demo/playbook.yml
@@ -1,4 +1,4 @@
- name: My play
- hosts: myhost
+ hosts: all
tasks:
- ping: