需求与思路
在云服务器上部署了一个公司内部系统,该系统设置了只允许白名单中的IP访问。我们需要将办公网的IP添加到白名单,但由于办公网的IP每两天会发生变化,必须确保办公网用户能够正常访问该网站。
为此,我们可以让办公网的机器每小时向服务器发送请求。服务器将获取客户端的请求信息,并记录下其公网IP。当服务器接收到新的公网IP请求时,将该IP替换到NGINX的白名单中。
通过这种方式,我们可以实现动态更新白名单,确保办公网用户始终能够访问该网站。同时,为了避免allow白名单列表不断增加,我们可以将新IP替换到指定的行,以保持白名单的整洁。
实现
注:以下脚本均在python2.7环境下运行
1. 客户端脚本
#coding=utf-8
import base64
import logging
import urllib2
# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# 定义服务器的URL和请求的路径
server_urls = ["http://42.240.xxx.xxx:65306", "http://42.240.xxx.xxx:65306"]
request_path = "/api/update-ip"
username = "user"
password = "asdf5321"
# 获取家里电脑的公网IP地址
def get_public_ip():
logging.info("正在获取公网IP地址")
try:
ip = urllib2.urlopen('https://ifconfig.me/ip').read().strip()
logging.info("获取到公网IP地址: {}".format(ip))
return ip
except Exception as e:
logging.error("获取公网IP地址时发生错误: {}".format(e))
return None
# 发送请求到服务器
def send_request():
public_ip = get_public_ip()
if not public_ip:
logging.error("无法获取公网IP,终止请求")
return
for server_url in server_urls:
url = "{}{}?ip={}".format(server_url, request_path, public_ip)
logging.info("正在发送请求到: {}".format(url))
try:
request = urllib2.Request(url)
# 添加HTTP Basic认证头
credentials = base64.b64encode("{}:{}".format(username, password))
request.add_header("Authorization", "Basic {}".format(credentials))
response = urllib2.urlopen(request)
if response.getcode() == 200:
logging.info("请求成功: {}".format(url))
else:
logging.warning("请求失败: {}".format(url))
except urllib2.URLError as e:
logging.error("请求发生异常: {} - {}".format(url, e))
except Exception as e:
logging.error("发生错误: {}".format(e))
# 发送请求
send_request()
循环执行
配置定时任务,每小时执行一次
crontab -e
## 每小时向git服务器发送本机公网IP
0 * * * * python /root/shell/get_local_PublicIP.py
2. 服务端脚本
pip install flask_httpauth
pip install Flask-BasicAuth
pip install psutil
# coding: utf-8
import os
import datetime
import glob
import logging
import socket
from flask import Flask, request
from flask_basicauth import BasicAuth
app = Flask(__name__)
app.config['BASIC_AUTH_USERNAME'] = 'user'
app.config['BASIC_AUTH_PASSWORD'] = 'asdf5321'
basic_auth = BasicAuth(app)
# 配置日志记录
log_path = '/data/script/logs/'
if not os.path.exists(log_path):
os.makedirs(log_path)
# 创建日志记录器
logger = logging.getLogger('update_ip')
logger.setLevel(logging.INFO)
# 创建文件处理器,将日志写入文件
today = datetime.datetime.now().strftime("%Y-%m-%d")
log_file = os.path.join(log_path, 'update_ip_log_' + today + '.txt')
# 检查日志文件是否存在,如果不存在,则创建一个空的日志文件
if not os.path.exists(log_file):
open(log_file, 'a').close()
file_handler = logging.FileHandler(log_file)
file_handler.setLevel(logging.INFO)
# 创建格式化器,定义日志记录的格式
formatter = logging.Formatter('%(message)s', datefmt='%Y-%m-%d %H:%M:%S')
file_handler.setFormatter(formatter)
# 将文件处理器添加到日志记录器
logger.addHandler(file_handler)
# 移除可能的默认处理器
logger.handlers = [file_handler]
# 定义接收请求的路由和方法
@app.route('/api/update-ip', methods=['GET'])
@basic_auth.required # 添加账号密码验证
def update_ip():
# 获取请求参数中的 IP 地址
ip = request.args.get('ip')
# 在这里可以对 IP 地址进行处理或存储
# 替换文件中的第 1 行为接收到的 IP 地址
file_path = '/www/server/nginx/conf/allow'
with open(file_path, 'r') as file:
lines = file.readlines()
file_timestamp = lines[1].strip().split('_')[-1].split('.')[0].replace('-', ' ')
lines[1] = 'allow ' + ip + ';\n' # 将第 1 行替换为 "allow IP 地址;"
with open(file_path, 'w') as file:
file.writelines(lines)
# 重启 Nginx 服务
os.system('nginx -s reload')
# 记录日志
timestamp = datetime.datetime.now()
log_message = "{} - 新的 IP 地址:{}".format(timestamp.strftime('%Y-%m-%d %H:%M:%S'), ip)
logger.info(log_message)
# 删除 30 天之前的日志
thirty_days_ago = datetime.datetime.now().date() - datetime.timedelta(days=30)
log_files = glob.glob(os.path.join(log_path, 'update_ip_log_*.txt'))
for file in log_files:
file_timestamp = file.split('_')[-1].split('.')[0]
log_date = datetime.datetime.strptime(file_timestamp, "%Y-%m-%d").date()
if log_date < thirty_days_ago:
os.remove(file)
log_message = "{} - 删除了过期日志文件:{}".format(timestamp.strftime('%Y-%m-%d %H:%M:%S'), file)
logger.info(log_message)
return "IP 地址已更新"
def is_service_running():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex(('127.0.0.1', 65306))
if result == 0:
log_message = "{} - 检测到服务正在运行".format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
logger.info(log_message)
return True
else:
log_message = "{} - 未检测到服务运行!".format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
logger.info(log_message)
return False
if __name__ == '__main__':
if not is_service_running():
log_message = "{} - 启动服务".format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
logger.info(log_message)
# 监听所有网络接口,使其可以接受来自其他机器的请求
app.run(host='0.0.0.0', port=65306)
else:
log_message = "{} - 服务已在运行,无需再次启动".format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
logger.info(log_message)
后台启动
nohup python get_staff_publicIP.py &
写入定时任务
为了防止该程序被异常关闭导致服务不可用,定时启动脚本(脚本已配置如果正在运行则不作操作,如果未运行则后台运行)
crontab -e
58 * * * * nohup python /data/script/ get_staff_ip.py &
关闭脚本
ps aux | grep get_staff_ip.py | grep -v grep | awk '{print $2}' | xargs kill
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
评论(0)