├── images └── ISE_with_Meraki_in_AWS.png ├── templates ├── resource_template.j2 └── list_of_dicts.j2 ├── .gitignore ├── vars ├── internal_users.yaml ├── repositories.yaml ├── endpoints.yaml ├── main.yaml ├── network_devices.yaml ├── endpoint_groups.yaml └── network_device_groups.yaml ├── tasks ├── ise_initialized.yaml ├── endpoint_group.create.yaml ├── network_device_group.create.yaml ├── repository.create.yaml ├── ise_set_facts.yaml ├── internal_user.create.yaml ├── endpoint.create.yaml ├── radius_probes.yaml ├── ise_apis_enabled.yaml └── network_device.create.yaml ├── ssh_key_pair.yaml ├── LICENSE.txt ├── inventory ├── localhost.yaml └── aws_ec2.yaml ├── ansible.cfg ├── ise_cli_exec.yaml ├── ise_in_aws.vpc.yaml ├── ise_in_aws.ping_vm.yaml ├── ise_in_aws.yaml ├── ise_in_aws.ise.yaml ├── ise.configuration.yaml ├── meraki.show.yaml ├── ise_in_aws.mr_ssids.yaml ├── aws.show.yaml ├── ise_in_aws.vmx.yaml ├── ise_in_aws.terminate.yaml ├── README.md └── files └── ISE-3-1-518.CFT.yaml /images/ISE_with_Meraki_in_AWS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1homas/ISE_with_Meraki_in_AWS/HEAD/images/ISE_with_Meraki_in_AWS.png -------------------------------------------------------------------------------- /templates/resource_template.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # ⓘ This file was automatically generated! 4 | # 5 | {{ resource_name }}: 6 | {{ resources | to_nice_yaml(width=80, indent=2) }} 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Environments 2 | .env 3 | .venv 4 | env/ 5 | venv/ 6 | ENV/ 7 | env.bak/ 8 | venv.bak/ 9 | 10 | 11 | # Hidden Files 12 | .DS_Store 13 | 14 | 15 | # pipenv 16 | Pipfile* 17 | 18 | -------------------------------------------------------------------------------- /vars/internal_users.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # internal_users 4 | # 5 | 6 | identity_group_ids: a1740510-8c01-11e6-996c-525400b48521 # Employee 7 | 8 | internal_users: 9 | - username: charlie 10 | - username: hsingtsu 11 | - username: joff 12 | - username: pavan 13 | - username: thomas 14 | -------------------------------------------------------------------------------- /vars/repositories.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repositories: 3 | - name: FTP 4 | serverName: "{{ lookup('env', 'ISE_REPOSITORY') }}" 5 | protocol: FTP 6 | path: / 7 | userName: "{{ lookup('env', 'ISE_REPOSITORY_USERNAME') }}" 8 | password: "{{ lookup('env', 'ISE_REPOSITORY_PASSWORD') }}" 9 | -------------------------------------------------------------------------------- /tasks/ise_initialized.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Test for ISE Application Server Initialization 4 | # 5 | - name: Wait for ISE App Server (GUI) | {{ inventory_hostname }} 6 | delegate_to: localhost 7 | ansible.builtin.uri: 8 | url: https://{{ ansible_host }}/admin/login.jsp 9 | method: GET 10 | follow_redirects: safe 11 | timeout: 10 12 | validate_certs: no 13 | return_content: no 14 | register: result 15 | until: result.status == 200 16 | retries: 1000 17 | delay: 10 18 | -------------------------------------------------------------------------------- /tasks/endpoint_group.create.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create Endpoint Group | {{ item.name }} 3 | delegate_to: localhost 4 | cisco.ise.endpoint_group: 5 | ise_hostname: "{{ ansible_host }}" 6 | ise_username: "{{ ise_username }}" 7 | ise_password: "{{ ise_password }}" 8 | ise_verify: "{{ ise_verify }}" 9 | state: "{{ item.state | default('present') }}" 10 | name: "{{ item.name }}" 11 | description: "{{ item.description }}" 12 | systemDefined: "{{ item.systemDefined | default('false') }}" 13 | tags: [endpointgroup, endpointgroups, endpoint_group, endpoint_groups] 14 | -------------------------------------------------------------------------------- /tasks/network_device_group.create.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # - name: Show item 3 | # ansible.builtin.debug: var=item 4 | 5 | - name: Create NDG | {{ item.name }} 6 | delegate_to: localhost 7 | cisco.ise.network_device_group: 8 | ise_hostname: "{{ ansible_host }}" 9 | ise_username: "{{ ise_username }}" 10 | ise_password: "{{ ise_password }}" 11 | ise_verify: "{{ ise_verify }}" 12 | ise_debug: "{{ ise_debug }}" 13 | state: "{{ item.state | default('present') }}" 14 | name: "{{ item.name }}" 15 | description: "{{ item.description }}" 16 | othername: "{{ item.othername }}" 17 | tags: [network_device_group, network_device] 18 | -------------------------------------------------------------------------------- /ssh_key_pair.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Requires 4 | # - ssh_keypair_directory (`~/.ssh`) 5 | # - ssh_keypair_name 6 | # 7 | 8 | - name: Check for existing keypair 9 | ansible.builtin.stat: 10 | path: "{{ ssh_keypair_directory }}/{{ ssh_keypair_name }}" 11 | register: keypair_stat 12 | 13 | # - name: Show keypair_stat 14 | # ansible.builtin.debug: var=keypair_stat 15 | 16 | - name: Create and Save New SSH KeyPair 17 | when: not keypair_stat.stat.exists 18 | block: 19 | - name: Create EC2 SSH Key Pair 20 | amazon.aws.ec2_key: 21 | name: "{{ ssh_keypair_name }}" 22 | state: present 23 | register: key_pair 24 | 25 | # - name: Show key_pair 26 | # ansible.builtin.debug: var=key_pair 27 | 28 | - name: Save Private Key Locally 29 | when: key_pair.changed 30 | ansible.builtin.copy: 31 | content: "{{ key_pair.key.private_key }}" 32 | dest: "{{ ssh_keypair_directory }}/{{ ssh_keypair_name }}" 33 | mode: '0400' 34 | 35 | 36 | ... 37 | -------------------------------------------------------------------------------- /tasks/repository.create.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Where repositories is a list of repositories. Example: 4 | # 5 | # - name: FTP 6 | # serverName: 10.10.20.90 7 | # protocol: FTP 8 | # path: / 9 | # userName: ise 10 | # password: C1sco12345 11 | # enablePki: false 12 | 13 | - name: Create Repository | {{ item.protocol }}:{{ item.name }}{{ item.path }} 14 | delegate_to: localhost 15 | cisco.ise.repository: 16 | ise_hostname: "{{ ansible_host }}" 17 | ise_username: "{{ ise_username }}" 18 | ise_password: "{{ ise_password }}" 19 | ise_verify: "{{ ise_verify }}" 20 | ise_debug: "{{ ise_debug }}" 21 | state: "{{ item.state | default('present') }}" 22 | name: "{{ item.name }}" 23 | serverName: "{{ item.serverName }}" 24 | protocol: "{{ item.protocol }}" # CDROM|DISK|FTP|SFTP|HTTP|HTTPS|NFS|TFTP 25 | path: "{{ item.path | default('/') }}" 26 | userName: "{{ item.userName | default('') }}" 27 | password: "{{ item.password | default('') }}" 28 | enablePki: "{{ item.enablePki | default(false) }}" 29 | tags: repository 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Thomas Howard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /inventory/localhost.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ----------------------------------------------------------------------------- 4 | # Verify your inventory: 5 | # ansible-inventory --graph 6 | # ansible-inventory --list 7 | # 8 | # There are two default groups: 9 | # - all : contains every host 10 | # - ungrouped : contains all hosts not belonging to another group 11 | # 12 | # You may create groups based on 13 | # - What : an application, stack or microservice 14 | # - Where : a datacenter, region, local, storage, etc. 15 | # - When : the development stage for prod, test, etc. 16 | # 17 | # For details on creating Ansible inventory files, see 18 | # https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html 19 | # For common patterns for targeting inventory hosts and groups: 20 | # https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html 21 | # ----------------------------------------------------------------------------- 22 | 23 | all: 24 | # 25 | # Ungrouped Hosts - names should be DNS-compatible 26 | # 27 | hosts: 28 | localhost: 29 | ansible_connection: local # deploy playbook to control machine 30 | ansible_host: 127.0.0.1 31 | ise: 32 | 33 | # global vars 34 | vars: 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /tasks/ise_set_facts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Sets facts for ISE in an ise_facts variable 4 | # 5 | # ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ 6 | # 💡 Not used! Must update to account for multiple nodes using ise_nodes 7 | # ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ ⟁ 8 | 9 | - name: Create ise_facts 10 | ansible.builtin.set_fact: 11 | ise_facts: 12 | ise_hostname: "{{ item.private_ip }}" 13 | 14 | # - name: Verify ise_facts 15 | # ansible.builtin.debug: var=ise_facts 16 | 17 | - name: Get ISE Version 18 | delegate_to: localhost 19 | ansible.builtin.uri: 20 | url: "https://{{ item.private_ip }}/ers/config/op/systemconfig/iseversion" 21 | url_username: "{{ ise_username }}" 22 | url_password: "{{ ise_password }}" 23 | headers: 24 | Accept: application/json 25 | validate_certs: "{{ ise_verify }}" 26 | register: result 27 | until: result.status == 200 28 | retries: 10 29 | delay: 10 30 | 31 | # - name: Show Full Version result 32 | # ansible.builtin.debug: var=result 33 | 34 | - name: Set Facts for ISE Version & Patch 35 | loop: "{{ result.json.OperationResult.resultValue }}" 36 | ansible.builtin.set_fact: 37 | ise_facts: "{{ ise_facts | default({}) | combine( { item.name : item.value } ) }}" 38 | 39 | - name: Show ise_facts 40 | ansible.builtin.debug: var=ise_facts 41 | -------------------------------------------------------------------------------- /tasks/internal_user.create.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create ISE Internal User | {{ item.username }} 3 | delegate_to: localhost 4 | vars: 5 | default_identity_groups: a1740510-8c01-11e6-996c-525400b48521 # Employee 6 | cisco.ise.internal_user: 7 | ise_hostname: "{{ ansible_host }}" 8 | ise_username: "{{ ise_username }}" 9 | ise_password: "{{ ise_password }}" 10 | ise_verify: "{{ ise_verify }}" 11 | ise_debug: "{{ ise_debug }}" 12 | state: "{{ item.state | default('present') }}" 13 | name: "{{ item.username }}" 14 | password: "{{ item.password | default('ISEisC00L') }}" 15 | changePassword: "{{ item.changePassword | default(False) }}" 16 | enabled: "{{ item.enabled | default(True) }}" 17 | expiryDateEnabled: "{{ item.expiryDateEnabled | default(False) }}" 18 | passwordIDStore: "{{ item.idStore | default('Internal Users') }}" 19 | identityGroups: "{{ item.identityGroups | default(default_identity_groups) }}" 20 | # ▼▼▼ optional attributes ▼▼▼ 21 | # changePassword: '{{ item.changePassword | default(False) }}' 22 | # passwordIDStore: '{{ item.idStore | default(Internal Users) }}' 23 | # identityGroups: a1740510-8c01-11e6-996c-525400b48521 24 | # customAttributes: 25 | # Created: 26 | # Expired: register: create_users 27 | register: created 28 | tags: 29 | - internal_user 30 | - create 31 | -------------------------------------------------------------------------------- /vars/endpoints.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Endpoints 4 | # 5 | endpoints: 6 | #------------------------------------------------------------------------------ 7 | # Cameras 8 | #------------------------------------------------------------------------------ 9 | 10 | - mac: "11:22:33:44:55:66" 11 | description: Minimal endpoint definition with IEEE 802 MAC format (XX-XX-XX-XX-XX-XX) 12 | 13 | - mac: "C0:FF:EE:EE:CA:FE" 14 | description: Minimal endpoint definition with Colon format (XX:XX:XX:XX:XX:XX) 15 | 16 | - mac: "DEAD.BEEF.CAFE" 17 | description: Minimal required definition with alternative dot-format (XXXX.XXXX.XXXX) 18 | 19 | - mac: "CC:00:FF:FF:EE:EE" 20 | description: Coffee Machine 21 | 22 | - mac: "3141.5926.5358" 23 | description: Raspberry Pi 8-) 24 | 25 | - mac: D8-EB-97-85-F8-C9 26 | endpoint_type: Camera 27 | description: Surveillance Camera 28 | staticGroupAssignment: true 29 | groupId: 3a88eec0-8c00-11e6-996c-525400b48521 # Trendnet-Device 30 | 31 | #------------------------------------------------------------------------------ 32 | # IP Phones 33 | #------------------------------------------------------------------------------ 34 | 35 | - mac: 00-11-BB-EF-EE-66 36 | endpoint_type: IP Phone 37 | description: IP Phone 38 | staticGroupAssignment: true 39 | groupId: 14f5cac0-8c00-11e6-996c-525400b48521 # Cisco-IP-Phone 40 | 41 | #------------------------------------------------------------------------------ 42 | # Printers 43 | #------------------------------------------------------------------------------ 44 | 45 | - mac: 00-00-AA-41-8C-A8 46 | endpoint_type: Printer 47 | description: Printers 48 | staticGroupAssignment: true 49 | groupId: 22c6c780-8c00-11e6-996c-525400b48521 # Epson-Device 50 | 51 | -------------------------------------------------------------------------------- /tasks/endpoint.create.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # - name: Default endpoint group ID 3 | # ansible.builtin.set_fact: 4 | # endpoint_group_default: aa13bb40-8bff-11e6-996c-525400b48521 5 | 6 | - name: Create Endpoint | {{ item.mac }} 7 | delegate_to: localhost 8 | vars: 9 | endpoint_group_default: aa13bb40-8bff-11e6-996c-525400b48521 10 | cisco.ise.endpoint: 11 | ise_hostname: "{{ ansible_host }}" 12 | ise_username: "{{ ise_username }}" 13 | ise_password: "{{ ise_password }}" 14 | ise_verify: "{{ ise_verify }}" 15 | ise_debug: "{{ ise_debug }}" 16 | state: "{{ item.state | default('present') }}" # ['present', 'absent'] 17 | mac: "{{ item.mac }}" 18 | 19 | # ▼▼▼ optional attributes ▼▼▼ 20 | description: "{{ item.description | default(omit, true) }}" # string 21 | 22 | # identityStore: string 23 | # identityStoreId: string 24 | 25 | # portalUser: string 26 | 27 | # Endpoint Group Assignment 28 | groupId: "{{ item.groupId | default( omit ) }}" # UUID 29 | # groupId: "{{ item.groupId | default( endpoint_group_default ) }}" # UUID 30 | 31 | # profileId: "{{ groupId | default('0a9c6890-8c00-11e6-996c-525400b48521') }}" 32 | staticGroupAssignment: "{{ item.staticGroupAssignment | default(false) }}" 33 | 34 | # Endpoint Profile Assignment 35 | staticProfileAssignment: "{{ item.staticProfileAssignment | default(false) }}" 36 | 37 | customAttributes: 38 | customAttributes: "{{ item.customAttributes | default( omit ) }}" 39 | 40 | # MDM Attributes 41 | # mdmAttributes: 42 | # mdmComplianceStatus: true 43 | # mdmEncrypted: true 44 | # mdmEnrolled: true 45 | # mdmIMEI: string 46 | # mdmJailBroken: true 47 | # mdmManufacturer: string 48 | # mdmModel: string 49 | # mdmOS: string 50 | # mdmPhoneNumber: string 51 | # mdmPinlock: true 52 | # mdmReachable: true 53 | # mdmSerial: string 54 | # mdmServerName: string 55 | 56 | # ignore_errors: yes 57 | tags: [create, endpoint, endpoints] 58 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; For all Ansible configuration options, see: 3 | ; https://docs.ansible.com/ansible/latest/reference_appendices/config.html 4 | ; 5 | ; ansible-config view ; show current Ansible configuration file 6 | ; ansible-config dump ; show all Ansible configuration variable values 7 | ; ansible-config list ; show all Ansible configuration variable options 8 | ; ansible-config init --disabled > ansible.cfg ; create Ansible config file 9 | ;------------------------------------------------------------------------------ 10 | [defaults] 11 | enable_plugins = auto, yaml, host_list ; inventory plugins and order used: host_list, script, auto, yaml, ini, toml, community.docker.docker_containers 12 | inventory = inventory/ ; Ansible's host file. Default: /etc/ansible/hosts.yml 13 | interpreter_python = auto_silent ; use `ansible_python_interpreter` to override 14 | 15 | forks = 5 ; Number of concurrent processes executed on client hosts 16 | host_key_checking = false ; automatically add hosts to SSH known_hosts file 17 | # private_key_file = ~/.ssh/id_rsa ; Default SSH private key 18 | 19 | stdout_callback = yaml ; How to display Ansible output: default | minimal | yaml 20 | callbacks_enabled = ansible.posix.profile_tasks ; Show the execution time of each task 21 | ; log_path = ./ansible.log ; Log file. Default: /var/log/ansible.log 22 | 23 | [callback_profile_tasks] 24 | task_output_limit = 100 ; Default: 20 25 | sort_order = none ; { descending (default) | ascending | none } 26 | 27 | ;💡 Increase times to 60s for ISE CLI commands (`show app status ise`) 28 | [persistent_connection] 29 | connect_timeout = 60 ; Time the connection is idle before being destroyed. Default: 30s 30 | command_timeout = 60 ; Time to wait before timing out persistent connection. Default: 30s 31 | 32 | [ssh_connection] 33 | pipelining = False ; performance improvement when enabled however conflicts with `become` 34 | -------------------------------------------------------------------------------- /ise_cli_exec.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | #------------------------------------------------------------------------------ 3 | # Example commands: 4 | # ✅ show version 5 | # ✅ show application status ise 6 | # 🛑 show logging system ade/ADE.log | include patch # patch progress 7 | # 🛑 application reset-passwd ise {{ username }} 8 | # 🛑 configure terminal 9 | # 🛑 service cache enable hosts ttl 300 # enable DNS caching 10 | # 11 | # ISE uses the network_cli Connection Plugin: 12 | # https://docs.ansible.com/ansible/2.9/plugins/connection/network_cli.html 13 | # 14 | # ISE SSH CLI commands uses the cisco.ios Platform Options. 15 | # For details, see 16 | # https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html 17 | # 18 | # network_os: ? # configures the device platform network operating system 19 | # password: "{{ ansible_password }}" # ansible_password, ansible_ssh_pass, ansible_ssh_password 20 | # port: 22 21 | # private_key_file: "{{ ansible_private_key_file }}" 22 | # remote_user: "{{ ansible_user }}" 23 | # terminal_initial_prompt: # single or sequence of prompt patterns to evaluate on initial login 24 | # terminal_initial_answer: 25 | # terminal_inital_prompt_newline: yes 26 | #------------------------------------------------------------------------------ 27 | 28 | - name: ISE CLI Command 29 | hosts: ise 30 | gather_facts: no 31 | vars_files: 32 | - vars/main.yaml 33 | tasks: 34 | - name: ISE CLI Command | {{ cmd }} 35 | vars: 36 | ansible_connection: ansible.netcommon.network_cli 37 | ansible_network_os: cisco.ios.ios 38 | ansible_ssh_user: "{{ lookup('env','ISE_USERNAME') }}" 39 | ansible_ssh_private_key_file: "{{ ssh_keypair_private_key }}" 40 | ansible_become: no 41 | cmd: "{{ lookup('env','cmd') | default('show version', true) }}" 42 | cisco.ios.ios_command: 43 | commands: 44 | - "{{ cmd }}" 45 | - exit # 💡 Always `exit` after commands to prevent hanging sessions 46 | register: out 47 | 48 | - name: Output | {{ cmd }} 49 | when: out is defined and out.stdout | count > 0 50 | ansible.builtin.debug: 51 | msg: 52 | - "{{ out.stdout | replace('\\n\\n','\\n') }}" 53 | -------------------------------------------------------------------------------- /ise_in_aws.vpc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create VPC 3 | amazon.aws.ec2_vpc_net: 4 | state: present 5 | name: "{{ aws_vpc_name }}" 6 | region: "{{ aws_region }}" 7 | cidr_block: "{{ aws_vpc_cidr }}" 8 | tags: 9 | Name: "vpc_{{ project_name }}" 10 | project: "{{ project_name }}" 11 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 12 | register: vpc 13 | 14 | - name: Create an Internet Gateway to connect VPC to Internet 15 | community.aws.ec2_vpc_igw: 16 | state: present 17 | vpc_id: "{{ vpc.vpc.id }}" 18 | tags: 19 | Name: "igw_{{ project_name }}" 20 | project: "{{ project_name }}" 21 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 22 | register: igw 23 | 24 | - name: Create Public_Subnet 25 | amazon.aws.ec2_vpc_subnet: 26 | state: present 27 | vpc_id: "{{ vpc.vpc.id }}" 28 | cidr: "{{ aws_public_subnet_cidr }}" 29 | region: "{{ aws_region }}" 30 | map_public: yes # assigned public IP address by default 31 | tags: 32 | Name: Public_Subnet 33 | project: "{{ project_name }}" 34 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 35 | register: subnet_public 36 | 37 | - name: Create Private_Subnet 38 | amazon.aws.ec2_vpc_subnet: 39 | state: present 40 | vpc_id: "{{ vpc.vpc.id }}" 41 | cidr: "{{ aws_private_subnet_cidr }}" 42 | region: "{{ aws_region }}" 43 | tags: 44 | Name: Private_Subnet 45 | project: "{{ project_name }}" 46 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 47 | register: subnet_private 48 | 49 | - name: Create Public Route Table; Add Route from VPC to Internet Gateway 50 | community.aws.ec2_vpc_route_table: 51 | state: present 52 | vpc_id: "{{ vpc.vpc.id }}" 53 | subnets: 54 | - "{{ subnet_public.subnet.id }}" 55 | routes: 56 | - dest: 0.0.0.0/0 57 | gateway_id: "{{ igw.gateway_id }}" 58 | tags: 59 | Name: RT_Public 60 | project: "{{ project_name }}" 61 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 62 | register: rt_public 63 | 64 | - name: Create Private Route Table 65 | community.aws.ec2_vpc_route_table: 66 | vpc_id: "{{ vpc.vpc.id }}" 67 | subnets: 68 | - "{{ subnet_private.subnet.id }}" 69 | routes: 70 | - dest: 0.0.0.0/0 71 | gateway_id: "{{ igw.gateway_id }}" 72 | # 💡 Update this with other VPN networks after vMX creation! 💡 73 | # - dest: 192.168.0.0/16 74 | # instance_id: "{{ vmx.instance_id }}" 75 | tags: 76 | Name: RT_Private 77 | project: "{{ project_name }}" 78 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 79 | register: rt_private 80 | -------------------------------------------------------------------------------- /vars/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | project_name: ISE_Meraki_AWS # use for tagging VMs and resources 3 | domain_name: trust0.net # your domain for DNS, if any 4 | ntp_server: time.nist.gov 5 | dns_server: 208.67.222.222 # Cisco Umbrella 6 | timezone: America/Los_Angeles 7 | 8 | # 9 | # ISE REST API 10 | # 11 | ise_username: "{{ lookup('env','ISE_USERNAME') }}" 12 | ise_password: "{{ lookup('env','ISE_PASSWORD') }}" 13 | ise_verify: false 14 | ise_debug: false 15 | 16 | radius_secret: "{{ lookup('env','ISE_RADIUS_SECRET') }}" 17 | tacacs_secret: "{{ lookup('env','ISE_TACACS_SECRET') }}" 18 | snmp_secret: "{{ lookup('env','ISE_SNMP_SECRET') }}" 19 | 20 | ssh_keypair_directory: ~/.ssh 21 | ssh_keypair_name: "{{ project_name }}" 22 | ssh_keypair_private_key: "{{ ssh_keypair_directory }}/{{ ssh_keypair_name }}" 23 | 24 | meraki_org_name: "{{ lookup('env','MERAKI_ORG_NAME') }}" # your Meraki Organization 25 | meraki_org_id: "{{ lookup('env','MERAKI_ORG_ID') }}" # your Meraki Organization 26 | meraki_vmx_net_name: "{{ project_name }}" # Meraki vMX network name 27 | meraki_vpn_hub: # Meraki VPN hub to connect vMX into 28 | name: Lab # Network name in Dashboard 29 | cidr: 192.168.128.0/24 # VPN Hub Network CIDR 30 | 31 | # 32 | # AWS VPC 33 | # 34 | aws_region: "{{ lookup('env','AWS_REGION') | default('us-west-1') }}" 35 | aws_vpc_name: "{{ project_name }}" 36 | aws_vpc_cidr: 172.31.0.0/16 37 | aws_public_subnet_cidr: 172.31.1.0/24 38 | aws_private_subnet_cidr: 172.31.2.0/24 39 | 40 | # 41 | # Linux "Ping" VM 42 | # 43 | aws_linux_ami: ami-04b6c97b14c54de18 # us-west-1 Amazon Linux 2 AMI (HVM) 44 | aws_linux_instance_type: t2.micro 45 | pingvm_name: ping 46 | pingvm_private_ip: 172.31.2.111 47 | 48 | # 49 | # vMX Instance 50 | # ⓘ Use c5.large for VMX-S size and c5.xlarge for VMX-L 51 | # 52 | vmx_aws_ami: ami-09db17cd0ae68ce37 # us-west-1 53 | vmx_aws_instance_type: c5.xlarge # c5.large | c5.xlarge 54 | vmx_license_size: large # small (VMX-S) | large (VMX-L) 55 | vmx_name: vMX # Name in AWS 56 | vmx_private_ip: 172.31.1.5 # AWS reserves the first 2 IPs 57 | 58 | # 59 | # Cisco ISE VM(s) 60 | # 61 | # See https://cs.co/ise-aws for AMIs and Instance Types 62 | # 63 | ise_nodes: 64 | - name: ise 65 | # ami: ami-0965fef2e601ad4d0 # us-west-1 ISE 3.1 Patch 1 20211209 66 | # ami: ami-0768dd8e82836d887 # us-west-1 ISE 3.2.0.542 20221103 67 | ami: ami-0c6108f8e0494c81a # us-west-1 ISE 3.3.0.430 20230709 68 | instance_type: t3.xlarge # ISE Eval/Demo size 69 | private_ip: 172.31.2.11 70 | role: Primary 71 | personas: ["Standalone"] # [ "Standalone", "PAN", "MNT", "PSN", "PXG" ] 72 | # - name: ise-span 73 | # private_ip: 172.31.2.12 74 | # role: Secondary 75 | # personas: [ "PAN", "MNT", "PSN" ] 76 | -------------------------------------------------------------------------------- /tasks/radius_probes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Create RADIUS probes identity groups and internal usernames+passwords 4 | # 5 | 6 | # - name: Create RADIUS_Probes 7 | # hosts: ise_deployment 8 | # vars_files: 9 | # - ../vars/credentials.dCloud.yaml 10 | # gather_facts: no 11 | # tasks: 12 | 13 | - name: Create `RADIUS_Probes` identity group 14 | cisco.ise.identity_group: 15 | ise_hostname: "{{ ansible_host }}" 16 | ise_username: "{{ ise_username }}" 17 | ise_password: "{{ ise_password }}" 18 | ise_verify: "{{ ise_verify }}" 19 | state: present 20 | name: RADIUS_Probes 21 | description: Group for RADIUS probe internal users 22 | parent: NAC Group:NAC:IdentityGroups:User Identity Groups 23 | register: result 24 | 25 | # - name: result 26 | # ansible.builtin.debug: var=result 27 | 28 | - name: Get All Identity Groups 29 | cisco.ise.identity_group_info: 30 | ise_hostname: "{{ ansible_host }}" 31 | ise_username: "{{ ise_username }}" 32 | ise_password: "{{ ise_password }}" 33 | ise_verify: "{{ ise_verify }}" 34 | register: result 35 | 36 | # - name: Result 37 | # ansible.builtin.debug: var=result 38 | 39 | - name: Identity Groups 40 | # when: authorization_profiles is defined and authorization_profiles != [] 41 | delegate_to: localhost 42 | changed_when: false 43 | ansible.builtin.set_fact: 44 | group_list: '{{ result.ise_response 45 | | list 46 | | rejectattr("name", "!=", "RADIUS_Probes") 47 | }}' 48 | 49 | - name: Set RADIUS_Probes identity group ID 50 | ansible.builtin.set_fact: 51 | radius_probes_group_id: "{{ group_list[0].id }}" 52 | 53 | - name: radius_probes_group_id 54 | ansible.builtin.debug: var=radius_probes_group_id 55 | 56 | - name: Internal User Accounts 57 | 58 | vars: 59 | radius_probe_users: 60 | - username: meraki_8021x_test 61 | password: C1sco12345 62 | description: "Cisco Meraki RADIUS Test Probe" 63 | 64 | - username: radius-probe 65 | password: C1sco12345 66 | description: "Cisco RADIUS Test Probe" 67 | 68 | loop: "{{ radius_probe_users }}" 69 | cisco.ise.internal_user: 70 | ise_hostname: "{{ ansible_host }}" 71 | ise_username: "{{ ise_username }}" 72 | ise_password: "{{ ise_password }}" 73 | ise_verify: "{{ ise_verify }}" 74 | state: "{{ item.state | default('present') }}" 75 | name: "{{ item.username }}" 76 | password: "{{ item.password }}" 77 | changePassword: "{{ item.changePassword | default(false) }}" 78 | enabled: "{{ item.enabled | default(true) }}" 79 | expiryDateEnabled: "{{ item.expiryDateEnabled | default(false) }}" 80 | passwordIDStore: Internal Users 81 | identityGroups: "{{ radius_probes_group_id }}" 82 | -------------------------------------------------------------------------------- /tasks/ise_apis_enabled.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Tasks to enable and confirm ISE APIs 4 | # 5 | 6 | - name: Enable ISE OpenAPIs (ISE 3.1+) 7 | delegate_to: localhost 8 | ansible.builtin.uri: 9 | url: "https://{{ ansible_host }}/admin/API/apiService/update" 10 | method: POST 11 | url_username: "{{ ise_username }}" 12 | url_password: "{{ ise_password }}" 13 | force_basic_auth: yes 14 | body: '{ "papIsEnabled":true, "psnsIsEnabled":true }' 15 | status_code: 200,500 16 | body_format: json 17 | validate_certs: "{{ ise_verify }}" 18 | return_content: true 19 | register: response 20 | 21 | - name: Show ISE OpenAPIs Enabled Status 22 | when: (response.status == 200) or (response.status == 500 and response.content.find('already enabled') != -1) 23 | ansible.builtin.debug: 24 | msg: "✅ {{ inventory_hostname }} OpenAPIs Enabled" 25 | 26 | - name: Show ISE OpenAPIs Disabled Status 27 | when: (response.status != 200) and (response.status != 500) 28 | ansible.builtin.debug: 29 | msg: "❌ {{ ansible_host }} OpenAPIs Disabled" 30 | 31 | - name: Get ISE ERS APIs Status 32 | delegate_to: localhost 33 | ansible.builtin.uri: 34 | url: "https://{{ ansible_host }}/admin/API/NetworkAccessConfig/ERS" 35 | method: GET 36 | url_username: "{{ ise_username }}" 37 | url_password: "{{ ise_password }}" 38 | force_basic_auth: yes 39 | headers: 40 | Accept: application/xml 41 | Content-Type: application/xml 42 | status_code: 200 43 | validate_certs: "{{ ise_verify }}" 44 | return_content: true 45 | register: response 46 | 47 | - name: ISE ERS APIs Status 48 | when: response.status == 200 49 | ansible.builtin.debug: 50 | msg: "✅ {{ inventory_hostname }} OpenAPIs Enabled" 51 | 52 | - name: Enable {{ inventory_hostname }} ERS APIs 53 | delegate_to: localhost 54 | ansible.builtin.uri: 55 | url: "https://{{ ansible_host }}/admin/API/NetworkAccessConfig/ERS" 56 | method: PUT 57 | url_username: "{{ ise_username }}" 58 | url_password: "{{ ise_password }}" 59 | force_basic_auth: yes 60 | headers: 61 | Accept: application/xml 62 | Content-Type: application/xml 63 | body: | 64 | 65 | 66 | 1 67 | false 68 | true 69 | true 70 | 71 | status_code: 200 72 | validate_certs: "{{ ise_verify }}" 73 | return_content: true 74 | register: response 75 | 76 | - name: Show {{ inventory_hostname }} ERS Enabled Status 77 | when: response.status == 200 78 | ansible.builtin.debug: 79 | msg: "✅ {{ inventory_hostname }} ERS APIs Enabled" 80 | 81 | - name: Show {{ inventory_hostname }} ERS Disabled Status 82 | when: response.status != 200 83 | ansible.builtin.debug: 84 | msg: "❌ {{ inventory_hostname }} ERS APIs Disabled" 85 | -------------------------------------------------------------------------------- /inventory/aws_ec2.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | #------------------------------------------------------------------------------ 3 | # To use the `aws_ec2` dynamic inventory plugin, add this entry to the 4 | # ansible.cfg file's [defaults] section : 5 | # [defaults] 6 | # inventory=inventory/aws_ec2.yaml 7 | # ⚠ This file must end with `aws_ec2.y[a]ml` 8 | # 9 | # You may verify that it works with the command 10 | # `ansible-inventory --graph [-i inventory/aws_ec2.yaml]` 11 | # 12 | # For more examples, see 13 | # https://docs.ansible.com/ansible/latest/collections/amazon/aws/aws_ec2_inventory.html 14 | #------------------------------------------------------------------------------ 15 | 16 | # plugin: aws_ec2 17 | plugin: amazon.aws.aws_ec2 18 | 19 | # project: aws_s3 20 | 21 | aws_access_key: "{{ lookup('env','AWS_ACCESS_KEY') }}" 22 | aws_secret_key: "{{ lookup('env','AWS_SECRET_KEY') }}" 23 | 24 | # 💡 It takes 10X longer to search all regions if you do not list them explicitly! 25 | regions: 26 | # - eu-north-1 27 | # - ap-south-1 28 | # - eu-west-3 29 | # - eu-west-2 30 | # - eu-west-1 31 | # - ap-northeast-3 32 | # - ap-northeast-2 33 | # - ap-northeast-1 34 | # - sa-east-1 35 | # - ca-central-1 36 | # - ap-southeast-1 37 | # - ap-southeast-2 38 | # - eu-central-1 39 | # - us-east-1 40 | # - us-east-2 41 | - us-west-1 42 | # - us-west-2 43 | 44 | filters: 45 | # instance-state-name: ['running'] 46 | # tag:product: ISE 47 | 48 | strict: False 49 | 50 | keyed_groups: 51 | - key: tags.Name 52 | # prefix: product 53 | separator: "" 54 | - key: instance_type 55 | # prefix: name 56 | separator: "" 57 | # - key: tags 58 | # prefix: tag 59 | # separator: '_' 60 | # - key: tags.Name 61 | # # prefix: name_ 62 | # separator: '' 63 | - key: tags.product # or tags['product'] 64 | prefix: product 65 | separator: "_" 66 | - key: tags.project # or tags['project'] 67 | prefix: project 68 | separator: "_" 69 | - key: placement.region # group per region e.g. aws_region_us_east_2 70 | # prefix: region 71 | separator: "" 72 | - key: placement.availability_zone 73 | # prefix: az 74 | separator: "" 75 | - key: placement.group 76 | # prefix: group 77 | separator: "" 78 | - key: tags.roles 79 | prefix: role 80 | separator: "_" 81 | - key: tags.services 82 | prefix: service 83 | separator: "_" 84 | 85 | # List in order of precedence for hostname variables 86 | hostnames: 87 | - tag:Name 88 | - ip-address 89 | - dns-name 90 | # - private-ip-address 91 | 92 | # Set individual variables with compose 93 | compose: 94 | # ansible_host: public_ip_address # Use private IP address to connect to the host 95 | ansible_host: private_ip_address # Use private IP address to connect to the host 96 | # inventory_hostname: private_ip_address # Use private IP address to connect to the host 97 | # ansible_host: name # Use name to connect to the host 98 | # ansible_host: public_dns_name 99 | -------------------------------------------------------------------------------- /ise_in_aws.ping_vm.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create sg_ping_ssh Security Group 3 | amazon.aws.ec2_group: 4 | name: sg_ping_ssh 5 | description: Allow Ping and SSH to Linux VM 6 | vpc_id: "{{ vpc.vpc.id }}" 7 | region: "{{ aws_region }}" 8 | rules: 9 | - proto: icmp 10 | from_port: -1 11 | to_port: -1 12 | cidr_ip: 0.0.0.0/0 # any 13 | rule_desc: Allow ICMP Ping 14 | - proto: tcp 15 | from_port: 22 16 | to_port: 22 17 | cidr_ip: 0.0.0.0/0 # any 18 | rule_desc: Allow SSH 19 | rules_egress: 20 | - proto: all 21 | cidr_ip: 0.0.0.0/0 # any 22 | tags: 23 | Name: sg_ping_ssh 24 | project: "{{ project_name }}" 25 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 26 | register: sg_ping_ssh 27 | 28 | # 29 | # 💡 Must use the community.aws.ec2_instance module which supports the 30 | # `user_data` field for inclusion of the Meraki vMX Authentication Token! 31 | # 32 | - name: Create Ping_VM 33 | community.aws.ec2_instance: 34 | state: running 35 | name: "{{ pingvm_name }}" 36 | region: "{{ aws_region }}" 37 | vpc_subnet_id: "{{ subnet_private.subnet.id }}" 38 | image_id: "{{ aws_linux_ami }}" 39 | instance_type: "{{ aws_linux_instance_type }}" 40 | key_name: "{{ ssh_keypair_name }}" # SSH Keypair Name 41 | security_group: "{{ sg_ping_ssh.group_name }}" 42 | network: 43 | assign_public_ip: yes 44 | delete_on_termination: yes 45 | private_ip_address: "{{ pingvm_private_ip }}" 46 | volumes: 47 | - device_name: /dev/xvda 48 | ebs: 49 | delete_on_termination: true 50 | volume_size: 10 51 | wait: yes 52 | tags: 53 | Name: "{{ pingvm_name }}" 54 | project: "{{ project_name }}" 55 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 56 | register: ping_vm 57 | 58 | - name: Show SSH Commands for Instance 59 | ansible.builtin.debug: 60 | msg: | 61 |   62 |   _ 63 |   ,--(_) 64 |   _/ ;-._\ ping {{ ping_vm.instances[0].public_ip_address }} 65 |   (_)( ) ) ping {{ ping_vm.instances[0].private_ip_address }} 66 |   \ ;-'_/ ssh -i {{ ssh_keypair_private_key }} ec2-user@{{ ping_vm.instances[0].private_ip_address }} 67 |   `--(_) 68 |   69 |   70 | 71 | # 72 | # Advertise the same internal IP for public and private DNS 73 | # 74 | - name: Add public DNS entry for the PingVM 75 | when: domain_name is defined 76 | community.aws.route53: 77 | state: present 78 | zone: "{{ domain_name }}" 79 | record: "ping.{{ domain_name }}" 80 | overwrite: yes 81 | private_zone: no 82 | type: A 83 | ttl: 7200 84 | value: "{{ pingvm_private_ip }}" 85 | wait: no 86 | 87 | - name: Add private DNS entry for the PingVM 88 | when: domain_name is defined 89 | community.aws.route53: 90 | state: present 91 | zone: "{{ domain_name }}" 92 | record: "ping.{{ domain_name }}" 93 | overwrite: yes 94 | private_zone: yes 95 | type: A 96 | ttl: 7200 97 | value: "{{ pingvm_private_ip }}" 98 | wait: no 99 | -------------------------------------------------------------------------------- /templates/list_of_dicts.j2: -------------------------------------------------------------------------------- 1 | {############################################################################## 2 | Template a table from a list of dicts with auto-sized columns. 3 | Uses all of the columns by default if not specified by `head[]` 4 | Required Variables: 5 | - rows[] : a list of dicts 6 | Optional Variables: 7 | - head[] : the list of columns by name (headers) to show from the rows. 8 | - hide[] : the list of columns to hide by name 9 | - maxw : the maximum width (int) of all columns or they are truncated with '…' 10 | ##############################################################################} 11 | {% if head is undefined %} 12 | {% set head = rows[0] | dict2items | community.general.json_query('[].key') %} 13 | {% endif %} 14 | {############################################################################## 15 | Remove any columns in the `hide` list 16 | Use '_' variable to increase scope beyond if and for blocks! 17 | ##############################################################################} 18 | {% if hide is defined %} 19 | {% for col in hide %} 20 | {% set _ = head.remove(col) %} 21 | {% endfor %} 22 | {% endif %} 23 | {############################################################################## 24 | Set missing column values empty string ('') 25 | ##############################################################################} 26 | {% for row in rows %} 27 | {% for col in head %} 28 | {% set row = row.setdefault(col, '') %} 29 | {% endfor %} 30 | {% endfor %} 31 | {############################################################################## 32 | head_widths{}: the maximum width of each column 33 | - include (union) the header name in case it is longer than the values 34 | - convert to string because booleans have no length 35 | ##############################################################################} 36 | {% set head_widths = dict() %} 37 | {% for col in head %} 38 | {% set head_widths = head_widths.update( { col : rows | map(attribute=col) | union([col]) | map('string') | map('length') | max } ) %} 39 | {% endfor %} 40 | {############################################################################## 41 | Ensure column widths do not exceed the max column width (maxw) 42 | ##############################################################################} 43 | {% if maxw is undefined %} 44 | {% set maxw = 255 %} 45 | {% endif %} 46 | {% for key in head_widths %} 47 | {% set head_widths = head_widths.update( { key : ([head_widths[key],maxw]) | min } ) %} 48 | {% endfor %} 49 | {############################################################################## 50 | Align columns by type: text is 51 | ##############################################################################} 52 | {% set head_aligns = dict() %} 53 | {% for col in head %} 54 | {% if rows[0][col] is number %} 55 | {% set head_aligns = head_aligns.update( { col : '>' } ) %} 56 | {% else %} 57 | {% set head_aligns = head_aligns.update( { col : '<' } ) %} 58 | {% endif %} 59 | {% endfor %} 60 | {% for col in head %} 61 | | {{ '{:^{w}}'.format(col|truncate(head_widths[col],true,'…',0), w=head_widths[col]) }} {% endfor %}| 62 | {% for col in head %} 63 | | {{ '{:^{w}}'.format(('-'*head_widths[col])|truncate(maxw,true,'…',0), w=head_widths[col]) }} {% endfor %}| 64 | {% for row in rows %} 65 | {% for col in head %} 66 | | {{ '{:{a}{w}}'.format(row[col]|string|truncate(head_widths[col],true,'…',0), a=head_aligns[col], w=head_widths[col]) }} {% endfor %}| 67 | {% endfor %} -------------------------------------------------------------------------------- /ise_in_aws.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | #------------------------------------------------------------------------------ 3 | # Main YAML Playbook to launch ISE with Meraki vMX in AWS 4 | #------------------------------------------------------------------------------ 5 | - name: Provision AWS VPC with Cisco ISE and Meraki vMX 6 | hosts: localhost 7 | gather_facts: no 8 | vars_files: vars/main.yaml 9 | tasks: 10 | - name: Check Required Environment Variables 11 | delegate_to: localhost 12 | vars: 13 | env_vars: 14 | - AWS_REGION 15 | - MERAKI_ORG_NAME 16 | - MERAKI_ORG_ID 17 | - ISE_USERNAME 18 | - ISE_PASSWORD 19 | - ISE_RADIUS_SECRET 20 | - ISE_TACACS_SECRET 21 | loop: "{{ env_vars }}" 22 | ansible.builtin.assert: 23 | that: 24 | - lookup('env', item) # is defined does not work 25 | fail_msg: | 26 | X Please set the required environment variable {{ item }} in your terminal: 27 | export {{ item }}=__________ 28 | success_msg: | 29 | ✔ Environment variable {{ item }} is set 30 | 31 | - name: Create SSH KeyPair 32 | ansible.builtin.include_tasks: ssh_key_pair.yaml 33 | 34 | - name: Create VPC 35 | ansible.builtin.include_tasks: ise_in_aws.vpc.yaml 36 | 37 | - name: Create vMX 38 | ansible.builtin.include_tasks: ise_in_aws.vmx.yaml 39 | tags: meraki,vmx 40 | 41 | - name: Create PingVM 42 | ansible.builtin.include_tasks: ise_in_aws.ping_vm.yaml 43 | 44 | - name: Create ISE (no wait) 45 | ansible.builtin.include_tasks: ise_in_aws.ise.yaml 46 | 47 | - name: Create Meraki MR SSIDs 48 | ansible.builtin.include_tasks: ise_in_aws.mr_ssids.yaml 49 | 50 | - name: Refresh AWS Inventory to get the new Instance(s) 51 | ansible.builtin.meta: refresh_inventory 52 | 53 | - name: Initialize ISE Node(s) 54 | hosts: ise 55 | gather_facts: no 56 | vars_files: vars/main.yaml 57 | tasks: 58 | - name: Wait for ISE Application Server Initialization 59 | ansible.builtin.include_tasks: tasks/ise_initialized.yaml 60 | 61 | - name: Show ISE Node Login URLs 62 | loop: "{{ ise_nodes }}" 63 | ansible.builtin.debug: 64 | msg: | 65 |   66 |   . 67 |   /|\ 68 |   /|||\ 69 |   @ /|||||\ @ 70 |   @ \|/ \|/ @ https://{{ ansible_host }} 71 |   @ @ https://{{ inventory_hostname }}.{{ domain_name }} 72 |   @. .@ 73 |   `Y@ @ @Y` 74 |   75 |   76 | 77 | # - name: Press Enter to Continue 78 | # ansible.builtin.pause: 79 | # prompt: | 80 | #   81 | #   █ █ 82 | #   █ █ Press Enter to Continue and Configure ISE! 83 | #   █ █ 84 | #   85 | 86 | - name: Configure ISE 87 | ansible.builtin.include_tasks: ise.configuration.yaml 88 | 89 | - name: ISE ({{ inventory_hostname }}) is Ready! 90 | ansible.builtin.pause: 91 | seconds: 1 92 | prompt: | 93 |   94 |   95 |   . 96 |   /|\ 97 |   @ /|||\ @ ___ _ _ 98 |   @ /|||||\ @ | _ \ ___ __ _ __| | _ _ | | 99 |   @ \|/ \|/ @ | // -_)/ _` |/ _` || || ||_| 100 |   @. .@ |_|_\\___|\__,_|\__,_| \_, |(_) 101 |   `Y@ @ @Y` |__/ 102 |   103 |   104 | -------------------------------------------------------------------------------- /vars/network_devices.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Network Devices 4 | # 5 | 6 | network_devices: [] 7 | 8 | #------------------------------------------------------------------------------ 9 | # Cisco Catalyst WLCs 10 | #------------------------------------------------------------------------------ 11 | 12 | # - name: dCloud-9800CL-1 13 | # description: Cisco vWLC in dCloud 14 | # state: present 15 | # NetworkDeviceIPList: 16 | # - ipaddress: 198.19.11.10 17 | # mask: 32 18 | # NetworkDeviceGroupList: 19 | # - Device Type#All Device Types#Wireless#WLC 20 | # - Location#All Locations#AMER#SJC 21 | # profileName: Cisco 22 | # radiusSharedSecret: ISEisC00L # RADIUS 23 | # sharedSecret: ISEisC00L # TACACS 24 | 25 | 26 | #------------------------------------------------------------------------------ 27 | # Cisco Catalyst Switches 28 | #------------------------------------------------------------------------------ 29 | 30 | # - name: lab-3560cx-1 31 | # description: Cisco 3560CX 32 | # state: present 33 | # NetworkDeviceIPList: 34 | # - ipaddress: 10.80.60.152 35 | # mask: 32 36 | # NetworkDeviceGroupList: 37 | # - Device Type#All Device Types#Switches#Catalyst#3K 38 | # - Location#All Locations#AMER#HBC 39 | # profileName: Cisco 40 | # radiusSharedSecret: ISEisC00L # RADIUS 41 | # sharedSecret: ISEisC00L # TACACS 42 | 43 | 44 | #------------------------------------------------------------------------------ 45 | # Meraki MX 46 | #------------------------------------------------------------------------------ 47 | 48 | # - name: lab-mx68-1 49 | # description: MX68 50 | # state: present 51 | # NetworkDeviceIPList: 52 | # - ipaddress: 192.168.101.1 53 | # mask: 32 54 | # NetworkDeviceGroupList: 55 | # - Device Type#All Device Types#SDWAN#MX#MX68 56 | # - Location#All Locations#AMER#HBC 57 | # profileName: Cisco 58 | # radiusSharedSecret: ISEisC00L # RADIUS 59 | 60 | 61 | #------------------------------------------------------------------------------ 62 | # Meraki MR APs 63 | #------------------------------------------------------------------------------ 64 | 65 | # - name: lab-mr46-1 66 | # description: Cisco Meraki MR46 67 | # state: present 68 | # NetworkDeviceIPList: 69 | # - ipaddress: 10.80.60.150 70 | # mask: 32 71 | # NetworkDeviceGroupList: 72 | # - Device Type#All Device Types#Wireless#MR#MR46 73 | # - Location#All Locations#AMER#HBC 74 | # profileName: Cisco 75 | # radiusSharedSecret: ISEisC00L # RADIUS 76 | # sharedSecret: ISEisC00L # TACACS 77 | 78 | 79 | #------------------------------------------------------------------------------ 80 | # Meraki Z 81 | #------------------------------------------------------------------------------ 82 | 83 | # - name: teleworker-thomas 84 | # description: Cisco Meraki Z3 85 | # state: present 86 | # NetworkDeviceIPList: 87 | # - ipaddress: 192.168.111.1 88 | # mask: 32 89 | # NetworkDeviceGroupList: 90 | # - Device Type#All Device Types#SDWAN#Z#Z3 91 | # - Location#All Locations#AMER#HBC 92 | # profileName: Cisco 93 | # radiusSharedSecret: ISEisC00L # RADIUS 94 | 95 | 96 | # - name: teleworker-employee 97 | # description: Cisco Meraki Z3 98 | # state: present 99 | # NetworkDeviceIPList: 100 | # - ipaddress: 192.168.112.1 101 | # mask: 32 102 | # NetworkDeviceGroupList: 103 | # - Device Type#All Device Types#SDWAN#Z#Z3 104 | # - Location#All Locations#AMER#HBC 105 | # profileName: Cisco 106 | # radiusSharedSecret: ISEisC00L # RADIUS 107 | 108 | 109 | #------------------------------------------------------------------------------ 110 | # Meraki MS 111 | #------------------------------------------------------------------------------ 112 | 113 | # - name: lab-ms390-1 114 | # description: MS390 115 | # state: present 116 | # NetworkDeviceIPList: 117 | # - ipaddress: 192.168.101.5 118 | # mask: 32 119 | # NetworkDeviceGroupList: 120 | # - Device Type#All Device Types#Switches#MS#MS390 121 | # - Location#All Locations#AMER#HBC 122 | # profileName: Cisco 123 | # radiusSharedSecret: ISEisC00L # RADIUS 124 | 125 | 126 | ... -------------------------------------------------------------------------------- /ise_in_aws.ise.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # ⚠ Limit CIDR IPs to the Lab Network to Prevent Public Internet Access! 4 | # 5 | - name: Create SG-ISE Security Group 6 | amazon.aws.ec2_group: 7 | name: SG-ISE 8 | description: SG-ISE 9 | # vpc_id: "{{ vpcs.vpcs[0].id }}" 10 | vpc_id: "{{ vpc.vpc.id }}" 11 | region: "{{ aws_region }}" 12 | rules: 13 | - proto: -1 14 | from_port: 0 15 | to_port: 0 16 | cidr_ip: 172.31.0.0/16 17 | rule_desc: Allow all traffic within VPC 18 | - proto: tcp 19 | from_port: 22 20 | to_port: 22 21 | cidr_ip: 0.0.0.0/0 22 | rule_desc: Allow SSH from anywhere 23 | # 💡 Uncomment *only* if you want ISE directly accessible from Internet 24 | # - proto: tcp 25 | # from_port: 443 26 | # to_port: 443 27 | # cidr_ip: 0.0.0.0/0 28 | # rule_desc: Allow HTTPS from anywhere 29 | - proto: -1 30 | from_port: 0 31 | to_port: 0 32 | cidr_ip: 192.168.0.0/16 33 | rule_desc: Allow all traffic from on-premises 34 | rules_egress: 35 | - proto: all 36 | cidr_ip: 0.0.0.0/0 # any 37 | rule_desc: Allow All 38 | tags: 39 | Name: SG-ISE 40 | project: "{{ project_name }}" 41 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 42 | register: sg_ise 43 | tags: 44 | - sg 45 | - security_group 46 | 47 | - name: Create ISE Instance in AWS 48 | loop: "{{ ise_nodes }}" 49 | amazon.aws.ec2_instance: 50 | # state: present # instances exist but not guarantee of state (e.g. running) 51 | state: running # present + ensures the instances are running for public IP address! 52 | # state: started # running + waits for EC2 status checks; ~3 minutes per node 53 | region: "{{ aws_region }}" 54 | vpc_subnet_id: "{{ subnet_private.subnet.id }}" 55 | image_id: "{{ item.ami }}" 56 | instance_type: "{{ item.instance_type }}" 57 | key_name: "{{ ssh_keypair_name }}" 58 | network: 59 | assign_public_ip: yes 60 | delete_on_termination: yes 61 | private_ip_address: "{{ item.private_ip}}" 62 | security_group: "{{ sg_ise.group_id }}" 63 | volumes: 64 | - device_name: /dev/sda1 65 | ebs: 66 | delete_on_termination: true 67 | volume_size: "{{ item.volume_size | default( 300 ) }}" 68 | wait: yes 69 | tags: 70 | Name: "{{ item.name }}" 71 | product: "ISE" 72 | hostname: "{{ item.name }}" 73 | project: "{{ project_name }}" 74 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 75 | role: "{{ item.role | default('') }}" 76 | personas: "{{ item.personas | default( 'standalone') }}" 77 | user_data: "hostname={{ item.name | lower }}\nprimarynameserver={{ dns_server | default('208.67.222.222') }}\ndnsdomain={{ domain_name | default('demo.local') }}\nntpserver={{ ntp_server | default('time.nist.gov') }}\ntimezone={{ timezone | default('Etc/UTC') }}\nusername={{ ise_username }}\npassword={{ ise_password }}" 78 | register: instances 79 | 80 | # - name: Show ISE Instances 81 | # ansible.builtin.debug: var=instances 82 | 83 | - name: Add public DNS entry for the ISE node(s) 84 | when: domain_name is defined 85 | loop: "{{ instances.results[0].instances }}" 86 | community.aws.route53: 87 | state: present 88 | zone: "{{ domain_name }}" 89 | record: "{{ item.tags.Name }}.{{ domain_name }}" 90 | overwrite: yes 91 | private_zone: no 92 | type: A 93 | ttl: 7200 94 | value: "{{ item.public_ip_address }}" 95 | wait: no 96 | 97 | - name: Add private DNS entry for the ISE node(s) 98 | when: domain_name is defined 99 | loop: "{{ instances.results[0].instances }}" 100 | community.aws.route53: 101 | state: present 102 | zone: "{{ domain_name }}" 103 | record: "{{ item.tags.Name }}.{{ domain_name }}" 104 | overwrite: yes 105 | private_zone: yes 106 | type: A 107 | ttl: 7200 108 | value: "{{ item.private_ip_address }}" 109 | wait: no 110 | 111 | - name: Show SSH Commands for ISE Instances 112 | loop: "{{ ise_nodes }}" 113 | ansible.builtin.debug: 114 | msg: | 115 |   116 |   . 117 |   /|\ 118 |   /|||\ 119 |   @ /|||||\ @ 120 |   @ \|/ \|/ @ ping {{ item.private_ip }} 121 |   @ @ ssh -i {{ ssh_keypair_private_key }} {{ ise_username }}@{{ item.private_ip }} 122 |   @. .@ 123 |   `Y@ @ @Y` 124 |   125 |   126 | -------------------------------------------------------------------------------- /ise.configuration.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | # ⟁ Wait for ISE Application Server to be available after [re]boot 5 | - name: Test for ISE Application Server Initialization 6 | ansible.builtin.include_tasks: tasks/ise_initialized.yaml 7 | 8 | # ⟁ Verify APIs are enabled *before* gathering facts and configuring 9 | - name: Enable ISE ERS & OpenAPIs 10 | ansible.builtin.include_tasks: tasks/ise_apis_enabled.yaml 11 | 12 | - name: Include Repositories 13 | ansible.builtin.include_vars: vars/repositories.yaml 14 | tags: 15 | - repository 16 | 17 | - name: Create Repositories 18 | when: repositories is defined and repositories | count > 0 19 | loop: "{{ repositories }}" 20 | ansible.builtin.include_tasks: tasks/repository.create.yaml 21 | ignore_errors: true 22 | tags: 23 | - repository 24 | 25 | - name: Create RADIUS Probes - identity_group and internal_users 26 | ansible.builtin.include_tasks: tasks/radius_probes.yaml 27 | ignore_errors: true 28 | tags: 29 | - internal_user 30 | 31 | - name: Create Internal Users 32 | block: 33 | - name: Include Internal Users 34 | ansible.builtin.include_vars: vars/internal_users.yaml 35 | - name: Create Internal Users 36 | loop: "{{ internal_users }}" 37 | ansible.builtin.include_tasks: tasks/internal_user.create.yaml 38 | ignore_errors: true 39 | tags: 40 | - internal_user 41 | 42 | 43 | #---------------------------------------------------------------------------- 44 | # Network Device Groups 45 | #---------------------------------------------------------------------------- 46 | 47 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 48 | # 🐞 ISE 3.2.0.542 `networkdevicegroup` create fails. 49 | # 🐞 It does not support the `othername` attribute. 50 | # 🐞 It says it wants the `ndgtype` attribute that it does not recognize 51 | # 💡 Fixed in ISE 3.2 + Patch 2 and later 52 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 53 | 54 | - name: Create network_device_groups 55 | block: 56 | - name: Include network_device_groups 57 | ansible.builtin.include_vars: vars/network_device_groups.yaml 58 | - name: Create Network Device Groups 59 | loop: "{{ network_device_groups }}" 60 | ansible.builtin.include_tasks: tasks/network_device_group.create.yaml 61 | ignore_errors: true 62 | tags: 63 | - network_device 64 | - network_device_group 65 | 66 | 67 | - name: Create network_devices 68 | block: 69 | - name: Include demo network_devices 70 | ansible.builtin.include_vars: vars/network_devices.yaml 71 | - name: Create network_devices 72 | when: network_devices is defined and network_devices | count > 0 73 | loop: "{{ network_devices }}" 74 | ansible.builtin.include_tasks: tasks/network_device.create.yaml 75 | ignore_errors: true 76 | tags: 77 | - network_device 78 | 79 | - name: Get All Meraki Devices in the Org+Network 80 | delegate_to: localhost 81 | cisco.meraki.meraki_device: 82 | state: query 83 | org_name: "{{ meraki_org_name }}" 84 | net_name: "{{ meraki_lab_net_name }}" 85 | register: meraki_devices 86 | #--------------------------------------------------- 87 | # Example output 88 | #--------------------------------------------------- 89 | # - configuration_updated_at: '2022-09-21T22:14:34Z' 90 | # firmware: wireless-28-7-1 91 | # lan_ip: 192.168.101.4 92 | # lat: 37.0000000000000 93 | # lng: -122.0000000000000 94 | # mac: 2c:3f:0b:56:e3:6c 95 | # model: MR46 96 | # name: lab-mr46-1 97 | # network_id: L_585467371558187322 98 | # notes: '' 99 | # product_type: wireless 100 | # serial: Q3AC-JCYG-3NL5 101 | #--------------------------------------------------- 102 | 103 | # - name: Show meraki_devices 104 | # ansible.builtin.debug: var=meraki_devices 105 | 106 | # 107 | # Add Meraki Devices to ISE 108 | # 109 | - name: Add Meraki Network Devices to ISE 110 | delegate_to: localhost 111 | loop: "{{ meraki_devices.data }}" 112 | when: item.lan_ip is defined # APs and Switches 113 | cisco.ise.network_device: 114 | ise_hostname: "{{ ansible_host }}" 115 | ise_username: "{{ ise_username }}" 116 | ise_password: "{{ ise_password }}" 117 | ise_verify: "{{ ise_verify }}" 118 | ise_debug: "{{ ise_debug }}" 119 | state: "{{ item.state | default('present') }}" 120 | name: "{{ item.name }}" 121 | description: "{{ item.firmware | default('')}}" 122 | profileName: "{{ item.profileName | default('Cisco') }}" 123 | modelName: "{{ item.modelName | default( omit ) }}" 124 | softwareVersion: "{{ item.softwareVersion | default( omit ) }}" 125 | NetworkDeviceIPList: 126 | - ipaddress: "{{ item.lan_ip }}" 127 | mask: 32 128 | NetworkDeviceGroupList: "{{ item.network_device_groups | default( omit ) }}" 129 | authenticationSettings: 130 | networkProtocol: RADIUS 131 | radiusSharedSecret: "{{ radius_secret }}" 132 | coaPort: "{{ item.coaPort | default(1700) }}" 133 | ignore_errors: true 134 | 135 | 136 | - name: Endpoint Groups 137 | block: 138 | - name: Include Endpoint Groups 139 | ansible.builtin.include_vars: vars/endpoint_groups.yaml 140 | - name: Create Endpoint Groups 141 | loop: "{{ endpoint_groups }}" 142 | ansible.builtin.include_tasks: tasks/endpoint_group.create.yaml 143 | ignore_errors: true 144 | tags: 145 | - endpoint 146 | 147 | 148 | - name: Create Endpoints 149 | block: 150 | - name: Include Endpoints 151 | ansible.builtin.include_vars: vars/endpoints.yaml 152 | - name: Create Endpoints 153 | loop: "{{ endpoints }}" 154 | ansible.builtin.include_tasks: tasks/endpoint.create.yaml 155 | ignore_errors: true 156 | tags: 157 | - endpoint 158 | 159 | 160 | 161 | 162 | ... -------------------------------------------------------------------------------- /tasks/network_device.create.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create Network Device | {{ item.name }} 3 | delegate_to: localhost 4 | cisco.ise.network_device: 5 | ise_hostname: "{{ ansible_host }}" 6 | ise_username: "{{ ise_username }}" 7 | ise_password: "{{ ise_password }}" 8 | ise_verify: "{{ ise_verify }}" 9 | ise_debug: "{{ ise_debug }}" 10 | 11 | state: "{{ item.state | default('present') }}" # string 12 | name: "{{ item.name }}" # string 13 | description: "{{ item.description | default('')}}" # string 14 | profileName: "{{ item.profileName | default('Cisco') }}" # string 15 | modelName: "{{ item.modelName | default( omit ) }}" # string 16 | softwareVersion: "{{ item.softwareVersion | default( omit ) }}" # string 17 | 18 | NetworkDeviceIPList: "{{ item.NetworkDeviceIPList }}" # list of dicts 19 | # - getIpaddressExclude: string 20 | # ipaddress: string 21 | # mask: 0 22 | NetworkDeviceGroupList: "{{ item.network_device_groups | default( omit ) }}" # list of strings 23 | 24 | #------------------------------------------------------------------------ 25 | # RADIUS Authentication Settings 26 | #------------------------------------------------------------------------ 27 | authenticationSettings: 28 | # enabled: true 29 | # RADIUS UDP Settings 30 | networkProtocol: RADIUS 31 | radiusSharedSecret: "{{ item.radiusSharedSecret | default( ise.radius.secret ) | default( omit ) }}" 32 | enableMultiSecret: "{{ item.enableMultiSecret | default('false') }}" # ⚠ string, not boolean! 33 | secondRadiusSharedSecret: "{{ item.secondRadiusSharedSecret | default( omit ) }}" 34 | # RADIUS DTLS Settings 35 | dtlsRequired: "{{ item.dtlsRequired | default( false ) }}" 36 | # General Settings 37 | enableKeyWrap: "{{ item.enableKeyWrap | default( false ) }}" 38 | keyEncryptionKey: "{{ item.keyEncryptionKey | default( omit ) }}" # string 39 | messageAuthenticatorCodeKey: "{{ item.keyInputFormat | default( omit ) }}" # string 40 | keyInputFormat: "{{ item.keyInputFormat | default( omit ) }}" # [ 'ASCII', 'HEXADECIMAL' ] 41 | coaPort: "{{ item.coaPort | default(1700) }}" # string 42 | dtlsDnsName: "{{ item.dtlsDnsName | default( omit ) }}" # string 43 | 44 | #------------------------------------------------------------------------ 45 | # TACACS Settings 46 | #------------------------------------------------------------------------ 47 | tacacsSettings: 48 | sharedSecret: "{{ item.sharedSecret | default( ise.tacacs.secret ) | default( omit ) }}" # string 49 | connectModeOptions: "{{ item.connectModeOptions | default('OFF') }}" # string 50 | 51 | #------------------------------------------------------------------------ 52 | # SNMP Settings 53 | # ToDo: Fix NetworkDevice.snmpsettings.pollingInterval must be integer 54 | #------------------------------------------------------------------------ 55 | # snmpsettings: 56 | # pollingInterval: "{{ item.pollingInterval | default(0) | int }}" # int (seconds) 0, 28800, 600-86400 57 | # version: "{{ item.version | default( omit ) }}" # string: ['1','2c','3'] 58 | # roCommunity: "{{ item.roCommunity | default( omit ) }}" # string 59 | 60 | # # Unsupported Attributes 61 | # # SNMP Username 62 | # # Security Level 63 | # # Auth Protocol 64 | # # Auth Password 65 | # # Privacy Protocol 66 | # # Privacy Password 67 | 68 | # # Traps 69 | # linkTrapQuery: "{{ item.linkTrapQuery | default( false ) }}" # boolean 70 | # macTrapQuery: "{{ item.macTrapQuery | default( false ) }}" # boolean 71 | # originatingPolicyServicesNode: "{{ item.originatingPolicyServicesNode | default( omit ) }}" # string ('Auto') 72 | 73 | #------------------------------------------------------------------------ 74 | # Advanced TrustSec Settings 75 | #------------------------------------------------------------------------ 76 | # trustsecsettings: 77 | # # Device Authentication Settings 78 | # pushIdSupport: "{{ item.pushIdSupport | default( false ) }}" # boolean 79 | # deviceAuthenticationSettings: 80 | # # Unsupported: Use Device ID for TrustSec Identification 81 | # sgaDeviceId: "{{ item.sgaDeviceId | default( omit ) }}" # string 82 | # sgaDevicePassword: "{{ item.sgaDevicePassword | default( omit ) }}" # string 83 | 84 | # Enable HTTP REST API 85 | # Username 86 | # Password 87 | # Support TrustSec Verification reports 88 | 89 | # # Device Configuration Deployment 90 | # deviceConfigurationDeployment: 91 | # includeWhenDeployingSGTUpdates: "{{ item.includeWhenDeployingSGTUpdates | default( false ) }}" 92 | # # Device Interface Credentials 93 | # execModeUsername: "{{ item.execModeUsername | default( omit ) }}" # string 94 | # execModePassword: "{{ item.execModePassword | default( omit ) }}" # string 95 | # enableModePassword: "{{ item.enableModePassword | default( omit ) }}" # string 96 | 97 | # TrustSec Notifications and Updates 98 | #---------------------------------------------------------------------- 99 | # ⚠ ToDo: Fix integer errors: 100 | # downlaodEnvironmentDataEveryXSeconds must be integer 101 | # downlaodPeerAuthorizationPolicyEveryXSeconds must be integer 102 | # reAuthenticationEveryXSeconds must be integer 103 | # downloadSGACLListsEveryXSeconds must be integer 104 | #---------------------------------------------------------------------- 105 | # sgaNotificationAndUpdates: 106 | # # ⚠ API attribute is mispelled: "downlaod" 107 | # downlaodEnvironmentDataEveryXSeconds: "{{ item.downlaodEnvironmentDataEveryXSeconds | default(0) | int }}" # 0 (off), 86400 (default) 108 | # # ⚠ API attribute is mispelled: "downlaod" 109 | # downlaodPeerAuthorizationPolicyEveryXSeconds: "{{ item.downlaodPeerAuthorizationPolicyEveryXSeconds | default(0) | int }}" # 0 (off), 86400 (default) 110 | # reAuthenticationEveryXSeconds: "{{ item.reAuthenticationEveryXSeconds | default(0) | int }}" # 0 (off), 86400 (default) 111 | # downloadSGACLListsEveryXSeconds: "{{ item.downloadSGACLListsEveryXSeconds | default(0) | int }}" # 0 (off), 86400 (default) 112 | # otherSGADevicesToTrustThisDevice: "{{ item.otherSGADevicesToTrustThisDevice | default(true) }}" 113 | # sendConfigurationToDevice: "{{ item.sendConfigurationToDevice | default(true) }}" 114 | # sendConfigurationToDeviceUsing: "{{ item.sendConfigurationToDeviceUsing | default( omit ) }}" # string: ['CoA', 'CLI (SSH)'] 115 | # coaSourceHost: "{{ item.coaSourceHost | default( omit ) }}" # string: (ISE node name) 116 | # # ⚠ Missing: Ssh Key 117 | 118 | # Out of Band (OOB) TrustSec PAC 119 | # Issue Date 120 | # Expiration Date 121 | # Issued By 122 | 123 | tags: [network_device, network_devices, nad, nads] 124 | -------------------------------------------------------------------------------- /meraki.show.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | #------------------------------------------------------------------------------ 3 | # Shows Cisco Meraki Org, Admin, Networks, and Devices Information 4 | # 5 | # Requires the following environment variables: 6 | # export MERAKI_DASHBOARD_API_KEY='EXAMPLE+KEYc320e12ee407159487a4cabc41abb' 7 | # 8 | # Run with 9 | # ansible-playbook meraki.show.yaml 10 | # ansible-playbook -v meraki.show.yaml # use -v to see the intermediate results 11 | #------------------------------------------------------------------------------ 12 | 13 | - name: Show Meraki Admins, Organizations, Networks, and Devices 14 | hosts: localhost 15 | vars_files: 16 | - vars/main.yaml 17 | gather_facts: no 18 | 19 | pre_tasks: 20 | 21 | - name: Check Required Environment Variables 22 | delegate_to: localhost 23 | vars: 24 | env_vars: 25 | - MERAKI_DASHBOARD_API_KEY 26 | loop: "{{ env_vars }}" 27 | ansible.builtin.assert: 28 | that: 29 | - lookup('env', item) # is defined does not work 30 | fail_msg: | 31 | X Please set the required environment variable {{ item }} in your terminal: 32 | export {{ item }}=__________ 33 | success_msg: | 34 | ✔ Environment variable {{ item }} is set 35 | 36 | tasks: 37 | - name: Get Organizations for user's authentication key 38 | delegate_to: localhost 39 | cisco.meraki.organizations_info: 40 | # organizationId: "{{ meraki_org_id }}" 41 | register: results 42 | 43 | - name: Show Meraki Orgs 44 | delegate_to: localhost 45 | vars: 46 | hide: ["url"] 47 | # maxw: 40 48 | rows: "{{ results.meraki_response }}" 49 | temp: "{{ lookup('template', 'templates/list_of_dicts.j2') }}" 50 | ansible.builtin.debug: 51 | msg: "{{ temp }}" 52 | 53 | - name: Set org_names and org_ids 54 | ansible.builtin.set_fact: 55 | org_names: "{{ results.meraki_response | community.general.json_query('[*].name') }}" 56 | org_ids: "{{ results.meraki_response | community.general.json_query('[*].id') }}" 57 | 58 | - name: Get Org Administrators 59 | delegate_to: localhost 60 | loop: "{{ org_ids }}" 61 | cisco.meraki.organizations_admins_info: 62 | organizationId: "{{ item }}" 63 | register: results 64 | 65 | - name: Show Meraki Org Admins 66 | delegate_to: localhost 67 | vars: 68 | hide: ["authenticationMethod"] 69 | maxw: 30 70 | rows: "{{ results.results | community.general.json_query('[*].meraki_response') | first }}" 71 | temp: "{{ lookup('template', 'templates/list_of_dicts.j2') }}" 72 | ansible.builtin.debug: 73 | msg: "{{ temp }}" 74 | 75 | - name: Get All Networks 76 | delegate_to: localhost 77 | loop: "{{ org_ids }}" 78 | cisco.meraki.networks_info: 79 | organizationId: "{{ item }}" 80 | register: results 81 | 82 | - name: Set networks 83 | ansible.builtin.set_fact: 84 | networks: "{{ results.results[0].meraki_response }}" 85 | 86 | - name: Show All Networks 87 | delegate_to: localhost 88 | vars: 89 | hide: ["enrollmentString", "url"] 90 | maxw: 30 91 | rows: "{{ networks }}" 92 | # rows: "{{ results.results | community.general.json_query('[*].meraki_response') | first }}" 93 | temp: "{{ lookup('template', 'templates/list_of_dicts.j2') }}" 94 | ansible.builtin.debug: 95 | msg: "{{ temp }}" 96 | 97 | - name: Get All Devices in the Organization 98 | delegate_to: localhost 99 | loop: "{{ org_ids }}" 100 | cisco.meraki.devices_info: 101 | organizationId: "{{ item }}" 102 | register: results 103 | 104 | - name: Show All Meraki Devices 105 | delegate_to: localhost 106 | vars: 107 | hide: ["address", "firmware", "lat", "lng", "notes", "url"] 108 | maxw: 30 109 | # rows: "{{ results.meraki_response }}" 110 | rows: "{{ results.results | community.general.json_query('[*].meraki_response') | first }}" 111 | temp: "{{ lookup('template', 'templates/list_of_dicts.j2') }}" 112 | ansible.builtin.debug: 113 | msg: "{{ temp }}" 114 | 115 | - name: Get All Wireless SSIDs 116 | loop: "{{ networks | selectattr('productTypes', 'contains', 'wireless') }}" 117 | cisco.meraki.networks_wireless_ssids_info: 118 | networkId: "{{ item.id }}" 119 | register: ssid_results 120 | 121 | - name: Set networks_wireless_ssids 122 | ansible.builtin.set_fact: 123 | networks_wireless_ssids: "{{ ssid_results.results | community.general.json_query('[*].meraki_response') | first }}" 124 | 125 | - name: Show Wireless SSIDs' General Configuration 126 | delegate_to: localhost 127 | vars: 128 | # hide: ["address", "firmware", "lat", "lng", "notes", "url"] 129 | head: 130 | - enabled 131 | - number 132 | - name 133 | - visible 134 | - authMode 135 | - authModeencryptionMode 136 | - wpaEncryptionMode 137 | - availableOnAllAps 138 | - splashPage 139 | - namedVlans 140 | - ipAssignmentMode 141 | maxw: 30 142 | # rows: "{{ results.meraki_response }}" 143 | # rows: "{{ ssid_results.results | community.general.json_query('[*].meraki_response') | first }}" 144 | rows: "{{ networks_wireless_ssids }}" 145 | temp: "{{ lookup('template', 'templates/list_of_dicts.j2') }}" 146 | ansible.builtin.debug: 147 | msg: "{{ temp }}" 148 | 149 | - name: Wireless SSIDs' RADIUS Configuration 150 | delegate_to: localhost 151 | vars: 152 | # hide: ["address", "firmware", "lat", "lng", "notes", "url"] 153 | head: 154 | # - enabled 155 | # - number 156 | - name 157 | # - radiusAuthenticationNasId 158 | # - radiusCalledStationId 159 | - radiusServers 160 | # - radiusAccountingServers 161 | - radiusServerTimeout 162 | - radiusServerAttemptsLimit 163 | - radiusTestingEnabled 164 | # - radiusAccountingEnabled 165 | - radiusAccountingInterimInterval 166 | - radiusAttributeForGroupPolicies 167 | - radiusCoaEnabled 168 | # - radiusFallbackEnabled 169 | # - radiusProxyEnabled 170 | maxw: 30 171 | # rows: "{{ results.meraki_response }}" 172 | rows: "{{ ssid_results.results | community.general.json_query('[*].meraki_response') | first }}" 173 | temp: "{{ lookup('template', 'templates/list_of_dicts.j2') }}" 174 | ansible.builtin.debug: 175 | msg: "{{ temp }}" 176 | 177 | 178 | - name: Create directory | {{ dir_configs | default("configs") }} 179 | delegate_to: localhost 180 | ansible.builtin.file: 181 | path: "{{ dir_configs | default('configs') }}" 182 | state: directory 183 | mode: "0700" 184 | 185 | 186 | - name: To YAML File | {{ dir_configs | default("configs") }}/networks_wireless_ssids.yaml 187 | delegate_to: localhost 188 | when: 189 | - networks_wireless_ssids is defined 190 | - networks_wireless_ssids | count > 0 191 | vars: 192 | resource_name: networks_wireless_ssids 193 | resources: "{{ networks_wireless_ssids }}" 194 | ansible.builtin.template: 195 | src: templates/resource_template.j2 196 | dest: "{{ dir_configs | default('configs') }}/networks_wireless_ssids.yaml" 197 | mode: "0644" 198 | -------------------------------------------------------------------------------- /ise_in_aws.mr_ssids.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | #------------------------------------------------------------------------------ 3 | # .corp : 802.1X with ISE from Secure Cisco Meraki Wireless with ISE 4 | #------------------------------------------------------------------------------ 5 | - name: Configure SSID | {{ meraki_org_name }}:{{ meraki_lab_net_name }}:.corp 6 | delegate_to: localhost 7 | cisco.meraki.meraki_ssid: 8 | state: present 9 | org_name: "{{ meraki_org_name }}" 10 | net_name: "{{ meraki_lab_net_name }}" 11 | name: .corp 12 | number: 0 13 | enabled: yes 14 | visible: yes 15 | auth_mode: 8021x-radius # [open|psk|open-with-radius|8021x-meraki|8021x-radius] 16 | encryption_mode: wpa # [wpa|eap|wpa-eap] 17 | wpa_encryption_mode: WPA2 only # 🛑 ipsk-with-radius NOT SUPPORTED! [open|psk|open-with-radius|8021x-meraki|8021x-radius] 18 | splash_page: None 19 | radius_servers: 20 | - host: 172.31.2.11 21 | port: 1812 22 | secret: "{{ radius_secret }}" 23 | radius_accounting_servers: 24 | - host: 172.31.2.11 25 | port: 1813 26 | secret: "{{ radius_secret }}" 27 | available_on_all_aps: true 28 | ip_assignment_mode: NAT mode 29 | 30 | # 🛑 ▼▼▼ Unsupported with Ansible ▼▼▼ 31 | # radius_attribute_for_group_policies: Airespace-ACL-Name 32 | # radius_server_attempts_limit: 3 33 | # radius_server_timeout: 1 34 | # radius_accounting_enabled: true 35 | # radius_accounting_interim_interval: 600 36 | # radius_authentication_nas_id: $NODE_MAC$:$VAP_NUM$ 37 | # radius_called_station_id: $NODE_MAC$:$VAP_NAME$ 38 | # radius_testing_enabled: true 39 | # radius_failover_policy: Deny access # [Deny access|Allow access] 40 | # radius_fallback_enabled: false 41 | # radius_load_balancing_policy: null 42 | # radius_proxy_enabled: false 43 | # adult_content_filtering_enabled: false 44 | # availability_tags: [] 45 | # available_on_all_aps: true 46 | # band_selection: Dual band operation 47 | # dns_rewrite: 48 | # dns_custom_nameservers: [] 49 | # enabled: false 50 | # dot11r: 51 | # adaptive: false 52 | # enabled: false 53 | # dot11w: 54 | # enabled: true 55 | # required: false 56 | # ip_assignment_mode: NAT mode 57 | # mandatory_dhcp_enabled: false 58 | # min_bitrate: 11 59 | # per_client_bandwidth_limit_down: 0 60 | # per_client_bandwidth_limit_up: 0 61 | # per_ssid_bandwidth_limit_down: 0 62 | # per_ssid_bandwidth_limit_up: 0 63 | # speed_burst: 64 | # enabled: false 65 | # ssid_admin_accessible: false 66 | 67 | #------------------------------------------------------------------------------ 68 | # .iot : MAB from Secure Cisco Meraki Wireless with ISE 69 | # 70 | # 🛑 cisco.meraki.meraki_ssid module does not recognize ipsk-with-radius 🛑 71 | # 🛑 'value of auth_mode must be one of: open, psk, open-with-radius, 8021x-meraki, 8021x-radius, got: ipsk-with-radius' 72 | #------------------------------------------------------------------------------ 73 | - name: Configure SSID | {{ meraki_org_name }}:{{ meraki_lab_net_name }}:.iot 74 | delegate_to: localhost 75 | cisco.meraki.meraki_ssid: 76 | state: present 77 | org_name: "{{ meraki_org_name }}" 78 | net_name: "{{ meraki_lab_net_name }}" 79 | name: .iot 80 | number: 1 81 | enabled: yes 82 | visible: yes 83 | auth_mode: 8021x-radius # [open|psk|open-with-radius|8021x-meraki|8021x-radius] 84 | encryption_mode: wpa # [wpa|eap|wpa-eap] 85 | wpa_encryption_mode: WPA2 only # 🛑 ipsk-with-radius NOT SUPPORTED! [open|psk|open-with-radius|8021x-meraki|8021x-radius] 86 | splash_page: None 87 | radius_servers: 88 | - host: 172.31.2.11 89 | port: 1812 90 | secret: "{{ radius_secret }}" 91 | radius_accounting_servers: 92 | - host: 172.31.2.11 93 | port: 1813 94 | secret: "{{ radius_secret }}" 95 | available_on_all_aps: true 96 | ip_assignment_mode: NAT mode 97 | 98 | # 🛑 ▼▼▼ Unsupported with Ansible ▼▼▼ 99 | # radius_attribute_for_group_policies: Airespace-ACL-Name 100 | # radius_authentication_nas_id: $NODE_MAC$:$VAP_NUM$ 101 | # radius_called_station_id: $NODE_MAC$:$VAP_NAME$ 102 | # radius_coa_enabled: true 103 | # radius_testing_enabled: true 104 | # radius_accounting_enabled: true 105 | # radius_accounting_interim_interval: 600 106 | # dot11w: 107 | # enabled: true 108 | # required: false 109 | # # 🛑 ▼▼▼ Unsupported with Ansible ▼▼▼ 110 | # radius_failover_policy: null 111 | # radius_fallback_enabled: false 112 | # radius_load_balancing_policy: null 113 | # radius_proxy_enabled: false 114 | # radius_server_attempts_limit: 3 115 | # radius_server_timeout: 1 116 | # admin_splash_url: null 117 | # adult_content_filtering_enabled: false 118 | # availability_tags: [] 119 | # band_selection: Dual band operation 120 | # dns_rewrite: 121 | # dns_custom_nameservers: [] 122 | # enabled: false 123 | # dot11r: 124 | # adaptive: false 125 | # enabled: false 126 | # mandatory_dhcp_enabled: true 127 | # min_bitrate: 11 128 | # per_client_bandwidth_limit_down: 0 129 | # per_client_bandwidth_limit_up: 0 130 | # per_ssid_bandwidth_limit_down: 0 131 | # per_ssid_bandwidth_limit_up: 0 132 | # speed_burst: 133 | # enabled: false 134 | # splash_page: Cisco ISE 135 | # splash_timeout: 1440 minutes 136 | # ssid_admin_accessible: false 137 | # walled_garden_enabled: false 138 | 139 | - name: Manually change the SSID | {{ meraki_org_name }}:{{ meraki_lab_net_name }}:.iot 140 | ansible.builtin.pause: 141 | prompt: | 142 | 143 | You must now manually change the SSID to 'Identity PSK with RADIUS' 144 | because the Meraki Ansible module does not support 145 | wpa_encryption_mode: ipsk-with-radius 146 | 147 | 1. Open the Meraki Dashboard 148 | 2. Go to Wireless > Configure > SSID 149 | 3. Select .iot 150 | 4. Select Security : Identity PSK with RADIUS 151 | 5. Save 152 | 153 | Press Enter to Continue... 154 | 155 | #------------------------------------------------------------------------------ 156 | # .guest : MAB WebAuth with ISE from Secure Cisco Meraki Wireless with ISE 157 | #------------------------------------------------------------------------------ 158 | - name: Configure SSID | {{ meraki_org_name }}:{{ meraki_lab_net_name }}:.guest 159 | delegate_to: localhost 160 | cisco.meraki.meraki_mr_ssid: 161 | state: present 162 | org_name: "{{ meraki_org_name }}" 163 | net_name: "{{ meraki_lab_net_name }}" 164 | name: .guest 165 | number: 2 166 | enabled: no 167 | visible: true 168 | available_on_all_aps: true 169 | auth_mode: open-with-radius # [open|psk|open-with-radius|8021x-meraki|8021x-radius] 170 | radius_servers: 171 | - host: 172.31.2.11 172 | port: 1812 173 | secret: "{{ radius_secret }}" 174 | radius_accounting_servers: 175 | - host: 172.31.2.11 176 | port: 1813 177 | secret: "{{ radius_secret }}" 178 | radius_coa_enabled: true 179 | radius_accounting_enabled: true 180 | ip_assignment_mode: NAT mode 181 | splash_page: Cisco ISE 182 | # splash_timeout: 1440 minutes # 🛑 Unsupported 183 | walled_garden_enabled: true 184 | walled_garden_ranges: 185 | - 172.31.2.11/32 186 | # # 🛑 ▼▼▼ Unsupported with Ansible ▼▼▼ 187 | # radius_attribute_for_group_policies: Airespace-ACL-Name # 🛑 Unsupported 188 | # radius_authentication_nas_id: $NODE_MAC$:$VAP_NUM$ # 🛑 Unsupported 189 | # radius_called_station_id: $NODE_MAC$:$VAP_NAME$ # 🛑 Unsupported 190 | # radius_failover_policy: null 191 | # radius_fallback_enabled: false 192 | # radius_load_balancing_policy: null 193 | # radius_proxy_enabled: false 194 | # radius_server_attempts_limit: 3 195 | # radius_server_timeout: 1 196 | # radius_testing_enabled: true 197 | # radius_accounting_interim_interval: 600 198 | # admin_splash_url: '' 199 | # adult_content_filtering_enabled: false 200 | # availability_tags: [] 201 | # band_selection: Dual band operation 202 | # dns_rewrite: 203 | # dns_custom_nameservers: [] 204 | # enabled: false 205 | # mandatory_dhcp_enabled: false 206 | # min_bitrate: 11 207 | # per_client_bandwidth_limit_down: 0 208 | # per_client_bandwidth_limit_up: 0 209 | # per_ssid_bandwidth_limit_down: 0 210 | # per_ssid_bandwidth_limit_up: 0 211 | # speed_burst: 212 | # enabled: false 213 | # ssid_admin_accessible: false 214 | -------------------------------------------------------------------------------- /vars/endpoint_groups.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # ISE Endpoint Groups 4 | # 5 | 6 | endpoint_groups: 7 | 8 | #------------------------------------------------------------------------------ 9 | # Generic Groups 10 | #------------------------------------------------------------------------------ 11 | 12 | - name: Allowed 13 | description: Blocked 14 | 15 | - name: Blocked 16 | description: Blocked 17 | 18 | - name: Assets 19 | description: Assets 20 | 21 | - name: IOT 22 | description: IOT 23 | 24 | 25 | #------------------------------------------------------------------------------ 26 | # Office Devices 27 | #------------------------------------------------------------------------------ 28 | 29 | # - name: Computer 30 | # description: Computer 31 | 32 | # - name: Mobile 33 | # description: Mobile 34 | 35 | # - name: Desktops 36 | # description: Desktops 37 | 38 | # - name: Laptops 39 | # description: Laptops 40 | 41 | # - name: Smartphones 42 | # description: Smartphones 43 | 44 | # - name: Tablets 45 | # description: Tablets 46 | 47 | # - name: Servers 48 | # description: Servers 49 | 50 | # - name: Workstations 51 | # description: Workstations 52 | 53 | - name: Printers 54 | description: Printers 55 | 56 | 57 | #------------------------------------------------------------------------------ 58 | # Networking Devices 59 | #------------------------------------------------------------------------------ 60 | 61 | # - name: AP 62 | # description: Access Point 63 | 64 | - name: Raspberry_Pi 65 | description: Raspberry Pi 66 | 67 | 68 | #------------------------------------------------------------------------------ 69 | # Computer Lab Devices 70 | #------------------------------------------------------------------------------ 71 | 72 | # - name: Lab 73 | # description: Lab 74 | 75 | # - name: Power 76 | # description: Power Supplies, Outlets, UPS, etc. 77 | 78 | # - name: RFID 79 | # description: RFID Sensors 80 | 81 | # - name: UPS 82 | # description: Uninterruptible Power Supply (UPS) 83 | 84 | 85 | #------------------------------------------------------------------------------ 86 | # Communications 87 | #------------------------------------------------------------------------------ 88 | 89 | # - name: Phones 90 | # description: Phones 91 | 92 | # - name: Webex 93 | # description: Webex 94 | 95 | 96 | #------------------------------------------------------------------------------ 97 | # Physical Security 98 | #------------------------------------------------------------------------------ 99 | 100 | # - name: Badge_Readers 101 | # description: Badge Readers 102 | 103 | # - name: Cameras 104 | # description: Cameras 105 | 106 | 107 | #------------------------------------------------------------------------------ 108 | # Building / Facilities 109 | #------------------------------------------------------------------------------ 110 | 111 | # - name: Lighting 112 | # description: Lighting 113 | 114 | # - name: HVAC 115 | # description: HVAC 116 | 117 | # - name: Thermostats 118 | # description: Thermostats 119 | 120 | # - name: Elevators 121 | # description: Elevators 122 | 123 | # - name: Pumps 124 | # description: Pumps 125 | 126 | # - name: Vending 127 | # description: Vending 128 | 129 | 130 | #------------------------------------------------------------------------------ 131 | # Entertainment Devices 132 | #------------------------------------------------------------------------------ 133 | 134 | # - name: Entertainment 135 | # description: Entertainment 136 | 137 | # - name: Amazon_Echo 138 | # description: AmazonTV 139 | 140 | # - name: Amazon_TV 141 | # description: AmazonTV 142 | 143 | # - name: Amazon_FireStick 144 | # description: AmazonTV 145 | 146 | # - name: Apple_TV 147 | # description: Apple TV 148 | 149 | # - name: Apple_iPad 150 | # description: Apple iPad 151 | 152 | # - name: Roku 153 | # description: Roku 154 | 155 | # - name: TV 156 | # description: Television (any manufacturer) 157 | 158 | 159 | #------------------------------------------------------------------------------ 160 | # Vertical: Manufacturing 161 | #------------------------------------------------------------------------------ 162 | 163 | # - name: Manufacturing 164 | # description: Manufacturing 165 | 166 | 167 | #------------------------------------------------------------------------------ 168 | # Vertical: Medical 169 | #------------------------------------------------------------------------------ 170 | 171 | # - name: Medical 172 | # description: Medical 173 | 174 | 175 | #------------------------------------------------------------------------------ 176 | # Vertical: Retail 177 | #------------------------------------------------------------------------------ 178 | 179 | # - name: PoS 180 | # description: Point of Sale 181 | 182 | # - name: Register 183 | # description: Scanner 184 | 185 | # - name: Scanner 186 | # description: Scanner 187 | 188 | 189 | 190 | #------------------------------------------------------------------------------ 191 | # Device Types from https://nmap.org/book/osdetect-device-types.html 192 | #------------------------------------------------------------------------------ 193 | 194 | # - name: general_purpose 195 | # description: This category contains general-purpose operating systems like Linux and Windows 196 | 197 | # - name: bridge 198 | # description: A bridge combines two or more subnetworks into one 199 | 200 | # - name: broadband_router 201 | # description: A router that connects a network to the Internet via cable, ADSL, fiber optics, etc. 202 | 203 | # - name: firewall 204 | # description: A firewall controls what traffic is allowed into or out of a network 205 | 206 | # - name: game_console 207 | # description: A video game console like the Xbox or PlayStation. 208 | 209 | # - name: hub 210 | # description: A hub joins network segments by re-broadcasting all traffic 211 | 212 | # - name: load_balancer 213 | # description: A device that distributes inbound traffic to multiple devices to ease the load on those devices 214 | 215 | # - name: media_device 216 | # description: All kinds of audiovisual equipment: music players, audio systems, TVs, and projectors 217 | 218 | # - name: PBX 219 | # description: A private branch exchange, or PBX, routes telephone calls within a private organization and connects them to the public telephone network or VoIP 220 | 221 | # - name: PDA 222 | # description: A handheld computer 223 | 224 | # - name: phone 225 | # description: A network-capable telephone that is not a VoIP phone 226 | 227 | # - name: power-device 228 | # description: Miscellaneous power devices like uninterruptable power supplies and surge protectors 229 | 230 | # - name: printer 231 | # description: Network-enabled printers, including printers with an embedded print server 232 | 233 | # - name: print_server 234 | # description: A print server connects a printer to a network 235 | 236 | # - name: proxy_server 237 | # description: Any kind of proxy 238 | 239 | # - name: remote_management 240 | # description: Devices that allow servers or other equipment to be monitored or managed remotely 241 | 242 | # - name: router 243 | # description: Routers connect multiple networks and route packets between different networks 244 | 245 | # - name: security-misc 246 | # description: Any security device that doesn't fall into the “firewall” category belongs in this category 247 | 248 | # - name: specialized 249 | # description: If a device doesn't fall into one of the other categories, it is specialized. Examples in this category are diverse and include such things as clocks, oscilloscopes, climate sensors, and more. 250 | 251 | # - name: storage-misc 252 | # description: Data storage devices like tape decks and network-attached storage appliances. 253 | 254 | # - name: switch 255 | # description: A device that extends a network by selectively re-broadcasting packets 256 | 257 | # - name: telecom-misc 258 | # description: Devices used by telephone systems that aren't PBXs, like voicemail and ISDN systems. 259 | 260 | # - name: terminal 261 | # description: A device with a keyboard and monitor that communicates with a terminal server or mainframe 262 | 263 | # - name: terminal_server 264 | # description: A device providing terminal facilities to clients over a network. 265 | 266 | # - name: VoIP_Adapter 267 | # description: A device that converts between voice over IP (VoIP) protocols and normal telephone traffic 268 | 269 | # - name: VoIP_Phone 270 | # description: A phone capable of a VoIP protocol. 271 | 272 | # - name: WAP 273 | # description: Wireless access points offer a wireless connection to a network 274 | 275 | # - name: webcam 276 | # description: Any kind of camera that stores or transmits pictures or video 277 | 278 | 279 | ... -------------------------------------------------------------------------------- /aws.show.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | #------------------------------------------------------------------------------ 3 | # Show AWS Info 4 | # 5 | # Export your AWS Access & Secret keys into your terminal environment for 6 | # authentication of the calls below: 7 | # 8 | # export AWS_REGION='us-west-1' 9 | # export AWS_ACCESS_KEY='AKIAIOSF/EXAMPLE+KEY' 10 | # export AWS_SECRET_KEY='wJalrXUtnFEMI/K7MDENG/bPxRfi/EXAMPLE+KEY' 11 | # 12 | # Invoke with tag names to only get what you need: 13 | # 14 | # ansible-playbook aws.show.yaml --tags vpc,sg 15 | #------------------------------------------------------------------------------ 16 | 17 | - name: Show AWS Info Playbook 18 | gather_facts: no 19 | hosts: localhost 20 | vars_files: 21 | - vars/main.yaml 22 | tasks: 23 | 24 | 25 | # 26 | # Show Caller Info - the user and account being used to make AWS calls 27 | # 28 | 29 | - name: Get the current caller identity information 30 | amazon.aws.aws_caller_info: 31 | register: caller_info 32 | tags: 33 | - caller 34 | 35 | - name: caller_info 36 | ansible.builtin.debug: var=caller_info 37 | tags: 38 | - caller 39 | 40 | 41 | # 42 | # Show Regions 43 | # 44 | 45 | - name: Info for All Regions 46 | community.aws.aws_region_info: 47 | # filters: 48 | register: result 49 | tags: 50 | - region 51 | - regions 52 | 53 | - name: List of Region Names 54 | when: result is defined and result != [] 55 | loop: "{{ result.regions }}" 56 | vars: 57 | region_names: [] 58 | ansible.builtin.set_fact: 59 | region_names: "{{ region_names + [ item.region_name ] }}" 60 | tags: 61 | - region 62 | - regions 63 | 64 | - name: Region Names 65 | ansible.builtin.debug: var=region_names 66 | tags: 67 | - region 68 | - regions 69 | 70 | 71 | 72 | 73 | # 74 | # Show Availability Zones 75 | # 76 | - name: Get All Availability Zones in a Region 77 | amazon.aws.aws_az_info: 78 | register: azs 79 | tags: 80 | - az 81 | - availability_zone 82 | 83 | - name: List of Availability Zone Names 84 | when: azs is defined and azs != [] 85 | loop: "{{ azs.availability_zones }}" 86 | vars: 87 | az_names: [] 88 | ansible.builtin.set_fact: 89 | az_names: "{{ az_names + [ item.zone_name ] }}" 90 | tags: 91 | - az 92 | - availability_zone 93 | 94 | - name: Availability Zone Names 95 | ansible.builtin.debug: var=az_names 96 | tags: 97 | - az 98 | - availability_zone 99 | 100 | 101 | 102 | 103 | # 104 | # Show VPCs 105 | # 106 | 107 | - name: Get VPC(s) 108 | amazon.aws.ec2_vpc_net_info: 109 | # name: "{{ aws_vpc_name }}" 110 | # cidr_block: "{{ aws_vpc_cidr }}" 111 | # region: "{{ aws_region }}" 112 | register: vpcs 113 | tags: 114 | - vpc 115 | - vpcs 116 | - name: Show vpcs 117 | ansible.builtin.debug: var=vpcs 118 | tags: 119 | - vpc 120 | - vpcs 121 | 122 | 123 | 124 | 125 | # 126 | # EC2 Instances 127 | # 128 | - name: Query AWS EC2 Instances 129 | community.aws.ec2_instance_info: 130 | region: "{{ aws_region }}" 131 | filters: 132 | "tag:project": "{{ project_name }}" 133 | instance-state-name: running 134 | register: instances 135 | tags: 136 | - ec2 137 | - instances 138 | 139 | - name: Show instances 140 | ansible.builtin.debug: var=instances 141 | tags: 142 | - ec2 143 | - instances 144 | 145 | - name: List of AWS EC2 Instances 146 | when: instances is defined and instances != [] 147 | loop: "{{ instances.instances }}" 148 | vars: 149 | instance_names: [] 150 | attrs: ['image_id', 'instance_id', 'instance_type', 'key_name', 'private_ip_address', 'public_ip_address' ] 151 | ansible.builtin.set_fact: 152 | instance_names: "{{ instance_names + [ item.tags.Name ] }}" 153 | tags: 154 | - ec2 155 | - instances 156 | 157 | - name: Show AWS EC2 Instances by Name 158 | ansible.builtin.debug: var=instance_names 159 | tags: 160 | - ec2 161 | - instances 162 | 163 | 164 | 165 | 166 | # 167 | # Show Security Groups 168 | # 169 | 170 | 171 | - name: Show Security Groups 172 | amazon.aws.ec2_group_info: 173 | # filters: 174 | # vpc_id: "{{ vpcs.vpcs.id }}" 175 | # region: "{{ aws_region }}" 176 | register: security_groups 177 | tags: 178 | - sg 179 | - security_group 180 | 181 | - name: Show security_groups 182 | ansible.builtin.debug: var=security_groups 183 | tags: 184 | - sg 185 | - security_group 186 | 187 | - name: Get All Security Groups 188 | amazon.aws.ec2_group_info: 189 | register: sgs 190 | tags: 191 | - sg 192 | - security_group 193 | 194 | - name: List of Security Groups 195 | when: sgs is defined and sgs != [] 196 | loop: "{{ sgs.security_groups }}" 197 | vars: 198 | sg_names: [] 199 | ansible.builtin.set_fact: 200 | sg_names: "{{ sg_names + [ item.group_id + ' | ' + item.group_name ] }}" 201 | tags: 202 | - sg 203 | - security_group 204 | 205 | - name: sg_names 206 | ansible.builtin.debug: var=sg_names 207 | tags: 208 | - sg 209 | - security_group 210 | 211 | - name: Get details for Security Groups 212 | amazon.aws.ec2_group_info: 213 | filters: 214 | group-name: "{{ sg_names }}" 215 | register: sg_details 216 | tags: 217 | - sg 218 | - security_group 219 | 220 | - name: sg_details 221 | ansible.builtin.debug: var=sg_details 222 | tags: 223 | - sg 224 | - security_group 225 | 226 | 227 | # 228 | # Show CloudFormation stack(s) 229 | # 230 | - name: Get All CloudFormation info 231 | amazon.aws.cloudformation_info: 232 | register: stacks 233 | tags: 234 | - cf 235 | - cft 236 | - cloudformation 237 | - stacks 238 | 239 | 240 | - name: stacks.cloudformation 241 | ansible.builtin.debug: var=stacks.cloudformation 242 | tags: 243 | - cf 244 | - cft 245 | - cloudformation 246 | - stacks 247 | 248 | - name: List of CloudFormation Stacks 249 | when: stacks is defined and stacks != [] 250 | loop: "{{ lookup('dict', stacks.cloudformation) }}" 251 | vars: 252 | stack_names: [] 253 | ansible.builtin.set_fact: 254 | stack_names: "{{ stack_names + [ item.key ] }}" 255 | tags: 256 | - cf 257 | - cft 258 | - cloudformation 259 | - stacks 260 | 261 | - name: stack_names 262 | ansible.builtin.debug: var=stack_names 263 | tags: 264 | - cf 265 | - cft 266 | - cloudformation 267 | - stacks 268 | 269 | 270 | 271 | 272 | # 273 | # Show ec2 ENI interfaces in AWS 274 | # 275 | 276 | - name: Get All ec2_eni_info 277 | amazon.aws.ec2_group_info: 278 | # filters: 279 | # network-interface-id: eni-xxxxxxx 280 | register: result 281 | tags: 282 | - eni 283 | 284 | - name: List of ENI 285 | when: result is defined and result != [] 286 | loop: "{{ result.security_groups }}" 287 | vars: 288 | eni_names: [] 289 | ansible.builtin.set_fact: 290 | eni_names: "{{ eni_names + [ item.group_id + ' | ' + item.group_name ] }}" 291 | tags: 292 | - eni 293 | 294 | - name: eni_names 295 | ansible.builtin.debug: var=eni_names 296 | tags: 297 | - eni 298 | 299 | 300 | # 301 | # Show ec2 volumes in AWS 302 | # 303 | - name: Get All Volumes 304 | amazon.aws.ec2_vol_info: 305 | region: "{{ aws_region }}" 306 | register: result 307 | tags: 308 | - volume 309 | - volumes 310 | 311 | - name: result 312 | ansible.builtin.debug: var=result 313 | tags: 314 | - volume 315 | - volumes 316 | 317 | # 318 | # Show dhcp options sets in AWS 319 | # 320 | - name: Get All ec2_vpc_dhcp_option_info 321 | amazon.aws.ec2_vpc_dhcp_option_info: 322 | region: "{{ aws_region }}" 323 | register: result 324 | tags: 325 | - vpc 326 | - dhcp 327 | 328 | - name: result 329 | ansible.builtin.debug: var=result 330 | tags: 331 | - vpc 332 | - dhcp 333 | 334 | # 335 | # ec2_vpc_net_info – Gather information about ec2 VPCs in AWS 336 | # 337 | - name: Get All ec2_vpc_net_info 338 | amazon.aws.ec2_vpc_net_info: 339 | region: "{{ aws_region }}" 340 | register: result 341 | tags: 342 | - vpc 343 | - net 344 | - network 345 | 346 | - name: result 347 | ansible.builtin.debug: var=result 348 | tags: 349 | - vpc 350 | - net 351 | - network 352 | 353 | 354 | # 355 | # Show ec2 VPC subnets in AWS 356 | # 357 | - name: Get All ec2_vpc_subnet_info 358 | amazon.aws.ec2_vpc_subnet_info: 359 | region: "{{ aws_region }}" 360 | register: result 361 | tags: 362 | - subnet 363 | - vpc 364 | 365 | - name: result 366 | ansible.builtin.debug: var=result 367 | tags: 368 | - subnet 369 | - vpc 370 | 371 | 372 | ... 373 | -------------------------------------------------------------------------------- /ise_in_aws.vmx.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # 4 | # The default LAN Setting for a new network will be : 5 | # 6 | # | Name | Subnet | MX IP 7 | # |---------------------|-------------------|-------------- 8 | # | Single LAN Settings | 192.168.128.0/24 | 192.168.128.1 9 | # 10 | - name: Create a vMX Network '{{ meraki_org_name }}:{{ meraki_vmx_net_name }}' 11 | cisco.meraki.meraki_network: 12 | org_name: "{{ meraki_org_name }}" 13 | net_name: "{{ meraki_vmx_net_name }}" 14 | state: present 15 | type: appliance 16 | timezone: America/Los_Angeles # Timezones: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones 17 | tags: ise, demo, lab, hub, mx 18 | register: vmx_network 19 | 20 | # - name: vmx_network 21 | # ansible.builtin.debug: var=vmx_network 22 | 23 | - name: Create SG-AllowAll Security Group 24 | amazon.aws.ec2_group: 25 | name: SG-AllowAll 26 | description: Allow all traffic 27 | vpc_id: "{{ vpc.vpc.id }}" 28 | region: "{{ aws_region }}" 29 | rules: 30 | - proto: all 31 | cidr_ip: 0.0.0.0/0 # any 32 | rule_desc: Allow All 33 | rules_egress: 34 | - proto: all 35 | cidr_ip: 0.0.0.0/0 # any 36 | rule_desc: Allow All 37 | tags: 38 | Name: SG-AllowAll 39 | project: "{{ project_name }}" 40 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 41 | register: sg_allowall 42 | 43 | # - name: Show sg_allowall 44 | # ansible.builtin.debug: var=sg_allowall 45 | 46 | - name: Check for Existing vMX Instance (idempotency) | {{ project_name }} 47 | community.aws.ec2_instance_info: # get all by default 48 | filters: 49 | instance-state-name: ["running"] 50 | "tag:project": "{{ project_name }}" 51 | "tag:Name": "{{ vmx_name }}" 52 | "tag:product": "vMX" 53 | register: vmx 54 | 55 | - name: Show Existing vMX 56 | when: vmx is defined 57 | ansible.builtin.debug: var=vmx 58 | 59 | 60 | - name: Claim License, Generate Token, and Create vMX Instance 61 | when: vmx.instances | count <= 0 62 | block: 63 | - name: Claim vMX Device & License 64 | ansible.builtin.uri: 65 | url: "https://api.meraki.com/api/v1/networks/{{ vmx_network.data.id }}/devices/claim/vmx" 66 | method: POST 67 | headers: 68 | Accept: application/json 69 | Content-Type: application/json 70 | X-Cisco-Meraki-API-Key: "{{ lookup('env','MERAKI_KEY') }}" 71 | body: 72 | size: "{{ vmx_license_size }}" 73 | body_format: json 74 | status_code: 200 75 | validate_certs: false 76 | return_content: true 77 | register: new_vmx 78 | 79 | # - name: Show vmx 80 | # ansible.builtin.debug: var=new_vmx.json 81 | 82 | - name: Generate vMX Token 83 | ansible.builtin.uri: 84 | url: "https://api.meraki.com/api/v1/devices/{{ new_vmx.json.serial }}/appliance/vmx/authenticationToken" 85 | method: POST 86 | headers: 87 | Accept: application/json 88 | Content-Type: application/json 89 | X-Cisco-Meraki-API-Key: "{{ lookup('env','MERAKI_KEY') }}" 90 | body_format: json 91 | status_code: 201 92 | validate_certs: false 93 | return_content: true 94 | register: vmx_token_response 95 | 96 | # - name: Show vmx_token_response 97 | # ansible.builtin.debug: var=vmx_token_response.json 98 | 99 | - name: Extract Token 100 | ansible.builtin.set_fact: 101 | meraki_vmx_authentication_token: "{{ vmx_token_response.json.token }}" 102 | 103 | # - name: Show token 104 | # ansible.builtin.debug: var=meraki_vmx_authentication_token 105 | 106 | # 107 | # 💡 Uses the community.aws.ec2_instance module which supports `user_data` 108 | # field for inclusion of the Meraki vMX Authentication Token! 109 | # 110 | - name: Create vMX Instance 111 | community.aws.ec2_instance: 112 | # state: present # instances exist but not guarantee of state (e.g. running) 113 | state: running # present + ensures the instances are running for public IP address! 114 | # state: started # running + waits for EC2 status checks; ~3 minutes per node 115 | vpc_subnet_id: "{{ subnet_public.subnet.id }}" 116 | region: "{{ aws_region }}" 117 | image_id: "{{ vmx_aws_ami }}" 118 | instance_type: "{{ vmx_aws_instance_type }}" 119 | key_name: "{{ ssh_keypair_name }}" # SSH Keypair Name 120 | security_group: "{{ sg_allowall.group_name }}" 121 | network: 122 | assign_public_ip: yes 123 | delete_on_termination: yes 124 | private_ip_address: "{{ vmx_private_ip }}" 125 | volumes: 126 | - device_name: /dev/xvda 127 | ebs: 128 | delete_on_termination: true 129 | volume_size: 10 130 | user_data: "{{ meraki_vmx_authentication_token | trim }}" 131 | wait: yes # must wait to get eni for NAT and private RT changes 132 | tags: 133 | Name: "{{ vmx_name }}" 134 | project: "{{ project_name }}" 135 | product: vMX 136 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 137 | register: vmx 138 | 139 | - name: Show vMX Instance 140 | ansible.builtin.debug: var=vmx 141 | 142 | 143 | # 144 | # ⚠ Requires the vMX to be initialized; Use `wait: yes` above 145 | # ⚠ Works with eni_id but not subnet_id 146 | # 147 | - name: Disable Source/Destination Check for vMX as NAT device! 148 | amazon.aws.ec2_eni: 149 | instance_id: "{{ vmx.instances[0].instance_id }}" 150 | eni_id: "{{ vmx.instances[0].network_interfaces[0].network_interface_id }}" 151 | source_dest_check: false 152 | register: vmx_eni 153 | 154 | # - name: Show vmx_eni 155 | # ansible.builtin.debug: var=vmx_eni 156 | 157 | - name: Add Public DNS entry for the vMX 158 | when: domain_name is defined 159 | community.aws.route53: 160 | state: present 161 | zone: "{{ domain_name }}" 162 | record: "{{ project_name }}-vmx.{{ domain_name }}" 163 | overwrite: yes 164 | private_zone: no 165 | type: A 166 | ttl: 7200 167 | value: "{{ vmx.instances[0].public_ip_address }}" 168 | wait: no 169 | 170 | - name: Add private DNS entry for the vMX 171 | when: domain_name is defined 172 | community.aws.route53: 173 | state: present 174 | zone: "{{ domain_name }}" 175 | record: "{{ project_name }}-vmx.{{ domain_name }}" 176 | overwrite: yes 177 | private_zone: yes 178 | type: A 179 | ttl: 7200 180 | value: "{{ vmx.instances[0].private_ip_address }}" 181 | wait: no 182 | 183 | # 184 | # Update the Private Route Table 185 | # 186 | # | Destination | Target | 187 | # |-----------------|--------| 188 | # | 172.31.0.0/16 | local 189 | # | 192.168.0.0/16 | eni-* <=== add this 190 | # | 0.0.0.0/0 | igw-* 191 | # 192 | - name: Update the AWS Private Route Table with vMX VPN Network 193 | community.aws.ec2_vpc_route_table: 194 | vpc_id: "{{ vpc.vpc.id }}" 195 | subnets: 196 | - "{{ subnet_private.subnet.id }}" 197 | routes: 198 | - dest: 0.0.0.0/0 199 | gateway_id: "{{ igw.gateway_id }}" 200 | - dest: 192.168.0.0/16 201 | instance_id: "{{ vmx.instances[0].instance_id }}" 202 | tags: 203 | Name: RT_Private 204 | project: "{{ project_name }}" 205 | started: "{{ '%Y-%m-%dT%H:%M:%S-%Z' | strftime }}" 206 | register: rt_private 207 | 208 | - name: Find {{ meraki_vpn_hub.net_name }} Network to use as VPN Hub 209 | cisco.meraki.meraki_network: 210 | org_name: "{{ meraki_org_name }}" 211 | net_name: "{{ meraki_vpn_hub.net_name }}" 212 | state: query 213 | register: lab_network 214 | 215 | # - name: Show lab_network 216 | # ansible.builtin.debug: var=lab_network.data 217 | 218 | # ⓘ Meraki vMX must be configured "Passthrough or VPN Concentrator" mode! 219 | # "Routed" mode requires 2 or more ports but vMX only has 1 port! 220 | - name: Configure vMX Deployment as Passthrough or VPN Concentrator 221 | delegate_to: localhost 222 | ansible.builtin.uri: 223 | url: "https://api.meraki.com/api/v1/networks/{{ vmx_network.data.id }}/appliance/settings" 224 | method: PUT 225 | headers: 226 | Accept: application/json 227 | Content-Type: application/json 228 | X-Cisco-Meraki-API-Key: "{{ lookup('env','MERAKI_KEY') }}" 229 | body: 230 | deploymentMode: passthrough 231 | body_format: json 232 | status_code: 200 233 | validate_certs: false 234 | return_content: true 235 | register: vmx_deployment 236 | 237 | - name: Show vMX Settings 238 | ansible.builtin.debug: var=vmx_deployment.json 239 | 240 | - name: Set vMX to VPN Spoke mode to Lab Hub 241 | cisco.meraki.meraki_site_to_site_vpn: 242 | org_name: "{{ meraki_org_name }}" 243 | net_name: "{{ meraki_vmx_net_name }}" 244 | state: present 245 | mode: spoke # use `spoke` to avoid AWS $$$ for outbound `hub` traffic 246 | hubs: 247 | - hub_id: "{{ lab_network.data.id }}" 248 | use_default_route: false # send all default route traffic to this hub 249 | register: spoke_mode 250 | # - name: spoke_mode 251 | # ansible.builtin.debug: var=spoke_mode 252 | 253 | - name: Manually add the vMX Local Subnet 254 | ansible.builtin.pause: 255 | prompt: | 256 | 257 | You must now manually add the vMX Local Subnet in the Site-to-Site VPN. 258 | 259 | 1. Open the Meraki Dashboard 260 | 2. Go to Security & SDWAN > Configure > Site-to-Site VPN 261 | 3. Under VPN Settings, Add a Local Network: 262 | Name: ISE_Meraki_AWS 263 | VPN Mode: Enabled 264 | Subnet: 172.31.0.0/16 265 | 4. Save! 266 | 267 | You may now ping through the auto-VPN into your AWS instance(s)! 268 | 269 | Press Enter to Continue... 270 | -------------------------------------------------------------------------------- /ise_in_aws.terminate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | #------------------------------------------------------------------------------ 3 | # Terminate AWS EC2 Instances for a tagged project: 4 | # - Terminate all EC2 instances 5 | # - Delete Subnets 6 | # - Delete Route Table 7 | # - Delete Internet Gateway 8 | # - Delete Security Groups in VPC 9 | # - Delete VPCs 10 | # - Delete private key 11 | # - TODO: Delete Route53 records 12 | # - TODO: Delete S3 Buckets 13 | # 14 | # Run: `ansible-playbook ise_in_aws.terminate.yaml` 15 | #------------------------------------------------------------------------------ 16 | 17 | - name: Destroy All Resources for project:"{{ project_name }}" 18 | hosts: localhost 19 | gather_facts: no 20 | vars_files: vars/main.yaml 21 | tasks: 22 | #---------------------------------------------------------------------------- 23 | # Confirm Project! 24 | #---------------------------------------------------------------------------- 25 | 26 | - name: Prompt for Project to Delete 27 | ansible.builtin.pause: 28 | prompt: "Project Name [{{ project_name | default('') }}]" 29 | register: result 30 | 31 | - name: Set Project Name 32 | when: result.user_input is defined and result.user_input | length > 0 33 | ansible.builtin.set_fact: 34 | project_name: "{{ result.user_input | trim }}" 35 | 36 | #---------------------------------------------------------------------------- 37 | # Get All Resources 38 | #---------------------------------------------------------------------------- 39 | 40 | - name: Get All EC2 Instances with tag project:"{{ project_name }}" 41 | amazon.aws.ec2_instance_info: # Get All by default 42 | filters: 43 | instance-state-name: 44 | - rebooted # convenience alias for state=stopped immediately followed by state=running 45 | - restarted # convenience alias for state=stopped immediately followed by state=started 46 | - running # state=present + ensures the instances are running 47 | - started # state=running + waits for EC2 status checks to report OK if wait=true 48 | - stopped # ensures an existing instance is stopped. 49 | - present # instances exist, but does not guarantee any state (e.g. running) 50 | # - terminated # ensures an existing instance is terminated. 51 | # - absent # alias for state=terminated 52 | "tag:project": "{{ project_name }}" 53 | register: ec2_instances 54 | 55 | - name: Get All VPCs | project:"{{ project_name }}" 56 | amazon.aws.ec2_vpc_net_info: 57 | filters: 58 | "tag:project": "{{ project_name }}" 59 | register: vpcs 60 | 61 | - name: Get All Dangling ENIs in the VPC 62 | when: vpcs.vpcs is defined and vpcs.vpcs | length > 0 63 | amazon.aws.ec2_eni_info: 64 | filters: 65 | vpc-id: "{{ vpcs.vpcs[0].id }}" 66 | "tag:project": "{{ project_name }}" 67 | register: enis 68 | 69 | # - name: Get All DHCP Option in the VPC 70 | # amazon.aws.ec2_vpc_dhcp_option_info: 71 | # # filters: 72 | # # "tag:project": "{{ project_name }}" 73 | # register: dhcp_info 74 | # - ansible.builtin.debug: var=dhcp_info 75 | 76 | - name: Get All Subnets | project:"{{ project_name }}" 77 | amazon.aws.ec2_vpc_subnet_info: 78 | filters: 79 | "tag:project": "{{ project_name }}" 80 | register: subnets 81 | 82 | - name: Get All Route Tables | project:"{{ project_name }}" 83 | amazon.aws.ec2_vpc_route_table_info: 84 | filters: 85 | "tag:project": "{{ project_name }}" 86 | register: route_tables 87 | 88 | - name: Get All Internet Gateways | project:"{{ project_name }}" 89 | amazon.aws.ec2_vpc_igw_info: 90 | filters: 91 | "tag:project": "{{ project_name }}" 92 | register: igws 93 | 94 | - name: Get All Security Groups | project:"{{ project_name }}" 95 | amazon.aws.ec2_group_info: 96 | filters: 97 | "tag:project": "{{ project_name }}" 98 | register: security_groups 99 | 100 | - name: Get Networks | {{ meraki_org_name }} ({{ meraki_org_id }}) 101 | delegate_to: localhost 102 | cisco.meraki.networks_info: 103 | organizationId: "{{ meraki_org_id }}" 104 | register: meraki_networks 105 | 106 | - name: Show Networks | {{ meraki_org_name }} ({{ meraki_org_id }}) 107 | delegate_to: localhost 108 | vars: 109 | hide: ["enrollmentString", "url"] 110 | maxw: 30 111 | rows: "{{ meraki_networks.meraki_response }}" 112 | temp: "{{ lookup('template', 'templates/list_of_dicts.j2') }}" 113 | ansible.builtin.debug: 114 | msg: "{{ temp }}" 115 | 116 | - name: Get Meraki vMX Networks | {{ project_name }} 117 | ansible.builtin.set_fact: 118 | vmx_network: "{{ meraki_networks.meraki_response | selectattr('name', 'equalto', project_name ) | first }}" 119 | 120 | #---------------------------------------------------------------------------- 121 | # Summarize Resources to Destroy 122 | #---------------------------------------------------------------------------- 123 | - name: Resource Summary 124 | ansible.builtin.debug: 125 | msg: | 126 | - {{ vpcs.vpcs | length }} VPCs 127 | - {{ subnets.subnets | length }} Subnets 128 | - {{ route_tables.route_tables | length }} Route Tables 129 | - {{ igws.internet_gateways | length }} Internet Gateways 130 | - {{ security_groups.security_groups | length }} Security Groups 131 | - {{ ec2_instances.instances | length }} EC2 Instances 132 | - {{ enis.network_interfaces | default([]) | length }} ENIs 133 | - {{ meraki_networks.meraki_response | length }} Meraki Networks 134 | - vMX Network: {{ vmx_network.name }} 135 | 136 | #---------------------------------------------------------------------------- 137 | # Confirm Destruction! 138 | #---------------------------------------------------------------------------- 139 | 140 | - name: Confirm Deletion 141 | ansible.builtin.pause: 142 | prompt: | 143 |   144 |   /\ 145 |   / \ 146 |   / ❕ \ Delete All resources in the project "{{ project_name }}"? [y/n] (yes) 147 |   /______\ 148 |   149 | register: input 150 | 151 | # - ansible.builtin.debug: var=input.user_input 152 | 153 | - name: Set Delete Confirmation 154 | when: input.user_input is defined 155 | ansible.builtin.set_fact: 156 | is_confirmed: "{{ (input.user_input | length == 0) or (input.user_input[0] | lower == 'y') }}" 157 | 158 | - name: Show is_confirmed 159 | ansible.builtin.debug: 160 | var: is_confirmed 161 | verbosity: 3 162 | 163 | - name: Delete the Meraki vMX Network | {{ vmx_network.name }} ({{ vmx_network.id }}) 164 | cisco.meraki.networks: 165 | state: absent 166 | organizationId: "{{ meraki_org_id }}" 167 | networkId: "{{ vmx_network.id }}" 168 | 169 | #---------------------------------------------------------------------------- 170 | # Delete VPC Resources 171 | #---------------------------------------------------------------------------- 172 | 173 | - name: Delete All EC2 instances | project:"{{ project_name }}" 174 | when: is_confirmed and ec2_instances is defined and ec2_instances | length > 0 175 | amazon.aws.ec2_instance: 176 | state: absent 177 | wait: yes 178 | filters: 179 | # instance-state-name: [ "running" ] 180 | "tag:project": "{{ project_name }}" 181 | register: ec2_instances_deleted 182 | # - ansible.builtin.debug: var=ec2_instances_deleted 183 | 184 | - name: Delete All dangling ENIs 185 | when: is_confirmed and enis.network_interfaces is defined and enis.network_interfaces | length > 0 186 | loop: "{{ enis.network_interfaces }}" 187 | amazon.aws.ec2_eni: 188 | state: absent 189 | eni_id: "{{ item.id }}" 190 | 191 | # - name: Delete All DHCP Options 192 | # amazon.aws.ec2_vpc_dhcp_option: 193 | # # vpc_id: "{{ vpcs.vpcs[0].id }}" 194 | # state: absent 195 | # register: dhcp_info_deleted 196 | # - ansible.builtin.debug: var=dhcp_info_deleted 197 | 198 | - name: Delete Subnets 199 | when: is_confirmed and subnets is defined and subnets.subnets | length > 0 200 | loop: "{{ subnets.subnets }}" 201 | amazon.aws.ec2_vpc_subnet: 202 | vpc_id: "{{ item.vpc_id }}" 203 | cidr: "{{ item.cidr_block }}" 204 | state: absent 205 | register: subnets_deleted 206 | 207 | # - ansible.builtin.debug: var=subnets_deleted 208 | 209 | - name: Delete Route Table 210 | when: is_confirmed and route_tables is defined and route_tables.route_tables | length > 0 211 | loop: "{{ route_tables.route_tables }}" 212 | amazon.aws.ec2_vpc_route_table: 213 | route_table_id: "{{ item.id }}" 214 | lookup: id 215 | state: absent 216 | register: route_tables_deleted 217 | 218 | # - ansible.builtin.debug: var=route_tables_deleted 219 | 220 | - name: Delete Internet Gateway 221 | when: is_confirmed and igws is defined # and igws.internet_gateways | length > 0 222 | loop: "{{ vpcs.vpcs }}" 223 | amazon.aws.ec2_vpc_igw: 224 | vpc_id: "{{ item.vpc_id }}" 225 | state: absent 226 | register: igws_deleted 227 | 228 | # - ansible.builtin.debug: var=igws_deleted 229 | 230 | - name: Delete Security Groups in VPC 231 | when: is_confirmed and security_groups is defined and security_groups.security_groups | length > 0 232 | loop: "{{ security_groups.security_groups }}" 233 | amazon.aws.ec2_group: 234 | group_id: "{{ item.group_id }}" 235 | state: absent 236 | register: security_groups_deleted 237 | 238 | # - ansible.builtin.debug: var=security_groups_deleted 239 | 240 | - name: Delete VPCs | project:"{{ project_name }}" 241 | when: is_confirmed and vpcs is defined and vpcs.vpcs | length > 0 242 | loop: "{{ vpcs.vpcs }}" 243 | amazon.aws.ec2_vpc_net: 244 | vpc_id: "{{ item.vpc_id }}" # required 245 | purge_cidrs: yes # Remove CIDRs associated with VPC and no in cidr_block 246 | state: absent 247 | register: vpcs_deleted 248 | 249 | - ansible.builtin.debug: var=vpcs_deleted 250 | when: debug is defined and debug 251 | 252 | - name: Delete Keypair in AWS | {{ ssh_keypair_name }} 253 | when: is_confirmed 254 | amazon.aws.ec2_key: 255 | name: "{{ ssh_keypair_name }}" 256 | state: absent 257 | register: keypair_remote_deleted 258 | # - ansible.builtin.debug: var=keypair_remote_deleted 259 | 260 | - name: Delete Local Private Key | {{ ssh_keypair_directory }}/{{ ssh_keypair_name }} 261 | when: is_confirmed and ssh_keypair_name is defined 262 | ansible.builtin.file: 263 | path: "{{ ssh_keypair_directory }}/{{ ssh_keypair_name }}" 264 | state: absent 265 | register: keypair_local_deleted 266 | # - ansible.builtin.debug: var=keypair_local_deleted 267 | 268 | # 269 | # ToDo: Delete Route53 DNS Records in Project 270 | # 271 | 272 | # - name: Retrieve the DNS records 273 | # community.aws.route53: 274 | # state: get 275 | # zone: "{{ domain_name }}" 276 | # record: new.foo.com 277 | # type: A 278 | # register: records 279 | # - ansible.builtin.debug: var=records 280 | 281 | # - name: Delete A record using the results from the get command 282 | # community.aws.route53: 283 | # state: absent 284 | # zone: "{{ domain_name }}" 285 | # record: "{{ rec.set.record }}" 286 | # ttl: "{{ rec.set.ttl }}" 287 | # type: "{{ rec.set.type }}" 288 | # value: "{{ rec.set.value }}" 289 | 290 | # - name: Delete public DNS entry for the ISE node(s) 291 | # community.aws.route53: 292 | # state: absent 293 | # zone: "{{ domain_name }}" 294 | # record: "{{ item.tags.Name }}.{{ domain_name }}" 295 | # # overwrite: yes 296 | # # private_zone: no 297 | # # type: A 298 | # # ttl: 7200 299 | # # value: "{{ item.public_ip_address }}" 300 | # # wait: no 301 | 302 | # - name: Delete private DNS entry for the ISE node(s) 303 | # community.aws.route53: 304 | # state: absent 305 | # zone: "{{ domain_name }}" 306 | # record: "{{ item.tags.Name }}.{{ domain_name }}" 307 | # # overwrite: yes 308 | # # private_zone: yes 309 | # # type: A 310 | # # wait: no 311 | 312 | # - name: Retrieve the DNS details 313 | # community.aws.route53: 314 | # state: get 315 | # zone: "{{ domain_name }}" 316 | # record: "{{ domain_name }}" 317 | # type: A 318 | # register: rec 319 | 320 | # - name: Show rec 321 | # ansible.builtin.debug: var=rec 322 | 323 | # - name: Delete A records using the results from the get command 324 | # community.aws.route53: 325 | # state: absent 326 | # zone: "{{ domain_name }}" 327 | # record: "{{ rec.set.record }}" 328 | # ttl: "{{ rec.set.ttl }}" 329 | # type: "{{ rec.set.type }}" 330 | # value: "{{ rec.set.value }}" 331 | 332 | # 333 | # ToDo: Delete S3 Buckets in Project 334 | # 335 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cisco ISE with Meraki in AWS 2 | 3 | This demo environment was created for use with the [Cisco ISE with Meraki Webinar](https://www.youtube.com/watch?v=snc0HIK0My4) on October 5, 2021. Watch the recording of the [Cisco ISE with Meraki Webinar](https://www.youtube.com/watch?v=snc0HIK0My4) in the [Cisco ISE YouTube Channel](https://cs.co/ise-videos): 4 | 5 | [![Cisco ISE with Meraki Webinar](http://img.youtube.com/vi/snc0HIK0My4/0.jpg)](http://www.youtube.com/watch?v=snc0HIK0My4) 6 | 7 | 8 | 9 | 10 | 11 | ## Quick Start 12 | 13 | ![ISE with Meraki in AWS](images/ISE_with_Meraki_in_AWS.png) 14 | 15 | You will need at least one additional Meraki MX or Z network to act as a VPN hub to terminate the other side of the VPN connection. You should have your hub MX working *before* you run the Ansible playbook because it will attempt to connect the vMX to an existing `Lab` VPN hub. You may edit the `vars/main.yaml` file to customize your VPN hub network name. I chose to have the vMX network in AWS be a VPN *spoke* because I do not want AWS to charge me for all of my network traffic flowing through AWS to the Internet! 16 | 17 | Running `ansible-playbook ise_in_aws.yaml` will create : 18 | - AWS VPC, subnets, route tables, internet gateway. For the gory details, see **Manual Configuration in AWS Console and Meraki Dashboard** below. 19 | - ISE 3.1 or later instance 20 | - Meraki vMX instance to secure RADIUS traffic from network devices to ISE 21 | - Linux VM instance to ping while ISE boots so you will feel confident that the VPN is going to work! You could also turn this into a web server for testing URL redirections or as an internal site that you block. 22 | 23 | 24 | 25 | 1. Clone this repository: 26 | 27 | ```bash 28 | git clone https://github.com/1homas/ISE_with_Meraki_in_AWS.git 29 | cd ISE_with_Meraki_in_AWS 30 | ``` 31 | 32 | 2. Create your Python environment and install Ansible with other Python packages for AWS and ISE : 33 | 34 | ```bash 35 | pip install --upgrade pip 36 | pip install pipenv 37 | pipenv install --python 3.11 38 | pipenv install ansible boto3 botocore ciscoisesdk jmespath paramiko 39 | pipenv shell 40 | ``` 41 | 42 | If you have any problems installing Python or Ansible, see [Installing Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html). 43 | 44 | 3. Export your various keys, tokens, and credentials for ISE, Meraki, and AWS APIs into your shell environment. You can store these in one or more `*.env` then load them with the `source` command. 45 | 46 | ```bash 47 | # AWS IAM API Keys 48 | export AWS_REGION='us-west-1' 49 | export AWS_ACCESS_KEY='AKIAIOSF/EXAMPLE+KEY' 50 | export AWS_SECRET_KEY='wJalrXUtnFEMI/K7MDENG/bPxRfi/EXAMPLE+KEY' 51 | ``` 52 | 53 | ```bash 54 | # Meraki API Authentication Key 55 | export MERAKI_KEY='EXAMPLE_KEYc320e12ee407159487a4cabc41abb' 56 | ``` 57 | 58 | ```bash 59 | # ISE REST API Credentials 60 | export ISE_USERNAME=admin 61 | export ISE_PASSWORD=ISEisC00L 62 | export ISE_VERIFY=false 63 | export ISE_DEBUG=false 64 | export ISE_INIT_PASSWORD=C1sco12345 65 | # Secrets 66 | export ISE_RADIUS_SECRET=ISEisC00L 67 | export ISE_TACACS_SECRET=ISEisC00L 68 | export ISE_SNMP_SECRET=ISEisC00L 69 | # Repository & Backups 70 | export ISE_REPOSITORY=ftp.trust0.net 71 | export ISE_REPOSITORY_PROTOCOL=FTP 72 | export ISE_REPOSITORY_PATH=/ 73 | export ISE_REPOSITORY_USERNAME=ise 74 | export ISE_REPOSITORY_PASSWORD=ISEisC00L 75 | export ISE_BACKUP_ENCRYPTION_KEY=ISEisC00L 76 | ``` 77 | 78 | Alternatively, keep your environment variables in files in a `.secrets` or similar folder in your home directory and use `source {filename}` to load environment variables from the files: 79 | 80 | ```bash 81 | source ~/.secrets/aws.sh 82 | source ~/.secrets/ise.sh 83 | source ~/.secrets/ise_repo.sh 84 | source ~/.secrets/meraki.sh 85 | ``` 86 | 87 | 4. Review the `vars/*.yaml` configuration files and un/comment or edit them to suit your environment. You *must* edit the `vars/main.yaml` and change the `meraki_org_name` to your respective Meraki org. You will want to review the other settings and change them to match your environment: 88 | - your desired `project_name` 89 | - the AMI identifiers for your respective AWS region if not `us-west-1` 90 | - your desired network CIDR ranges 91 | - your desired VM instance types 92 | - your Meraki vMX instance type and license (S/M/L) 93 | - your default password(s) or pre-shared keys 94 | 95 | 5. Run the Ansible playbook: 96 | 97 | ```bash 98 | ansible-playbook ise_in_aws.yaml 99 | ``` 100 | 101 | 6. Due to a Meraki VPN API error, you will need to manually add the vMX Local Network definition in the Meraki Dashboard to advertise the VPC subnet: 102 | 1. In the [Meraki Dashboard](https://dashboard.meraki.com), view your `ISE_Meraki_AWS` network 103 | 2. Choose `Security & SD-WAN > Configure > Site-to-Site VPN` and for the Local Networks, **Add a Local Network**: 104 | | Network | VPN mode | Subnet | 105 | |----------------|----------|-----------------| 106 | | ISE_Meraki_AWS | Enabled | `172.31.0.0/16` | 107 | 108 | > ⚠ If you cannot ping or SSH to the `Ping` Linux VM this is probably the reason! 109 | 110 | 7. When ISE is up, you may configure it using the additional playbook : 111 | 112 | ```bash 113 | ansible-playbook ise.configuration.yaml 114 | ``` 115 | 116 | 8. When you are done, terminate the instances and delete all resources to prevent surprise AWS bills: 117 | 118 | ```bash 119 | ansible-playbook ise_in_aws.terminate.yaml 120 | ``` 121 | 122 | 123 | 124 | 125 | ## Manual Configuration in AWS Console and Meraki Dashboard 126 | 127 | In case you wondered exactly what these Ansible playbooks are doing ... here is how to do it the hard way! If you want to do it the old-fashioned way or just understand what the time spent on automation is saving you from! 128 | 129 | 130 | 131 | ### Create an SSH Key Pair 132 | 133 | Your AWS instance(s) will have a public IP address so anyone can - and will - eventually find it and try to login and use it. For this reason, AWS does not allow the use of normal passwords. Instead, they use a private/public cryptographic key pair which is *much* stronger than a password. 134 | 135 | 1. Login to the [Amazon Web Services (AWS) Console](https://console.aws.amazon.com) as a root user (not IAM user) of your account 136 | 2. Verify or choose your **Region** in the drop-down menu next to your account name 137 | 3. Open the **Services** menu and choose **Compute > EC2** 138 | 4. From the left menu, choose **Network & Security > Key Pairs** 139 | 5. Click **Create Key Pair**, fill in the attributes below, and click **Create Key Pair** 140 | - Name: `ISEinAWS` 141 | - Key pair type: **RSA** 142 | - Private key file format: **.pem** 143 | 6. When prompted, save the `ISEinAWS.pem` private key file to your home directory in a folder named `.ssh` (`~/.ssh/ISEinAWS.pem`) 144 | 7. If you are using macOS, Linux, or WSL, change the file permissions so it cannot be viewed by others or accidentally overwritten or deleted by you: 145 | 146 | ```bash 147 | chmod 400 ~/.ssh/ISEinAWS.pem 148 | ``` 149 | 150 | > 🛑 Do not lose this private key file! You will not be able to login to your AWS EC2 instances configured with the corresponding public key! 151 | 152 | When you create instances in AWS, you may choose to put the matching public key into your VMs to authorize your SSH login. To use your key with AWS EC2 instances, you will connect using SSH and authenticate with the `-i` *identity file* option which is your `ISEinAWS.pem` private key : 153 | 154 | ```bash 155 | ssh -i ~/.ssh/ISEinAWS.pem admin@{hostname | IP} 156 | ``` 157 | 158 | 159 | 160 | 161 | 162 | ### Create AWS VPC 163 | 164 | 1. In the [AWS Console](https://console.aws.amazon.com), go to **Services > Networking & Content Delivery > VPC** 165 | 2. Choose your region: `us-west1` 166 | 3. Select `Create VPC` 167 | - Name: `ISEinAWS` 168 | - IPv4 CIDR: `172.31.0.0/16` 169 | - Tenancy: `Default` 170 | - Add Tag: `Project : ISEinAWS` 171 | Click `Create VPC` 172 | 173 | 174 | 175 | 176 | 177 | ### Create Subnets 178 | 179 | 1. From the left menu, select `Virtual Private Cloud > Subnets` 180 | 2. Click `Create Subnet` 181 | 3. Create your Public subnet for the Meraki vMX: 182 | 1. VPC ID: `ISEinAWS` 183 | 2. Subnet name: `Public-Subnet` 184 | 3. Availability Zone: `No preference` or *choose your desired AZ* 185 | 4. CIDR: `172.31.1.0/24` 186 | 4. Select `Add a New Subnet` for the Private subnet with ISE 187 | 1. VPC ID: `ISEinAWS` 188 | 2. Subnet name: `Private-Subnet` 189 | 3. Availability Zone: `No preference` or *choose your desired AZ* 190 | 4. CIDR: `172.31.2.0/24` 191 | 5. Select `Create Subnet` 192 | 6. Check ✅ `Public-Subnet`, choose `Actions > Modify auto-assign IP settings`, check ✅ `Enable auto-assign public IPv4 address` and click `Save` 193 | 194 | 195 | 196 | 197 | 198 | ### Create Internet Gateway 199 | 200 | 1. From the left menu, select `Virtual Private Cloud > Internet Gateways` 201 | 1. Click `Create Internet Gateway` 202 | - Name: `vMX-IG` 203 | Click `Create Internet Gateway` 204 | 1. Associate the Internet Gateway to the VPC by selecting `Actions > Attach to VPC` > `ISEinAWS` and click `Attach Internet Gateway` 205 | 206 | 207 | 208 | 209 | 210 | ### Create Route Tables 211 | 212 | 1. From the left menu, select `Virtual Private Cloud > Route Tables` 213 | 2. Click `Create Route Table` 214 | 3. Create the *Public* Route Table 215 | - Name: `Public-RT` 216 | - VPC: `ISEinAWS` 217 | Click `Create Route Table` 218 | 4. From the left menu, select `Virtual Private Cloud > Route Tables` 219 | 5. Create the *Private* Route Table 220 | - Name: `Private-RT` 221 | - VPC: `ISEinAWS` 222 | Click `Create Route Table` 223 | 6. Associate the respective route tables and subnets: 224 | 1. Check ✅ `Public-RT` and select the `Subnet Assocations` tab below 225 | 2. Click `Edit Subnet Associations`, check ✅ `Public-Subnet` and click `Save Associations` 226 | 3. Check ✅ `Private-RT` and select the `Subnet Assocations` tab below 227 | 4. Click `Edit Subnet Associations`, check ✅ `Private-Subnet` and click `Save Associations` 228 | 229 | 230 | 231 | 232 | 233 | ### Edit Route Tables 234 | 235 | 1. Check ✅ `Public-RT`, select the `Routes` tab below, and click `Edit Routes` 236 | 2. Click `Add Route` and add a `0.0.0.0/0` default route to the target type `Internet Gateway` > `igw-*` then click `Save Changes` 237 | 3. Your Public Route Table should now look like this: 238 | | Destination | Target | 239 | |-----------------|-----------------------| 240 | | `172.31.0.0/16` | local | 241 | | `0.0.0.0/0` | igw-0ed2b71a84a9588ac | 242 | 243 | 244 | 245 | 246 | 247 | ## Generate Cisco Meraki vMX Authentication Token 248 | 249 | 1. Login to the [Meraki Dashboard](https://dashboard.meraki.com) 250 | 2. From the network menu, choose `Create a New Network` 251 | - Network name: `ISEinAWS` 252 | - Network type: `Security Appliance` 253 | - Network Configuration: `Default Meraki configuration` 254 | - Check ✅ the **vMX Serial Number** you want to use 255 | Click `Create Network` 256 | 3. Scroll down and select `Generate Authentication Token` and copy the text for use in the `User Data` of the vMX instance in the next section. 257 | 258 | 259 | 260 | 261 | 262 | ### Create Cisco Meraki vMX Instance 263 | 264 | 1. In the AWS Search Box at the top of the page, search for "Meraki vMX" and open the link to [Cisco Meraki vMX](https://aws.amazon.com/marketplace/pp/prodview-o5hpcs2rygxnk) 265 | 1. Click `Continue to Subscribe` 266 | 1. Click `Continue to Configuration` 267 | 1. Choose your region (`us-west`) and click `Continue to Launch` 268 | 1. ami-09db17cd0ae68ce37 269 | 2. For **Choose Action**, choose `Launch Through EC2` then click `Launch` 270 | 3. Choose the appropriate Instance Type, `c5.large` and click `Next: Configure Instance Details` 271 | 4. For Configure Instance Details use the settings: 272 | - Network: `vpc-* | ISEinAWS` 273 | - Subnet: `subnet-* | Public-Subnet` 274 | - Auto-assign Public IP : `Enable` 275 | - User data: `As Text`, *paste the vMX Authentication Token from the Meraki Dashboard* 276 | 5. Click `Next: Add Storage` 277 | 6. Click `Next: Add Tags` 278 | 7. Click `Add Tag` and use a key:value of `Name` : `vMX` 279 | 8. Click `Next: Configure Security Group` 280 | 9. For the Security Group, use the settings: 281 | - Assign a security group : `⦿ Create a new security group` 282 | - Security group name: `vMX-SG` 283 | - Description: `vMX-SG` 284 | - Change the existing rule to be: 285 | - Type : `All Traffic` 286 | - Description: `Allow All` 287 | 11. Click `Review and Launch` 288 | 12. Click `Launch` 289 | 13. Select your Key Pair `ISEinAWS.pem`, acknowledge that you have the private key file and click `Launch Instances` 290 | 14. After launching, select `View Instances` and you should see your instance running! 291 | 15. Check ✅ your vMX, choose `Actions > Networking > Change Source / destination check`, ✅ `Stop` Source / destination checking and click `Save` 292 | 293 | 294 | 295 | 296 | 297 | ### Create a Linux Test Instance for Pinging 298 | 299 | 1. In the AWS Console, go to `Services > EC2` 300 | 1. Click `Launch Instances` 301 | 1. Find a free tier Linux AMI such as the `Amazon Linux 2 AMI (HVM)` and click it's `Select` button 302 | 2. Choose the `t2.micro` instance type and click `Next: Configure Instance Details` 303 | 3. For Configure Instance Details use the settings: 304 | - Network: `vpc-* | ISEinAWS` 305 | - Subnet: `subnet-* | Private-Subnet` 306 | - Auto-assign Public IP : `Enable)` 307 | 4. Click `Next: Add Storage` 308 | 5. Click `Next: Add Tags` 309 | 6. Click `Add Tag` and use a key:value of `Name` : `Ping` 310 | 7. Click `Next: Configure Security Group` 311 | 8. For the Security Group, use the settings: 312 | - Assign a security group : `⦿ Create a new security group` 313 | - Security group name: `SSH+Ping` 314 | - Description: `SSH+Ping` 315 | - Click `Add Rule` and choose : 316 | - Type: `All ICMP-IPv4` 317 | - Source: `0.0.0.0/0` 318 | 9. Click `Review and Launch` 319 | 10. Click `Launch` 320 | 11. Select your Key Pair `ISEinAWS.pem`, acknowledge that you have the private key file and click `Launch Instances` 321 | 12. Click `View Instances` and you should see your instance running! 322 | 13. Login to your Linux VM is you need to do any troubleshooting or add software: 323 | 324 | ```bash 325 | ssh -i "~/.ssh/ISEinAWS.pem" ec2-user@{ hostname | IP } 326 | ``` 327 | 328 | 329 | 330 | 331 | 332 | ### Create Site-to-Site VPN Connection 333 | 334 | 1. In the [Meraki Dashboard](https://dashboard.meraki.com), view your `ISEinAWS` network 335 | 2. Choose `Security & SD-WAN > Configure > Site-to-Site VPN` 336 | 3. For the Site-to-Site VPN settings, use: 337 | - Type: `Spoke` 338 | - Local network: 339 | | Network | VPN mode | Subnet | 340 | |----------------|----------|-----------------| 341 | | Private-Subnet | Enabled | `172.31.2.0/24` | 342 | - NAT traversal : `⦿ Automatic` 343 | 4. Click `Save Changes` 344 | 5. Choose `Security & SD-WAN > Appliance Status` and you should now see the vMX public WAN address and it should be **Active**! 345 | 346 | Now you will connect your other MX in the mesh to the vMX 347 | 348 | 1. Choose your Meraki `Lab` network for your physical, on-premise MX 349 | 2. Choose `Security & SD-WAN > Configure > Site to Site VPN` 350 | 3. For the Site-to-Site VPN settings, use: 351 | - Type: `Hub (Mesh)` 352 | - Local Networks : 353 | > 💡 you may use a Single LAN or VLANs - I used a Single LAN to keep it simple 354 | | Network | VPN mode | Subnet | 355 | |-------------|----------|--------| 356 | | Main Subnet | Enabled | `192.168.101.0/24` 357 | - NAT traversal : `⦿ Automatic` 358 | - If you have alreaady configured a Meraki MX has a hub, you should see `ISEinAWS` under **Remote VPN participants**! 359 | 4. Click `Save Changes` 360 | 361 | 362 | 363 | 364 | 365 | ### Update the Private Route Table 366 | 367 | You will need to update the `Private-RT` to the `Lab` MX 368 | 369 | 1. In the AWS Console, go to `Services > VPC` and select the `Route Tables` 370 | 2. Check ✅ `Private-RT` and select the `Routes` tab below 371 | 3. Click `Edit Routes` 372 | 4. Select `Add Route` 373 | - Destination: `192.168.0.0/16` 374 | - Target: `Instance` > `i-* | vMX` 375 | Click `Save Changes` 376 | 4. Select `Add Route` 377 | - Destination: `0.0.0.0/0` 378 | - Target: `Internet Gateway` > `igw-*` 379 | Click `Save Changes` 380 | 5. Your **Private Route Table** should now look like this: 381 | | Destination | Target | 382 | |------------------|-----------| 383 | | `172.31.0.0/16` | local | 384 | | `192.168.0.0/16` | i-* / vMX | 385 | | `0.0.0.0/0` | igw-* | 386 | 6. You can now try to ping through your site-to-site VPN to the Linux instance 387 | 388 | 389 | 390 | 391 | 392 | ### Ping the Linux Instance 393 | 394 | 1. In the AWS Console, go to `Services > EC2` and 395 | 2. Select the `Ping` Linux VM instance and locate it's `Private IPv4 addresses` 396 | 3. SSH to the instance: 397 | 398 | ```bash 399 | ssh -i ~/.ssh/ISEinAWS.pem ec2-user@172.31.2.35 400 | ``` 401 | 402 | 403 | 404 | 405 | 406 | ### Create Cisco ISE Instance 407 | 408 | 409 | 1. In the AWS Search Box at the top of the page, search for "Cisco ISE" and open the link to [Cisco Identity Services Engine (ISE)](https://aws.amazon.com/marketplace/pp/prodview-uvsybra7r3iug?sr=0-1&ref_=beagle&applicationId=AWSMPContessa) 410 | 1. Click `Continue to Subscribe` 411 | 2. Click `Continue to Configuration` 412 | 3. For Configure This Software, choose: 413 | - Delivery Method: `Cloud Formation Template` then choose the normal or GovCloud version of `Cisco Identity Services Engine (ISE)` 414 | - Software Version: `3.1` 415 | - Region: `us-west` 416 | Click `Continue to Launch` 417 | 4. For Launch this Software, choose: `Launch CloudFormation` then click `Launch` 418 | 5. Choose `Upload a template file`, choose your file (`files/ISE-3-1-518.CFT.yaml`) and click `Next` 419 | 6. Verify and complete the ISE CloudFormation Parameters then click `Next` 420 | - Stack Name: `ISE-3-1-518` 421 | - AMIid: `ami-00a1a68f5519aa150` # ISE in us-west-1 422 | - Hostname: `ise` 423 | - KeyName / Instance Key Pair: `ISEinAWS` 424 | - Management Security Group: `ISE` 425 | - Management Network: `Private-Subnet` 426 | - TimeZone: `America/Los_Angeles` 427 | - ISEInstanceType: `c5.4xlarge` 428 | - EBS Encryption : `false` 429 | - Volume Size / StorageSize: `300` 430 | - DNSDomain: `aws.local` 431 | - NameServer: `208.67.222.222` 432 | - NTPServer: `time.nist.gov` 433 | - ERS: `yes` 434 | - OpenAPI: `yes` 435 | - pxGrid: `no` 436 | - pxGridCloud: `no` 437 | - ERS: `yes` 438 | - password: `C1sco12345` 439 | - ConfirmPwd: `C1sco12345` 440 | Click `Next` 441 | 7. Review the Stack Options then click `Next` 442 | 8. Do a final review of the parameters then click `Creat Stack` 443 | 444 | To create another instance: 445 | 1. In the AWS Console, navigate to **CloudFormation > Stacks** 446 | 2. Select `ISE-3-1-518` 447 | 3. Choose Create Stack > With New Resources (standard) 448 | 4. For Create Stack, choose `Upload a template file`, choose your file (`ISE-3-1-518.CFT.yaml`) and click `Next` 449 | 5. choose a unique Stack Name (`ISE-3-1-518`) 450 | 451 | SSH to the ISE console 452 | ```bash 453 | ssh -i "~/.ssh/ISEinAWS.pem" admin@{ hostname | IP } 454 | ``` 455 | 456 | 457 | 458 | 459 | 460 | ## Resources 461 | - [Installing Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) for all platforms 462 | - Documentation for Ansible collections: 463 | - [cisco.ise](https://ciscoise.github.io/ansible-ise/main/plugins/index.html) 464 | - [cisco.meraki](https://docs.ansible.com/ansible/latest/collections/cisco/meraki/index.html) 465 | - [amazon.aws](https://docs.ansible.com/ansible/latest/collections/amazon/aws/) 466 | - [community.aws](https://docs.ansible.com/ansible/latest/collections/community/aws/) 467 | - [Cisco Meraki vMX en AWS](https://www.youtube.com/watch?v=KfbihKbe-HI) - YouTube video for vMX in AWS (Spanish) 468 | - [AWS re:Invent 2019: AWS Networking Fundamentals (NET201-R2)](https://www.youtube.com/watch?v=gj4CD73Wmns) provides an excellent overview of the networking elements that are automatically created when using the [Launch Instance wizard](https://console.aws.amazon.com/ec2/home#LaunchInstanceWizard) 469 | - [Best practices for managing AWS access keys](https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html) 470 | 471 | 472 | 473 | 474 | 475 | ## License 476 | 477 | This repository is licensed under the [MIT License](https://choosealicense.com/licenses/mit/). 478 | 479 | 480 | -------------------------------------------------------------------------------- /files/ISE-3-1-518.CFT.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: >- 3 | AWS Cloud Formation Template for Cisco Identity Service Engine. CFT Version : 4 | 3.1.518 5 | Parameters: 6 | KeyName: 7 | Default: 1homas-AWS-ISE 8 | Description: >- 9 | To access the Cisco ISE instance via SSH, choose the PEM file that you 10 | created in AWS for the username "admin". Create a PEM key pair in AWS now 11 | if you have not configured one already. Usage example: ssh -i 12 | mykeypair.pem admin@myhostname.compute-1.amazonaws.com 13 | Type: 'AWS::EC2::KeyPair::KeyName' 14 | AllowedPattern: .+ 15 | ConstraintDescription: Instance Key Pair cannot be empty 16 | ISEInstanceType: 17 | Default: c5.4xlarge 18 | Description: Choose the required Cisco ISE instance type. 19 | Type: String 20 | AllowedValues: 21 | - c5.4xlarge 22 | - m5.4xlarge 23 | - c5.9xlarge 24 | ConstraintDescription: Instance type should be one of the allowed values 25 | EBSEncrypt: 26 | Default: 'false' 27 | Description: Choose true to enable EBS encryption. 28 | Type: String 29 | AllowedValues: 30 | - false 31 | - true 32 | ConstraintDescription: It can either be true or false 33 | ERSapi: 34 | Default: 'yes' 35 | Description: Do you wish to enable ERS? 36 | Type: String 37 | AllowedValues: 38 | - 'yes' 39 | - 'no' 40 | ConstraintDescription: It can either be yes or no 41 | OpenAPI: 42 | Default: 'yes' 43 | Description: Do you wish to enable OpenAPI? 44 | Type: String 45 | AllowedValues: 46 | - 'yes' 47 | - 'no' 48 | ConstraintDescription: It can either be yes or no 49 | PXGrid: 50 | Default: 'no' 51 | Description: Do you wish to enable pxGrid? 52 | Type: String 53 | AllowedValues: 54 | - 'yes' 55 | - 'no' 56 | ConstraintDescription: It can either be yes or no 57 | PXGridCloud: 58 | Default: 'no' 59 | Description: Do you wish to enable pxGrid Cloud? 60 | Type: String 61 | AllowedValues: 62 | - 'yes' 63 | - 'no' 64 | ConstraintDescription: It can either be yes or no 65 | MSecurityGroup: 66 | Default: ISE_from_Anywhere 67 | Type: 'AWS::EC2::SecurityGroup::Id' 68 | Description: >- 69 | Choose the Security Group to attach to the Cisco ISE interface. Create a 70 | Security Group in AWS now if you have not configured one already. 71 | AllowedPattern: .+ 72 | ConstraintDescription: Security group cannot be empty 73 | ManagementSubnetId: 74 | Default: subnet-33789069 75 | Type: 'AWS::EC2::Subnet::Id' 76 | Description: >- 77 | Choose the subnet to be used for the Cisco ISE interface. To enable IPv6 78 | addresses, you must associate an IPv6 CIDR block with your VPC and 79 | subnets. Create a Subnet in AWS now if you have not configured one 80 | already. 81 | AllowedPattern: .+ 82 | ConstraintDescription: Subnet cannot be empty 83 | Hostname: 84 | Default: ise 85 | Description: >- 86 | Enter the hostname. This field only supports alphanumeric characters and 87 | hyphen (-). The length of the hostname should not exceed 19 characters. 88 | Type: String 89 | AllowedPattern: '^[a-zA-Z0-9-]{1,19}$' 90 | ConstraintDescription: >- 91 | This field only supports alphanumeric characters and hyphen (-). Hostname 92 | should not be more than 19 characters. 93 | DNSDomain: 94 | Default: aws.local 95 | Description: >- 96 | Enter a domain name in correct syntax (for example, cisco.com). The valid 97 | characters for this field are ASCII characters, numerals, hyphen (-), and 98 | period (.). If you use the wrong syntax, Cisco ISE services might not come 99 | up on launch. 100 | Type: String 101 | AllowedPattern: '^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$' 102 | ConstraintDescription: >- 103 | Cannot be an IP address. Valid characters include ASCII characters, any 104 | numerals, the hyphen (-), and the period (.) for DNS domain. 105 | NameServer: 106 | Default: 208.67.222.222 107 | Description: >- 108 | Enter the IP address of the name server in correct syntax. If you use the 109 | wrong syntax, Cisco ISE services might not come up on launch. 110 | Type: String 111 | AllowedPattern: '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' 112 | ConstraintDescription: Must be a valid IPv4 address for the primary name server. 113 | NTPServer: 114 | Default: time.nist.gov 115 | Description: >- 116 | Enter the IP address or hostname of the NTP server in correct syntax (for 117 | example, time.nist.gov). Your entry is not verified on submission. If you 118 | use the wrong syntax, Cisco ISE services might not come up on launch. 119 | Type: String 120 | AllowedPattern: .+ 121 | ConstraintDescription: NTP server cannot be empty 122 | TimeZone: 123 | Default: America/Los_Angeles 124 | Description: Choose a system time zone. 125 | Type: String 126 | AllowedValues: 127 | - Africa/Abidjan 128 | - Africa/Accra 129 | - Africa/Algiers 130 | - Africa/Bissau 131 | - Africa/Cairo 132 | - Africa/Casablanca 133 | - Africa/Ceuta 134 | - Africa/El_Aaiun 135 | - Africa/Johannesburg 136 | - Africa/Juba 137 | - Africa/Khartoum 138 | - Africa/Lagos 139 | - Africa/Maputo 140 | - Africa/Monrovia 141 | - Africa/Nairobi 142 | - Africa/Ndjamena 143 | - Africa/Sao_Tome 144 | - Africa/Tripoli 145 | - Africa/Tunis 146 | - Africa/Windhoek 147 | - America/Adak 148 | - America/Anchorage 149 | - America/Araguaina 150 | - America/Argentina/Buenos_Aires 151 | - America/Argentina/Catamarca 152 | - America/Argentina/Cordoba 153 | - America/Argentina/Jujuy 154 | - America/Argentina/La_Rioja 155 | - America/Argentina/Mendoza 156 | - America/Argentina/Rio_Gallegos 157 | - America/Argentina/Salta 158 | - America/Argentina/San_Juan 159 | - America/Argentina/San_Luis 160 | - America/Argentina/Tucuman 161 | - America/Argentina/Ushuaia 162 | - America/Asuncion 163 | - America/Atikokan 164 | - America/Bahia 165 | - America/Bahia_Banderas 166 | - America/Barbados 167 | - America/Belem 168 | - America/Belize 169 | - America/Blanc-Sablon 170 | - America/Boa_Vista 171 | - America/Bogota 172 | - America/Boise 173 | - America/Cambridge_Bay 174 | - America/Campo_Grande 175 | - America/Cancun 176 | - America/Caracas 177 | - America/Cayenne 178 | - America/Chicago 179 | - America/Chihuahua 180 | - America/Costa_Rica 181 | - America/Creston 182 | - America/Cuiaba 183 | - America/Curacao 184 | - America/Danmarkshavn 185 | - America/Dawson 186 | - America/Dawson_Creek 187 | - America/Denver 188 | - America/Detroit 189 | - America/Edmonton 190 | - America/Eirunepe 191 | - America/El_Salvador 192 | - America/Fort_Nelson 193 | - America/Fortaleza 194 | - America/Glace_Bay 195 | - America/Goose_Bay 196 | - America/Grand_Turk 197 | - America/Guatemala 198 | - America/Guayaquil 199 | - America/Guyana 200 | - America/Halifax 201 | - America/Havana 202 | - America/Hermosillo 203 | - America/Indiana/Indianapolis 204 | - America/Indiana/Knox 205 | - America/Indiana/Marengo 206 | - America/Indiana/Petersburg 207 | - America/Indiana/Tell_City 208 | - America/Indiana/Vevay 209 | - America/Indiana/Vincennes 210 | - America/Indiana/Winamac 211 | - America/Inuvik 212 | - America/Iqaluit 213 | - America/Jamaica 214 | - America/Juneau 215 | - America/Kentucky/Louisville 216 | - America/Kentucky/Monticello 217 | - America/La_Paz 218 | - America/Lima 219 | - America/Los_Angeles 220 | - America/Maceio 221 | - America/Managua 222 | - America/Manaus 223 | - America/Martinique 224 | - America/Matamoros 225 | - America/Mazatlan 226 | - America/Menominee 227 | - America/Merida 228 | - America/Metlakatla 229 | - America/Mexico_City 230 | - America/Miquelon 231 | - America/Moncton 232 | - America/Monterrey 233 | - America/Montevideo 234 | - America/Nassau 235 | - America/New_York 236 | - America/Nipigon 237 | - America/Nome 238 | - America/Noronha 239 | - America/North_Dakota/Beulah 240 | - America/North_Dakota/Center 241 | - America/North_Dakota/New_Salem 242 | - America/Nuuk 243 | - America/Ojinaga 244 | - America/Panama 245 | - America/Pangnirtung 246 | - America/Paramaribo 247 | - America/Phoenix 248 | - America/Port-au-Prince 249 | - America/Port_of_Spain 250 | - America/Porto_Velho 251 | - America/Puerto_Rico 252 | - America/Punta_Arenas 253 | - America/Rainy_River 254 | - America/Rankin_Inlet 255 | - America/Recife 256 | - America/Regina 257 | - America/Resolute 258 | - America/Rio_Branco 259 | - America/Santarem 260 | - America/Santiago 261 | - America/Santo_Domingo 262 | - America/Sao_Paulo 263 | - America/Scoresbysund 264 | - America/Sitka 265 | - America/St_Johns 266 | - America/Swift_Current 267 | - America/Tegucigalpa 268 | - America/Thule 269 | - America/Thunder_Bay 270 | - America/Tijuana 271 | - America/Toronto 272 | - America/Vancouver 273 | - America/Whitehorse 274 | - America/Winnipeg 275 | - America/Yakutat 276 | - America/Yellowknife 277 | - Antarctica/Casey 278 | - Antarctica/Davis 279 | - Antarctica/DumontDUrville 280 | - Antarctica/Macquarie 281 | - Antarctica/Mawson 282 | - Antarctica/Palmer 283 | - Antarctica/Rothera 284 | - Antarctica/Syowa 285 | - Antarctica/Troll 286 | - Antarctica/Vostok 287 | - Asia/Almaty 288 | - Asia/Amman 289 | - Asia/Anadyr 290 | - Asia/Aqtau 291 | - Asia/Aqtobe 292 | - Asia/Ashgabat 293 | - Asia/Atyrau 294 | - Asia/Baghdad 295 | - Asia/Baku 296 | - Asia/Bangkok 297 | - Asia/Barnaul 298 | - Asia/Beirut 299 | - Asia/Bishkek 300 | - Asia/Brunei 301 | - Asia/Chita 302 | - Asia/Choibalsan 303 | - Asia/Colombo 304 | - Asia/Damascus 305 | - Asia/Dhaka 306 | - Asia/Dili 307 | - Asia/Dubai 308 | - Asia/Dushanbe 309 | - Asia/Famagusta 310 | - Asia/Gaza 311 | - Asia/Hebron 312 | - Asia/Ho_Chi_Minh 313 | - Asia/Hong_Kong 314 | - Asia/Hovd 315 | - Asia/Irkutsk 316 | - Asia/Jakarta 317 | - Asia/Jayapura 318 | - Asia/Jerusalem 319 | - Asia/Kabul 320 | - Asia/Kamchatka 321 | - Asia/Karachi 322 | - Asia/Kathmandu 323 | - Asia/Khandyga 324 | - Asia/Kolkata 325 | - Asia/Krasnoyarsk 326 | - Asia/Kuala_Lumpur 327 | - Asia/Kuching 328 | - Asia/Macau 329 | - Asia/Magadan 330 | - Asia/Makassar 331 | - Asia/Manila 332 | - Asia/Nicosia 333 | - Asia/Novokuznetsk 334 | - Asia/Novosibirsk 335 | - Asia/Omsk 336 | - Asia/Oral 337 | - Asia/Pontianak 338 | - Asia/Pyongyang 339 | - Asia/Qatar 340 | - Asia/Qostanay 341 | - Asia/Qyzylorda 342 | - Asia/Riyadh 343 | - Asia/Sakhalin 344 | - Asia/Samarkand 345 | - Asia/Seoul 346 | - Asia/Shanghai 347 | - Asia/Singapore 348 | - Asia/Srednekolymsk 349 | - Asia/Taipei 350 | - Asia/Tashkent 351 | - Asia/Tbilisi 352 | - Asia/Tehran 353 | - Asia/Thimphu 354 | - Asia/Tokyo 355 | - Asia/Tomsk 356 | - Asia/Ulaanbaatar 357 | - Asia/Urumqi 358 | - Asia/Ust-Nera 359 | - Asia/Vladivostok 360 | - Asia/Yakutsk 361 | - Asia/Yangon 362 | - Asia/Yekaterinburg 363 | - Asia/Yerevan 364 | - Atlantic/Azores 365 | - Atlantic/Bermuda 366 | - Atlantic/Canary 367 | - Atlantic/Cape_Verde 368 | - Atlantic/Faroe 369 | - Atlantic/Madeira 370 | - Atlantic/Reykjavik 371 | - Atlantic/South_Georgia 372 | - Atlantic/Stanley 373 | - Australia/Adelaide 374 | - Australia/Brisbane 375 | - Australia/Broken_Hill 376 | - Australia/Darwin 377 | - Australia/Eucla 378 | - Australia/Hobart 379 | - Australia/Lindeman 380 | - Australia/Lord_Howe 381 | - Australia/Melbourne 382 | - Australia/Perth 383 | - Australia/Sydney 384 | - CET 385 | - CST6CDT 386 | - EET 387 | - EST 388 | - EST5EDT 389 | - Etc/GMT 390 | - Etc/GMT+1 391 | - Etc/GMT+10 392 | - Etc/GMT+11 393 | - Etc/GMT+12 394 | - Etc/GMT+2 395 | - Etc/GMT+3 396 | - Etc/GMT+4 397 | - Etc/GMT+5 398 | - Etc/GMT+6 399 | - Etc/GMT+7 400 | - Etc/GMT+8 401 | - Etc/GMT+9 402 | - Etc/GMT-1 403 | - Etc/GMT-10 404 | - Etc/GMT-11 405 | - Etc/GMT-12 406 | - Etc/GMT-13 407 | - Etc/GMT-14 408 | - Etc/GMT-2 409 | - Etc/GMT-3 410 | - Etc/GMT-4 411 | - Etc/GMT-5 412 | - Etc/GMT-6 413 | - Etc/GMT-7 414 | - Etc/GMT-8 415 | - Etc/GMT-9 416 | - Etc/UTC 417 | - Europe/Amsterdam 418 | - Europe/Andorra 419 | - Europe/Astrakhan 420 | - Europe/Athens 421 | - Europe/Belgrade 422 | - Europe/Berlin 423 | - Europe/Brussels 424 | - Europe/Bucharest 425 | - Europe/Budapest 426 | - Europe/Chisinau 427 | - Europe/Copenhagen 428 | - Europe/Dublin 429 | - Europe/Gibraltar 430 | - Europe/Helsinki 431 | - Europe/Istanbul 432 | - Europe/Kaliningrad 433 | - Europe/Kiev 434 | - Europe/Kirov 435 | - Europe/Lisbon 436 | - Europe/London 437 | - Europe/Luxembourg 438 | - Europe/Madrid 439 | - Europe/Malta 440 | - Europe/Minsk 441 | - Europe/Monaco 442 | - Europe/Moscow 443 | - Europe/Oslo 444 | - Europe/Paris 445 | - Europe/Prague 446 | - Europe/Riga 447 | - Europe/Rome 448 | - Europe/Samara 449 | - Europe/Saratov 450 | - Europe/Simferopol 451 | - Europe/Sofia 452 | - Europe/Stockholm 453 | - Europe/Tallinn 454 | - Europe/Tirane 455 | - Europe/Ulyanovsk 456 | - Europe/Uzhgorod 457 | - Europe/Vienna 458 | - Europe/Vilnius 459 | - Europe/Volgograd 460 | - Europe/Warsaw 461 | - Europe/Zaporozhye 462 | - Europe/Zurich 463 | - HST 464 | - Indian/Chagos 465 | - Indian/Christmas 466 | - Indian/Cocos 467 | - Indian/Kerguelen 468 | - Indian/Mahe 469 | - Indian/Maldives 470 | - Indian/Mauritius 471 | - Indian/Reunion 472 | - MET 473 | - MST 474 | - MST7MDT 475 | - PST8PDT 476 | - Pacific/Apia 477 | - Pacific/Auckland 478 | - Pacific/Bougainville 479 | - Pacific/Chatham 480 | - Pacific/Chuuk 481 | - Pacific/Easter 482 | - Pacific/Efate 483 | - Pacific/Enderbury 484 | - Pacific/Fakaofo 485 | - Pacific/Fiji 486 | - Pacific/Funafuti 487 | - Pacific/Galapagos 488 | - Pacific/Gambier 489 | - Pacific/Guadalcanal 490 | - Pacific/Guam 491 | - Pacific/Honolulu 492 | - Pacific/Kiritimati 493 | - Pacific/Kosrae 494 | - Pacific/Kwajalein 495 | - Pacific/Majuro 496 | - Pacific/Marquesas 497 | - Pacific/Nauru 498 | - Pacific/Niue 499 | - Pacific/Norfolk 500 | - Pacific/Noumea 501 | - Pacific/Pago_Pago 502 | - Pacific/Palau 503 | - Pacific/Pitcairn 504 | - Pacific/Pohnpei 505 | - Pacific/Port_Moresby 506 | - Pacific/Rarotonga 507 | - Pacific/Tahiti 508 | - Pacific/Tarawa 509 | - Pacific/Tongatapu 510 | - Pacific/Wake 511 | - Pacific/Wallis 512 | - WET 513 | password: 514 | Default: C1sco12345 515 | Description: >- 516 | Enter a password for the username "admin". The password must be aligned 517 | with the Cisco ISE password policy. The configured password is used for 518 | Cisco ISE GUI access. Warning: The password is displayed in plaintext in 519 | the User Data section of the Instance settings window in the AWS Console. 520 | NoEcho: 'True' 521 | Type: String 522 | AllowedPattern: >- 523 | ^(?=.*?[A-Z])(?=.*?[a-z])(?i)(?!.*?admin|.*?cisco|.*?nimda|.*?ocsic)(?-i)(?=.*?[0-9]).{6,}$ 524 | ConstraintDescription: >- 525 | Password constraints: One digit is required. One uppercase letter. One 526 | lowercase letter. Password should not be the same as username(admin). 527 | Should not contain the word cisco. Minimum password length should be 6 528 | character. 529 | ConfirmPwd: 530 | Default: C1sco12345 531 | Description: Retype Password 532 | NoEcho: 'True' 533 | Type: String 534 | StorageSize: 535 | Default: '300' 536 | Description: >- 537 | Specify the storage in GB (Minimum 300GB and Maximum 2400GB). 600GB is 538 | recommended for production use, storage lesser than 600GB can be used for 539 | evaluation purpose only. On terminating the instance, volume will be 540 | deleted as well. 541 | Type: Number 542 | MinValue: '300' 543 | MaxValue: '2400' 544 | ConstraintDescription: >- 545 | Specify the storage in GB (Minimum 300GB and Maximum 2400GB). 600GB is 546 | recommended for production use, storage lesser than 600GB can be used for 547 | evaluation purpose only. On terminating the instance, volume will be 548 | deleted as well. 549 | ManagementPrivateIpAddress: 550 | Type: String 551 | Description: >- 552 | (Optional) Enter the IPv4 address from the subnet that you chose earlier. 553 | If this field is left blank, the AWS DHCP will assign an IP address. 554 | ConstraintDescription: must be a valid IP address of the form x.x.x.x. 555 | Metadata: 556 | 'AWS::CloudFormation::Interface': 557 | ParameterGroups: 558 | - Label: 559 | default: Instance Details 560 | Parameters: 561 | - Hostname 562 | - KeyName 563 | - MSecurityGroup 564 | - ManagementSubnetId 565 | - ManagementPrivateIpAddress 566 | - TimeZone 567 | - ISEInstanceType 568 | - EBSEncrypt 569 | - StorageSize 570 | - Label: 571 | default: Network Configuration 572 | Parameters: 573 | - DNSDomain 574 | - NameServer 575 | - NTPServer 576 | - Label: 577 | default: Services 578 | Parameters: 579 | - ERSapi 580 | - OpenAPI 581 | - PXGrid 582 | - PXGridCloud 583 | - Label: 584 | default: User Details 585 | Parameters: 586 | - password 587 | - ConfirmPwd 588 | ParameterLabels: 589 | ERSapi: 590 | default: ERS 591 | OpenAPI: 592 | default: OpenAPI 593 | PXGrid: 594 | default: pxGrid 595 | PXGridCloud: 596 | default: pxGrid Cloud 597 | DNSDomain: 598 | default: DNS Domain 599 | NameServer: 600 | default: Name Server 601 | NTPServer: 602 | default: NTP Server 603 | password: 604 | default: Enter Password 605 | ConfirmPwd: 606 | default: Confirm Password 607 | MSecurityGroup: 608 | default: Management Security Group 609 | ManagementPrivateIpAddress: 610 | default: Management Private IP 611 | ManagementSubnetId: 612 | default: Management Network 613 | KeyName: 614 | default: Instance Key Pair 615 | TimeZone: 616 | default: Time Zone 617 | ISEInstanceType: 618 | default: Instance Type 619 | StorageSize: 620 | default: Volume Size 621 | EBSEncrypt: 622 | default: EBS Encryption 623 | 'AWS::CloudFormation::Designer': 624 | ad677dc1-dda5-4cd8-a80e-5563937922c4: 625 | size: 626 | width: 60 627 | height: 60 628 | position: 629 | x: 60 630 | 'y': 90 631 | z: 1 632 | embeds: [] 633 | Conditions: 634 | HasPrivateIp: !Not 635 | - !Equals 636 | - '' 637 | - !Ref ManagementPrivateIpAddress 638 | Resources: 639 | IseEc2Instance: 640 | Type: 'AWS::EC2::Instance' 641 | Properties: 642 | InstanceType: !Ref ISEInstanceType 643 | NetworkInterfaces: 644 | - DeviceIndex: '0' 645 | PrivateIpAddress: !If 646 | - HasPrivateIp 647 | - !Ref ManagementPrivateIpAddress 648 | - !Ref 'AWS::NoValue' 649 | SubnetId: !Ref ManagementSubnetId 650 | GroupSet: 651 | - !Ref MSecurityGroup 652 | Tags: 653 | - Key: Role 654 | Value: Test Instance 655 | KeyName: !Ref KeyName 656 | ImageId: !FindInMap 657 | - CiscoISE31AMI 658 | - !Ref 'AWS::Region' 659 | - BYOL 660 | BlockDeviceMappings: 661 | - DeviceName: /dev/sda1 662 | Ebs: 663 | VolumeType: gp2 664 | DeleteOnTermination: 'true' 665 | Encrypted: !Ref EBSEncrypt 666 | VolumeSize: !Ref StorageSize 667 | UserData: !Base64 668 | 'Fn::Join': 669 | - '' 670 | - - hostname= 671 | - !Ref Hostname 672 | - |+ 673 | 674 | - dnsdomain= 675 | - !Ref DNSDomain 676 | - |+ 677 | 678 | - primarynameserver= 679 | - !Ref NameServer 680 | - |+ 681 | 682 | - ntpserver= 683 | - !Ref NTPServer 684 | - |+ 685 | 686 | - username=admin 687 | - |+ 688 | 689 | - password= 690 | - !Ref password 691 | - |+ 692 | 693 | - timezone= 694 | - !Ref TimeZone 695 | - |+ 696 | 697 | - ersapi= 698 | - !Ref ERSapi 699 | - |+ 700 | 701 | - openapi= 702 | - !Ref OpenAPI 703 | - |+ 704 | 705 | - pxGrid= 706 | - !Ref PXGrid 707 | - |+ 708 | 709 | - pxgrid_cloud= 710 | - !Ref PXGridCloud 711 | - |+ 712 | 713 | Metadata: 714 | 'AWS::CloudFormation::Designer': 715 | id: ad677dc1-dda5-4cd8-a80e-5563937922c4 716 | Outputs: 717 | InstanceID: 718 | Description: 'InstanceID of the newly created ISE EC2 instance ' 719 | Value: !Ref IseEc2Instance 720 | AZ: 721 | Description: Availability Zone of the newly created EC2 instance 722 | Value: !GetAtt 723 | - IseEc2Instance 724 | - AvailabilityZone 725 | PrivateDnsName: 726 | Description: Private DNSName of the newly created EC2 instance 727 | Value: !GetAtt 728 | - IseEc2Instance 729 | - PrivateDnsName 730 | PrivateIp: 731 | Description: Private IP address of the newly created EC2 instance 732 | Value: !GetAtt 733 | - IseEc2Instance 734 | - PrivateIp 735 | Mappings: 736 | CiscoISE31AMI: 737 | us-east-1: 738 | BYOL: ami-0cbed48cc9df4f880 739 | us-east-2: 740 | BYOL: ami-0890340336c48c89f 741 | us-west-1: 742 | BYOL: ami-00a1a68f5519aa150 743 | us-west-2: 744 | BYOL: ami-0ef2cc6c45ca5fc1f 745 | ca-central-1: 746 | BYOL: ami-04681986db6c36e2e 747 | eu-central-1: 748 | BYOL: ami-0a9555cddbcb11fe1 749 | eu-west-1: 750 | BYOL: ami-0e23f00231cbe8685 751 | eu-west-2: 752 | BYOL: ami-03764f7408e02964a 753 | eu-west-3: 754 | BYOL: ami-080aa4921de0e82ab 755 | eu-north-1: 756 | BYOL: ami-0ffc58893472137cd 757 | ap-southeast-1: 758 | BYOL: ami-01229aabec61a0653 759 | ap-southeast-2: 760 | BYOL: ami-0ded88aa03eeb6b9d 761 | ap-south-1: 762 | BYOL: ami-03ab7eac5525bd00d 763 | ap-northeast-1: 764 | BYOL: ami-020bdb75aa5e1c4fc 765 | ap-northeast-2: 766 | BYOL: ami-0fd83de5878dcc27e 767 | sa-east-1: 768 | BYOL: ami-0b40700455de971a2 769 | Rules: 770 | PasswdMismatch: 771 | Assertions: 772 | - Assert: !Equals 773 | - !Ref password 774 | - !Ref ConfirmPwd 775 | AssertDescription: Password mismatch 776 | -------------------------------------------------------------------------------- /vars/network_device_groups.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | # Network Device Groups 4 | # 5 | 6 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 7 | # 🐞 ISE ERS API does not like `-` in NDG names?! `_` is OK! 8 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 9 | # 🛑 Do not try to create or delete these default Network Device Groups! 10 | # - Device Type#All Device Types 11 | # - IPSEC#Is IPSEC Device 12 | # - IPSEC#Is IPSEC Device#No 13 | # - IPSEC#Is IPSEC Device#Yes 14 | # - Location#All Locations 15 | #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 16 | 17 | network_device_groups: 18 | 19 | #------------------------------------------------------------------------------ 20 | # Network Device Groups by Enforcement 21 | #------------------------------------------------------------------------------ 22 | 23 | # - name: Enforcement#Enforcement 24 | # description: All Enforcement Options 25 | # othername: Enforcement 26 | 27 | # - name: Enforcement#Enforcement#Monitor 28 | # description: Monitor 29 | # othername: Enforcement 30 | 31 | # - name: Enforcement#Enforcement#LowImpact 32 | # description: LowImpact 33 | # othername: Enforcement 34 | 35 | # - name: Enforcement#Enforcement#Closed 36 | # description: Closed 37 | # othername: Enforcement 38 | 39 | 40 | #------------------------------------------------------------------------------ 41 | # Network Device Groups by Place In The Network (PIN) 42 | #------------------------------------------------------------------------------ 43 | 44 | # - name: PIN#PIN 45 | # description: Place in the Network (PIN) 46 | # othername: PIN 47 | 48 | # - name: PIN#PIN#Branch 49 | # description: Branch 50 | # othername: PIN 51 | 52 | # - name: PIN#PIN#Campus 53 | # description: Campus 54 | # othername: PIN 55 | 56 | # - name: PIN#PIN#WAN 57 | # description: WAN 58 | # othername: PIN 59 | 60 | # - name: PIN#PIN#InternetEdge 61 | # description: InternetEdge 62 | # othername: PIN 63 | 64 | # - name: PIN#PIN#Cloud 65 | # description: Cloud 66 | # othername: PIN 67 | 68 | 69 | #------------------------------------------------------------------------------ 70 | # Device Type#All Device Types#Wireless 71 | #------------------------------------------------------------------------------ 72 | 73 | - name: Device Type#All Device Types#Wireless 74 | description: Wireless 75 | othername: Device Type 76 | 77 | - name: Device Type#All Device Types#Wireless#9800CL 78 | description: Cisco Catalyst Catalyst 9800CL WLC 79 | othername: Device Type 80 | 81 | # - name: Device Type#All Device Types#Wireless#9800EWCAP 82 | # description: Cisco Catalyst 9800-EWC-AP Embedded Wireless Controller (EWC) 83 | # othername: Device Type 84 | 85 | - name: Device Type#All Device Types#Wireless#MR 86 | description: Cisco Meraki MR 87 | othername: Device Type 88 | 89 | - name: Device Type#All Device Types#Wireless#MR#MR46 90 | description: Cisco Meraki MR46 91 | othername: Device Type 92 | 93 | 94 | #------------------------------------------------------------------------------ 95 | # Device Type#All Device Types#Switches 96 | #------------------------------------------------------------------------------ 97 | 98 | - name: Device Type#All Device Types#Switches 99 | description: Switches 100 | othername: Device Type 101 | 102 | - name: Device Type#All Device Types#Switches#Catalyst 103 | description: Cisco Catalyst Switch 104 | othername: Device Type 105 | 106 | - name: Device Type#All Device Types#Switches#Catalyst#3K 107 | description: Cisco Catalyst 3000 Series Switch 108 | othername: Device Type 109 | 110 | # - name: Device Type#All Device Types#Switches#Catalyst#6K 111 | # description: Cisco Catalyst 6500 Series Switch 112 | # othername: Device Type 113 | 114 | - name: Device Type#All Device Types#Switches#Catalyst#9K 115 | description: Cisco Catalyst 9000 Series Switch 116 | othername: Device Type 117 | 118 | # - name: Device Type#All Device Types#Switches#Micro 119 | # description: Cisco Catalyst Micro Switch 120 | # othername: Device Type 121 | 122 | # - name: Device Type#All Device Types#Switches#IE 123 | # description: Cisco Industrial Ethernet (IE) Switches 124 | # othername: Device Type 125 | 126 | - name: Device Type#All Device Types#Switches#MS 127 | description: Cisco Meraki MS 128 | othername: Device Type 129 | 130 | # - name: Device Type#All Device Types#Switches#MS#MS120 131 | # description: Cisco Meraki MS390 132 | # othername: Device Type 133 | 134 | - name: Device Type#All Device Types#Switches#MS#MS390 135 | description: Cisco Meraki MS390 136 | othername: Device Type 137 | 138 | 139 | #------------------------------------------------------------------------------ 140 | # Device Type#All Device Types#Routers 141 | #------------------------------------------------------------------------------ 142 | - name: Device Type#All Device Types#Routers 143 | description: Routers 144 | othername: Device Type 145 | 146 | 147 | #------------------------------------------------------------------------------ 148 | # Device Type#All Device Types#SDWAN / VPN 149 | #------------------------------------------------------------------------------ 150 | 151 | - name: Device Type#All Device Types#SDWAN#MX 152 | description: Cisco Meraki MX 153 | othername: Device Type 154 | 155 | - name: Device Type#All Device Types#SDWAN#MX#MX68 156 | description: Cisco Meraki MX68 157 | othername: Device Type 158 | 159 | - name: Device Type#All Device Types#SDWAN#MX#vMX 160 | description: Cisco Meraki vMX 161 | othername: Device Type 162 | 163 | # - name: Device Type#All Device Types#SDWAN#Z 164 | # description: Cisco Meraki vMX 165 | # othername: Device Type 166 | 167 | # - name: Device Type#All Device Types#SDWAN#Z#Z3 168 | # description: Cisco Meraki vMX 169 | # othername: Device Type 170 | 171 | 172 | #------------------------------------------------------------------------------ 173 | # Device Type#All Device Types#VPN 174 | #------------------------------------------------------------------------------ 175 | 176 | - name: Device Type#All Device Types#VPN 177 | description: VPN 178 | othername: Device Type 179 | 180 | # - name: Device Type#All Device Types#VPN#ASA 181 | # description: Cisco ASA 182 | # othername: Device Type 183 | 184 | 185 | #------------------------------------------------------------------------------ 186 | # Network Device Groups by Operations 187 | #------------------------------------------------------------------------------ 188 | 189 | # - name: Operation#Operation 190 | # description: All Operations 191 | # othername: Operation 192 | 193 | # - name: Operation#Operation#Zone1 194 | # description: Zone 1 195 | # othername: Operation 196 | 197 | # - name: Operation#Operation#Zone2 198 | # description: Zone 2 199 | # othername: Operation 200 | 201 | # - name: Operation#Operation#Zone3 202 | # description: Zone 3 203 | # othername: Operation 204 | 205 | # - name: Operation#Operation#Zone4 206 | # description: Zone 4 207 | # othername: Operation 208 | 209 | # - name: Operation#Operation#Zone5 210 | # description: Zone 5 211 | # othername: Operation 212 | 213 | 214 | 215 | 216 | #------------------------------------------------------------------------------ 217 | # Network Device Groups by Regions 218 | #------------------------------------------------------------------------------ 219 | 220 | # - name: Region#Region 221 | # description: All Regions 222 | # othername: Region 223 | 224 | # - name: Region#Region#Region1 225 | # description: Region 1 226 | # othername: Region 227 | 228 | # - name: Region#Region#Region2 229 | # description: Region 2 230 | # othername: Region 231 | 232 | # - name: Region#Region#Region3 233 | # description: Region 3 234 | # othername: Region 235 | 236 | # - name: Region#Region#Region4 237 | # description: Region 4 238 | # othername: Region 239 | 240 | # - name: Region#Region#Region5 241 | # description: Region 5 242 | # othername: Region 243 | 244 | 245 | 246 | #------------------------------------------------------------------------------ 247 | # Network Device Groups by Corporate Departments 248 | #------------------------------------------------------------------------------ 249 | 250 | # - name: Department#Department 251 | # description: All Department 252 | # othername: Department 253 | 254 | # - name: Department#Department#Finance 255 | # description: Finance 256 | # othername: Department 257 | 258 | # - name: Department#Department#HR 259 | # description: HR 260 | # othername: Department 261 | 262 | # - name: Department#Department#IT 263 | # description: IT 264 | # othername: Department 265 | 266 | # - name: Department#Department#Management 267 | # description: Management 268 | # othername: Department 269 | 270 | # - name: Department#Department#Marketing 271 | # description: Marketing 272 | # othername: Department 273 | 274 | # - name: Department#Department#Product 275 | # description: Product 276 | # othername: Department 277 | 278 | # - name: Department#Department#Services 279 | # description: Services 280 | # othername: Department 281 | 282 | # - name: Department#Department#Sales 283 | # description: Sales 284 | # othername: Department 285 | 286 | # - name: Department#Department#Vendors 287 | # description: Vendors 288 | # othername: Department 289 | 290 | 291 | 292 | 293 | #------------------------------------------------------------------------------ 294 | # Network Device Groups by Locations 295 | #------------------------------------------------------------------------------ 296 | 297 | - name: Location#All Locations#AMER 298 | description: AMER 299 | othername: Location 300 | 301 | # - name: Location#All Locations#AMER#AST 302 | # description: Austin, TX, US 303 | # othername: Location 304 | 305 | # - name: Location#All Locations#AMER#ATL 306 | # description: Atlanta, GA, US 307 | # othername: Location 308 | 309 | # - name: Location#All Locations#AMER#CHI 310 | # description: Chicago, IL, US 311 | # othername: Location 312 | 313 | - name: Location#All Locations#AMER#HBC 314 | description: Huntington Beach, CA, US 315 | othername: Location 316 | 317 | # - name: Location#All Locations#AMER#HRN 318 | # description: Herndon, VA, US 319 | # othername: Location 320 | 321 | # - name: Location#All Locations#AMER#IRV 322 | # description: Irvine, CA, US 323 | # othername: Location 324 | 325 | # - name: Location#All Locations#AMER#MXC 326 | # description: Mexico City, MX 327 | # othername: Location 328 | 329 | # - name: Location#All Locations#AMER#NYC 330 | # description: New York, NY, US 331 | # othername: Location 332 | 333 | # - name: Location#All Locations#AMER#RCD 334 | # description: Richardson, TX, US 335 | # othername: Location 336 | 337 | # - name: Location#All Locations#AMER#RTP 338 | # description: Raleigh, NC, US 339 | # othername: Location 340 | 341 | - name: Location#All Locations#AMER#SJC 342 | description: San Jose, CA, US 343 | othername: Location 344 | 345 | # - name: Location#All Locations#AMER#SJC#SJC01 346 | # description: San Jose, Buiding 01 347 | # othername: Location 348 | 349 | # - name: Location#All Locations#AMER#SJC#SJC02 350 | # description: San Jose, Buiding 02 351 | # othername: Location 352 | 353 | # - name: Location#All Locations#AMER#SJC#SJC03 354 | # description: San Jose, Buiding 03 355 | # othername: Location 356 | 357 | # - name: Location#All Locations#AMER#SJC#SJC04 358 | # description: San Jose, Buiding 04 359 | # othername: Location 360 | 361 | # - name: Location#All Locations#AMER#SJC#SJC05 362 | # description: San Jose, Buiding 05 363 | # othername: Location 364 | 365 | # - name: Location#All Locations#AMER#SJC#SJC06 366 | # description: San Jose, Buiding 06 367 | # othername: Location 368 | 369 | # - name: Location#All Locations#AMER#SJC#SJC07 370 | # description: San Jose, Buiding 07 371 | # othername: Location 372 | 373 | # - name: Location#All Locations#AMER#SJC#SJC08 374 | # description: San Jose, Buiding 08 375 | # othername: Location 376 | 377 | # - name: Location#All Locations#AMER#SJC#SJC09 378 | # description: San Jose, Buiding 09 379 | # othername: Location 380 | 381 | # - name: Location#All Locations#AMER#SJC#SJC10 382 | # description: San Jose, Buiding 10 383 | # othername: Location 384 | 385 | # - name: Location#All Locations#AMER#SJC#SJC11 386 | # description: San Jose, Buiding 11 387 | # othername: Location 388 | 389 | # - name: Location#All Locations#AMER#SJC#SJC12 390 | # description: San Jose, Buiding 12 391 | # othername: Location 392 | 393 | # - name: Location#All Locations#AMER#SJC#SJC13 394 | # description: San Jose, Buiding 13 395 | # othername: Location 396 | 397 | # - name: Location#All Locations#AMER#SJC#SJC14 398 | # description: San Jose, Buiding 14 399 | # othername: Location 400 | 401 | # - name: Location#All Locations#AMER#SJC#SJC15 402 | # description: San Jose, Buiding 15 403 | # othername: Location 404 | 405 | # - name: Location#All Locations#AMER#SJC#SJC16 406 | # description: San Jose, Buiding 16 407 | # othername: Location 408 | 409 | # - name: Location#All Locations#AMER#SJC#SJC17 410 | # description: San Jose, Buiding 17 411 | # othername: Location 412 | 413 | # - name: Location#All Locations#AMER#SJC#SJC18 414 | # description: San Jose, Buiding 18 415 | # othername: Location 416 | 417 | # - name: Location#All Locations#AMER#SJC#SJC19 418 | # description: San Jose, Buiding 19 419 | # othername: Location 420 | 421 | # - name: Location#All Locations#AMER#SJC#SJC20 422 | # description: San Jose, Buiding 20 423 | # othername: Location 424 | 425 | # - name: Location#All Locations#AMER#SJC#SJC21 426 | # description: San Jose, Buiding 21 427 | # othername: Location 428 | 429 | # - name: Location#All Locations#AMER#SJC#SJC22 430 | # description: San Jose, Buiding 22 431 | # othername: Location 432 | 433 | # - name: Location#All Locations#AMER#SJC#SJC23 434 | # description: San Jose, Buiding 23 435 | # othername: Location 436 | 437 | # - name: Location#All Locations#AMER#SJC#SJC24 438 | # description: San Jose, Buiding 24 439 | # othername: Location 440 | 441 | # - name: Location#All Locations#APJC 442 | # description: APJC 443 | # othername: Location 444 | 445 | # - name: Location#All Locations#APJC#BGL 446 | # description: Bengaluru 447 | # othername: Location 448 | 449 | # - name: Location#All Locations#APJC#SEO 450 | # description: Seoul 451 | # othername: Location 452 | 453 | # - name: Location#All Locations#APJC#SIN 454 | # description: Singapore 455 | # othername: Location 456 | 457 | # - name: Location#All Locations#APJC#SYD 458 | # description: Sydney 459 | # othername: Location 460 | 461 | # - name: Location#All Locations#APJC#TYO 462 | # description: Tokyo 463 | # othername: Location 464 | 465 | # - name: Location#All Locations#EMEAR 466 | # description: EMEAR 467 | # othername: Location 468 | 469 | # - name: Location#All Locations#EMEAR#AMS 470 | # description: Amsterdam 471 | # othername: Location 472 | 473 | # - name: Location#All Locations#EMEAR#BER 474 | # description: Berlin 475 | # othername: Location 476 | 477 | # - name: Location#All Locations#EMEAR#DUB 478 | # description: Dubai 479 | # othername: Location 480 | 481 | # - name: Location#All Locations#EMEAR#JBG 482 | # description: Johannesburg 483 | # othername: Location 484 | 485 | # - name: Location#All Locations#EMEAR#LON 486 | # description: London 487 | # othername: Location 488 | 489 | # - name: Location#All Locations#EMEAR#MLN 490 | # description: Milan 491 | # othername: Location 492 | 493 | # - name: Location#All Locations#EMEAR#MSW 494 | # description: Moscow 495 | # othername: Location 496 | 497 | # - name: Location#All Locations#EMEAR#PRG 498 | # description: Prague 499 | # othername: Location 500 | 501 | # - name: Location#All Locations#EMEAR#PRS 502 | # description: Paris 503 | # othername: Location 504 | 505 | 506 | 507 | 508 | #------------------------------------------------------------------------------ 509 | # Network Device Groups by Medical Department 510 | #------------------------------------------------------------------------------ 511 | 512 | # - name: Department#Department 513 | # description: All Department 514 | # othername: Department 515 | 516 | # - name: Department#Department#Accounts 517 | # description: Accounts 518 | # othername: Department 519 | 520 | # - name: Department#Department#Administration 521 | # description: Administration 522 | # othername: Department 523 | 524 | # - name: Department#Department#Admitting 525 | # description: Admitting 526 | # othername: Department 527 | 528 | # - name: Department#Department#Bacteriology 529 | # description: Bacteriology 530 | # othername: Department 531 | 532 | # - name: Department#Department#Biochemistry 533 | # description: Biochemistry 534 | # othername: Department 535 | 536 | # - name: Department#Department#BloodBank 537 | # description: BloodBank 538 | # othername: Department 539 | 540 | # - name: Department#Department#BusinessManagement 541 | # description: BusinessManagement 542 | # othername: Department 543 | 544 | # - name: Department#Department#Cardiology 545 | # description: Cardiology 546 | # othername: Department 547 | 548 | # - name: Department#Department#Dental 549 | # description: Dental 550 | # othername: Department 551 | 552 | # - name: Department#Department#Dietary 553 | # description: Dietary 554 | # othername: Department 555 | 556 | # - name: Department#Department#EarNoseThroat 557 | # description: EarNoseThroat 558 | # othername: Department 559 | 560 | # - name: Department#Department#Gynecology 561 | # description: Gynecology 562 | # othername: Department 563 | 564 | # - name: Department#Department#Hematology 565 | # description: Hematology 566 | # othername: Department 567 | 568 | # - name: Department#Department#Housekeeping 569 | # description: Housekeeping 570 | # othername: Department 571 | 572 | # - name: Department#Department#InfectiousDisease 573 | # description: InfectiousDisease 574 | # othername: Department 575 | 576 | # - name: Department#Department#Inpatient 577 | # description: Inpatient 578 | # othername: Department 579 | 580 | # - name: Department#Department#Laundry 581 | # description: Laundry 582 | # othername: Department 583 | 584 | # - name: Department#Department#Maintenance 585 | # description: Maintenance 586 | # othername: Department 587 | 588 | # - name: Department#Department#Mechanical 589 | # description: Mechanical 590 | # othername: Department 591 | 592 | # - name: Department#Department#Neurology 593 | # description: Neurology 594 | # othername: Department 595 | 596 | # - name: Department#Department#Nuclear 597 | # description: Nuclear 598 | # othername: Department 599 | 600 | # - name: Department#Department#Nursing 601 | # description: Nursing 602 | # othername: Department 603 | 604 | # - name: Department#Department#Obstetrics 605 | # description: Obstetrics 606 | # othername: Department 607 | 608 | # - name: Department#Department#Opthamology 609 | # description: Opthamology 610 | # othername: Department 611 | 612 | # - name: Department#Department#Orthopedics 613 | # description: Orthopedics 614 | # othername: Department 615 | 616 | # - name: Department#Department#Outpatient 617 | # description: Outpatient 618 | # othername: Department 619 | 620 | # - name: Department#Department#Pediatrics 621 | # description: Pediatrics 622 | # othername: Department 623 | 624 | # - name: Department#Department#Paramedical 625 | # description: Paramedical 626 | # othername: Department 627 | 628 | # - name: Department#Department#Parasitology 629 | # description: Parasitology 630 | # othername: Department 631 | 632 | # - name: Department#Department#Pastoral 633 | # description: Pastoral 634 | # othername: Department 635 | 636 | # - name: Department#Department#Pathology 637 | # description: Pathology 638 | # othername: Department 639 | 640 | # - name: Department#Department#Personnel 641 | # description: Personnel 642 | # othername: Department 643 | 644 | # - name: Department#Department#Pharmacy 645 | # description: Pharmacy 646 | # othername: Department 647 | 648 | # - name: Department#Department#Reconstruction 649 | # description: Reconstruction 650 | # othername: Department 651 | 652 | # - name: Department#Department#Psychiatry 653 | # description: Psychiatry 654 | # othername: Department 655 | 656 | # - name: Department#Department#Purchasing 657 | # description: Purchasing 658 | # othername: Department 659 | 660 | # - name: Department#Department#Radiology 661 | # description: Radiology 662 | # othername: Department 663 | 664 | # - name: Department#Department#Records 665 | # description: Records 666 | # othername: Department 667 | 668 | # - name: Department#Department#Rehabilitation 669 | # description: Rehabilitation 670 | # othername: Department 671 | 672 | # - name: Department#Department#Serology 673 | # description: Serology 674 | # othername: Department 675 | 676 | # - name: Department#Department#Skin 677 | # description: Skin 678 | # othername: Department 679 | 680 | # - name: Department#Department#SocialServices 681 | # description: SocialServices 682 | # othername: Department 683 | 684 | # - name: Department#Department#Sterilization 685 | # description: Sterilization 686 | # othername: Department 687 | 688 | # - name: Department#Department#Supplies 689 | # description: Supplies 690 | # othername: Department 691 | 692 | # - name: Department#Department#Surgery 693 | # description: Surgery 694 | # othername: Department 695 | 696 | # - name: Department#Department#Waste 697 | # description: Waste 698 | # othername: Department 699 | 700 | 701 | 702 | 703 | #------------------------------------------------------------------------------ 704 | # Network Device Groups by University Department 705 | #------------------------------------------------------------------------------ 706 | 707 | # - name: Department#Department 708 | # description: All Department 709 | # othername: Department 710 | 711 | # - name: Department#Department#AAG 712 | # description: Anthropology and Geography 713 | # othername: Department 714 | 715 | # - name: Department#Department#AER 716 | # description: Aerospace 717 | # othername: Department 718 | 719 | # - name: Department#Department#AGB 720 | # description: Agricultural Business 721 | # othername: Department 722 | 723 | # - name: Department#Department#AGR 724 | # description: Agriculture 725 | # othername: Department 726 | 727 | # - name: Department#Department#AGS 728 | # description: Agricultural Science 729 | # othername: Department 730 | 731 | # - name: Department#Department#ARC 732 | # description: Architecture 733 | # othername: Department 734 | 735 | # - name: Department#Department#ARE 736 | # description: Architectural Engineering 737 | # othername: Department 738 | 739 | # - name: Department#Department#ART 740 | # description: Art and Design 741 | # othername: Department 742 | 743 | # - name: Department#Department#ASC 744 | # description: Animal Science 745 | # othername: Department 746 | 747 | # - name: Department#Department#BIO 748 | # description: Biochemistry 749 | # othername: Department 750 | 751 | # - name: Department#Department#BM 752 | # description: Biomedical 753 | # othername: Department 754 | 755 | # - name: Department#Department#BSC 756 | # description: Biological Sciences 757 | # othername: Department 758 | 759 | # - name: Department#Department#BUS 760 | # description: Business 761 | # othername: Department 762 | 763 | # - name: Department#Department#CE 764 | # description: Civil Engineering 765 | # othername: Department 766 | 767 | # - name: Department#Department#CES 768 | # description: Comparative Ethnic Studies 769 | # othername: Department 770 | 771 | # - name: Department#Department#CHM 772 | # description: Chemistry 773 | # othername: Department 774 | 775 | # - name: Department#Department#CM 776 | # description: Construction Management 777 | # othername: Department 778 | 779 | # - name: Department#Department#CON 780 | # description: Construction 781 | # othername: Department 782 | 783 | # - name: Department#Department#CPE 784 | # description: Computer Engineering 785 | # othername: Department 786 | 787 | # - name: Department#Department#CRP 788 | # description: City and Regional Planning 789 | # othername: Department 790 | 791 | # - name: Department#Department#CS 792 | # description: Computer Science 793 | # othername: Department 794 | 795 | # - name: Department#Department#ECN 796 | # description: Economics 797 | # othername: Department 798 | 799 | # - name: Department#Department#EE 800 | # description: Electrical Engineering 801 | # othername: Department 802 | 803 | # - name: Department#Department#EGR 804 | # description: Engineering 805 | # othername: Department 806 | 807 | # - name: Department#Department#ENG 808 | # description: English 809 | # othername: Department 810 | 811 | # - name: Department#Department#ES 812 | # description: Ethnic Studies 813 | # othername: Department 814 | 815 | # - name: Department#Department#FS 816 | # description: Food Science 817 | # othername: Department 818 | 819 | # - name: Department#Department#GE 820 | # description: General Engineering 821 | # othername: Department 822 | 823 | # - name: Department#Department#HIS 824 | # description: History 825 | # othername: Department 826 | 827 | # - name: Department#Department#IE 828 | # description: Industrial Engineering 829 | # othername: Department 830 | 831 | # - name: Department#Department#IT 832 | # description: Industrial Technology 833 | # othername: Department 834 | 835 | # - name: Department#Department#JRN 836 | # description: Journalism 837 | # othername: Department 838 | 839 | # - name: Department#Department#KIN 840 | # description: Kinesiology 841 | # othername: Department 842 | 843 | # - name: Department#Department#LA 844 | # description: Landscape Architecture 845 | # othername: Department 846 | 847 | # - name: Department#Department#LAN 848 | # description: Languages 849 | # othername: Department 850 | 851 | # - name: Department#Department#LS 852 | # description: Liberal Studies 853 | # othername: Department 854 | 855 | # - name: Department#Department#MAN 856 | # description: Manufacturing Engineering 857 | # othername: Department 858 | 859 | # - name: Department#Department#MAT 860 | # description: Materials Engineering 861 | # othername: Department 862 | 863 | # - name: Department#Department#MB 864 | # description: Microbiology 865 | # othername: Department 866 | 867 | # - name: Department#Department#ME 868 | # description: Mechanical Engineering 869 | # othername: Department 870 | 871 | # - name: Department#Department#MS 872 | # description: Marine Sciences 873 | # othername: Department 874 | 875 | # - name: Department#Department#MSC 876 | # description: Music 877 | # othername: Department 878 | 879 | # - name: Department#Department#MTH 880 | # description: Mathematics 881 | # othername: Department 882 | 883 | # - name: Department#Department#NRM 884 | # description: Natural Resources Management 885 | # othername: Department 886 | 887 | # - name: Department#Department#NUT 888 | # description: Nutrition 889 | # othername: Department 890 | 891 | # - name: Department#Department#NVE 892 | # description: Environmental Engineering 893 | # othername: Department 894 | 895 | # - name: Department#Department#NVS 896 | # description: Environmental Sciences 897 | # othername: Department 898 | 899 | # - name: Department#Department#PH 900 | # description: Public Health 901 | # othername: Department 902 | 903 | # - name: Department#Department#PHL 904 | # description: Philosophy 905 | # othername: Department 906 | 907 | # - name: Department#Department#PHY 908 | # description: Physics 909 | # othername: Department 910 | 911 | # - name: Department#Department#PLS 912 | # description: Plant Sciences 913 | # othername: Department 914 | 915 | # - name: Department#Department#POL 916 | # description: Political Science 917 | # othername: Department 918 | 919 | # - name: Department#Department#PSY 920 | # description: Psychology 921 | # othername: Department 922 | 923 | # - name: Department#Department#REC 924 | # description: Recreation Administration 925 | # othername: Department 926 | 927 | # - name: Department#Department#SCI 928 | # description: Science 929 | # othername: Department 930 | 931 | # - name: Department#Department#SOC 932 | # description: Sociology 933 | # othername: Department 934 | 935 | # - name: Department#Department#STS 936 | # description: Statistics 937 | # othername: Department 938 | 939 | # - name: Department#Department#SWE 940 | # description: Software Engineering 941 | # othername: Department 942 | 943 | # - name: Department#Department#TA 944 | # description: Theatre Arts 945 | # othername: Department 946 | 947 | # - name: Department#Department#VIT 948 | # description: Viticulture 949 | # othername: Department 950 | 951 | 952 | 953 | 954 | ... 955 | --------------------------------------------------------------------------------