As I have been working on some a routed link between IOS-XE and NX-OS component, I have discovered a behaviour I have not been aware of. Imagine a routed point to point link between a NX-OS and IOS-XE router
Here is the configurations referred to:
IOS/IOS-XE:
key chain p2plink
key 1
key-string cisco
!
router ospf 1
area 0 authentication message-digest
!
interface fa1/1
ip ospf authentication key-chain p2plink
NX-OS:
key chain p2plink
key 1
key-string cisco
!
router ospf 1
area 0.0.0.0 authentication message-digest
!
int e1/1
ip ospf authentication key-chain p2plink
This configuration will not result in a successful neighborship. The OSPF neighbours will not form a connection. IOS-XE supports additional cryptographic algorithm. Both operating systems support clear text and MD5 authentication RFC 2328, appendix D But IOS-XE supports additionally the SHA (Secure Hash Algorithm) encryption/authentication which has been described in RFC 5709.
The error message that arrives if you do not specify the encryption algorightm is:
%OSPF-5-NOCRYPTOALG: Key ID 1 in key chain p2plink does not have a cryptographic algorithm
%OSPF-4-NOVALIDKEY: No valid authentication key is available on interface FastEthernet1/1
Out without defining a specific cryptographic algorithm IOS-XE/IOS will not assume a value for it.
key chain p2plink
key 1
key-string cisco
cryptographic-algorithm md5
Defining MD5 as cryptographic algorithm is the only choice if the point to point link is between NX-OS and IOS-XE/IOS.
Verification of the interface configuration:
NX-OS:
NX-OS# sh ip ospf interface e1/1
Ethernet1/1 is up, line protocol is up
IP address 192.0.2.1/30, Process ID 1 VRF default, area 0.0.0.0
Enabled by interface configuration
State P2P, Network type P2P, cost 100
Index 21, Transmit delay 1 sec
1 Neighbors, flooding to 1, adjacent with 1
Timer intervals: Hello 10, Dead 40, Wait 40, Retransmit 5
Hello timer due in 00:00:00
Message-digest authentication, using keychain p2plink (ready)
Number of opaque link LSAs: 0, checksum sum 0
IOS-XE/IOS:
IOS-XE#sh ip ospf interface fa1/1
FastEthernet1/1 is up, line protocol is up (connected)
Internet Address 192.0.2.2/30, Area 0, Attached via Interface Enable
Process ID 1, Router ID 192.0.2.2, Network Type POINT_TO_POINT, Cost: 100
Topology-MTID Cost Disabled Shutdown Topology Name
0 100 no no Base
Enabled by interface config, including secondary ip addresses
Transmit Delay is 1 sec, State POINT_TO_POINT
Timer intervals configured, Hello 10, Dead 40, Wait 40, Retransmit 5
oob-resync timeout 40
Hello due in 00:00:05
Supports Link-local Signaling (LLS)
Cisco NSF helper support enabled
IETF NSF helper support enabled
Index 2/2, flood queue length 0
Next 0x0(0)/0x0(0)
Last flood scan length is 1, maximum is 51
Last flood scan time is 0 msec, maximum is 4 msec
Neighbor Count is 1, Adjacent neighbor count is 1
Adjacent with neighbor 192.0.2.1
Suppress hello for 0 neighbor(s)
Cryptographic authentication enabled
Sending SA: Key 1, Algorithm MD5 - key chain p2plink
NX-OS has no support for SHA algorithms at the day of writing this entry, MD5 is the only option at the momemnt. Following options are available for IOS/IOS-XE:
IOS-XE(config-keychain-key)#cryptographic-algorithm ?
hmac-sha-1 HMAC-SHA-1 authentication algorithm
hmac-sha-256 HMAC-SHA-256 authentication algorithm
hmac-sha-384 HMAC-SHA-384 authentication algorithm
hmac-sha-512 HMAC-SHA-512 authentication algorithm
md5 MD5 authentication algorithm
These are the AFS commands I have to deal from time to time but tend to forget them.
Display quota, size and additional information:
% fs listquota
Volume Name Quota Used %Used Partition
user.larry 1000000 34187 3% 24%
To display quota, current size, and more partition information:
% fs examine /afs/example.com/user/larry
Volume status for vid = 538685364 named user.uninv.larry
Current disk quota is 1000000
Current blocks used are 34187
The partition has 201592443 blocks available out of 263988580
List AFS ACL's for current directory
user@host ~ % fs la .
Access list for . is
Normal rights:
system:administrators rlidwka
system:anyuser l
user rlidwka
List AFS ACL's for ~/public_html directory
fs la ~/public_html
Access list for /afs/example.com/user/larry/public_html is
Normal rights:
system:administrators rlidwka
system:anyuser l
user rlidwka
Find all snmp-server hosts configured in a config repository:
grep "snmp-server host" * | cut -d ":" -f 2- | sort | uniq > bogus
Find all secret4 deprecated hashes in a config:
grep "secret 4" * | cut -d ":" -f -1 | sed "s|-confg||g
grep IP adresses in files, logs, messages etc.:
grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])'
Saving login credentials within ansible playbooks.
There are at least 4 possible methods on howto handle secret data within ansible playbooks.
The first 2 methods have been deprecated with the release of ansible 2.3. However they are still working, also within ansible 2.4 and is the simplest method to authenticate to a network device. The example is self explaining. The credentials are "cisco" and "cisco". I do not need to mention that it is generally a bad idea to save credentials in a plain text file like below. However it might be helpful to start with the simplest authentication method within a playbook.
#
# 01-show-version-simple-auth.yml
#
# As of ansible version 2.3 this method is deprecated
#
- hosts: test
connection: local
tasks:
- name: "Cisco IOS run show version"
ios_command:
commands: show version
username: cisco
password: cisco
The second example is similar to the first. This method is called top-level authentication. The credentials are declared at the top of the playbook. The advantage of this authentication method compared to the first one is, that within a playbook the username and password are defined at the top and stored in a variable called cli. The authentication within the playbook is called with a keyword provider. It is somehow simpler and less prone to error, and the credentials need to be declared only one time.
#
# 02-show-version-top-level-auth.yml
#
# As of ansible version 2.3 this method is deprecated
#
- hosts: staging
connection: local
vars:
cli:
username: cisco
password: cisco
tasks:
- name: "Cisco IOS run show version"
ios_command:
commands: show version
provider: "{{ cli }}"
The third authentication method has been released with ansible 2.4 and is at the time of writing the method that will replace the both that are described above. This is my favourite method of authentication since the authetication credentials are not stored at all. Credentials are called from the command line with the execution of the ansible playbook.
Execution of playbook for the user -u cisco with password -k cisco
ansible-playbook -i hosts show-version.yml -u cisco -k
Execution for the current username echo $USER
ansible-playbook -i hosts show-version.yml -k
#
# 03-show-version-current-auth.yml
#
- hosts: staging
connection: local
tasks:
- name: "Cisco IOS run show version"
ios_command:
commands: show version
The fourth authentication method uses a vault. A ansible vault is a encrypted file where the credentials are stored. A ansible-vault creation works with following command:
ansible-vault create vault.yml
After that the passphrase will be asked. With that passphrase or Vault password access to the file is given.
The content of the unencrypted vault.yml looks like here:
---
username: cisco
password: cisco
The content of the encrypted vault file is following:
# more test.yml
$ANSIBLE_VAULT;1.1;AES256
33643762323531343035333136623235373639316232306666623137323265386337366631353864
3464653430656533353862643438363530613164616336620a393261346530386335386262623233
64363163646538376365643832663333363834383465633135646638643038303330663134303664
3339363161373433390a346365323537383736363265383636663136323930323061643536303230
37303533323766396666643063656565616237373033303737653833393366623537666434373434
6132376365663062343030306462386339303064376365303732
After the vault file with encrypted credentials is stored in a file called vault.yml in the root of the ansible directory, point the playbook to the vault.yml file where credentials username and password are stored. This way one does not need to add an additional command line option while running the playbook. Additionally both credential variables have been aggregated in the var {{ cli }} for further usage. This is the same as described in the top-level authentication file 02-show-version-top-level-auth.yml.
#
# 04-show-version-vault-auth.yml
#
- hosts: staging
connection: local
gather_facts: no
vars_files:
- vault.yml
vars:
cli:
username: "{{ username }}"
password: "{{ password }}"
tasks:
- name: "Cisco IOS run show version"
ios_command:
commands: show version
provider: "{{ cli }}"
Peter Spryada has written a great article about Network device authentication with ansible 2.3, dealing with additional examples available on different networking device platforms, using API or HTTP authentication.