Some time ago I wrote about my first venture into creating Jinja2 switch templates for FreeZTP. This is a follow up to that post after having an opportunity to revisit the process for another project.

As before, I built this template with the intent of keeping the process as simple and unbreakable as possible for the intended end-users. There's still a bit of lifting going on in the template by design, which may not be everyone's cup of tea; but this was largely an exercise in figuring out what I could accomplish in the template, without having to manually intervene, whether it be via python, console, or otherwise.

Considerations

FreeZTP is configured to use external keystore and template files, which serves to keep the code and other sensitive template information somewhat concealed; i.e. out of reach from those needing to modify the keystore CSV file.

I typically create a Git repo to store the template and keystore files (on a private server). This allows me to maintain the files whether I'm at my office, on site using a local workstation, or remotely connected to a jumpbox. For this example, I created a public repo on Github which I cloned to /var/git/jinja2-switch-templating on the server running FreeZTP.

ztp set external-keystore ASW type csv
ztp set external-keystore ASW file '/var/git/j2-switch-template/keystore/ks_asw.csv'
ztp set external-template ASW file '/var/git/j2-switch-template/template/tmpl_asw.j2'

The keystore CSV file has minimal headings and content; keystore_id which is the hostname, association which is the template, and idarray_1 which is the switch serial number.

keystore_id,association,idarray_1
ASW-001,ASW,FOC11111111

What's New?

Refactoring: I have refactored the template code and used whitespace control to make the template read better; note the - in the {% set %} blocks, this makes template merges prettier, or easier to read.

Includes: {% include %} is being used so there can be one workhorse template file that contains code and variables which then calls on, or includes, other templates containing static configuration items such as banners and other base configs. This makes working on the code and variables in the workhorse template file much easier, with a side benefit of having sub-templates that can be reused in other projects as long as they don't contain any client-sensitive or proprietary configuration data.

Debug: If the debug flag at the top of the template is set to 1 then the config section of template, including the {% include %} templates, will be ommitted from the merge that FreeZTP does when called upon. This is primarily used to validate the Static and Dynamic variable sections of the workhorse template during development, using ztp request merge-test commands.

The Template

The workhorse template file is broken into four sections; Header, Static Variables, Dynamic Variables, and then the Config section.

The header contains a few variables that are used later in the template.

  • debug was explained in the Optionals section.
  • tmpl stores the name and revision of the template file which is then used for the snmp-server contact configuration. This is simply a way to reference how a switch was configured if issues arise that require troubleshooting or further revisions later.
  • indent is used to format the printing of dictionaries/lists within the static/dynamic variable sections for validation.
  • z is used in the config section to print out {!UNDEFINED!} during a merge-test if a variable is not yet set; another nice-to-have for validating the template code.
{# Setting DEBUG to '1' will omit the template from output for merge-tests. -#}
{% set debug = '0' -%}
{% set tmpl = {'file': 'tmpl_asw.j2',
               'rev': '20210906.1'} -%}
{% set indent = '\n!' ~ ' ' * 23 -%}
{% set z = '{!UNDEFINED!}' -%}
!-- Author:   DS
!-- Template: {{ '%s (rev: %s)'|format(tmpl.file, tmpl.rev) }}
!

Static Variables

These define variables that I didn't want to store in the CSV; e.g. protocol secrets/keys, syslog server addresses, and other things that the template will use.

The code on the left side is defining variables and the text on the right simply prints out the variable name and its value. This is useful when running ztp request merge-test commands to validate the template.

!-- ****************************************************** STATIC VARS ***** --!
!
!-- Static variables parsed from CSV keystore.
!
!---- KEYSTORE_ID     > {{ keystore_id }}
!---- ASSOCIATION     > {{ association }}
!---- IDARRAY_1       > {{ idarray_1 }}
!
!-- Static variables defined within the template.
!{# {% set VARIABLE = 'VALUE' %}         <<< set | print >>>                    !---- VARIABLE          {{ VARIABLE }}   #}
{% set tftp_addr = '172.17.251.251' -%}                                         !---- TFTP_ADDR       > {{ tftp_addr }}
{% set domain = 'domain.lan' -%}                                                !---- DOMAIN          > {{ domain }}
{% set stp_priority = '61440' -%}                                               !---- STP_PRIORITY    > {{ stp_priority }}
{% set enable_sec = '3n4b13' -%}                                                !---- ENABLE_SEC      > {{ enable_sec }}
{% set root_dir = '/var/git/jinja2-switch-templating/template/' -%}             !---- ROOT_DIR        > {{ root_dir }}
{% set radius_key = 'r4d1u5' -%}                                                !---- RADIUS_KEY      > {{ radius_key }}
{% set includes = 'banner.j2',
                  'interfaces.j2',
                  'ios-base.j2' -%}                                             !---- [INCLUDES]      > {{ includes|sort }}
{% set syslog_addr = '10.1.253.201',
                     '10.1.253.202' -%}                                         !---- [SYSLOG_ADDR]   > {{ syslog_addr|sort }}
{% set image = {'file': 'c2960x-universalk9-mz.152-4.E8.bin',
                'ver': '15.2(4)E8'} -%}                                         !---- (IMAGE)         > {{ image|dictsort|join(indent) }}
{% set vty_acl = {'10': '10.1.10.0 0.0.0.255',
                  '20': '10.1.253.0 0.0.0.255'} -%}                             !---- (VTY_ACL)       > {{ vty_acl|dictsort|join(indent) }}
{% set snmp_acl = {'10': '10.1.253.0 0.0.0.255'} -%}                            !---- (SNMP_ACL)      > {{ snmp_acl|dictsort|join(indent) }}
{% set snmp = {'comm': 'ESENEMPEE',
               'priv': 'ro'} -%}                                                !---- (SNMP)          > {{ snmp|dictsort|join(indent) }}
{% set snmpv3 = {'grp': 'SNMP_ASW',
                 'user': 'snmp_asw',
                 'auth': '5nmp4u7h',
                 'priv': '5nmppr1v'} -%}                                        !---- (SNMPV3)        > {{ snmpv3|dictsort|join(indent) }}
{% set creds = {'localadmin': 'p455w0rd'} -%}                                   !---- (CREDS)         > {{ creds|dictsort|join(indent) }}
{% set ntp_addr = {'pri': '10.1.253.11',
                   'sec': '10.1.253.12'} -%}                                    !---- (NTP_ADDR)      > {{ ntp_addr|dictsort|join(indent) }}
{% set mgmt = {'net': '10.1.252',
               'mask': '255.255.255.0'} -%}                                     !---- (MGMT)          > {{ mgmt|dictsort|join(indent) }}
{% set vlan = {'native': {'id': '999', 'name': 'NATIVE'},
               'mgmt': {'id': '252', 'name': 'MGMT'}} -%}                       !---- (VLAN)          > {{ vlan|dictsort|join(indent) }}
!

Dynamic Variables

These assign dynamic values to variables based on information pulled in from the keystore and static variables.

!-- Dynamic variables based on static and CSV keystore variables.
!
{# Copy HOSTNAME and SW from KEYSTORE_ID and SERIAL from IDARRAY_1.  -#}
{% set hostname = keystore_id -%}                                               !---- HOSTNAME        > {{ hostname }}
{% set sw = hostname.split('-')[1] -%}                                          !---- SW              > {{ sw }}
{% set serial = idarray_1 -%}                                                   !---- SERIAL          > {{ serial }}
!
{# Create VLAN.MGMT.IP and VLAN.MGMT.ROUTE from MGMT.NET, MGMT.MASK, and SW. -#}
{% set x = vlan.mgmt.update({'mask': mgmt.mask,
                             'ip': '%s.%s'|format(mgmt.net, sw),
                             'route': '%s.1'|format(mgmt.net)}) -%}             !---- (VLAN.MGMT)     > {{ vlan.mgmt|dictsort|join(indent) }}
!
{# Create VLAN_LIST from [VLAN]. -#}
{% set vlan_list=[] -%}
{% for key, vl in vlan|dictsort -%}
{%   set vlan_list=vlan_list.append(vl.id or z) -%}
{% endfor -%}
{% set vlan_list=vlan_list|sort|join(',') -%}                                   !---- VLAN_LIST       > {{ vlan_list }}
!

Config

The config section contains two things; first the config lines that depend on the static and dynamic variables, and then a for loop to bring in the aforementioned included static templates.

{% if debug == '0' -%}
!-- ********************************* CONFIG INCLUDED, DEBUG DISABLED ***** -- !
!
hostname {{ hostname or z }}
ip domain-name {{ domain or z }}
!
spanning-tree vlan 1-4094 priority {{ stp_priority or z }}
!
enable secret 0 {{ enable_sec or z }}
!
{% for cred, secret in creds|dictsort -%}
username {{ cred or z }} privilege 15 secret 0 {{ secret or z }}
{% endfor -%}
!
{% for key, vl in vlan|dictsort -%}
vlan {{ vl.id or z }}
 name {{ vl.name or z }}
{% endfor -%}
!
ip access-list extended VTY
{% for seq, net in vty_acl|dictsort -%}
 {{ seq or z }} permit tcp {{ net or z }} any eq 22
{% endfor -%}
 998 deny tcp any any eq 23 log
 999 deny tcp any any eq 22 log
!
line vty 0 15
 access-class VTY in
!
ip access-list standard SNMP
{% for seq, net in snmp_acl|dictsort -%}
 {{ seq or z }} permit {{ net or z }}
{% endfor -%}
 999 deny any
!
snmp-server community {{ snmp.comm or z }} {{ snmp.priv or z }} SNMP
snmp-server group {{ snmpv3.grp or z }} v3 priv
snmp-server user {{ snmpv3.user or z }} {{ 
                    snmpv3.grp or z }} v3 auth sha {{ 
                    snmpv3.auth or z }} priv aes 256 {{ 
                    snmpv3.priv or z }} access SNMP
snmp-server contact Provisioned with switch template: {{ '%s (Rev: %s)' | 
                                                         format(tmpl.file or z, 
                                                                tmpl.rev or z) }}
!
interface Vlan{{ vlan.mgmt.id or z }}
 description {{ vlan.mgmt.name or z }}
 no ip redirects
 no ip proxy-arp
 ip address {{ vlan.mgmt.ip or z }} {{ vlan.mgmt.mask or z }}
 no shutdown
!
ip default-gateway {{ vlan.mgmt.route or z }}
!
ip tftp source-interface Vlan{{ vlan.mgmt.id or z }}
logging source-interface Vlan{{ vlan.mgmt.id or z }}
!
{% for host in syslog_addr|sort -%}
logging host {{ host or z }}
{% endfor -%}
!
{% for key, host in ntp_addr|dictsort -%}
ntp server {{ host or z }}{{ ' prefer' if key == 'pri' }} source Vlan{{ vlan.mgmt.id or z }}
{% endfor -%}
!
!-- V V V V V V V V V V V V V V V V V V V V V V V V V V V V V INCLUDES V V V --!
{% for tmpl in includes -%}
!-- V V V V V V V V V V V V V V V V V V V V V V V V V V V V V {{ tmpl }}
{%  include root_dir ~ tmpl %}
{% endfor -%}
end
{% else -%}
!-- ********************************** CONFIG OMMITTED, DEBUG ENABLED ***** -- !
{% endif -%}

Merged Config

Below is the merged config in two scenarios; first with debug enabled at the template level, and then the full template without debug.

Debug Enabled

With debug enabled, only the following sections of the main workhorse template (tmpl_asx.j2) are merged: Header, Static Variables, Dynamic Variables.

Expand for merge with template debug enabled.
[root@freeztp jinja2-switch-templating]# ztp request merge-test FOC11111111
2021-09-07 19:24:06:   cfact.get_keystore_id: Checking Keystores and IDArrays for (FOC11111111)

2021-09-07 19:24:06:   cfact.get_keystore_id: Checking Keystore names for (FOC11111111)

2021-09-07 19:24:06:   cfact.get_keystore_id: ID (FOC11111111) not found in keystore names, checking local IDArrays

2021-09-07 19:24:06:   cfact.get_keystore_id: ID (FOC11111111) not found in local IDArrays, checking external Keystore names

2021-09-07 19:24:06:   cfact.get_keystore_id: ID (FOC11111111) not found in external Keystore names, checking external IDArrays

2021-09-07 19:24:06:   cfact.get_keystore_id: ID 'FOC11111111' resolved to arrayname 'ASW-001' in an external-keystore

2021-09-07 19:24:06:   cfact.get_template: Looking up association for identity (ASW-001)

2021-09-07 19:24:06:   cfact.get_template: Found associated template (ASW) in an external keystore

2021-09-07 19:24:06:   cfact.get_template: Template (ASW) exists as an external-template. Returning

2021-09-07 19:24:06:   cfact.pull_keystore_values: Inserting IDArray keys

2021-09-07 19:24:06:   cfact._global_lookup: Checking if a global-keystore is configured and ready...

2021-09-07 19:24:06:   cfact._global_lookup: Global-keystore configured as none. Discarding

2021-09-07 19:24:06:   cfact.merge_test: Merging with values:
{
    "keystore_id": "ASW-001", 
    "snmpinfo": {
        "WS_C3850_SERIAL_NUMBER": "WS_C3850_SERIAL_NUMBER_FAKESERIAL", 
        "WS_C2960_SERIAL_NUMBER": "WS_C2960_SERIAL_NUMBER_FAKESERIAL", 
        "matched": "FAKEMATCHEDSERIAL"
    }, 
    "idarray_1": "FOC11111111", 
    "association": "ASW", 
    "idarray": [
        "FOC11111111"
    ]
}

##############################
!-- Author:   DS
!-- Template: tmpl_asw.j2 (rev: 20210906.1)
!
!-- ****************************************************** STATIC VARS ***** --!
!
!-- Static variables parsed from CSV keystore.
!
!---- KEYSTORE_ID     > ASW-001
!---- ASSOCIATION     > ASW
!---- IDARRAY_1       > FOC11111111
!
!-- Static variables defined within the template.
!
!---- TFTP_ADDR       > 172.17.251.251
!---- DOMAIN          > domain.lan
!---- STP_PRIORITY    > 61440
!---- ENABLE_SEC      > 3n4b13
!---- ROOT_DIR        > /var/git/jinja2-switch-templating/template/
!---- RADIUS_KEY      > r4d1u5
!---- [INCLUDES]      > ['banner.j2', 'interfaces.j2', 'ios-base.j2']
!---- [SYSLOG_ADDR]   > ['10.1.253.201', '10.1.253.202']
!---- (IMAGE)         > ('file', 'c2960x-universalk9-mz.152-4.E8.bin')
!                       ('ver', '15.2(4)E8')
!---- (VTY_ACL)       > ('10', '10.1.10.0 0.0.0.255')
!                       ('20', '10.1.253.0 0.0.0.255')
!---- (SNMP_ACL)      > ('10', '10.1.253.0 0.0.0.255')
!---- (SNMP)          > ('comm', 'ESENEMPEE')
!                       ('priv', 'ro')
!---- (SNMPV3)        > ('auth', '5nmp4u7h')
!                       ('grp', 'SNMP_ASW')
!                       ('priv', '5nmppr1v')
!                       ('user', 'snmp_asw')
!---- (CREDS)         > ('localadmin', 'p455w0rd')
!---- (NTP_ADDR)      > ('pri', '10.1.253.11')
!                       ('sec', '10.1.253.12')
!---- (MGMT)          > ('mask', '255.255.255.0')
!                       ('net', '10.1.252')
!---- (VLAN)          > ('mgmt', {'id': '252', 'name': 'MGMT'})
!                       ('native', {'id': '999', 'name': 'NATIVE'})
!
!-- ***************************************************** DYNAMIC VARS ***** --!
!
!-- Dynamic variables based on static and CSV keystore variables.
!
!---- HOSTNAME        > ASW-001
!---- SW              > 001
!---- SERIAL          > FOC11111111
!
!---- (VLAN.MGMT)     > ('id', '252')
!                       ('ip', u'10.1.252.001')
!                       ('mask', '255.255.255.0')
!                       ('name', 'MGMT')
!                       ('route', u'10.1.252.1')
!
!---- VLAN_LIST       > 252,999
!
!-- ********************************** CONFIG OMMITTED, DEBUG ENABLED ***** -- !

##############################

Debug Disabled

With debug disabled, the Config section of the main workhorse template (tmpl_asx.j2) is also merged, along with the included templates.

Expand for merge with template debug disabled.
[root@freeztp jinja2-switch-templating]# ztp request merge-test FOC11111111
2021-09-07 19:27:16:   cfact.get_keystore_id: Checking Keystores and IDArrays for (FOC11111111)

2021-09-07 19:27:16:   cfact.get_keystore_id: Checking Keystore names for (FOC11111111)

2021-09-07 19:27:16:   cfact.get_keystore_id: ID (FOC11111111) not found in keystore names, checking local IDArrays

2021-09-07 19:27:16:   cfact.get_keystore_id: ID (FOC11111111) not found in local IDArrays, checking external Keystore names

2021-09-07 19:27:16:   cfact.get_keystore_id: ID (FOC11111111) not found in external Keystore names, checking external IDArrays

2021-09-07 19:27:16:   cfact.get_keystore_id: ID 'FOC11111111' resolved to arrayname 'ASW-001' in an external-keystore

2021-09-07 19:27:16:   cfact.get_template: Looking up association for identity (ASW-001)

2021-09-07 19:27:16:   cfact.get_template: Found associated template (ASW) in an external keystore

2021-09-07 19:27:16:   cfact.get_template: Template (ASW) exists as an external-template. Returning

2021-09-07 19:27:16:   cfact.pull_keystore_values: Inserting IDArray keys

2021-09-07 19:27:16:   cfact._global_lookup: Checking if a global-keystore is configured and ready...

2021-09-07 19:27:16:   cfact._global_lookup: Global-keystore configured as none. Discarding

2021-09-07 19:27:16:   cfact.merge_test: Merging with values:
{
    "keystore_id": "ASW-001", 
    "snmpinfo": {
        "WS_C3850_SERIAL_NUMBER": "WS_C3850_SERIAL_NUMBER_FAKESERIAL", 
        "WS_C2960_SERIAL_NUMBER": "WS_C2960_SERIAL_NUMBER_FAKESERIAL", 
        "matched": "FAKEMATCHEDSERIAL"
    }, 
    "idarray_1": "FOC11111111", 
    "association": "ASW", 
    "idarray": [
        "FOC11111111"
    ]
}

##############################
!-- Author:   DS
!-- Template: tmpl_asw.j2 (rev: 20210906.1)
!
!-- ****************************************************** STATIC VARS ***** --!
!
!-- Static variables parsed from CSV keystore.
!
!---- KEYSTORE_ID     > ASW-001
!---- ASSOCIATION     > ASW
!---- IDARRAY_1       > FOC11111111
!
!-- Static variables defined within the template.
!
!---- TFTP_ADDR       > 172.17.251.251
!---- DOMAIN          > domain.lan
!---- STP_PRIORITY    > 61440
!---- ENABLE_SEC      > 3n4b13
!---- ROOT_DIR        > /var/git/jinja2-switch-templating/template/
!---- RADIUS_KEY      > r4d1u5
!---- [INCLUDES]      > ['banner.j2', 'interfaces.j2', 'ios-base.j2']
!---- [SYSLOG_ADDR]   > ['10.1.253.201', '10.1.253.202']
!---- (IMAGE)         > ('file', 'c2960x-universalk9-mz.152-4.E8.bin')
!                       ('ver', '15.2(4)E8')
!---- (VTY_ACL)       > ('10', '10.1.10.0 0.0.0.255')
!                       ('20', '10.1.253.0 0.0.0.255')
!---- (SNMP_ACL)      > ('10', '10.1.253.0 0.0.0.255')
!---- (SNMP)          > ('comm', 'ESENEMPEE')
!                       ('priv', 'ro')
!---- (SNMPV3)        > ('auth', '5nmp4u7h')
!                       ('grp', 'SNMP_ASW')
!                       ('priv', '5nmppr1v')
!                       ('user', 'snmp_asw')
!---- (CREDS)         > ('localadmin', 'p455w0rd')
!---- (NTP_ADDR)      > ('pri', '10.1.253.11')
!                       ('sec', '10.1.253.12')
!---- (MGMT)          > ('mask', '255.255.255.0')
!                       ('net', '10.1.252')
!---- (VLAN)          > ('mgmt', {'id': '252', 'name': 'MGMT'})
!                       ('native', {'id': '999', 'name': 'NATIVE'})
!
!-- ***************************************************** DYNAMIC VARS ***** --!
!
!-- Dynamic variables based on static and CSV keystore variables.
!
!---- HOSTNAME        > ASW-001
!---- SW              > 001
!---- SERIAL          > FOC11111111
!
!---- (VLAN.MGMT)     > ('id', '252')
!                       ('ip', u'10.1.252.001')
!                       ('mask', '255.255.255.0')
!                       ('name', 'MGMT')
!                       ('route', u'10.1.252.1')
!
!---- VLAN_LIST       > 252,999
!
!-- ********************************* CONFIG INCLUDED, DEBUG DISABLED ***** -- !
!
hostname ASW-001
ip domain-name domain.lan
!
spanning-tree vlan 1-4094 priority 61440
!
enable secret 0 3n4b13
!
username localadmin privilege 15 secret 0 p455w0rd
!
vlan 252
 name MGMT
vlan 999
 name NATIVE
!
ip access-list extended VTY
 10 permit tcp 10.1.10.0 0.0.0.255 any eq 22
 20 permit tcp 10.1.253.0 0.0.0.255 any eq 22
 998 deny tcp any any eq 23 log
 999 deny tcp any any eq 22 log
!
line vty 0 15
 access-class VTY in
!
ip access-list standard SNMP
 10 permit 10.1.253.0 0.0.0.255
 999 deny any
!
snmp-server community ESENEMPEE ro SNMP
snmp-server group SNMP_ASW v3 priv
snmp-server user snmp_asw SNMP_ASW v3 auth sha 5nmp4u7h priv aes 256 5nmppr1v access SNMP
snmp-server contact Provisioned with switch template: tmpl_asw.j2 (Rev: 20210906.1)
!
interface Vlan252
 description MGMT
 no ip redirects
 no ip proxy-arp
 ip address 10.1.252.001 255.255.255.0
 no shutdown
!
ip default-gateway 10.1.252.1
!
ip tftp source-interface Vlan252
logging source-interface Vlan252
!
logging host 10.1.253.201
logging host 10.1.253.202
!
ntp server 10.1.253.11 prefer source Vlan252
ntp server 10.1.253.12 source Vlan252
!
!-- V V V V V V V V V V V V V V V V V V V V V V V V V V V V V INCLUDES V V V --!
!-- V V V V V V V V V V V V V V V V V V V V V V V V V V V V V banner.j2
!-- Template: banner.j2 (rev: 1.00)
!
banner motd @
!-- ------------------------------------------------------------------------ --!
                UNAUTHORIZED ACCESS TO THIS DEVICE IS PROHIBITED

   You must have explicit, authorized permission to access or configure this
   device. Unauthorized attempts and actions to access or use this system may
                   result in civil and/or criminal penalties.

        ALL ACTIVITIES PERFORMED ON THIS DEVICE ARE LOGGED AND MONITORED
!-- ------------------------------------------------------------------------ --!
@
!
!-- V V V V V V V V V V V V V V V V V V V V V V V V V V V V V interfaces.j2
!-- Template: interfaces.j2 (rev: 1.00)
!
interface GigabitEthernet1/0/48
 switchport mode access
 switchport nonegotiate
 spanning-tree portfast
 ip dhcp snooping trust
!
!-- V V V V V V V V V V V V V V V V V V V V V V V V V V V V V ios-base.j2
!-- Template: ios_base.j2 (rev: 1.00)
!
service tcp-keepalives-in
service tcp-keepalives-out
service timestamps debug datetime msec localtime show-timezone year
service timestamps log datetime msec localtime show-timezone year
service password-encryption
service counters max age 5
!
clock timezone PST -8 0
clock summer-time PDT recurring
!
no ip domain lookup
!
logging count
logging buffered 409600 debugging
logging rate-limit 100
logging console debug
!
crypto key generate rsa modulus 2048

!
ip ssh logging events
ip ssh version 2
!
spanning-tree mode rapid-pvst
spanning-tree loopguard default
spanning-tree portfast bpdufilter default
spanning-tree etherchannel guard misconfig
spanning-tree pathcost method long
!
vtp mode transparent
!
file prompt quiet
!
ip dhcp snooping vlan 1-4094
no ip dhcp snooping information option
ip dhcp snooping
!
udld aggressive
!
errdisable recovery cause all
!
mac address-table notification change interval 60
mac address-table notification change history-size 100
mac address-table notification change
mac address-table notification mac-move
mac address-table aging-time 14400
!
alias exec intstat show interf status
alias exec ipint show ip interf br | e una
alias exec ver show ver | i Soft|file
alias exec vlbr show vlan br | i active
alias exec rundiff show arch config diff
!
aaa new-model
!
aaa authentication login default local
aaa authentication login console local
aaa authorization console
aaa authorization exec default local if-authenticated
!
ip tftp blocksize 8192
!
no ip http server
no ip http secure-server
!
line console 0
 login authentication CONSOLE
 logging synchronous
 exec-timeout 15 0
line vty 0 15
 logging synchronous
 exec-timeout 30 0
 transport input ssh
 transport preferred none
!
end

##############################