Ansible - Basis oppsett switch

Ansible - Basis oppsett switch


I dette eksempelet så skal vi sette opp standard oppsett for switchene vår med Ansible.
Noen av switchene er konfigurert med å kun tillate telnet.
Oppgaven vår blir å konfigurere switchene med å slå av telnet og sette opp SSH med en aksessliste.

,I dette eksempelet så skal vi sette opp standard oppsett for switchene vår med Ansible.,Noen av switchene er konfigurert med å kun tillate telnet.,Oppgaven vår blir å konfigurere switchene med å slå av telnet og sette opp SSH med en aksessliste.




Det er switch IOS_XE_switch_4 og IOS_switch_1 som har kun telnet aktivert.
Ved kjøre anible -m ping så kan vi bekrefte at vi har kontakt med switchene.

ansible -m ping IOS_XE_switch_3 --ask-vault-password
Vault password: 
IOS_XE_switch_3 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
            

Du kan bekrefte at du ikke kan nå enheten med SSH ved å prøve å kjøre en ad hoc kommando.
ansible -m ios_command -a "commands='show version'" IOS_XE_switch_3 --ask-vault-password
Vault password: 
IOS_XE_switch_3 | FAILED! => {
    "changed": false,
    "msg": "ssh connection failed: ssh connect failed: Connection refused"
            


Jeg oppretter en playbook med formål å konfigurere switchene med SSH.
Her er anible-doc kommandoen fin p bruke for å få mer informasjon om modulen.
ansible-doc ios_command

Det er mange måter å definere hosts i en playbook.
I dette tilfellet så setter jeg hosts som en variabel i playbooken.
---
  - name: Aktivere ssh
    hosts: "{{ telnet_hosts }}"
    gather_facts: no

    tasks:
      - name: Konfigurere ssh
        ansible.netcommon.telnet:
          user: autom8
          password: "{{ ansible_password }}"
          login_prompt: 'Username: '
          prompts:
          - '[>#]'
          command:
            - configure terminal
            - ip ssh version 2
            - ip domain-name autom8.no
            - crypto key generate rsa modulus 4096
            - line vty  0 15
            - transport input ssh
             


ansible-playbook playbook_telnet_ssh_basis_oppsett.yaml --ask-vault-password -e "telnet_hosts=IOS_XE_switch_3"
Vault password: 

PLAY [Aktivere ssh] ********************************************************************************************************************************************************************************************************************

TASK [Konfigurere ssh] *****************************************************************************************************************************************************************************************************************
changed: [IOS_XE_switch_3]

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
IOS_XE_switch_3            : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
              

Jeg kjørere samme playbook mot IOS_switch_1
Jeg kan kjøre playbooken på nytt mot begge switchene for å bekrefte at Telnet er slått av.
ansible-playbook playbook_telnet_ssh_basis_oppsett.yaml --ask-vault-password -e "{"telnet_hosts": ["IOS_XE_switch_3", "IOS_switch_1"]}"
Vault password: 

PLAY [Aktivere ssh] ********************************************************************************************************************************************************************************************************************

TASK [Konfigurere ssh] *****************************************************************************************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ConnectionRefusedError: [Errno 111] Connection refused
fatal: [IOS_XE_switch_3]: FAILED! => {"msg": "Unexpected failure during module execution: [Errno 111] Connection refused", "stdout": ""}
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ConnectionRefusedError: [Errno 111] Connection refused
fatal: [IOS_switch_1]: FAILED! => {"msg": "Unexpected failure during module execution: [Errno 111] Connection refused", "stdout": ""}

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
IOS_XE_switch_3            : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
IOS_switch_1               : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
              

Jeg kan bekrefte at Telnet er slått av ved å kjøre en ad hoc kommando.
ansible -m ios_command -a "commands='show run | inc transport'" IOS_XE_switch_3 --ask-vault-password {
    "changed": false,
    "stdout": [
        "transport input ssh
 transport input ssh
 transport input ssh"
    ],
    "stdout_lines": [
        [
            "transport input ssh",
            " transport input ssh",
            " transport input ssh"
        ]
    ]
}
ansible -m ios_command -a "commands='show run | inc transport'" IOS_switch_1 --ask-vault-password {
    "changed": false,
    "stdout": [
        "transport input ssh
 transport input ssh
 transport input ssh"
    ],
    "stdout_lines": [
        [
            "transport input ssh",
            " transport input ssh",
            " transport input ssh"
        ]
    ]
}
                  

Neste steg er å sette opp en aksessliste for å begrense hvilke IP adresser som kan koble til switchene.
Det er flere måter å gjøre dette på.
Du kan bruke ios_config modulen, ios_acl modulen, ios_command modulen eller jinja2 template.
Jeg kommer til å vise eksempler på flere av disse modulene.
Først så skal jeg vise et eksempel på hvordan du kan bruke ios_config modulen.
Vi forsetter med å sette hosts som en variabel i playbooken.
Planen er at vi skal kunne gjennombruke playbooken på switcher og routere.
Hvis du ikke husker hvilke felt som er nødvendig for ios_config modulen så kan du bruke ansible-doc ios_config.

ios_confg
---
  - name: Basis oppsett
    hosts: "{{ basis_oppsett_hosts }}"
    gather_facts: no

    vars:
      access_list: mgmt_tilgang

    tasks:
      - name: Oppretter standard akksess liste for ssh tilgang
        ios_config:
          lines:
            - "ip access-list standard {{ access_list }}"
      
      - name: Legger til IP adresser på aksessliste
        ios_config:
          lines:
            - permit 10.0.0.0 0.0.0.255
          parents: "ip access-list standard {{ access_list }}"
          
                   


ansible-playbook playbook_basis_oppsett.yaml --ask-vault-password -e "basis_oppsett_hosts=IOS_switch_1"
Vault password: 

PLAY [Basis oppsett] *******************************************************************************************************************************************************************************************************************

TASK [Oppretter standard akksess liste for ssh tilgang] ********************************************************************************************************************************************************************************
changed: [IOS_switch_1]

TASK [Legger til IP adresser på aksessliste] *******************************************************************************************************************************************************************************************
changed: [IOS_switch_1]

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
IOS_switch_1               : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
                   

Jeg kan kjøre samme playbook mot gruppen switcher
ansible-playbook playbook_basis_oppsett.yaml --ask-vault-password -e "basis_oppsett_hosts=switcher"
Vault password: 

PLAY [Basis oppsett] *******************************************************************************************************************************************************************************************************************

TASK [Oppretter standard akksess liste for ssh tilgang] ********************************************************************************************************************************************************************************
[WARNING]: To ensure idempotency and correct diff the input configuration lines should be similar to how they appear if present in the running configuration on device
changed: [IOS_XE_switch_3]
changed: [IOS_switch_2]
changed: [IOS_XE_switch_4]
ok: [IOS_switch_1]

TASK [Legger til IP adresser på aksessliste] *******************************************************************************************************************************************************************************************
ok: [IOS_switch_1]
changed: [IOS_XE_switch_3]
changed: [IOS_XE_switch_4]
changed: [IOS_switch_2]

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
IOS_XE_switch_3            : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_XE_switch_4            : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_switch_1               : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_switch_2               : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
                   

Hvis du kjører playbooken en gang til så vil du se at IOS XE switchene fortsatt får 1 changed.
Aksess listen har en litt annerledes utsende i running config.
For å tilpass dette så kunne vi brukt ios_facts modulen for å hente ut hvilken type switch vi har.
Vi har allerede fordelt dem inn i grupper i inventory filen.
Så vi legger til en when: statement for å kjøre permit kommandoen litt forskjellig for IOS og IOS XE i playbooken.

---
  - name: Basis oppsett
    hosts: "{{ basis_oppsett_hosts }}"
    gather_facts: no

    vars:
      access_list: mgmt_tilgang

    tasks:
      - name: Oppretter standard akksess liste for ssh tilgang
        ios_config:
          lines:
            - "ip access-list standard {{ access_list }}"
      
      - name: Legger til IP adresser på aksessliste
        ios_config:
          lines:
            - permit 10.0.0.0 0.0.0.255
          parents: "ip access-list standard {{ access_list }}"
        when: "'IOS_switcher' in group_names" 

      - name: Legger til IP adresser på aksessliste
        ios_config:
          lines:
            - 10 permit 10.0.0.0 0.0.0.255
          parents: "ip access-list standard {{ access_list }}"
        when: "'IOS_XE_switcher' in group_names"  
                     

Jeg kan kjøre samme playbook mot gruppen switcher uten at noen står til changed.
ansible-playbook playbook_basis_oppsett.yaml --ask-vault-password -e "basis_oppsett_hosts=switcher"
Vault password: 

PLAY [Basis oppsett] *******************************************************************************************************************************************************************************************************************

TASK [Oppretter standard akksess liste for ssh tilgang] ********************************************************************************************************************************************************************************
ok: [IOS_XE_switch_3]
ok: [IOS_switch_2]
ok: [IOS_switch_1]
ok: [IOS_XE_switch_4]

TASK [Legger til IP adresser på aksessliste] *******************************************************************************************************************************************************************************************
skipping: [IOS_XE_switch_3]
skipping: [IOS_XE_switch_4]
ok: [IOS_switch_2]
ok: [IOS_switch_1]

TASK [Legger til IP adresser på aksessliste] *******************************************************************************************************************************************************************************************
skipping: [IOS_switch_1]
skipping: [IOS_switch_2]
ok: [IOS_XE_switch_3]
ok: [IOS_XE_switch_4]

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
IOS_XE_switch_3            : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
IOS_XE_switch_4            : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
IOS_switch_1               : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
IOS_switch_2               : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
                            

Hvordan blir dette hvis vi bruker ios_acl modulen?
vars:
  access_list: mgmt_tilgang
  access_list_ios_acls: ios_acls_mgmt_tilgang_acl
  - name: aksessliste med ios_acls
    tags: acl
    ios_acls:
      config:
        - afi: ipv4
          acls:
            - name: "{{ access_list_ios_acls }}"
              acl_type: standard
              aces:
                - grant: permit
                  source:
                    address: 10.100.100.1
                - grant: permit
                  source:
                    address: 10.0.0.0
                    wildcard_bits: 0.0.0.255
      state: merged
                             

Aksesslisten blir opprettet på samme måte som med ios_config modulen.
ios_acl modulen gir ikke noe direkt fordel med tanke på at tasken blir kjørt gang på gang og vi får en changed.

Hvordan blir det jinja2 templates?
vars:
      access_list_jinja2: jinja2_mgmt_tilgang_acl
      acl_list:
        - 10.0.0.0 0.0.0.255
        - 10.0.1.0 0.0.0.255

      - name: opprette aksessliste med jinja2
        tags: acl_jinja2
        ios_config:
          src: "acl.j2"
          match: line
                               

jinja2 template
ip access-list standard {{ access_list_jinja2 }}"
{% for acl in acl_list %}
 permit {{ acl }}
{% endfor %}
                                 

For IOS enhetene fungerer dette veldig bra.
Men for IOS-XE enhetene så bruker den nummereringen på aksesslisten som en del av navnet.
Som gjør at vi får en changed hver gang vi kjører playbooken.
Ved å endre jinja2 template så kan vi få dette til å fungere.
ip access-list standard {{ access_list_jinja2 }}"
{% for acl in acl_list %}
 {{ 10 + loop.index0 * 10 }} permit {{ acl }}
{% endfor %}
                                 

Dette løser problemet med at aksesslisten blir opprettet på nytt hver gang vi kjører playbooken for IOS-XE.
Da har vi samme problem med IOS enhetene.
Vi kan løse dette ved å legge til when statement i jinja2 templaten.
Jinja 2 templates gir oss mulighet til å lage mer dynamiske konfigurasjoner.
Så jeg syns jinja2 templates er beste løsning for å opprette aksesslister.
Ved å justere jinja2 template til å ta hensyn til group_names kan vi få en løsning som fungerer for både IOS og IOS-XE enheter.

ip access-list standard {{ access_list_jinja2 }}"
{% if 'IOS_XE_switcher' in group_names %}
{% for acl in acl_list %}
 {{ 10 + loop.index0 * 10 }} permit {{ acl }}
{% endfor %}
{% endif %}
{% if 'IOS_switcher' in group_names %}
{% for acl in acl_list %}
  permit {{ acl }}
{% endfor %}
{% endif %}
                                 

ansible-playbook playbook_basis_oppsett.yaml --ask-vault-password -t acl_jinja2 -e "basis_oppsett_hosts=switcher"
Vault password: 

PLAY [Basis oppsett] *************************************************************************************************************************************************************************************************

TASK [opprette aksessliste med jinja2] *******************************************************************************************************************************************************************************
ok: [IOS_XE_switch_3]
ok: [IOS_switch_1]
ok: [IOS_switch_2]
ok: [IOS_XE_switch_4]

PLAY RECAP ***********************************************************************************************************************************************************************************************************
IOS_XE_switch_3            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_XE_switch_4            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_switch_1               : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_switch_2               : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
                                 

Siste del av oppgaven er å sette aksesslisten på VTY linjene.
Vi får da samme problem som med aksesslisten.
Vi kan løse dette på samme måte.
ip access-list standard {{ access_list_jinja2 }}"
{% if 'IOS_XE_switcher' in group_names %}
{% for acl in acl_list %}
 {{ 10 + loop.index0 * 10 }} permit {{ acl }}
{% endfor %}
{% endif %}
{% if 'IOS_switcher' in group_names %}
{% for acl in acl_list %}
  permit {{ acl }}
{% endfor %}
{% endif %}
{% if 'IOS_XE_switcher' in group_names %}
line vty 0 3
 transport input ssh
 access-class {{ access_list_jinja2 }} in
line vty 4
 transport input ssh
 access-class {{ access_list_jinja2 }} in
line vty 5 15
 transport input ssh
 access-class {{ access_list_jinja2 }} in
{% endif %}
{% if 'IOS_switcher' in group_names %}
line vty 0 2
 transport input ssh
 access-class {{ access_list_jinja2 }} in
line vty 3 4
 transport input ssh
 access-class {{ access_list_jinja2 }} in
line vty 5 15
 transport input ssh
 access-class {{ access_list_jinja2 }} in
{% endif %}
                                    

ansible-playbook playbook_basis_oppsett.yaml --ask-vault-password -t acl_jinja2 -e "basis_oppsett_hosts=switcher" 
Vault password: 

PLAY [Basis oppsett] *************************************************************************************************************************************************************************************************

TASK [opprette aksessliste med jinja2] *******************************************************************************************************************************************************************************
ok: [IOS_XE_switch_3]
ok: [IOS_switch_1]
ok: [IOS_switch_2]
ok: [IOS_XE_switch_4]

PLAY RECAP ***********************************************************************************************************************************************************************************************************
IOS_XE_switch_3            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_XE_switch_4            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_switch_1               : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
IOS_switch_2               : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0