441 Redirect SHH to jails¶
Use case¶
Create multiple jails with auto UUID names. In the inventory, compose the variables
ansible_host and ansible_port to connect the jails via the redirected SSH
ports. See the example 440 Configure DHCP and pf how pf is configured.
Tree¶
shell> tree .
.
├── ansible.cfg
├── hosts
│ ├── 05_iocage.yml
│ └── 99_constructed.yml
├── host_vars
│ └── iocage_05.yml
├── iocage.ini
└── pb-test.yml
Synopsis¶
At a managed node:
In the playbook vbotka.freebsd.pb_iocage_ansible_clients.yml:
create jails
start jails
optionally, stop and destroy the jails.
Create dynamic inventory to redirect SSH to the jails.
At all created jails:
In the playbook
pb-test.yml:connect to the created jails
display basic configuration of the jails.
Requirements¶
root privilege in the managed nodes
templates created in 202 Create iocage templates. Clone DHCP jails.
Notes¶
The only difference between this example and the example 442 Connection jailexec instead of ssh are the
following two lines in the file hosts/05_iocage.yml
ansible_host: dict(iocage_properties.notes | split | map('split', '=')).vmm
ansible_port: iocage_ip4 | split('.') | last | int - 100 + 2200
See also
example 050 Connection jailexec
Templates at iocage_05¶
[iocage_05]# iocage list -lt
+------+-----------------------+------+-------+----------+--------------+--------------------+-----+----------+----------+
| JID | NAME | BOOT | STATE | TYPE | RELEASE | IP4 | IP6 | TEMPLATE | BASEJAIL |
+======+=======================+======+=======+==========+==============+====================+=====+==========+==========+
| None | ansible_client | off | down | template | 15.0-RELEASE | DHCP (not running) | - | - | no |
+------+-----------------------+------+-------+----------+--------------+--------------------+-----+----------+----------+
| None | ansible_client_apache | off | down | template | 15.0-RELEASE | DHCP (not running) | - | - | no |
+------+-----------------------+------+-------+----------+--------------+--------------------+-----+----------+----------+
| None | ansible_client_pull | off | down | template | 15.0-RELEASE | DHCP (not running) | - | - | no |
+------+-----------------------+------+-------+----------+--------------+--------------------+-----+----------+----------+
ansible.cfg¶
[defaults]
gathering = explicit
callback_result_format = yaml
display_skipped_hosts = false
[connection]
pipelining = true
Inventory iocage.ini¶
iocage_05
[iocage]
iocage_05
[iocage:vars]
ansible_user=admin
ansible_become=true
ansible_python_interpreter=auto_silent
host_vars¶
properties:
bpf: 1
dhcp: 1
vnet: 1
notes: "vmm={{ inventory_hostname }}"
swarms:
sw_01:
count: 3
template: ansible_client
Playbook output - Create and start swarms¶
(env) > ansible-playbook vbotka.freebsd.pb_iocage_ansible_clients.yml \
-i iocage.ini \
-t swarm \
-e swarm=true \
-e debug=true
PLAY [Create and start jails. Optionally stop and destroy jails.] **************
TASK [Get iocage facts] ********************************************************
ok: [iocage_05]
TASK [Debug cmd_create debug=true] *********************************************
ok: [iocage_05] => (item=sw_01) =>
msg: |-
iocage create --short --template ansible_client --count 3 bpf=1 dhcp=1 vnet=1 notes="vmm=iocage_05 swarm=sw_01"
TASK [Create swarms] ***********************************************************
changed: [iocage_05] => (item=sw_01)
TASK [Debug create swarms debug=true] ******************************************
ok: [iocage_05] =>
out:
changed: true
msg: All items completed
results:
- ansible_loop_var: item
changed: true
cmd:
- iocage
- create
- --short
- --template
- ansible_client
- --count
- '3'
- bpf=1
- dhcp=1
- vnet=1
- notes=vmm=iocage_05 swarm=sw_01
delta: '0:00:00.851656'
end: '2026-04-19 07:21:21.207287'
failed: false
invocation:
module_args:
_raw_params: null
_uses_shell: false
argv: null
chdir: null
cmd: |-
iocage create --short --template ansible_client --count 3 bpf=1 dhcp=1 vnet=1 notes="vmm=iocage_05 swarm=sw_01"
creates: null
executable: null
expand_argument_vars: true
removes: null
stdin: null
stdin_add_newline: true
strip_empty_ends: true
item:
key: sw_01
value:
count: 3
template: ansible_client
msg: ''
rc: 0
start: '2026-04-19 07:21:20.355631'
stderr: ''
stderr_lines: []
stdout: |-
0a3ea428 successfully created!
93d13878 successfully created!
ffb2c114 successfully created!
stdout_lines:
- 0a3ea428 successfully created!
- 93d13878 successfully created!
- ffb2c114 successfully created!
skipped: false
TASK [Get iocage facts] ********************************************************
ok: [iocage_05]
TASK [Debug cmd_start debug=true] **********************************************
ok: [iocage_05] => (item=sw_01) =>
msg: |-
iocage start 0a3ea428 ffb2c114 93d13878
TASK [Start swarms] ************************************************************
changed: [iocage_05] => (item=sw_01)
TASK [Debug start swarms debug=true] *******************************************
ok: [iocage_05] =>
out:
changed: true
msg: All items completed
results:
- ansible_loop_var: item
changed: true
cmd:
- iocage
- start
- 0a3ea428
- ffb2c114
- 93d13878
delta: '0:00:07.786053'
end: '2026-04-19 07:21:34.470440'
failed: false
invocation:
module_args:
_raw_params: null
_uses_shell: false
argv: null
chdir: null
cmd: |-
iocage start 0a3ea428 ffb2c114 93d13878
creates: null
executable: null
expand_argument_vars: true
removes: null
stdin: null
stdin_add_newline: true
strip_empty_ends: true
item:
key: sw_01
value:
count: 3
template: ansible_client
msg: ''
rc: 0
start: '2026-04-19 07:21:26.684387'
stderr: |-
No default gateway found for ipv6.
No default gateway found for ipv6.
No default gateway found for ipv6.
stderr_lines:
- No default gateway found for ipv6.
- No default gateway found for ipv6.
- No default gateway found for ipv6.
stdout: |-
* Starting 0a3ea428
+ Started OK
+ Using devfs_ruleset: 1000 (iocage generated default)
+ Configuring VNET OK
+ Using IP options: vnet
+ Starting services OK
+ Executing poststart OK
+ DHCP Address: 10.10.99.106/24
* Starting ffb2c114
+ Started OK
+ Using devfs_ruleset: 1001 (iocage generated default)
+ Configuring VNET OK
+ Using IP options: vnet
+ Starting services OK
+ Executing poststart OK
+ DHCP Address: 10.10.99.107/24
* Starting 93d13878
+ Started OK
+ Using devfs_ruleset: 1002 (iocage generated default)
+ Configuring VNET OK
+ Using IP options: vnet
+ Starting services OK
+ Executing poststart OK
+ DHCP Address: 10.10.99.108/24
stdout_lines:
- '* Starting 0a3ea428'
- ' + Started OK'
- ' + Using devfs_ruleset: 1000 (iocage generated default)'
- ' + Configuring VNET OK'
- ' + Using IP options: vnet'
- ' + Starting services OK'
- ' + Executing poststart OK'
- ' + DHCP Address: 10.10.99.106/24'
- '* Starting ffb2c114'
- ' + Started OK'
- ' + Using devfs_ruleset: 1001 (iocage generated default)'
- ' + Configuring VNET OK'
- ' + Using IP options: vnet'
- ' + Starting services OK'
- ' + Executing poststart OK'
- ' + DHCP Address: 10.10.99.107/24'
- '* Starting 93d13878'
- ' + Started OK'
- ' + Using devfs_ruleset: 1002 (iocage generated default)'
- ' + Configuring VNET OK'
- ' + Using IP options: vnet'
- ' + Starting services OK'
- ' + Executing poststart OK'
- ' + DHCP Address: 10.10.99.108/24'
skipped: false
PLAY RECAP *********************************************************************
iocage_05 : ok=8 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
Jails at iocage_05¶
[iocage_05]# iocage list -l
+-----+----------+------+-------+------+--------------+----------------------+-----+----------------+----------+
| JID | NAME | BOOT | STATE | TYPE | RELEASE | IP4 | IP6 | TEMPLATE | BASEJAIL |
+=====+==========+======+=======+======+==============+======================+=====+================+==========+
| 7 | 0a3ea428 | off | up | jail | 15.0-RELEASE | epair0b|10.10.99.106 | - | ansible_client | no |
+-----+----------+------+-------+------+--------------+----------------------+-----+----------------+----------+
| 9 | 93d13878 | off | up | jail | 15.0-RELEASE | epair0b|10.10.99.108 | - | ansible_client | no |
+-----+----------+------+-------+------+--------------+----------------------+-----+----------------+----------+
| 8 | ffb2c114 | off | up | jail | 15.0-RELEASE | epair0b|10.10.99.107 | - | ansible_client | no |
+-----+----------+------+-------+------+--------------+----------------------+-----+----------------+----------+
Inventory hosts¶
plugin: vbotka.freebsd.iocage
host: iocage_05
user: admin
sudo: true
get_properties: true
hooks_results:
- /var/db/dhclient-hook.address.epair0b
compose:
ansible_host: dict(iocage_properties.notes | split | map('split', '=')).vmm
ansible_port: iocage_ip4 | split('.') | last | int - 100 + 2200
ansible_user: "'admin'"
ansible_python_interpreter: "'auto_silent'"
iocage_tags: dict(iocage_properties.notes | split | map('split', '='))
Note
In the example 440 Configure DHCP and pf, the variables
ssh_rdr_start=2200anddhcp_ip_start=100are used in the playbookpb-pf-setup.ymlto calculate the ports to redirect SSH from, and to create the filepf-rdr-ssh.conf.For example, from the controller, the following command connects to the jail at <bsd_dhcpd_subnet>.106:
shell> ssh -p 2206 admin@iocage_05
See the variable
bsd_dhcpd_subnetin the example 440 Configure DHCP and pf
plugin: ansible.builtin.constructed
keyed_groups:
- prefix: swarm
key: iocage_tags.swarm
- prefix: vmm
key: iocage_tags.vmm
Display inventory¶
(env) > ansible-inventory -i hosts --graph
@all:
|--@ungrouped:
|--@swarm_sw_01:
| |--0a3ea428
| |--93d13878
| |--ffb2c114
|--@vmm_iocage_05:
| |--0a3ea428
| |--93d13878
| |--ffb2c114
Playbook pb-test.yml¶
- name: Test the SSH redirection to the jails.
hosts: swarm_sw_01
gather_facts: false
tasks:
- ansible.builtin.debug:
msg: |
ansible_connection: {{ ansible_connection }}
ansible_host: {{ ansible_host }}
ansible_port: {{ ansible_port }}
ansible_user: {{ ansible_user }}
iocage_ip4: {{ iocage_ip4 }}
iocage_tags: {{ iocage_tags }}
Playbook output - Test SSH redirection¶
(env) > ansible-playbook pb-test.yml -i hosts
PLAY [Test the SSH redirection to the jails.] **********************************
TASK [ansible.builtin.debug] ***************************************************
ok: [0a3ea428] =>
msg: |-
ansible_connection: ssh
ansible_host: iocage_05
ansible_port: 2206
ansible_user: admin
iocage_ip4: 10.10.99.106
iocage_tags: {'vmm': 'iocage_05', 'swarm': 'sw_01'}
ok: [93d13878] =>
msg: |-
ansible_connection: ssh
ansible_host: iocage_05
ansible_port: 2208
ansible_user: admin
iocage_ip4: 10.10.99.108
iocage_tags: {'vmm': 'iocage_05', 'swarm': 'sw_01'}
ok: [ffb2c114] =>
msg: |-
ansible_connection: ssh
ansible_host: iocage_05
ansible_port: 2207
ansible_user: admin
iocage_ip4: 10.10.99.107
iocage_tags: {'vmm': 'iocage_05', 'swarm': 'sw_01'}
PLAY RECAP *********************************************************************
0a3ea428 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
93d13878 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ffb2c114 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Hint
The below play stops and destroys the jails in swarms
ansible-playbook vbotka.freebsd.pb_iocage_ansible_clients.yml \
-i iocage.ini \
-t swarm_destroy \
-e swarm_destroy=true