Regex over multiple lines with \n - python-3.x

In the following code I would like to capture the instance ID and then the body underneath it. The pattern is recurring so that there are multiple instances with the same bodies. I can't seem to figure out how to get it to continue past the newline segments.
import re
config = '''
Instance: evpn-a
VLAN ID: 123, MAC address: 00:05:86:71:05:f0
Source: irb.0, Rank: 1, Status: Active
State: <Local-MAC-Only Local-Gateway Remote-Adv-Allowed>
IP address: 192.168.10.251
VLAN ID: 123, MAC address: 00:05:86:71:ab:f0
Source: 20.1.1.2, Rank: 1, Status: Active
State: <Remote-Gateway Local-Adv-Allowed Local-Adv-Done>
IP address: 192.168.10.252
L3 route: 192.168.10.252/32, L3 context: bridge-vrf (irb.0)
Instance: evpn-b
VLAN ID: 123, MAC address: 00:05:86:71:05:f0
Source: irb.0, Rank: 1, Status: Active
State: <Local-MAC-Only Local-Gateway Remote-Adv-Allowed>
IP address: 192.168.10.251
VLAN ID: 123, MAC address: 00:05:86:71:ab:f0
Source: 20.1.1.2, Rank: 1, Status: Active
State: <Remote-Gateway Local-Adv-Allowed Local-Adv-Done>
IP address: 192.168.10.252
L3 route: 192.168.10.252/32, L3 context: bridge-vrf (irb.0)
'''
evpn_obj_list = re.compile(r'Instance:\s+(\S+)(.*?)(?:\S+|\Z)',re.S|re.M).findall(config)
evpn = evpn_obj_list
print(evpn)
The result I get from the above is:
[('evpn-a', '\n\n'), ('evpn-b', '\n\n')]

You may use
rx = re.compile(r'^Instance:\s+(\S+)\s*(.*?)(?=\n\s*Instance:\s|\Z)', re.S|re.M)
evpn_obj_list = rx.findall(config)
See the regex demo.
Details
^ - start of a line
Instance: - a string
\s+ - 1+ whitespaces
(\S+) - Group 1: any one or more non-whitespace chars
\s* - 0+ whitespaces
(.*?) - Group 2: any 0 or more chars, as few as possible
(?=\n\s*Instance:\s|\Z) - a positive lookahead that requires a newline, 0+ whitespaces, Instance:, a whitespace OR the end of file immediately to the right of the current location.
See the Python demo yielding
[('evpn-a', 'VLAN ID: 123, MAC address: 00:05:86:71:05:f0\n Source: irb.0, Rank: 1, Status: Active\n State: <Local-MAC-Only Local-Gateway Remote-Adv-Allowed>\n IP address: 192.168.10.251\n\nVLAN ID: 123, MAC address: 00:05:86:71:ab:f0\n Source: 20.1.1.2, Rank: 1, Status: Active\n State: <Remote-Gateway Local-Adv-Allowed Local-Adv-Done>\n IP address: 192.168.10.252\n L3 route: 192.168.10.252/32, L3 context: bridge-vrf (irb.0)'), ('evpn-b', 'VLAN ID: 123, MAC address: 00:05:86:71:05:f0\n Source: irb.0, Rank: 1, Status: Active\n State: <Local-MAC-Only Local-Gateway Remote-Adv-Allowed>\n IP address: 192.168.10.251\n\nVLAN ID: 123, MAC address: 00:05:86:71:ab:f0\n Source: 20.1.1.2, Rank: 1, Status: Active\n State: <Remote-Gateway Local-Adv-Allowed Local-Adv-Done>\n IP address: 192.168.10.252\n L3 route: 192.168.10.252/32, L3 context: bridge-vrf (irb.0)\n')]

Related

How to get names of devices in your local network using node js

I need to get HueBridge IP address in my app in node js, I would like to scan the whole network and then search for the name "Hue Bridge" or something similar, I found npm package named 'local-devices', but it doesn't return a device name for me for some reason.
const find = require('local-devices');
find().then(devices => {
console.log(devices)
})
Output:
[
{ name: '?', ip: '192.168.1.72', mac: 'secret_mac'},
{ name: '?', ip: '192.168.1.116', mac: 'secret_mac'},
{ name: '?', ip: '192.168.1.117', mac: 'secret_mac'}
]

what is every item in the `/var/lib/misc/dnsmasq.leases`?

The context in /var/lib/misc/dnsmasq.leases like below
1646438467 12:03:f2:19:41:4d 192.168.4.239 * 01:12:03:f2:19:41:4d
lease time: 1646438467
MAC address: 12:03:f2:19:41:4d
IP address: 192.168.4.13
hostname: *
but what is the 01:12:03:f2:19:41:4d? It likes like 01: and Mac address
https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html does not mention that

How to fix this error? Failed validating 'oneOf' in schema

I am creating an API using Flask, Connexion and SQLAlchemy to access a database. To do this I needed the following dependencies:
Flask-SQLAlchemy
Flask-Marshmallow
Marshmallow-SQLAlchemy
Marshmallow
When I run the file with the app instance using the command python3 <filename>, this is the error produced:
Traceback (most recent call last):
File "server.py", line 16, in <module>
connex_app.add_api("swagger.yml")
File "/home/fidelis/repo/proj4/env/lib/python3.6/site-packages/connexion/apps/flask_app.py", line 57, in add_api
api = super(FlaskApp, self).add_api(specification, **kwargs)
File "/home/fidelis/repo/proj4/env/lib/python3.6/site-packages/connexion/apps/abstract.py", line 153, in add_api
options=api_options.as_dict())
File "/home/fidelis/repo/proj4/env/lib/python3.6/site-packages/connexion/apis/abstract.py", line 75, in __init__
self.specification = Specification.load(specification, arguments=arguments)
File "/home/fidelis/repo/proj4/env/lib/python3.6/site-packages/connexion/spec.py", line 153, in load
return cls.from_file(spec, arguments=arguments)
File "/home/fidelis/repo/proj4/env/lib/python3.6/site-packages/connexion/spec.py", line 107, in from_file
return cls.from_dict(spec)
File "/home/fidelis/repo/proj4/env/lib/python3.6/site-packages/connexion/spec.py", line 144, in from_dict
return Swagger2Specification(spec)
File "/home/fidelis/repo/proj4/env/lib/python3.6/site-packages/connexion/spec.py", line 38, in __init__
self._validate_spec(raw_spec)
File "/home/fidelis/repo/proj4/env/lib/python3.6/site-packages/connexion/spec.py", line 214, in _validate_spec
raise InvalidSpecification.create_from(e)
connexion.exceptions.InvalidSpecification: None is not valid under any of the given schemas
Failed validating 'oneOf' in schema['properties']['paths']['patternProperties']['^/']['properties']['delete']['properties']['responses']['patternProperties']['^([0-9]{3})$|^(default)$']:
{'oneOf': [{'$ref': '#/definitions/response'},
{'$ref': '#/definitions/jsonReference'}]}
On instance['paths']['/people/{person_id}']['delete']['responses']['200']:
Below is the swagger.yml file:
swagger: "2.0"
info:
description: This is the swagger file that goes with our server code
version: "1.0.0"
title: Swagger Rest Article
consumes:
- application/json
produces:
- application/json
basePath: /api
# Paths supported by the server application
paths:
/people:
get:
operationId: people.read_all
tags:
- People
summary: Read the entire set of people, sorted by last name
description: Read the entire set of people, sorted by last name
responses:
200:
description: Successfully read people set operation
schema:
type: array
items:
properties:
person_id:
type: string
description: Id of the person
fname:
type: string
description: First name of the person
lname:
type: string
description: Last name of the person
timestamp:
type: string
description: Creation/Update timestamp of the person
post:
operationId: people.create
tags:
- People
summary: Create a person
description: Create a new person
parameters:
- name: person
in: body
description: Person to create
required: True
schema:
type: object
properties:
fname:
type: string
description: First name of person to create
lname:
type: string
description: Last name of person to create
responses:
201:
description: Successfully created person
schema:
properties:
person_id:
type: string
description: Id of the person
fname:
type: string
description: First name of the person
lname:
type: string
description: Last name of the person
timestamp:
type: string
description: Creation/Update timestamp of the person record
/people/{person_id}:
get:
operationId: people.read_one
tags:
- People
summary: Read one person
description: Read one person
parameters:
- name: person_id
in: path
description: Id of the person to get
type: integer
required: True
responses:
200:
description: Successfully read person from people data operation
schema:
type: object
properties:
person_id:
type: string
description: Id of the person
fname:
type: string
description: First name of the person
lname:
type: string
description: Last name of the person
timestamp:
type: string
description: Creation/Update timestamp of the person record
put:
operationId: people.update
tags:
- People
summary: Update a person
description: Update a person
parameters:
- name: person_id
in: path
description: Id the person to update
type: integer
required: True
- name: person
in: body
schema:
type: object
properties:
fname:
type: string
description: First name of the person
lname:
type: string
description: Last name of the person
responses:
200:
description: Successfully updated person
schema:
properties:
person_id:
type: string
description: Id of the person in the database
fname:
type: string
description: First name of the person
lname:
type: string
description: Last name of the person
timestamp:
type: string
description: Creation/Update timestamp of the person record
delete:
operationId: people.delete
tags:
- People
summary: Delete a person from the people list
description: Delete a person
parameters:
- name: person_id
in: path
type: integer
description: Id of the person to delete
required: true
responses:
200:
I can't figure out how to solve the error.
I forgot to include the description right below the delete response 200.This is the line i had forgotten.
description: successfully deleted a person

Get all host names associated with the IP

I want to retrieve all the hostnames associated with the IP.
I ran into an error while using requests module in python. And the data that the error contains I want that data.
First I got the IP of of youtube.com I wanted to get the webpage using ip address only so using ping I got the IP address of youtube.com
IP 172.217.163.78
Then I made the request
import requests
session_ = requests.Session()
res_ = session_.get('https://172.217.163.78')
ERROR
\Python3.7.2\lib\site-packages\requests\adapters.py", line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='172.217.163.78', port=443):
Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError("hostname '172.217.163.78'
doesn't match either of '*.google.com', '*.android.com',
'*.appengine.google.com', '*.cloud.google.com', '*.g.co', '*.gcp.gvt2.com', '*.ggpht.cn', '*.google-analytics.com',
'*.google.ca', '*.google.cl', '*.google.co.in',
'*.google.co.jp', '*.google.co.uk', '*.google.com.ar',
'*.google.com.au', '*.google.com.br', '*.google.com.co',
'*.google.com.mx', '*.google.com.tr', '*.google.com.vn',
'*.google.de', '*.google.es', '*.google.fr', '*.google.hu',
'*.google.it', '*.google.nl', '*.google.pl', '*.google.pt',
'*.googleadapis.com', '*.googleapis.cn',
'*.googlecommerce.com', '*.googlevideo.com', '*.gstatic.cn',
'*.gstatic.com', '*.gstaticcnapps.cn', '*.gvt1.com',
'*.gvt2.com', '*.metric.gstatic.com', '*.urchin.com',
'*.url.google.com', '*.youtube-nocookie.com',
'*.youtube.com', '*.youtubeeducation.com',
'*.youtubekids.com', '*.yt.be', '*.ytimg.com',
'android.clients.google.com', 'android.com',
'developer.android.google.cn',
'developers.android.google.cn', 'g.co', 'ggpht.cn', 'goo.gl',
'google-analytics.com', 'google.com', 'googlecommerce.com'
, 'source.android.google.cn', 'urchin.com', 'www.goo.gl',
'youtu.be', 'youtube.com', 'youtubeeducation.com',
'youtubekids.com', 'yt.be'")))
Is there a way to get all the above hostnames, and is there a way to solve this problem SSLError that i'm getting
Does this work for you?
import requests
session_ = requests.Session()
res_ = session_.get('https://172.217.163.78', verify=False)
print (res_.url)
#Output
# http://www.google.com
Have you concerned using socket instead of request?
import socket
from pprint import pprint
ip_address = socket.gethostbyname('www.abc.com')
pprint (socket.gethostbyaddr(ip_address))
sys.exit(0)
OUTPUT
('www.pitchsharktank.com',
['250.132.181.199.in-addr.arpa',
'www.disneycampusrep.com',
'www.disneycollateral.com',
'www.disneyinternsinfo.com',
'www.missiontimekeeper.com',
'www.watchdisneyjunior.go.com',
'www.disneycastingscout.com',
'www.disneyimaginations.com',
'www.disneyprogramsblog.com',
'www.disneyvacationclub.disney.go.com',
'www.watchdisneychannel.go.com',
'www.wdwcollegeprogramecard.com',
'www.wdwcollegeprogramecard2.com',
'www.disneyinternationalepresentation.com',
many many more here],
['199.181.132.250'])
UPDATE
I spent more than half the day looking into the hostname issue. I have found that this problem is complex, especially for IP addresses assigned to Google.
For example:
ping www.youtube.com
PING youtube-ui.l.google.com (64.233.185.93): 56 data bytes
64 bytes from 64.233.185.93: icmp_seq=0 ttl=41 time=19.820 ms
#############################################################
nslookup www.youtube.com
www.youtube.com canonical name = youtube-ui.l.google.com.
Name: youtube-ui.l.google.com
Address: 172.217.11.142
Name: youtube-ui.l.google.com
Address: 64.233.176.190
Name: youtube-ui.l.google.com
Address: 64.233.177.91
Name: youtube-ui.l.google.com
Address: 64.233.177.93
Name: youtube-ui.l.google.com
Address: 64.233.177.190
Name: youtube-ui.l.google.com
Address: 64.233.185.91
Name: youtube-ui.l.google.com
Address: 64.233.185.93
Name: youtube-ui.l.google.com
Address: 64.233.185.136
Name: youtube-ui.l.google.com
Address: 64.233.185.190
Name: youtube-ui.l.google.com
Address: 74.125.138.190
Name: youtube-ui.l.google.com
Address: 74.125.196.91
Name: youtube-ui.l.google.com
Address: 108.177.122.91
Name: youtube-ui.l.google.com
Address: 108.177.122.93
Name: youtube-ui.l.google.com
Address: 108.177.122.136
Name: youtube-ui.l.google.com
Address: 108.177.122.190
Name: youtube-ui.l.google.com
Address: 172.217.0.78
#############################################################
dig www.youtube.com
;; QUESTION SECTION:
;www.youtube.com. IN A
;; ANSWER SECTION:
www.youtube.com. 9446 IN CNAME youtube-ui.l.google.com.
youtube-ui.l.google.com. 132 IN A 64.233.185.190
youtube-ui.l.google.com. 132 IN A 74.125.138.136
youtube-ui.l.google.com. 132 IN A 74.125.138.190
youtube-ui.l.google.com. 132 IN A 74.125.196.91
youtube-ui.l.google.com. 132 IN A 74.125.196.93
youtube-ui.l.google.com. 132 IN A 172.217.0.78
youtube-ui.l.google.com. 132 IN A 172.217.0.142
youtube-ui.l.google.com. 132 IN A 172.217.2.46
youtube-ui.l.google.com. 132 IN A 172.217.4.14
youtube-ui.l.google.com. 132 IN A 172.217.164.78
youtube-ui.l.google.com. 132 IN A 173.194.219.136
youtube-ui.l.google.com. 132 IN A 173.194.219.190
youtube-ui.l.google.com. 132 IN A 64.233.177.91
youtube-ui.l.google.com. 132 IN A 64.233.177.93
youtube-ui.l.google.com. 132 IN A 64.233.177.136
youtube-ui.l.google.com. 132 IN A 64.233.177.190
The IP address that you provided in your original question doesn't appear in either the ping, nslookup or dig results.
In Apple Safari, Google Chrome and Mozilla Firefox the URL https://172.217.163.78 returns https://www.google.com.
The ShowIP extension in Mozilla Firefox shows that the IP address for https://www.youtube.com is 2607:f8b0:4002:c00::88, which is an IPv6 address.
I also found this:
FQDN: youtube.com
Domain Name: youtube.com
Name servers: ns1.google.com
ns2.google.com
ns3.google.com
ns4.google.com
IP numbers: 2404:6800:4003:805::200e
2404:6800:4004:801::200e
2404:6800:4006:809::200e
2607:f8b0:4004:802::200e
2607:f8b0:4005:807::200e
2607:f8b0:400a:804::200e
2800:3f0:4001:80a::200e
2a00:1450:4009:812::200e
2a00:1450:400b:c01::be
74.125.193.91
74.125.193.93
74.125.193.136
74.125.193.190
172.217.7.238
172.217.24.78
172.217.30.78
216.58.195.78
216.58.197.174
216.58.203.110
216.58.206.46
216.58.217.46
LOOKUP fully qualified domain names:
import socket
##############################################
# IP addresses linked to YouTube on 01-28-2019
##############################################
ip_addresses =['2404:6800:4003:805::200e',
'2404:6800:4004:801::200e',
'2404:6800:4006:809::200e',
'2607:f8b0:4004:802::200e',
'2607:f8b0:4005:807::200e',
'2607:f8b0:400a:804::200e',
'2800:3f0:4001:80a::200e',
'2a00:1450:4009:812::200e',
'2a00:1450:400b:c01::be',
'74.125.193.91',
'74.125.193.93',
'74.125.193.136',
'74.125.193.190',
'172.217.7.238',
'172.217.24.78',
'172.217.30.78',
'216.58.195.78',
'216.58.197.174',
'216.58.203.110',
'216.58.206.46',
'216.58.217.46']
for iP_address in ip_addresses:
fully_qualified_domain_name = socket.getfqdn(str(iP_address))
print (fully_qualified_domain_name)
# OUTPUT
sin10s06-in-x0e.1e100.net
nrt12s02-in-x0e.1e100.net
syd09s15-in-x0e.1e100.net
iad23s58-in-x0e.1e100.net
sfo07s16-in-x0e.1e100.net
sea15s08-in-x0e.1e100.net
2800:3f0:4001:80a::200e
lhr35s10-in-x0e.1e100.net
2a00:1450:400b:c01::be
ig-in-f91.1e100.net
ig-in-f93.1e100.net
ig-in-f136.1e100.net
ig-in-f190.1e100.net
iad23s58-in-f14.1e100.net
sin10s06-in-f14.1e100.net
gru06s34-in-f14.1e100.net
sfo07s16-in-f78.1e100.net
nrt12s02-in-f14.1e100.net
syd09s15-in-f14.1e100.net
lhr35s10-in-f14.1e100.net
sea15s08-in-f14.1e100.net
As you can see, not one of these FQDN equals youtube.com.
I also decided to lookup the IP addresses assigned to YouTube through ARIN. the code below loops through those addresses.
import socket
import ipaddress
from dns import reversename, resolver
# IPv4 addresses listed at whois.arin.net for YouTube
# 64.15.112.0/20 = number of hosts 4,096
# 104.237.160.0/19 = number of hosts 8,192
# 208.65.152.0/22 = number of hosts 1,024
# 208.117.224.0/19 = number of hosts 8,192
youtube_IPv4_addresses = ['64.15.112.0/20','104.237.160.0/19', '208.65.152.0/22', '208.117.224.0/19']
# IPv6 addresses listed at whois.arin.net for YouTube
# Start Range: 2620:11a:a000:0:0:0:0:0
# End Range: 2620:11a:a0ff:ffff:ffff:ffff:ffff:ffff
# No. of host: 309485009821345068724781056
youtube_IPv6_addresses = ['2620:11A:A000::/40']
#############################################
# This function is designed to query the IPv4
# address blocks assigned to YouTube for their
# corresponding PTR records, which are used
# for the Reverse DNS (Domain Name System)
#############################################
def get_ipv4_hostnames():
for network in youtube_IPv4_addresses:
ip_addresses = ipaddress.IPv4Network(network)
for ip_address in ip_addresses:
try:
rev_name = reversename.from_address(str(ip_address))
reversed_dns = str(resolver.query(rev_name,"PTR")[0])
print (reversed_dns)
except Exception as error:
print ('The following error occurred: \n {}'.format(error))
#############################################
# WARNING WARNING WARNING WARNING WARNING
#############################################
# There are 309485009821345068724781056
# possible hosts within the IPv6 address
# range assigned to YouTube at ARIN
#############################################
# WARNING WARNING WARNING WARNING WARNING
#############################################
#############################################
def get_ipv6_hostnames():
for network in youtube_IPv6_addresses:
ip_addresses = ipaddress.IPv6Network(network)
for ip_address in ip_addresses:
try:
fully_qualified_domain_name = socket.getfqdn(str(ip_address))
if fully_qualified_domain_name != str(ip_address):
print (fully_qualified_domain_name)
except Exception as error:
print('The following error occurred: \n {}'.format(error))

Not getting any external outbound traffic from nodes in a Azure VM Scale Set behind a loadbalancer

I'm experiencing difficulties regarding accessing external resources from nodes (RHEL) configured in a VM Scale Set.
To sketch the environment I'm trying to describe using Azure Resource Manager Templates, I'm looking to create:
1 common virtualNetwork
1 Frontend VM (running RHEL, and is working as intended)
1 Cluster (vmss) running 2 nodes (RHEL)
Nodes are spawned in the same private subnet as the frontend VM
1 loadbalancer should work as a NAT gateway (but it's not working this way)
The loadbalancer has an external IP, inboundNatPool (which works), backendAddressPool (in which nodes are successfully registered)
the Network Security Group manages access to ports (set to allow all outbound connections)
As a footnote, I'm comfortable writing up AWS cloudformation files in YAML, so I'm handling Azure Resource Manager Templates in a similar way, for the sake of readability and the added functionality of adding comments in my template.
An Example of my vmss config (short snippet)
... #(yaml-template is first converted to json and than deployed using the azure cli)
# Cluster
# -------
# Scale Set
# ---------
# | VM Scale Set can not connect to external sources
# |
- type: Microsoft.Compute/virtualMachineScaleSets
name: '[variables(''vmssName'')]'
location: '[resourceGroup().location]'
apiVersion: '2017-12-01'
dependsOn:
- '[variables(''vnetName'')]'
- '[variables(''loadBalancerName'')]'
- '[variables(''networkSecurityGroupName'')]'
sku:
capacity: '[variables(''instanceCount'')]' # Amount of nodes to be spawned
name: Standard_A2_v2
tier: Standard
# zones: # If zone is specified, no sku can be chosen
# - '1'
properties:
overprovision: 'true'
upgradePolicy:
mode: Manual
virtualMachineProfile:
networkProfile:
networkInterfaceConfigurations:
- name: '[variables(''vmssNicName'')]'
properties:
ipConfigurations:
- name: '[variables(''ipConfigName'')]'
properties:
loadBalancerBackendAddressPools:
- id: '[variables(''lbBackendAddressPoolsId'')]'
loadBalancerInboundNatPools:
- id: '[variables(''lbInboundNatPoolsId'')]'
subnet:
id: '[variables(''subnetId'')]'
primary: true
networkSecurityGroup:
id: '[variables(''networkSecurityGroupId'')]'
osProfile:
computerNamePrefix: '[variables(''vmssName'')]'
adminUsername: '[parameters(''sshUserName'')]'
# adminPassword: '[parameters(''adminPassword'')]'
linuxConfiguration:
disablePasswordAuthentication: True
ssh:
publicKeys:
- keyData: '[parameters(''sshPublicKey'')]'
path: '[concat(''/home/'',parameters(''sshUserName''),''/.ssh/authorized_keys'')]'
storageProfile:
imageReference: '[variables(''clusterImageReference'')]'
osDisk:
caching: ReadWrite
createOption: FromImage
...
The Network Security Group referenced from the template above is:
# NetworkSecurityGroup
# --------------------
- type: Microsoft.Network/networkSecurityGroups
name: '[variables(''networkSecurityGroupName'')]'
apiVersion: '2017-10-01'
location: '[resourceGroup().location]'
properties:
securityRules:
- name: remoteConnection
properties:
priority: 101
access: Allow
direction: Inbound
protocol: Tcp
description: Allow SSH traffic
sourceAddressPrefix: '*'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
- name: allow_outbound_connections
properties:
description: This rule allows outbound connections
priority: 200
access: Allow
direction: Outbound
protocol: '*'
sourceAddressPrefix: 'VirtualNetwork'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '*'
And the loadbalancer, where I assume the error should be, is described as:
# Loadbalancer as NatGateway
# --------------------------
- type: Microsoft.Network/loadBalancers
name: '[variables(''loadBalancerName'')]'
apiVersion: '2017-10-01'
location: '[resourceGroup().location]'
sku:
name: Standard
dependsOn:
- '[variables(''natIPAddressName'')]'
properties:
backendAddressPools:
- name: '[variables(''lbBackendPoolName'')]'
frontendIPConfigurations:
- name: LoadBalancerFrontEnd
properties:
publicIPAddress:
id: '[variables(''natIPAddressId'')]'
inboundNatPools:
- name: '[variables(''lbNatPoolName'')]'
properties:
backendPort: '22'
frontendIPConfiguration:
id: '[variables(''frontEndIPConfigID'')]'
frontendPortRangeStart: '50000'
frontendPortRangeEnd: '50099'
protocol: tcp
I keep reading articles about configuring a SNAT with port masquerading, but I'm missing relevant examples of such setup.
Any help is greatly appreciated.
It took a lot of searching but the article from Azure about Azure Load Balancer outbound Connections (Scenario #2) stated a load-balancing rule (and complementary Health Probe) was necessary for SNAT to function.
the new code for the load balancer became:
...
- type: Microsoft.Network/loadBalancers
name: '[variables(''loadBalancerName'')]'
apiVersion: '2017-10-01'
location: '[resourceGroup().location]'
sku:
name: Standard
dependsOn:
- '[variables(''natIPAddressName'')]'
properties:
backendAddressPools:
- name: '[variables(''lbBackendPoolName'')]'
frontendIPConfigurations:
- name: LoadBalancerFrontEnd
properties:
publicIPAddress:
id: '[variables(''natIPAddressId'')]'
probes: # Needed for loadBalancingRule to work
- name: '[variables(''lbProbeName'')]'
properties:
protocol: Tcp
port: 22
intervalInSeconds: 5
numberOfProbes: 2
loadBalancingRules: # Needed for SNAT to work
- name: '[concat(variables(''loadBalancerName''),''NatRule'')]'
properties:
disableOutboundSnat: false
frontendIPConfiguration:
id: '[variables(''frontEndIPConfigID'')]'
backendAddressPool:
id: '[variables(''lbBackendAddressPoolsId'')]'
probe:
id: '[variables(''lbProbeId'')]'
protocol: tcp
frontendPort: 80
backendPort: 80
...

Resources