Skip to content

Commit

Permalink
Merge remote-tracking branch 'gh/main' into master_bb
Browse files Browse the repository at this point in the history
  • Loading branch information
speed47 committed Nov 10, 2023
2 parents 671e7f3 + c88030e commit d05ce16
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 6 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
name: pre-commit
on: [push, pull_request]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- uses: pre-commit/[email protected]
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repos:
- id: requirements-txt-fixer
- id: trailing-whitespace
- repo: https://github.com/PyCQA/isort
rev: 5.10.1
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/psf/black
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#
# Please keep the list sorted.
#
Julien Riou <[email protected]>
Nicolas Payart <[email protected]>
Stéphane Lesimple <[email protected]>
Wifried Roset <[email protected]>
61 changes: 57 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ here, each host may have its bastion_X vars defined in group_vars and host_vars.
If environement vars are not defined, or if the module does not send them, then the sshwrapper is doing a lookup on the ansible-inventory to fetch the bastion_X vars.

## Using vars from a config file

For some use cases (AWX in a non containerised environment for instance), the environment is overridden by the job, and there is no fixed inventory source path.

So we may not get the vars from the environment nor the inventory.
Expand All @@ -102,6 +103,9 @@ bastion_user: "my_bastion_user"

The configuration file is read after checking the environment variables sent in the ssh command line, and will only set them if not defined.

The location of the configuration file can be set with `BASTION_CONFIG_FILE`
environment variable (defaults to `/etc/ovh/bastion/config.yml`).

## Configuration priority

Source of variables are read in the following order:
Expand All @@ -116,18 +120,67 @@ The wrapper is going to lookup the ansible inventory to look for the host and it

You may define multiple inventories sources in an ENV var. Example:

```
export BASTION_ANSIBLE_INV_OPTIONS='-i my_first_inventory_source -i my_second_inventory_source'
```

## Configuration via ansible.cfg
## Connection via SSH

The wrapper can be configured using `ansible.cfg` file as follow:

```ini
[ssh_connection]
scp_if_ssh = True
# Rely on bastion wrapper
pipelining = True
ssh_executable = ./extra/bastion/sshwrapper.py
```

Or by using the `ANSIBLE_SSH_PIPELINING` and `ANSIBLE_SSH_EXECUTABLE`
environment variables.

## File transfer using SFTP

By default, Ansible uses SFTP to copy files. The executable should be defined
as follow in the ansible.cfg file:

```ini
[ssh_connection]
transfer_method = sftp
sftp_executable = ./extra/bastion/sftpbastion.sh
```

Or by using the `ANSIBLE_SFTP_EXECUTABLE` environment variable.

## File transfer using SCP (deprecated)

The SCP protocol is still allowed but will soon deprecated by OpenSSH. You
should consider using SFTP instead. If you still want to use the SCP protocol,
you can define the method and executable as follow:

File ansible.cfg:

```ini
[ssh_connection]
transfer_method = scp
scp_if_ssh = True # Ansible < 2.17
scp_extra_args = -O # OpenSSH >= 9.0
scp_executable = ./extra/bastion/scpbastion.sh
transfer_method = scp
```

Or by using the following environment variables:
* `ANSIBLE_SCP_IF_SSH`
* `ANSIBLE_SSH_TRANSFER_METHOD`
* `ANSIBLE_SCP_EXTRA_ARGS`
* `ANSIBLE_SCP_EXECUTABLE`

## Configuration example

File ansible.cfg:

```ini
[ssh_connection]
pipelining = True
ssh_executable = ./extra/bastion/sshwrapper.py
sftp_executable = ./extra/bastion/sftpbastion.sh
```

## Integration via submodule
Expand Down
11 changes: 10 additions & 1 deletion scpwrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
import sys

from lib import find_executable, get_hostvars
from lib import find_executable, get_hostvars, manage_conf_file


def main():
Expand All @@ -15,6 +15,7 @@ def main():
bastion_port = None
remote_user = None
remote_port = 22
default_configuration_file = "/etc/ovh/bastion/config.yml"

iteration = enumerate(argv)
sshcmdline = []
Expand Down Expand Up @@ -51,6 +52,14 @@ def main():
elif "bastion_port" in i.lower():
bastion_port = i.split("=")[1]

# read from configuration file
bastion_host, bastion_port, bastion_user = manage_conf_file(
os.getenv("BASTION_CONF_FILE", default_configuration_file),
bastion_host,
bastion_port,
bastion_user,
)

# lookup on the inventory may take some time, depending on the source, so use it only if not defined elsewhere
# it seems like some module like template does not send env vars too...
if not bastion_host or not bastion_port or not bastion_user:
Expand Down
2 changes: 2 additions & 0 deletions sftpbastion.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
exec sftp -S $(dirname $0)/sftpwrapper.py "$@"
78 changes: 78 additions & 0 deletions sftpwrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3

import getpass
import os
import sys

from lib import find_executable, get_hostvars, manage_conf_file


def main():
argv = list(sys.argv[1:])

bastion_user = None
bastion_host = None
bastion_port = None
remote_user = None
remote_port = 22
default_configuration_file = "/etc/ovh/bastion/config.yml"

iteration = enumerate(argv)
for i, e in iteration:
if e == "-o" and argv[i + 1].startswith("User="):
remote_user = argv[i + 1].split("=")[-1]
next(iteration)
elif e == "-o" and argv[i + 1].startswith("Port="):
remote_port = argv[i + 1].split("=")[-1]
next(iteration)

sftpcmd = argv.pop()
host = argv.pop()

# Playbook environment variables are not pushed to the sftp wrapper
# Skipping this source of configuration

# Read from configuration file
bastion_host, bastion_port, bastion_user = manage_conf_file(
os.getenv("BASTION_CONF_FILE", default_configuration_file),
bastion_host,
bastion_port,
bastion_user,
)

# Read from inventory and environment variables
if not bastion_host or not bastion_port or not bastion_user:
inventory = get_hostvars(host)
bastion_port = inventory.get("bastion_port", os.getenv("BASTION_PORT", 22))
bastion_user = inventory.get(
"bastion_user", os.getenv("BASTION_USER", getpass.getuser())
)
bastion_host = inventory.get("bastion_host", os.getenv("BASTION_HOST"))

args = [
"ssh",
"{}@{}".format(bastion_user, bastion_host),
"-p",
bastion_port,
"-o",
"StrictHostKeyChecking=no",
"-T",
"--",
"--user",
remote_user,
"--port",
remote_port,
"--host",
host,
"--osh",
"sftp",
]

os.execv(
find_executable("ssh"),
[str(e).strip() for e in args],
)


if __name__ == "__main__":
main()

0 comments on commit d05ce16

Please sign in to comment.