Password Handling

Passwords are defined in the testbed YAML file. This document describes the password handling logic used by the different plugins. Passwords are managed through device credentials in pyATS, the next section explains how credentials are handled in pyATS.

Credentials

The credentials connection parameter defines a dictionary of named credentials. A credential is a dictionary typically containing both username and password keys.

The login_creds connection parameter defines an optional sequence of credential names to try. Each time the device prompts for a username or password, the current credential is set to the next credential in the sequence if a current credential has not already been set. When a password is sent, the current credential is unset. The one exception is when entering an administrator’s password on a routing device coming up without configuration, in this case the current credential is reused. If the sequence has been exhausted and no more credentials are available to satisfy a username/password prompt, a CredentialsExhaustedError is raised.

Credentials are not retried, any username or password failure causes a UniconAuthenticationError to be raised, unless fallback credentials are defined. See Fallback Credentials.

It is possible to specify the password to use for routing devices to enter enable mode. This may be done via the enable_password entry under the current credential, or via a separate credential called enable. Please see Enable password handling for details.

Passwords specified as a Secret Strings are automatically decoded prior to being sent to the device.

In pyATS Testbed YAML

Credentials may be specified on a per-testbed, per-device or per-connection basis, as documented in Credential Password Modeling.

from pyats.topology import loader
tb = loader.load("""
    devices:
        my_device:
            type: router
            credentials:
                default:
                    username: admin
                    password: Cisc0123
                alternate:
                    username: alt_username
                    password: alt_password
                termserv:
                    username: tsuser
                    password: tspw
                enable:
                    password: enablepw
            connections:
                defaults: {class: 'unicon.Unicon'}
                a:
                  protocol: ssh
                  ip: 10.64.70.11
                  port: 2042
                  login_creds: [termserv, default]
                  ssh_options: "-v -i /path/to/identityfile"

""")
dev = tb.devices.my_device
dev.connect()

# To connect using different credentials than is contained in the
# testbed YAML ``login_creds`` key:
dev.destroy()
dev.connect(login_creds=['termserv', 'alternate'])

In Python

dev = Connnection(hostname=uut_hostname,
                   start=[uut_start_cmd],
                   credentials={\
                       {'default': {'username': 'admin', 'password': 'Cisc0123'}},\
                       {'enable': {'password': 'enablepw'}},\
                       {'termserv': {'username': 'tsuser', 'password': 'tspw'}},\
                   },
                   login_creds = ['termserv', 'default'],
                 )

Post credential action

In certain cases, e.g. when using a serial console server, an action is needed to get a response from the device connected to the serial port. There are two ways to configure this action. The first one is using a setting, the second one is using a post credential action. The post credential action takes precedence over the setting.

Example credentials for a device.

my_device:
    type: router
    credentials:
        default:
            username: admin
            password: Cisc0123
        terminal_server:
            username: tsuser
            password: tspw

Setting the credential action via settings in python.

# Name of the credential after which a "sendline()" should be executed
dev.settings.SENDLINE_AFTER_CRED = 'terminal_server'

Settings can also be specified for the connection in the topology file as shown below.

connections:
  cli:
    settings:
      SENDLINE_AFTER_CRED: terminal_server

The post credential action supports send and sendline, you can specify a string to be sent, e.g. send( ) to send a space or send(\x03) to send Ctrl-C. Quotes should not be specified.

connections:
  cli:
    login_creds: [terminal_server, default]
    arguments:
      cred_action:
        terminal_server:
          post: sendline()

Unicon supports passwords specified in encrypted form. Please see Credential Password Modeling for details.

Typically, credentials may be specified using any preferred name.

However, the following credentials are specified using well-known reserved names:

  • default : The default credential, which is the fallback if a named credential is not specified.

  • enable : The password sent when bringing a routing device to enable mode. Please see Enable password handling for details.

  • sudo : The fxos/ftd plugin requires this (see note below).

  • ssh : Used to authenticate against an ssh tunnel server. See SSH Tunnel for details.

  • bmc : The iosxr/spitfire plugin requires this (see note below).

These passwords can be defined in the testbed YAML file in the testbed section, for each device, or at the connection level.

# generic passwords
testbed:
    credentials:
        default:
            username: admin
            password: cisco123
        enable:
            password: my_enable_pw

The usage of these credentials depends on the plugin. The generic plugin is used when no os is specified in the testbed YAML file. The generic implementation is used also by most other plugins except (currently) the linux and asa plugins.

devices:
  lnx:
    type: linux
    os: linux
    credentials:
        default:
            username: cisco
            password: cisco

If username is not defined in the credentials, the default username for Linux is the OS user that is running the python script. The default linux password is empty (“”).

For all other devices, the default password logic is used (unless otherwise specified by the specific plugin).

login_creds is used to describe the order of credentials to use on initial login. If not specified, the default credential is used. Please see Credentials for more details.

devices:
  my_device:
    type: router
    os: ios
    credentials:
        default:
            username: cisco
            password: secret
        enable:
            password: enable
    connections:
      vty1:
        credentials:
            default:
                username: cisco1
                password: secret1
      vty2:
        credentials:
            first:
                username: first_user
                password: first_pw
            default:
                username: cisco2
                password: secret2
            enable:
                password: enable2
            login_creds: [first, default]

Enable password handling

The following example shows a case where a device may have multiple enable passwords. For example, different credentials could apply depending on whether or not a RADIUS server is reachable.

devices:
  my_device:
    type: router
    os: ios
    credentials:
        default:
            username: cisco
            password: secret
            enable_password: enable
        local:
            username: cisco_local
            password: secret_local
            enable_password: enable_local

The following command connects to the router and enters enable mode using local credential authentication:

device.connect(login_creds='local')

The following command connects to the router and enters enable mode using default credential authentication:

device.connect()

How enable password is chosen

When a router asks for an enable password, the password sent is determined by the following checks. If all checks are done and still no enable password is found then an exception is raised.

  1. The enable_password field of the credential specified by the login_creds in the connect call.

  2. The default credential enable_password

  3. The enable credential password (legacy)

  4. The default credential password (legacy)

Password sequences in service calls

Several services, including reload and switchover, accept a credential list that is used to authenticate against a sequence of username/password prompts encountered while the service is running.

Authentication Failure

The following response pattern generates a bad password exception:

bad_passwords = r'^.*?% (Bad passwords|Access denied|Authentication failed)'

Fallback Credentials

In case of authentication failure, fallback credentials are used to try and login to the device when they are defined for the connection. You can define one or more device credentials and define them as fallback credentials by adding them to the fallback credentials list under the defaults section or under the connection. The fallback credentials credentials will be used in sequence. If none of the combinations work on the device a bad password exception is raised.

Below an example of a testbed with fallback credentials defined.

devices:
  my_device:
    type: router
    os: ios
    credentials:
        default:
            username: cisco
            password: secret
        enable:
            password: enable
        set_1:
          password: lab
          username: lab
        set_2:
          password: admin
          username: admin
    connections:
        defaults:
          class: unicon.Unicon
          fallback_credentials:
            - set1
            - set2
        netconf:
          class: yang.connector.Netconf
          ip: 1.2.3.4
          port: 830
          protocol: netconf
        telnet:
          ip: 1.2.3.4
          port: 23
          protocol: telnet

Example of fallback credentials per connection:

devices:
  my_device:
    type: router
    os: ios
    credentials:
        default:
            username: cisco
            password: secret
        enable:
            password: enable
    connections:
        netconf:
          class: yang.connector.Netconf
          ip: 1.2.3.4
          port: 830
          protocol: netconf
          fallback_credentials:
              - set_1
          credentials:
              default:
                  username: cisco
                  password: secret
              set_1:
                password: lab
                username: lab
        telnet:
          ip: 1.2.3.4
          port: 23
          protocol: telnet
          fallback_credentials:
            - set_2
          credentials:
              default:
                  username: cisco
                  password: secret
              set_2:
                password: admin
                username: admin

Environment variables

You can use the environment variable syntax in the topology file so you don’t have to store passwords on the filesystem.

credentials:
  default:
    username: "%ENV{PYATS_USERNAME}"
    password "%ENV{PYATS_USERNAME}"
  enable:
    password "%ENV{PYATS_ENABLE_PASS}"

Passwords on HA enabled devices

Credentials are specified against the a: connection for HA enabled devices:

devices:
  ha_device
    type: router
    os: ios
    credentials:
        default:
            username: cisco
            password: secret
        enable:
            password: enable
    connections:
      a:
        credentials:
            default:
                username: cisco1
                password: secret1
        protocol: telnet
        ip: 1.1.1.1
        port: 2001
      b:
        protocol: telnet
        ip: 1.1.1.1
        port: 2002

Linux password logic

When connecting to the device, the password from the current credential is used. If another password prompt appears during command execution, no response is sent and the command will timeout by default.

To execute commands using sudo, use the sudo service. See sudo

If connecting via ssh, the username of the currently logged in user is used by default if not otherwise specified via credentials or via command or ssh_options keys in one of the following forms:

ssh -l username <address> or ssh username@<address>.

In order to execute a command that leads to a username/password prompt, you must explicitly add the password statement to the reply Dialog. If the default password statement is used (as in the example shown below), a single username/password prompt is responded to using the default credential.

Example code using the password statement:

from unicon.eal.dialogs import Dialog
from unicon.plugins.generic.statements import password_stmt

dialog = Dialog()
dialog.append(password_stmt)

device.execute('command that prompts for password', reply=dialog)

ASA password logic

If the pattern '^.+?@.+?'s +password: *$' is seen, the password of the current credential is sent.

If the pattern '^.*Password:s?$' is seen, the password of the enable credential is sent.

Please see Enable password handling for details.

iosxr/Spitfire password logic

The typical credential sequence is used to authenticate against each username/password request from the device.

However, if a BMC login prompt is seen, the password used is taken from the bmc credential instead.

fxos/ftd password logic

When transitioning from ftd_expert to ftd_expert_root state, the password from the sudo credential is sent if specified. Otherwise, the password from the default credential is sent. Otherwise, a UniconAuthenticationError is raised.

nxos password logic

The switchto service accepts a vdc_cred argument that identifies a named credential to use to authenticate against the VDC.

SSH passphrase

You can specify the passphrase that will be used to respond to the Enter passphrase for key prompt as part of the credential block.

devices:
  my_device:
    type: router
    os: ios
    credentials:
        default:
            username: cisco
            password: secret
            passphrase: secret phrase

SSH Options

You can specify additional SSH options (such as identity/key files) using the ssh_options key as part of the connection block:

devices:
  my_device:
    type: router
    os: ios
    connections:
        vty:
            protocol: ssh
            ip: 10.64.70.11
            port: 2042
            ssh_options: "-i /path/to/id_rsa -o UserKnownHostsFile /dev/null"