/teleport-ansible

Teleport Ansible Dynamic Inventory Provider

Primary LanguagePythonApache License 2.0Apache-2.0

Teleport Inventory Documentation

This is a very simple package which will use Teleport as a dynamic inventory source for Ansible. The script assumes you've logged in and have access to the teleport service. Examples of all the base requirements are provided within this readme.

Checkout https://cloudnull.io/2022/09/ansible-inventory-via-teleport for a more indepth review of integrating Teleport with Ansible.

Using the teleport-ansible inventory script

The script will read machines and return JSON information from teleport. Once the return information is sourced, it will format the inventory using the node name as the target host and the labels as hostvars and groups.

Using teleport-ansible requires a little setup, mostly client side for Teleport itself.

Installing teleport-ansible and using it

Installing the teleport-ansible inventory script can be accomplished with pip.

pip install teleport-ansible

The teleport-inventory script can also be installed using the git repository directly.

pip install git+https://github.com/cloudnull/teleport-ansible

If you don't want to install the script, you can also simply download the script using the hard link and run it from wherever you want.

curl https://raw.githubusercontent.com/cloudnull/teleport-ansible/master/teleport-inventory.py -o teleport-inventory.py

Example SSH configuration connect through Teleport

Create a compatible SSH configuration for Teleport.

export TELEPORT_DOMAIN=teleport.example.com
export TELEPORT_USER=cloudnull
cat > ~/.ssh/teleport.cfg <<EOF
Host * !${TELEPORT_DOMAIN}
    UserKnownHostsFile "${HOME}/.tsh/known_hosts"
    IdentityFile "${HOME}/.tsh/keys/${TELEPORT_DOMAIN}/${TELEPORT_USER}"
    CertificateFile "${HOME}/.tsh/keys/${TELEPORT_DOMAIN}/${TELEPORT_USER}-ssh/${TELEPORT_DOMAIN}-cert.pub"
    PubkeyAcceptedKeyTypes +ssh-rsa-cert-v01@openssh.com
    Port 3022
    CheckHostIP no
    ProxyCommand "$(which tsh)" proxy ssh --cluster=${TELEPORT_DOMAIN} --proxy=${TELEPORT_DOMAIN} %r@%h:%p
EOF

The above ssh configuration needs to have all variables replaced to work.

Example Ansible Setup

When running this inventory, Ansible requires some basic instructions which can be set via environment variables or through an Ansible config file.

export ANSIBLE_SCP_IF_SSH=False
export ANSIBLE_SSH_ARGS="-F ${HOME}/.ssh/teleport.cfg"
export ANSIBLE_INVENTORY_ENABLED=script
export ANSIBLE_HOST_KEY_CHECKING=False
export ANSIBLE_INVENTORY="$(command -v teleport-ansible)"

The ${HOME}/.ssh/teleport.cfg file is generated by using the tsh config command then customized based on individual needs.

Example login process

tsh login --proxy=teleport.example.com --user=teleport-admin

If browser window does not open automatically, open it by clicking on the link:
 http://127.0.0.1:42337/83facfc0-e899-44dc-aa6c-32179e3d5b0b
> Profile URL:        https://teleport.example.com:443
  Logged in as:       teleport-admin
  Cluster:            teleport.example.com
  Roles:              access
  Logins:             root, ubuntu, debian, fedora, centos, -teleport-internal-join
  Kubernetes:         enabled
  Valid until:        2022-09-16 08:03:05 -0500 CDT [valid for 12h0m0s]
  Extensions:         permit-agent-forwarding, permit-port-forwarding, permit-pty

The above tsh login will provide access to the teleport cluster, which will allow you to run inventory script which will return an Ansible inventory JSON.

Example inventory return

Running the teleport inventory command teleport-inventory will return something like this.

>>> {
...     "_meta": {
...         "hostvars": {
...             "alluvial-0": {
...                 "ansible_user": "ubuntu",
...                 "teleport_id": 1663292578982084621,
...                 "arch": "x86_64",
...                 "codename": "jammy",
...                 "environment": "dev"
...             },
...             "compute-0": {
...                 "ansible_user": "carter",
...                 "teleport_id": 1663292546493240726,
...                 "arch": "x86_64",
...                 "codename": "jammy",
...                 "environment": "prod"
...             },
...             "curator-0": {
...                 "ansible_user": "debian",
...                 "teleport_id": 1663292584620339609,
...                 "arch": "x86_64",
...                 "codename": "bullseye",
...                 "environment": "prod"
...             },
...             "plexmediaserver-0": {
...                 "ansible_user": "debian",
...                 "teleport_id": 1663292540612813467,
...                 "arch": "x86_64",
...                 "codename": "bullseye",
...                 "environment": "prod"
...             },
...             "rtmprelay-0": {
...                 "ansible_user": "debian",
...                 "teleport_id": 1663292583673456110,
...                 "arch": "x86_64",
...                 "codename": "bullseye",
...                 "environment": "prod"
...             },
...             "teleport-0": {
...                 "ansible_user": "debian",
...                 "teleport_id": 1663292588270337453,
...                 "arch": "x86_64",
...                 "codename": "bullseye",
...                 "environment": "prod"
...             },
...             "thelounge-0": {
...                 "ansible_user": "debian",
...                 "teleport_id": 1663292533524229273,
...                 "arch": "x86_64",
...                 "codename": "bullseye",
...                 "environment": "prod"
...             },
...             "unbound-0": {
...                 "ansible_user": "debian",
...                 "teleport_id": 1663292535344206453,
...                 "arch": "x86_64",
...                 "codename": "bullseye",
...                 "environment": "prod"
...             },
...             "unifi-0": {
...                 "ansible_user": "debian",
...                 "teleport_id": 1663292528952201832,
...                 "arch": "x86_64",
...                 "codename": "bullseye",
...                 "environment": "prod"
...             },
...             "wireguard-0": {
...                 "ansible_user": "debian",
...                 "teleport_id": 1663292535570354336,
...                 "arch": "x86_64",
...                 "codename": "bullseye",
...                 "environment": "prod"
...             }
...         }
...     },
...     "all": {
...         "hosts": [
...             "alluvial-0",
...             "compute-0",
...             "curator-0",
...             "plexmediaserver-0",
...             "rtmprelay-0",
...             "teleport-0",
...             "thelounge-0",
...             "unbound-0",
...             "unifi-0",
...             "wireguard-0"
...         ],
...         "children": []
...     },
...     "x86_64": {
...         "hosts": [
...             "alluvial-0",
...             "compute-0",
...             "curator-0",
...             "plexmediaserver-0",
...             "rtmprelay-0",
...             "teleport-0",
...             "thelounge-0",
...             "unbound-0",
...             "unifi-0",
...             "wireguard-0"
...         ],
...         "children": []
...     },
...     "jammy": {
...         "hosts": [
...             "alluvial-0",
...             "compute-0"
...         ],
...         "children": []
...     },
...     "dev": {
...         "hosts": [
...             "alluvial-0"
...         ],
...         "children": []
...     },
...     "teleport_cloudnull_dev": {
...         "hosts": [
...             "wireguard-0"
...         ],
...         "children": []
...     },
...     "prod": {
...         "hosts": [
...             "compute-0",
...             "curator-0",
...             "plexmediaserver-0",
...             "rtmprelay-0",
...             "teleport-0",
...             "thelounge-0",
...             "unbound-0",
...             "unifi-0",
...             "wireguard-0"
...         ],
...         "children": []
...     },
...     "bullseye": {
...         "hosts": [
...             "curator-0",
...             "plexmediaserver-0",
...             "rtmprelay-0",
...             "teleport-0",
...             "thelounge-0",
...             "unbound-0",
...             "unifi-0",
...             "wireguard-0"
...         ],
...         "children": []
...     }
... }

Once the ssh config is in place, the Ansible configuration is set, and teleport is logged in, Ansible can be run natively.

Example Ansible Ad-Hoc command

You'll notice that the command is SUPER basic. There's nothing special here.

ansible -m ping all

Example Ansible Playbook command

Just like the ad-hoc command, there's nothing special when running playbooks either.

ansible-playbook example-playbook.yaml