连接Azure新建SQL Server报错IP未被允许且与本机公网IP不一致如何解决
报错IP的说明
你看到的报错中yyy.yy.yy.yy是你当前网络访问Azure SQL服务时实际的公网出口IP。
因为你连接了公司VPN,VPN会根据路由规则分配不同流量的出口:你访问公网IP查询站点的流量走了本地运营商公网出口,拿到的是xxx.xx.xx.xx;而访问Azure SQL的流量被路由到了VPN的公网出口,最终Azure侧识别到的来源IP就是报错中的yyy.yy.yy.yy。
编程获取IP并配置白名单的方法
你可以通过捕获连接报错提取目标IP,再调用Azure Python SDK添加防火墙规则,实现自动化配置,参考实现逻辑如下:
- 首先尝试建立SQL连接,捕获40615错误码的报错,用正则从报错信息中提取被拦截的IP地址
- 调用Azure Python SDK的SQL管理接口,为提取到的IP添加防火墙规则
- 等待规则生效后重试连接即可
示例代码
import re import pyodbc from azure.identity import DefaultAzureCredential from azure.mgmt.sql import SqlManagementClient # 配置参数 subscription_id = "你的Azure订阅ID" resource_group = "SQL Server所在资源组名" sql_server_name = "SQL Server名称" sql_conn_str = "你的SQL连接字符串" firewall_rule_name = "auto-add-vpn-client-ip" def get_blocked_ip_from_error(err_msg): # 正则匹配报错中的客户端IP ip_pattern = r"Client with IP address '(\d+\.\d+\.\d+\.\d+)' is not allowed to access the server" match = re.search(ip_pattern, err_msg) if match: return match.group(1) return None def add_sql_firewall_rule(client_ip): credential = DefaultAzureCredential() sql_client = SqlManagementClient(credential, subscription_id) # 添加入站规则,起始和结束IP都填提取到的单IP sql_client.firewall_rules.create_or_update( resource_group_name=resource_group, server_name=sql_server_name, firewall_rule_name=firewall_rule_name, parameters={ "start_ip_address": client_ip, "end_ip_address": client_ip } ) # 等待规则生效,官方说明最长需要5分钟,可根据实际情况调整等待时间 import time time.sleep(60) if __name__ == "__main__": try: conn = pyodbc.connect(sql_conn_str) print("连接成功") except pyodbc.ProgrammingError as e: if e.args[0] == '42000' and '40615' in e.args[1]: blocked_ip = get_blocked_ip_from_error(str(e)) if blocked_ip: print(f"检测到被拦截的出口IP:{blocked_ip},正在添加防火墙规则") add_sql_firewall_rule(blocked_ip) # 重试连接 conn = pyodbc.connect(sql_conn_str) print("规则添加完成,连接成功") else: print("无法从报错中提取IP地址") else: raise e
注意事项
- 运行代码的账号需要持有对应SQL Server的防火墙规则编辑权限,建议分配SQL Server参与者角色
- 防火墙规则生效存在延迟,可根据实际网络情况调整等待时长
- 如果公司VPN出口IP是动态变化的网段,建议添加对应IP段而非单IP,避免重复配置
内容的提问来源于stack exchange,提问作者Ajmal Moideen
相关产品推荐
相关产品推荐

