Elasticsearch:RBAC 和 RAG – 最好的朋友 (二)

2024年6月3日   |   by mebius

在之前的文章 “Elasticsearch:RBAC 和 RAG – 最好的朋友(一)”,我们详细描述了如何使用 RBAC 来控制 RAG 的访问。在今天的文章中,我们来通过一个 jupyter notebook 来描述如何实现这个。

%title插图%num

安装

如果你还没有安装好自己的 Elasticsearch 及 Kibana,请参考如下的链接来进行安装:

在安装的时候,我们选择 Elastic Stack 8.x 来进行安装。特别值得指出的是:ES|QL 只在 Elastic Stack 8.11 及以后得版本中才有。你需要下载 Elastic Stack 8.11 及以后得版本来进行安装。

在首次启动 Elasticsearch 的时候,我们可以看到如下的输出:

%title插图%num

我们需要记下 Elasticsearch 超级用户 elastic 的密码。

我们还可以在安装 Elasticsearch 目录中找到 Elasticsearch 的访问证书:

$ pwd
/Users/liuxg/elastic/elasticsearch-8.13.2/config/certs
$ ls 
http.p12      http_ca.crt   transport.p12

在上面,http_ca.crt 是我们需要用来访问 Elasticsearch 的证书。

我们首先克隆已经写好的代码

git clone https://github.com/liu-xiao-guo/elasticsearch-labs

我们然后进入到该项目的根目录下:

$ pwd
/Users/liuxg/python/elasticsearch-labs/supporting-blog-content/rbac-and-rag-best-friends
$ cp ~/elastic/elasticsearch-8.13.2/config/certs/http_ca.crt .
$ ls
http_ca.crt                     rbac-and-rag-best-friends.ipynb

在上面,我们把 Elasticsearch 的证书拷贝到当前的目录下。上面的rbac-and-rag-best-friends.ipynb 就是我们下面要展示的 notebook。

展示

在运行 jupyter notebook 之前,我们先在命令行中打入如下的命令来设tgcode置变量:

export ES_USER="elastic"
export ES_PASSWORD="VDMlz5QnM_0g-349fFq7"
export ES_ENDPOINT="localhost"

我们需要根据自己的配置做相应的改动。然后,我们在当前的 terminal 中打入如下的命令:

jupyter notebook

安装并导入需要的 Python

!pip install elasticsearch python-dotenv
from elasticsearch import Elasticsearch
from IPython.display import HTML, ditgcodesplay
from pprint import pprint
from dotenv import load_dotenv
import os, json

在运行完上面的命令后,我们可以查看安装好的 elasticsearch 包的版本:

$ pip list | grep elasticsearch
elasticsearch                 8.13.0

客户端连接到 Elasticsearch

创建 elasticsearch 连接

load_dotenv()

ES_USER = os.getenv("ES_USER")
ES_PASSWORD = os.getenv("ES_PASSWORD")
ES_ENDPOINT = os.getenv("ES_ENDPOINT")

url = f"https://{ES_USER}:{ES_PASSWORD}@{ES_ENDPOINT}:9200"
print(url)

es = Elasticsearch(url, ca_certs = "./http_ca.crt", verify_certs = True)
print(es.info())

%title插图%num

更多有关如何使用 Python 连接到 Elasticsearch 的知识,请参阅文章 “Elasticsearch:关于在 Python 中使用 Elasticsearch 你需要知道的一切 – 8.x”。

删除演示索引(如果以前存在)

# Delete indices
def delete_indices():
    try:
        es.indices.delete(index="rbac_rag_demo-data_public")
        print("Deleted index: rbac_rag_demo-data_public")
    except Exception as e:
        print(f"Error deleting index rbac_rag_demo-data_public: {str(e)}")

    try:
        es.indices.delete(index="rbac_rag_demo-data_sensitive")
        print("Deleted index: rbac_rag_demo-data_sensitive")
    except Exception as e:
        print(f"Error deleting index rbac_rag_demo-data_sensitive: {str(e)}")


delete_indices()

%title插图%num

创建及装载数据到索引中

# Create indices
def create_indices():
    # Create data_public index
    es.indices.create(
        index="rbac_rag_demo-data_public",
        ignore=400,
        body={
            "settings": {"number_of_shards": 1},
            "mappings": {"properties": {"info": {"type": "text"}}},
        },
    )

    # Create data_sensitive index
    es.indices.create(
        index="rbac_rag_demo-data_sensitive",
        ignore=400,
        body={
            "settings": {"number_of_shards": 1},
            "mappings": {
                "properties": {
                    "document": {"type": "text"},
                    "confidentiality_level": {"type": "keyword"},
                }
            },
        },
    )


# Populate sample data
def populate_data():
    # Public HR information
    public_docs = [
        {"title": "Annual leave policies updated.", "confidentiality_level": "low"},
        {"title": "Remote work guidelines available.", "confidentiality_level": "low"},
        {
            "title": "Health benefits registration period starts next month.",
            "confidentiality_level": "low",
        },
    ]
    for doc in public_docs:
        es.index(index="rbac_rag_demo-data_public", document=doc)

    # Sensitive HR information
    sensitive_docs = [
        {
            "title": "Executive compensation details Q2 2024.",
            "confidentiality_level": "high",
        },
        {
            "title": "Bonus payout structure for all levels.",
            "confidentiality_level": "high",
        },
        {
            "title": "Employee stock options plan details.",
            "confidentiality_level": "high",
        },
    ]
    for doc in sensitive_docs:
        es.index(index="rbac_rag_demo-data_sensitive", document=doc)


create_indices()
populate_data()

我们可以在 Kibana 中使用如下的命令来查看索引:

%title插图%num

%title插图%num

创建两个具有不同访问级别的用户

# Create roles
def create_roles():
    # Role for the engineer
    es.security.put_role(
        name="engineer_role",
        body={
            "indices": [
                {"names": ["rbac_rag_demo-data_public"], "privileges": ["read"]}
            ]
        },
    )

    # Role for the manager
    es.security.put_role(
        name="manager_role",
        body={
            "indices": [
                {
                    "names": [
                        "rbac_rag_demo-data_public",
                        "rbac_rag_demo-data_sensitive",
                    ],
                    "privileges": ["read"],
                }
            ]
        },
    )


# Create users with respective roles
def create_users():
    # User 'engineer'
    es.security.put_user(
        username="engineer",
        body={
            "password": "password123",
            "roles": ["engineer_role"],
            "full_name": "Engineer User",
        },
    )

    # User 'manager'
    es.security.put_user(
        username="manager",
        body={
            "password": "password123",
            "roles": ["manager_role"],
            "full_name": "Manager User",
        },
    )


create_roles()
create_users()

运行完上面的代码后,我们可以在 Kibana 中进行查看:

%title插图%num

%title插图%num

我们其实也可以使用 Kibana 的 UI 来创建这些用户及 role。你可以想象阅读文章 “Elasticsearch:用户安全设置”。

测试安全角色如何影响查询数据的能力

创建 helper 函数

用于查询每个用户的辅助函数和一些输出格式

"""
def get_es_connection(cid, username, password):
    return Elasticsearch(cloud_id=cid, basic_auth=(username, password))
"""

def get_es_connection(username, password):
    url = f"https://{username}:{password}@{ES_ENDPOINT}:9200"
    print(url)
    return Elasticsearch(url, ca_certs = "./http_ca.crt", verify_certs = True)


def query_index(es, index_name, username):
    try:
        response = es.search(index=index_name, body={"query": {"match_all": {}}})

        # Prepare the message
        results_message = f'Results from querying as {username}:
' for hit in response["hits"]["hits"]: confidentiality_level = hit["_source"].get("confidentiality_level", "N/A") index_name = hit.get("_index", "N/A") title = hit["_source"].get("titltgcodee", "No title") # Set color based on confidentiality level if confidentiality_level == "low": conf_color = "lightgreen" elif confidentiality_level == "high": conf_color = "red" else: conf_color = "black" # Set color based on index name if index_name == "rbac_rag_demo-data_public": index_color = "lightgreen" elif index_name == "rbac_rag_demo-data_sensitive": index_color = "red" else: index_color = "black" # Default color results_message += ( f'Index: {index_name}t ' f'confidentiality level: {confidentiality_level} ' f'title: {title}
' ) display(HTML(results_message)) except Exception as e: print(f"Error accessing {index_name}: {str(e)}")

模拟 “工程师” 及 “经理” 的查询

index_pattern = "rbac_rag_demo-data*"
print(
    f"Each user will log in with their credentials and query the same index pattern: {index_pattern}nn"
)

for user in ["engineer", "manager"]:
    print(f"Logged in as {user}:")

    es_conn = get_es_connection(user, "password123")
    results = query_index(es_conn, index_pattern, user)
    print("nn")
index_pattern = "rbac_rag_demo-data*"
print(
    f"Each user will log in with their credentials and query the same index pattern: {index_pattern}nn"
)

for user in ["engineer", "manager"]:
    print(f"Logged in as {user}:")

    es_conn = get_es_connection(user, "password123")
    results = query_index(es_conn, index_pattern, user)
    print("nn")

%title插图%num

从上面的输出中,我们可以看出来经理可以同时访问两个索引的数据,但是工程师只能访问属于工程师的数据。

最终的源码在地址elasticsearch-labs/supporting-blog-content/rbac-and-rag-best-friends/rbac-and-rag-best-friends.ipynb at main liu-xiao-guo/elasticsearch-labs GitHub

文章来源于互联网:Elasticsearch:RBAC 和 RAG – 最好的朋友 (二)

相关推荐: 改进 Elastic Agent 和 Beats 中的事件队列

作者:Fae Charlton, Alexandros Sapranidis 内部改进如何降低 Elastic 8.13 中的内存使用。 在 8.12 版本中,我们引入了性能预设 —— 一种更简单的方法,用于调整 Elastic Agent 和 Beats 以…

Tags: , , , ,