components-contrib/.github/infrastructure/conformance/azure/allow-github-ips-in-azuresq...

121 lines
5.0 KiB
Python

#!/usr/bin/env python3
# ------------------------------------------------------------
# Copyright 2021 The Dapr Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ------------------------------------------------------------
import argparse
import ipaddress
import json
import os
import subprocess
import sys
import urllib.request
def parseArgs():
abscwd = os.path.abspath(os.getcwd())
arg_parser = argparse.ArgumentParser(description='Generates the IP ranges based on CIDRs for GitHub Actions from meta API.')
arg_parser.add_argument('--outpath', type=str, default=abscwd, help='Optional. Full path to write the JSON output to.')
arg_parser.add_argument('--sqlserver', type=str, help='Name of the Azure SQL server to update firewall rules of. Required for deployment.')
arg_parser.add_argument('--resource-group', type=str, help='Resouce group containing the target Azure SQL server. Required for deployment.')
arg_parser.add_argument('--no-deployment', action='store_true', help='Specify this flag to generate the ARM template without deploying it.')
args = arg_parser.parse_args()
if not args.no_deployment:
is_missing_args = False
if not args.sqlserver:
print('ERROR: the following argument is required: --sqlserver')
is_missing_args = True
if not args.resource_group:
print('ERROR: the following argument is required: --resource-group')
is_missing_args = True
if is_missing_args:
arg_parser.print_help()
sys.exit(-1)
print('Arguments parsed: {}'.format(args))
return args
def getResponse(url):
operUrl = urllib.request.urlopen(url)
if(operUrl.getcode()==200):
data = operUrl.read()
jsonData = json.loads(data)
else:
print('ERROR: failed to receive data', operUrl.getcode())
return jsonData
def writeAllowedIPRangesJSON(outpath):
url = 'https://api.github.com/meta'
jsonData = getResponse(url)
ipRanges = []
prevStart = ''
prevEnd = ''
# Iterate the public IP CIDRs used to run GitHub Actions, and convert them
# into IP ranges for test SQL server firewall access.
for cidr in jsonData['actions']:
net = ipaddress.ip_network(cidr)
# SQL server firewall only supports up to 128 firewall rules.
# As a first cut, exclude all IPv6 addresses.
if net.version == 4:
start = net[0]
end = net[-1]
# print(f'{cidr} --> [{start}, {end}]')
if prevStart == '':
prevStart = start
if prevEnd == '':
prevEnd = end
elif prevEnd + 65536 > start:
# If the current IP range is within the granularity of a /16
# subnet mask to the previous range, coalesce them into one.
# This is necessary to get the number of rules down to ~100.
prevEnd = end
else:
ipRange = [str(prevStart), str(prevEnd)]
ipRanges.append(ipRange)
prevStart = start
prevEnd = end
if prevStart != '' and prevEnd != '':
ipRange = [str(prevStart), str(prevEnd)]
ipRanges.append(ipRange)
with open(outpath, 'w') as outfile:
json.dump(ipRanges, outfile)
def main():
args = parseArgs()
# Get the GitHub IP Ranges to use as firewall allow-rules from the GitHub meta API
ipRangesFileName = os.path.join(args.outpath, 'github-ipranges.json')
writeAllowedIPRangesJSON(ipRangesFileName)
print(f'INFO: GitHub Actions public IP range rules written {ipRangesFileName}')
# Generate the ARM template from bicep to update Azure SQL server firewall rules
subprocess.call(['az', 'bicep', 'install'])
firewallTemplateName = os.path.join(args.outpath, 'update-sql-firewall-rules.json')
subprocess.call(['az', 'bicep', 'build', '--file', 'conf-test-azure-sqlserver-firewall.bicep', '--outfile', firewallTemplateName])
print(f'INFO: ARM template to update SQL Server firewall rules written to {firewallTemplateName}')
# Update the Azure SQL server firewall rules
if args.no_deployment:
print(f'INFO: --no-deployment specified, skipping update of SQL server {firewallTemplateName}')
else:
subprocess.call(['az', 'deployment', 'group', 'create', '--name', 'UpdateSQLFirewallRules', '--template-file', firewallTemplateName, '--resource-group', args.resource_group, '--parameters', f'sqlServerName={args.sqlserver}', '--parameters', f'ipRanges=@{ipRangesFileName}'])
sys.exit(0)
if __name__ == '__main__':
main()