OSPF authentication between IOS-XE and NX-OS

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
AFS commands

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

Source AFS Documentation

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

Source AFS Documentation

Grep cut sort oneliner

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])'
Ansible credentials management

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.