使用 Flask 运行 Shell 命令
介绍
Flask是一个非常轻量的框架,在我看来它是用 Python 编写简单应用程序的绝佳选择。
背景
我公司的一个应用程序执行一些任务,然后相应地更新 MySql 数据库。因此,要了解应用程序当天任务的进展情况,必须使用 SSH(安全 Shell 协议)进入应用程序服务器并使用 MySQL 客户端运行相应的查询。这是因为应用程序只有在所有任务完成后才会开始创建报告。
我的目标是找到一种方法,让没有系统管理知识的人无需额外帮助即可安全地访问这些数据。
开始了...
我的计划是创建一个可以从任何 Web 浏览器访问的 Flask 应用程序。在此应用程序中,当访问正确的路径时,软件将运行一些预定义的 shell 命令并将结果返回到浏览器。现在这个输出可能是敏感信息,所以我们不能允许任何人访问它。为了实现基本的安全层,我使用了IP 白名单,或者只允许某些 IP 访问应用程序。
我在 Ubuntu 14.04 Trusty 上运行了以下命令,如果您使用不同的操作系统,那么您的命令可能会有所不同。
先决条件
要遵循本教程,您必须在系统中安装以下软件。
- Python3 (Ubuntu 14.04 通常默认安装)
- 虚拟环境(sudo apt-get install python-virtualenv)
- MySql Server 5.5+ 和客户端(sudo apt-get install mysql-server-5.5)
- 主管(sudo apt-get install executive)
准备虚拟环境
使用以下命令准备你的虚拟环境(virtualenv) -
# go to your workspace directory
cd ~/workspace/
# create a virtualenv using python3
virtualenv -p /usr/bin/python3 flaskshell
# enter the virtualenv directory and perform the basic package installations and tasks
cd flaskshell
# activate virtualenv
source bin/activate
# install flask
pip install flask
# create src and logs directory
mkdir src logs
准备示例数据库
由于我们很快将运行 MySQL 查询,因此我们需要为我们的任务准备一个示例数据库。
# create the database
mysql -u root -p -e "CREATE DATABASE flasktest; GRANT ALL ON flasktest.* TO flaskuser@localhost IDENTIFIED BY 'flask123'; FLUSH PRIVILEGES"
# create a sample table
mysql -uflaskuser -pflask123 -e "CREATE TABLE flasktest.tasks (task_id INT NOT NULL AUTO_INCREMENT, task_title VARCHAR(50), task_status VARCHAR(50), PRIMARY KEY (task_id));"
# insert some sample data
mysql -uflaskuser -pflask123 -e "INSERT INTO flasktest.tasks (task_title, task_status) VALUES ('Task 1', 'Success');"
mysql -uflaskuser -pflask123 -e "INSERT INTO flasktest.tasks (task_title, task_status) VALUES ('Task 2', 'Pending');"
mysql -uflaskuser -pflask123 -e "INSERT INTO flasktest.tasks (task_title, task_status) VALUES ('Task 3', 'Failed');"
让我们检查数据库和表的创建是否按计划进行。
mysql -uflaskuser -pflask123 -e "USE flasktest; SELECT COUNT(*) FROM tasks WHERE task_status='Success';"
# the above command should print this,
+----------+
| COUNT(*) |
+----------+
| 1 |
+----------+
您也可以使用“待处理”和“失败”语句运行命令以进行复查。所有查询都应返回相同的结果。
代码
在 src 目录中创建一个名为app.py 的文件,
touch ~/workspace/flaskshell/src/app.py
在文件中输入下面列出的代码。
from flask import Flask
from flask import request
import subprocess
app = Flask('flaskshell')
ip_whitelist = ['192.168.1.2', '192.168.1.3']
query_success = "SELECT COUNT(*) FROM flasktest.tasks WHERE task_status='Success'"
query_pending = "SELECT COUNT(*) FROM flasktest.tasks WHERE task_status='Pending'"
query_failed = "SELECT COUNT(*) FROM flasktest.tasks WHERE task_status='Failed'"
def valid_ip():
client = request.remote_addr
if client in ip_whitelist:
return True
else:
return False
@app.route('/status/')
def get_status():
if valid_ip():
command_success = "mysql -uflaskuser -pflask123 -e '{0}'".format(
query_success)
command_pending = "mysql -uflaskuser -pflask123 -e '{0}'".format(
query_pending)
command_failed = "mysql -uflaskuser -pflask123 -e '{0}'".format(
query_failed)
try:
result_success = subprocess.check_output(
[command_success], shell=True)
result_pending = subprocess.check_output(
[command_pending], shell=True)
result_failed = subprocess.check_output(
[command_failed], shell=True)
except subprocess.CalledProcessError as e:
return "An error occurred while trying to fetch task status updates."
return 'Success %s, Pending %s, Failed %s' % (result_success, result_pending, result_failed)
else:
return """<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server.
If you entered the URL manually please check your
spelling and try again.</p>""", 404
if __name__ == '__main__':
app.run()
第 7 行>> 这是白名单 IP 的数组。您可以根据需要替换 IP。您可以在此数组中输入任意数量的 IP
第 8-10 行>> 我在这里定义查询。您可以更改查询以满足您的需要。
第 13-18 行>> 如果客户端的 IP 属于白名单,则 valid_ip() 方法返回 true,否则返回 false。它使用 Flask 中的请求包获取客户端的 IP。此请求包在第 2 行定义
第 21 行>> 定义访问应用程序的路由
第 23 行>> 在处理请求之前,检查客户端的 IP 是否属于白名单。如果不属于,则显示 Flask 的默认 404 页面(第 43-47 行)
第 24-29 行>> 使用之前定义的查询编写 shell 命令。
第 32-37 行>> 尝试运行 shell 命令。应用程序将抛出错误,或者如果执行成功,它将返回结果(第 41 行)
将应用程序作为服务运行
为了将应用程序作为服务运行,我使用了Supervisor。这是个人喜好问题;您可以随意使用任何其他过程控制系统。
在 Supervisor 上定义一个程序。
创建一个新的 Supervisor 配置文件。
sudo vim /etc/supervisor/conf.d/flaskshell.conf
将以下代码复制并粘贴到文件中。此时,您必须将应用程序放在 - /home/user/workspace/flaskshell中。
program:stats]
directory = /home/user/workspace/flaskshell/src
command = /home/user/workspace/flaskshell/bin/python app.py
redirect_stderr = true
stdout_logfile = /home/user/workspace/flaskshell/logs/out.log
stderr_logfile = /home/user/workspace/flaskshell/logs/error.log
现在您应该更新 Supervisor 配置并启动应用程序。
sudo supervisorctl update stats
sudo supervisorctl start stats
访问应用程序
由于我们没有为应用程序定义任何端口,它将默认为端口 5000。要更改此设置,请按照我在此 Stack Overflow 页面上找到的说明进行操作。
您可以在https://SERVER_IP:5000找到该应用程序。状态更新应在https://SERVER_IP:5000/status/上可用。
希望我的博文能让您感到愉快并对您有所帮助。欢迎在下方留言,分享您的想法和反馈。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~