Möchte man mit Ansible seine Cisco Nexus Konfigurationsdaten sichern, sollte man den Gedanken Security nicht außer acht lassen. Welche Anforderungen haben wir also?
- Ansible Nutzer darf auf dem Wirtssystem keine Root Rechte haben
- Ansible Nutzer darf keine Login Shell haben, um Angriffe von Außen zu eliminieren
- Ansible Nutzer muss eine keybasierte Authentifizierung auf unseren Nexus Switches haben
- Ansible Nutzer darf auf unseren Switches nur bestimmte Show Commands ausführen
- Ansible Nutzer muss nach erfolgter Sicherung die Konfiguration in ein GIT Repository schreiben
Auf unserem Linux System sind die folgenden Schritte notwendig. Wir gehen in unserem Beispiel davon aus das die Ansible Directory Struktur sich unterhalb von /opt/ansible befindet.
Anlegen der Keys für unsere Switches. Wir erzeugen für jeden Switch ein eigenes Public/Private Keypair.
mkdir -p /opt/ansible/keys
ssh-keygen -t ed25519 -f /opt/ansible/keys/SW001_ed25519 -C "ansible_backup@SW001"
ssh-keygen -t ed25519 -f /opt/ansible/keys/SW002_ed25519 -C "ansible_backup@SW002"
ssh-keygen -t ed25519 -f /opt/ansible/keys/SW003_ed25519 -C "ansible_backup@SW003"
ssh-keygen -t ed25519 -f /opt/ansible/keys/SW004_ed25519 -C "ansible_backup@SW004"
Cisco IOSXE hat sich ein wenig scheckig wenn es um die Keylänge geht, hier können wir nur mit 1024 Bit Länge arbeiten.
ssh-keygen -t rsa -b 1024 -f /opt/ansible/keys/SW007_ansible_rsa -C "ansible_backup@Ansible-Device"
Anlegen eines Backup User für unseren Ansible Backup Job
useradd -r -m -d /var/lib/ansible_backup -s /usr/sbin/nologin ansible_backup
chown ansible_backup:ansible_backup -R /opt/ansible/*
mkdir -p /opt/ansible/keys
chmod 700 /opt/ansible/keys
/opt/ansible/inventory.cfg
all:
children:
switches:
hosts:
SW001:
ansible_connection: network_cli
ansible_network_os: cisco.nxos.nxos
ansible_host: 192.168.1.11
ansible_user: ansible_backup
ansible_ssh_private_key_file: /opt/ansible/keys/SW001_ansible_ed25519
SW002:
ansible_connection: network_cli
ansible_network_os: cisco.nxos.nxos
ansible_host: 192.168.1.12
ansible_user: ansible_backup
ansible_ssh_private_key_file: /opt/ansible/keys/SW002_ansible_ed25519
SW003:
ansible_connection: network_cli
ansible_network_os: cisco.nxos.nxos
ansible_host: 192.168.1.13
ansible_user: ansible_backup
ansible_ssh_private_key_file: /opt/ansible/keys/SW003_ansible_ed25519
SW004:
ansible_connection: network_cli
ansible_network_os: cisco.nxos.nxos
ansible_host: 192.168.1.14
ansible_user: ansible_backup
ansible_ssh_private_key_file: /opt/ansible/keys/SW004_ansible_ed25519
/opt/ansible/playbooks/netzwerk_backup.yml
---
- name: Backup Nexus Config
hosts: switches
gather_facts: no
vars:
ansible_network_os: cisco.nxos.nxos
ansible_connection: network_cli
backup_dir: /opt/backup-config
backup_timestamp: "{{ lookup('pipe', 'date +%Y%m%d-%H-%M-%S') }}"
backup_keep: 60
tasks:
- name: Backup running config
cisco.nxos.nxos_config:
backup: yes
backup_options:
filename: "{{ inventory_hostname }}.cfg"
dir_path: "/opt/ansible/playbooks/files"
- name: Remove dynamic NX-OS headers from config
ansible.builtin.replace:
path: "/opt/ansible/playbooks/files/{{ inventory_hostname }}.cfg"
regexp: '^!(Time|Running configuration last done at|Last configuration change at|NVRAM config last updated at|Command|Device):.*$'
replace: ''
- name: Check files into Gitea via HTTP + Token
hosts: localhost
vars:
gitea_domain: "192.168.10.30:3000"
repo_name: "konfigurationssicherung"
repo_user: "config"
gitea_token: "1234567890"
repo_url: "http://{{ gitea_domain }}/{{ repo_user }}/{{ repo_name }}.git"
repo_dest: "/opt/backup-config/{{ repo_name }}"
git_branch: "master"
commit_msg: "Automated commit via Ansible"
files_to_add:
- { src: "SW001.cfg", dest: "SW001.cfg" }
- { src: "SW002.cfg", dest: "SW002.cfg" }
- { src: "SW003.cfg", dest: "SW003.cfg" }
- { src: "SW004.cfg", dest: "SW004.cfg" }
tasks:
- name: Ensure git is installed
ansible.builtin.package:
name: git
state: present
- name: Check if Git repo already exists
ansible.builtin.stat:
path: "{{ repo_dest }}/.git"
register: git_repo_present
- name: Clone repo if missing
git:
repo: "{{ repo_url }}"
dest: "{{ repo_dest }}"
version: "{{ git_branch }}"
force: no
when: not git_repo_present.stat.exists
- name: Set git user.name
command: git config user.name "pfconfig"
args:
chdir: "{{ repo_dest }}"
- name: Set git user.email
command: git config user.email "pfconfig@lkosl.local"
args:
chdir: "{{ repo_dest }}"
- name: Copy backup files
copy:
src: "{{ item.src }}"
dest: "{{ repo_dest }}/{{ item.dest }}"
loop: "{{ files_to_add }}"
- name: Git add files
command: git add .
args:
chdir: "{{ repo_dest }}"
- name: Commit changes (if any)
command: git commit -m "Automated commit via Ansible"
args:
chdir: "{{ repo_dest }}"
register: git_commit
failed_when: git_commit.rc != 0 and "'nothing to commit'" not in git_commit.stderr
- name: Ensure branch matches remote
command: git branch -M {{ git_branch }}
args:
chdir: "{{ repo_dest }}"
- name: Ensure origin remote uses token authentication
ansible.builtin.command: >
git remote set-url origin {{ repo_url }}
args:
chdir: "{{ repo_dest }}"
- name: Push changes to Gitea using token header
ansible.builtin.command: >
git -c http.extraHeader="Authorization: Bearer {{ gitea_token }}"
push -u origin {{ git_branch }}
args:
chdir: "{{ repo_dest }}"
Auf unserem Nexus Switch:
! Anlegen einer Rolle mit restriktiven Commands
role name ansible_backup
rule 10 permit command terminal length 0
rule 20 permit command terminal width 511
rule 30 permit command show running-config
rule 40 permit command show version
rule 50 permit command show hostname
rule 60 permit command read
rule 70 permit command show inventory
username ansible_backup password 1234567890 role ansible_backup
username ansible_backup sshkey ssh-dsa ...
Auf unserem IOSXE Switch:
username ansible_backup secret XXXXXXXX
conf t
ip ssh pubkey-chain
username ansible_backup
key-string
ssh-rsa 5AQ5pQCZEopy5ErOUD/fzf1g2BZIPOBqHB18otNLy5uU6lfJCV78agChymfmeP77GrFdXMpewj0fH9EPoPp59FSHmoZeScGqJ+HrmJEgTkp/yU4FNps0uH1YyrOBJdXBEXf90BKva76RUzaM8Cdp8S/dhNk73E365I+zgl6Q== ansible_backup@Ansible-Device
exit
exit
end