Help us improve your experience.

Let us know what you think.

Do you have time for a two-minute survey?

Authenticating Users Executing Ansible Modules on Devices Running Junos OS

 

Authentication Overview

Juniper Networks provides Ansible modules that you can use to manage devices running Junos OS. The Juniper Networks modules are distributed through the juniper.device collection and the Juniper.junos role, which are hosted on Ansible Galaxy.

The Juniper Networks modules enable you to directly connect to and manage devices running Junos OS using SSH, telnet, or a serial console connection. The modules also support connecting to the device through an SSH or telnet connection to a console server that is connected to the device’s CONSOLE port. The remote device must be able to authenticate the user using a password or other standard SSH authentication mechanisms, depending on the connection protocol.

When you use Ansible to manage devices running Junos OS, the most convenient way to access the device is to configure SSH keys. SSH keys enable the remote device to identify trusted users. Alternatively, you can provide a username and password when you execute modules and playbooks.

For SSH connections, the Juniper Networks modules first attempt SSH public key-based authentication and then try password-based authentication. When SSH keys are in use, the supplied password is used as the passphrase for unlocking the private SSH key. When password-based authentication is used, the supplied password is used as the device password. If SSH public key-based authentication is being used and the SSH private key has an empty passphrase, then a password is not required. However, SSH private keys with empty passphrases are not recommended. To retrieve a password for password-based authentication or password-protected SSH keys, you can prompt for the password from the playbook or command-line, or you can create a vault-encrypted data file that securely stores the password.

You can specify connection and authentication parameters for the Juniper Networks modules in the following ways. If you do not explicitly define the values, default values are used in some cases, as described in Understanding the Default Values for Juniper Networks Modules. If you define a parameter’s value in multiple places, Ansible selects the value based on variable precedence, as outlined in Understanding variable precedence in the official Ansible docs.

  • Ansible variables—You can specify the connection and authentication parameter values by using normal Ansible variables, for example, variables defined in inventory or vault files, in host or group variables, or using command-line options.

  • SSH client configuration file—For SSH connections, the Juniper Networks modules automatically query the default SSH configuration file at ~/.ssh/config, if one exists, unless you define the ssh_config option to specify a different configuration file. The modules use any relevant settings in the SSH configuration file for the given connection, unless you explicitly define variables that override the setting.

  • Module arguments—The juniper.device and Juniper.junos modules support specifying connection and authentication-related options for local connections (connection: local) as top-level module arguments. Additionally, Juniper.junos modules support using a provider dictionary in the module arguments as described in How to Define the provider Parameter in Juniper.junos Modules.

  • vars: section—The juniper.device modules support specifying connection and authentication-related options for local and persistent connections in a play’s vars: section, which is described in How to Define Authentication Parameters in the vars: Section for Local and Persistent Connections.

This document discusses the different aspects of authentication when using the Juniper Networks modules to manage devices running Junos OS.

Understanding the Default Values for Juniper Networks Modules

You can explicitly define the connection and authentication parameters for modules that manage devices running Junos OS. If you do not define a parameter, the module uses a default value in some cases. Table 1 outlines the default values and variable precedence for common connection parameters for modules in the juniper.device collection and Juniper.junos role. For information about the arguments accepted for the individual modules, see the API reference documentation for that module.

Table 1: Default Values and Variable Precedence for Connection Parameters

Parameter Name

Parameter Aliases

Description

Default Value and Variable Precedence

host

hostname

ip

Hostname or IP address of the remote device with which the connection should be established.

{{ inventory_hostname }}

passwd

password

The user’s password or SSH key passphrase used to authenticate with the managed device.

  1. ANSIBLE_NET_PASSWORD environment variable

  2. Value specified for -k or --ask-pass command-line option

ssh_config

Path to an SSH client configuration file.

If you omit this parameter, the modules uses the SSH configuration file in the default location, if one exists.

~/.ssh/config

ssh_private_key_file

ssh_keyfile

Path to the SSH private key file used to authenticate with the remote device.

If you do not explicitly specify the path and no default value is found, then the module uses the SSH private key file specified in the user’s SSH configuration or the operating-system-specific default.

  1. ANSIBLE_NET_SSH_KEYFILE environment variable

  2. Value specified for --private-key or --key-file command-line option

  3. none

user

username

Username that is used to authenticate with the managed node.

  1. ANSIBLE_NET_USERNAME environment variable

  2. remote_user as defined by Ansible

  3. USER environment variable

When executing Juniper Networks modules, the host argument is always required for a connection. However, you do not have to explicitly specify the host, because it defaults to {{ inventory_hostname }}.

You can execute Juniper Networks modules using any user account that has access to the managed device running Junos OS. When you execute the modules, Junos OS user account access privileges are enforced, and the class configured for the Junos OS user account determines the permissions. If you do not specify a user, the user is set according to the algorithm described for user in Table 1. See the Ansible documentation for the precedence used to define remote_user, which can be defined in a number of ways, including:

  • -u or --user command line option

  • ANSIBLE_REMOTE_USER environment variable

  • remote_user configuration setting

How to Define Authentication Parameters in the vars: Section for Local and Persistent Connections

You can define connection and authentication parameters for the juniper.device modules in the play’s vars: section, in addition to defining them as you normally would through other variables, for example, in the SSH configuration file, in the Ansible inventory file, as command-line arguments, or as module arguments. The vars: section enables you to define common connection parameters in a single location that all modules in the play can use to connect to a host. Additionally, certain Ansible connections require using the vars: section when you define the parameters within the play, as described here.

The juniper.device modules support the following Ansible connections types:

  • local connections, which are defined by using connection: local

  • persistent connections, which are defined by using connection: juniper.device.pyez

For both local and persistent connections, Ansible executes modules locally on the control node. When you use connection: local, Ansible establishes a separate connection to the host for each task in the play that requires a connection. By contrast, when you use connection: juniper.device.pyez, Ansible establishes a single, persistent connection to a host, which persists over the execution of all tasks in the play.

Note

Ansible has deprecated connection: local. Therefore, when you use the juniper.device collection modules, we recommend that you use connection: juniper.device.pyez in your playbook to avoid issues in the event that Ansible removes support for local connections in a later release.

You use the same connection and authentication parameters for persistent connections as you do for local connections, and the default parameter values discussed in Understanding the Default Values for Juniper Networks Modules apply to both types of connections. However, when you define connection and authentication parameters within a play for persistent connections, you must define the parameters in the vars: section as opposed to defining the parameters as top-level module arguments in each task because there is only a single connection, and thus the parameters must apply to all tasks in that play. For local connections, you can define the parameters either in the vars: section or as module arguments. If you define the parameters in both places, the module arguments take precedence.

The following playbook executes two juniper.device modules on each host in the inventory group. The play defines the Ansible connection as juniper.device.pyez, which establishes a connection to each host that persists over the execution of all tasks in the play. The authentication parameters for the persistent connection are defined within the play’s vars: section. The user and passwd values reference variables defined in the vault-vars.yaml vault file.

How to Define the provider Parameter in Juniper.junos Modules

Starting in Juniper.junos Release 2.0.0, the Juniper.junos modules support the provider parameter in addition to supporting individual top-level module arguments for each of the connection and authentication-related parameters. The provider parameter enables you to define the connection and authentication parameters for multiple modules in one place and easily pass those values to the modules that use them. Additionally, if you need to update the parameters later, you only need to make the update in a single location.

Note

The juniper.device collection modules do not support using the provider parameter.

The provider argument accepts a dictionary that contains the connection details required to connect to and authenticate with a device. The host argument is always required for a connection, but you do not have to explicitly specify a value if the module uses the default value for host. The dictionary can optionally define additional parameters required for the connection, including user, passwd, and ssh_private_key_file, among others. For information about the arguments accepted for the individual modules, see the API reference documentation for that module.

In the following example, the credentials variable is a dictionary that defines the host, user, and passwd parameters:

The following sample playbook uses the single provider argument to pass the connection details to the juniper_junos_facts module instead of defining individual module arguments. As you add additional tasks that use the Juniper.junos modules, you can then reference the same dictionary for each module.

How to Authenticate the User Using SSH Keys

The Juniper Networks juniper.device and Juniper.junos modules enable you to use SSH keys to connect to a device running Junos OS or to a console server that is connected to the device. To authenticate a user using SSH keys, first generate the keys on the Ansible control node and then configure the keys on the device to which the module will connect, either the managed device running Junos OS or the console server connected to the device running Junos OS.

Generating and Configuring the SSH Keys

To generate SSH keys on the Ansible control node and configure the public key on the remote device:

  1. On the Ansible control node, generate the public and private SSH key pair for the desired user, and provide any required options, for example:
  2. (Optional) Load the key into the native SSH key agent. For example:
  3. Configure the public key on each device to which the modules will connect, which could include devices running Junos OS or a console server connected to a device running Junos OS.

    The easiest method to configure the public key on a device running Junos OS is to load a file that contains the public key under the appropriate user account.

  4. Verify that the key works by logging in to the device using the key.

Using SSH Keys in Ansible Playbooks

After generating the SSH key pair and configuring the public key on the remote device, you can use the key to connect to the device. The Juniper Networks modules automatically query the default SSH configuration file at ~/.ssh/config, if one exists, unless you define the ssh_config option to specify a different configuration file. The modules use any relevant settings in the SSH configuration file for the given connection, unless you explicitly define variables that override the setting. In addition, the modules automatically look for keys in the default location and keys that are actively loaded in an SSH key agent.

To define specific settings for SSH keys, you can include the appropriate arguments in your Ansible playbook. Define the arguments in the location appropriate for your set of modules and Ansible connection, for example, in the vars: section for plays that use the juniper.device modules with a persistent connection. The arguments to include are determined by the location of the key, whether the key is actively loaded into an SSH key agent, whether the key is password-protected, and whether the user’s SSH configuration file already defines settings for that host.

  • To connect to a device running Junos OS using SSH keys that are actively loaded into the native SSH key agent or that are in the default location and do not have password protection, you do not need to define any connection or authentication-related arguments, unless they differ from the default.

  • To connect to a device running Junos OS using SSH keys that are not in the default location and do not have password protection, set the ssh_private_key_file argument to the path of the SSH private key file. For example:

    Alternatively, you can specify the path of the SSH private key by defining it in the SSH configuration file; by setting the ANSIBLE_NET_SSH_KEYFILE environment variable; or by defining the --private-key or --key-file command-line option when you execute the playbook.

  • To connect to a device running Junos OS using a password-protected SSH key file, which is the recommended method, you can reference the SSH key file passphrase in the passwd argument or provide the password by using normal Ansible variables or command-line options.

    It is the user's responsibility to obtain the SSH key file passphrase in a secure manner appropriate for their environment. It is best practice to either prompt for it during each invocation of the playbook or store the variables using an encrypted vault rather than storing the credentials in an unencrypted format. For example, you can execute the playbook with the --ask-pass command-line option and provide the SSH key file passphrase when prompted, as shown here:

    [user@localhost]$ ansible-playbook playbook.yaml --ask-pass

    For more information about using a prompt or encrypted vault file for the SSH key passphrase, see How to Authenticate the User Using a Playbook or Command-Line Password Prompt and How to Authenticate the User Using an Ansible Vault-Encrypted File.

For instructions on using SSH keys to connect to a console server, see How to Authenticate Through a Console Server.

How to Authenticate the User Using a Playbook or Command-Line Password Prompt

To authenticate a user executing Ansible modules, you can prompt for the user’s credentials when you execute the playbook. For example, you can define an interactive prompt in the playbook, or you can execute the playbook with the -k or --ask-pass command-line option to prompt for the password. When SSH keys are in use, the supplied password is used as the passphrase for unlocking the private SSH key. When password-based authentication is used, the supplied password is used as the device password.

To define an interactive prompt in the playbook to obtain the user’s password or SSH key passphrase:

  1. Include code under vars_prompt: that prompts for the user’s password or SSH key passphrase (and optionally the username) and stores the value in a variable.
  2. Set the user and passwd parameters so each references its respective variable.
  3. Execute the playbook, which prompts for the username and password and does not echo the password on the command line because the variable is set to private: yes.
    [user@localhost]$ ansible-playbook playbook.yaml

Alternatively, you can execute a playbook with the -k or --ask-pass command-line option to prompt for the password or passphrase. Consider the following playbook, which uses the default username:

Execute the playbook, and include the -k or --ask-pass command-line option, which prompts for the password and does not echo the password on the command line.

[user@localhost]$ ansible-playbook playbook.yaml --ask-pass

How to Authenticate the User Using an Ansible Vault-Encrypted File

You can create an Ansible vault that securely stores saved passwords and other sensitive connection and authentication values in an vault-encrypted data file. Your playbook can then reference those variables in the location appropriate for your set of modules and Ansible connection type, for example, in the play’s vars: section or as module arguments.

To create and use an Ansible vault file containing required variables, including passwords:

  1. Create a vault-encrypted data file, and specify the password required to encrypt, decrypt, edit, and use the data file.
  2. Define the required variables in the file and save it.
  3. Verify that the file is encrypted.
    [root@localhost]# cat vault-vars.yaml
  4. In the playbook, include the vault-encrypted variable file, and reference the required variables in the location appropriate for your modules and Ansible connection type.
    Note

    If you instead define the actual user and passwd variables in the vault, the modules pick them up automatically, and you do not need to explicitly define them in the playbook.

  5. Execute the playbook with the --ask-vault-pass option, which prompts for the vault password.
    [root@localhost]# ansible-playbook playbook-name.yaml --ask-vault-pass

How to Authenticate Through a Console Server

The Juniper Networks Ansible modules can connect to devices running Junos OS through a console server. For SSH connections through a console server, you need to provide the authentication credentials for both the console server and the device running Junos OS. You can provide either a device password or a password-protected SSH key file for the console server authentication.

To connect to a device running Junos OS through a console server, you must provide the following parameters in your playbook, if there is no default value or the default value is not appropriate:

  • host—Console server hostname or IP address

  • user and passwd—Junos OS login credentials

  • cs_user—Console server username

  • cs_passwd—Device password or SSH key file passphrase required to authenticate with the console server

In the following example, the credentials for the Junos OS user and the console server user are defined in an Ansible vault file. The vault variables are then referenced in the playbook. In this case, the cs_passwd argument is the passphrase for the SSH key specified in the ssh_private_key_file argument.