prometheus 添加 login 登录认证界面(nginx + flask 实现)

2023-11-05

前言

    prometheus是现在一个比较主流的监控软件,随着容器的普及,prometheus的应用越来越广泛,前面我也有专门讲到prometheus的相关文章。但是跟传统老牌的zabbix监控不一样,prometheus的web UI是没有登录认证的,有时候显得没有安全性,本文就主要讲解一下如何为prometheus添加一个登录认证界面。其实像elasticsearch、consul等一些服务的web UI也是没有登录认证的,都可以使用本文的方式进行实现。
 

1. 实现思路

    主要是通过nginx代理转发进行实现,我们可以在nginx转发到prometheus之前添加一层认证的过程,从而进行实现。当然,如果有实力的朋友也可以修改prometheus的源码来添加认证机制。
 

1.1 nginx auth_basic 方式

    nignx的ngx_http_auth_basic_module模块实现了访问nignx web页面必须输入用户名和密码,经过认证后才能进行访问,我们可以利用这个特性来为prometheus设置代理。
    该实现方式比较简单,只需要在nginx配置文件里面添加上auth_basic相关的参数即可,网上也有很多资料,这里就不在赘述了。
 

1.2 nginx auth_request 方式

    有时候我们需要自定义一个 web 登录网页作为我们的监控系统的登录入口,这就可以结合 auth_request 模块来实现。
 
auth_request原理:
(1)当auth_request对应的路由返回401或者403时,nginx会拦截请求,直接返回前端401或者403信息;
(2)当auth_request对应的路由返回2xx状态码时,nginx不会拦截请求,而是构建一个subrequest请求,再去请求真实受保护资源的接口;
 
登录认证实现思路:
(1)通过nginx代理prometheus访问,初次访问首页时,auth_request返回401,让其强制跳转到我们自定义的login 登录界面;
(2)在login登录认证界面,如果用户名密码认证正确,返回一个token,并且重定向到nginx首页;
(3)此时再次访问首页时,是带着token来进行访问,验证token正确,auth_request返回200,就成功转发 prometheus监控页面;
(4)如果token过期,登录首页时就返回到login页面,再次进行用户名密码认证。
 

2.实现代码

2.1 nginx配置文件

将如下配置添加到nginx的配置文件的 http{} 部分里面

server {
  listen 0.0.0.0:9190;			 # 访问首页入口
  location / {
    proxy_pass http://localhost:9090/;   # prometheus服务监听端口
    auth_request /auth;
    error_page 401 = @error401;
  }

  location @error401 {               # 401就转发到登录页面
    add_header Set-Cookie "ORIGINURL=$scheme://$http_host;Path=/";
    return 302 /login;
  }

  location /auth {
   # internal;
    proxy_pass http://localhost:5000/auth;	# 后端token认证
    auth_request off;
  }

  location /login {
    proxy_pass http://localhost:5000/login;	# 后端用户名密码认证
    auth_request off;
  }

  location /static/rainbowhhy {   # 此处很重要,需要自定义一个静态文件目录,本文为rainbowhhy,否则会与prometheus的静态文件冲突,导致prometheus的页面加载不完全
  proxy_pass http://localhost:5000/static/rainbowhhy;
  auth_request off;
    }
}

 

2.2 登录认证

登录认证部分是通过 flask 实现
代码目录结构如下

├── profiles.json
├── readme.md
├── requirements.txt
├── run.py
├── static
│   └── rainbowhhy
│       ├── css
│       │   └── style.css
│       └── js
│           └── jquery-1.8.2.min.js
└── templates
    └── login.html

安装包准备

pip3 install flask==1.1.1
pip3 install flask-login==0.4.1
pip3 install werkzeug==0.16.0

 

2.2.1 密码加密文件

profiles.json,采用json格式保存加密后的用户名和密码

cat profiles.json 
{"admin": ["pbkdf2:sha256:150000$8J65mjTc$db116dd4d5de7eff899d126bd57b4f73910afb1e57982a9ded6878c547b584c5"]}

生成密码的方式:

>>> from werkzeug.security import generate_password_hash
>>> generate_password_hash("12345678")
'pbkdf2:sha256:150000$8J65mjTc$db116dd4d5de7eff899d126bd57b4f73910afb1e57982a9ded6878c547b584c5'

 

2.2.2 后端认证服务

run.py,实现了登录认证过程

from flask import Flask, request, render_template
from flask_login import UserMixin
from werkzeug.security import check_password_hash
import json
import os

app = Flask(__name__)
app.config["SECRET_KEY"] = "123456"
app.secret_key = '123456'

# 存放用户名和密码的json文件
PROFILE_PATH = os.path.dirname(os.path.abspath(__file__))
PROFILE_FILE = os.path.join(PROFILE_PATH, "profiles.json")


# 用户名密码加密认证
class User(UserMixin):
    def __init__(self, username, password):
        self.username = username
        self.password_hash = self.get_password_hash()

    def verify_password(self, password):
        if self.password_hash is None:
            return False
        return check_password_hash(self.password_hash, password)

    def get_password_hash(self):
        # 从文件中获取密码
        try:
            with open(PROFILE_FILE) as f:
                user_profiles = json.load(f)
                user_info = user_profiles.get(self.username, None)
                if user_info is not None:
                    return user_info[0]
        except:
            print("get password error!")


@app.route("/auth", methods=["GET", "POST"])
def auth():
    url = request.cookies.get('ORIGINURL')
    token = request.cookies.get('token')
    if token == "ABCDE":
        return ("success", 200)
    else:
        return ("go to login", 401)


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]
        user = User(username, password)
        if user.verify_password(password):
            token = "ABCDE"
            return (token, 200)
        else:
            error = "用户名或密码错误..."
            return (error, 403)
    else:
        return render_template("login.html")


if __name__ == '__main__':
    app.config['JSON_AS_ASCII'] = False
    app.run(host="localhost", port=5000)

 

2.2.3 前端登录页面

login.html,简单实现了登录认证的前端web

<!DOCTYPE html>
<html>

<head>
        <title>监控系统</title>
        <link type="text/css" rel="stylesheet" href="../static/rainbowhhy/css/style.css">
</head>

<body>
        <div class="head">
                账号:<input type="text" name="username" id="username" />
                <br />
                密码:<input type="password" name="password" id="password" />
                <br />
                <input type="button" οnclick="token()" value="登录" />
                <div class="flash error" role="alert"></div>
        </div>


        <script type="text/javascript" src="../static/rainbowhhy/js/jquery-1.8.2.min.js"></script>
        <script type="text/javascript">
                function token() {
                        var url = "http://" + document.domain + ":" + location.port;
                        console.log(url);
                        var username = document.getElementById("username").value;
                        var password = document.getElementById("password").value;
                        var fd = new FormData();
                        fd.append("username", username);
                        fd.append("password", password);
                        xhr = new XMLHttpRequest();
                        xhr.open("POST", "/login");
                        xhr.send(fd);
                        xhr.onreadystatechange = function (res) {
                                if (xhr.readyState == 4 && xhr.status == 200) {
                                        // 登录成功则成功跳转
                                        console.log("success");
                                        var token = xhr.response;
                                        setCookie("token", token);
                                        location.href = url;
                                }
                                if (xhr.readyState == 4 && xhr.status == 403) {
                                        // 登录失败则重新登录
                                        var error = xhr.response;
                                        $(".flash")[0].innerHTML = error;
                                        $(".flash").fadeOut(3000);
                                        setTimeout(function () {
                                                location.href = url + "/login";
                                        }, 2000);
                                }
                        }
                }

                function setCookie(name, value) {
                        // 设置token有效期为60min
                        const exp = new Date();
                        exp.setTime(exp.getTime() + 60 * 60 * 1000);
                        document.cookie = name + "=" + value + ";expires=" + exp.toGMTString();
                }
        </script>
</body>

</html>

 
style.css,为了体现出自定义一个静态文件目录的重要性,这里特地写了一个简单的自定义css

.head {
    width: 500px;
    height: 200px;
    margin: 0 auto;
}

.error {
    color:red;
    font-size: 18px;
    margin: 0 auto;
}

 

3.启动服务

启动nginx服务

systemctl start nginx

启动flask认证服务

python3 run.py
生产上可以做成systemd或者supervisor的方式启动

 
之后就可以访问了,实现的效果
 
请添加图片描述

 
文本实现了一个比较简单的登录认证页面,大家可以根据实际情况进行代码修改,使得login页面更加完善美观,当然如果你的公司没有要求这么多,就可以直接使用本文的思路中的第一种:nginx auth_basic 方式,更加方便快捷。
 
如下,上一张完善的登录界面:
请添加图片描述
 
附完整代码:https://github.com/Rainbowhhy/prometheus_login_webUI
 

参考文档

http://nginx.org/en/docs/http/ngx_http_auth_request_module.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

prometheus 添加 login 登录认证界面(nginx + flask 实现) 的相关文章

随机推荐

  • 图解多态原理

    虚函数表 class Base public virtual void Func1 cout lt lt Func1 lt lt endl private int b 1 void test Base b cout lt
  • 空间(蓝桥杯)

    空间 本题为填空题 只需要算出结果后 在代码中使用输出语句将所填结果输出即可 小蓝准备用 256MB 的内存空间开一个数组 数组的每个元素都是 32 位 二进制整数 如果不考虑程序占用的空间和维护内存需要的辅助空间 请问 256MB 的空间
  • 定义内部类 继承 AsyncTask 来实现异步网络请求

    异步任务处理 创建内部类 来实现网络异步请求 新建内部类 继承 AsyncTask SuppressLint StaticFieldLeak class RequestNetworkDataTask extends AsyncTask
  • Docker、Portainer、K8S环境搭建

    Docker Portainer K8S环境搭建 安装Docker 安装步骤 安装依赖包 yum install y yum utils device mapper persistent data lvm2 配置阿里云yum源 以便加速下载
  • Vue 安装开发者工具

    1 下载开发者工具 下载地址 http book wiyp top App Vue3开发者工具 谷歌 Vue3 crx 2 打开谷歌浏览器 点击扩展 点击管理扩展程序 3 开启开发者模式 将 Vue3 开发者工具文件拖拽到浏览器中进行安装
  • 设计模式(十三)代理模式

    代理模式也是一种结构性模式 它的主要作用是创建一个现有对象的代理 以便我们能够针对对象的生命周期 访问权限等进行控制 代理模式和适配器模式的区别是 适配器模式主要用于现有接口和新接口之间的转换和衔接 而代理模式对现有接口进行控制 所以代理模
  • 【机器学习】PyTorch如何选择最优初始学习率

    众所周知 机器学习尤其是现在的深度学习 大量的工作都集中在调参上 一个模型能否很好的解决问题 调参占了很大的比重 而学习率又是模型众多超参数中最重要和最容易调节的一个 1 什么是学习率 目前深度学习优化的基本思想是梯度下降法 已经有很多优秀
  • Java DAO模式

    Java DAO模式 Data Access Objects 作用 隔离了数据库访问代码和业务逻辑代码 隔离了数据库连接代码 代码实现 DAO接口 DAO实现 实体类 连接数据库类和关闭数据库连接类
  • 研一寒假C++复习笔记--左值和右值的理解和使用

    目录 1 左值和右值的定义 2 简单理解左值和右值的代码 3 非const引用只能接受左值 1 左值和右值的定义 左值 L Value L理解为 Location 表示可寻 右值 R Value R理解为 Read 表示可读 左值和右值是相
  • 分布式数据库DBLE

    分布式数据库DBLE 第一章 绪论 研究背景 目前 在电商 金融 O2O 零售 电信等行业普遍存在用户基数大 营销活动频繁 核心交易系统响应日益变慢的问题 随着业务数据增长迅速 超过单机数据库的承受极限 制约业务的发展 在电力 气象 农业
  • 07、环境-虚拟机网络设置、开启远程登录

    1 Oracle VM VirtualBox默认网络方式 Oracle VM VirtualBox创建的虚拟机默认使用的是 网络地址转换 端口转发的方式 2 默认虚拟机ip地址不是固定IP 不方便开发 修改Vagrantfile confi
  • LaTeX怎样引用想要的包

    到网上下载相应包 得到 ins文件 官网 https www ctan org pkg 然后cmd运行latex ins即可得到 sty文件 放到LaTeX目录下即可
  • SSL工作原理

    SSL工作原理 关键词 SSL PKI MAC 摘 要 SSL利用数据加密 身份验证和消息完整性验证机制 为基于TCP等可靠连接的应用层协议提供安全性保证 本文介绍了SSL的产生背景 安全机制 工作过程及典型组网应用 缩略语 缩略语 英文全
  • 【Wi-Fi】IEEE 802.11 Standards 之 802.11a/b/g/n/ac/ax初探

    前言 日常在配置家里路由器以及在工作中学习到WiFi相关的知识的时候总是对于WiFi 标准协议 IEEE 802 11的几个版本不太理解 所以本文主要是介绍关于IEEE 802 11 中各个版本的由来和基本含义 各版本WiFi标准协议 IE
  • 剑指 Offer 30. 包含min函数的栈

    剑指 Offer 30 包含min函数的栈 方法一 使用两个栈 class MinStack Deque
  • C++学习(四八九)Could not download aapt2-windows.jar

    问题描述 Android Studio在编译生成Apk时报此错误 解决办法 去掉Gradle的offline模式 点击AndroidStudio的文件 gt 设置 选择Gradle标签页 去掉Offline work前面的对钩
  • BUU 【ACTF2020 新生赛】Include 1 解题大致思路

    1 首先打开靶场环境 看到链接tips 打开tips 2 首先看一下url中有什么东西 看到file 猜测可能是文件包含 3 文件包含读取的是他文件里的内容 要想读取源文件内容 我们可以用base64编码的方式来读文件flag php 构造
  • OAuth2.0原理和理解

    1 oauth简述 oauth本身不是技术 而是一项资源授权协议 重点是协议 Apache基金会提供了针对Java的oauth封装 我们做Java web项目想要实现oauth协议进行资源授权访问 直接使用该封装就可以 2 概述 2 1 官
  • imagenet图片

    imagenet数据集图片大小3 224 224
  • prometheus 添加 login 登录认证界面(nginx + flask 实现)

    前言 prometheus是现在一个比较主流的监控软件 随着容器的普及 prometheus的应用越来越广泛 前面我也有专门讲到prometheus的相关文章 但是跟传统老牌的zabbix监控不一样 prometheus的web UI是没有