Skip to content

Instantly share code, notes, and snippets.

@Sindweller
Last active October 22, 2022 05:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sindweller/59bb18dc9140b3a3c51c9e73def197d6 to your computer and use it in GitHub Desktop.
Save Sindweller/59bb18dc9140b3a3c51c9e73def197d6 to your computer and use it in GitHub Desktop.
TiDB Hackathon 2022 RFC
  • 团队名称:三恒诸浪
  • 作者:
姓名 GitHub Link
陈婧晗 https://github.com/Sindweller
刘恒 https://github.com/leonatone
申恒恒 https://github.com/rh01
南娇 https://github.com/DAMUfly

项目介绍

本项目将致力于使用 SSO 作为 TiDB 的登录认证方式,使得用户可以避免使用直接的数据库用户名密码连接TiDB,增强安全性与权限控制。

背景&动机

一个场景是,企业不希望员工直接拥有数据库的账号(特别是root账号),以免造成密码泄漏。当员工需要连接数据库时,不再通过指定的数据库用户+密码的方式登录。所有访问需要走oauth来登录。每次员工登录会发放token,通过token员工才能访问数据库。

如果人员离职,他只拥有sso登录的账户密码(离职后同样无法登录sso)。后台只需要把这个记录删除,并删除对应数据库用户名/密码的权限,就可以禁止这个人访问了。

同样,也可以通过登录记录,将sql操作与实际的执行人联系起来,提供审计功能。

整个过程中,用户不会得到明文的数据库密码,或者得到的是一个具有时效性的动态密码。

项目设计

思路:

编写 OAuth 服务, 构建 Token <-> 临时用户名/密码 映射,仅此服务知晓 Root 账户,进行临时用户的管理。

具体实现方式:

在tidb外围控制tidb的权限。tidb部署完之后,都会有一个root账号(不应发放给任何人,只有管理员(管理程序)拥有)。管理服务将对接用户、sso服务和tidb。管理服务能够知晓tidb的root账号,在每个用户尝试登录的时候,打开一个浏览器完成单点登录,并返回一个oauth token。本地的登录管理服务通过token,利用自己知道的root账号,为用户生成临时用户名密码,告诉用户登录成功了,这段时间就可以通过这个临时用户名和密码来访问数据库。管理员可以控制临时账号的访问权限。

登录流程说明:

当用户尝试连接数据库,tidb-login打开浏览器,用户在浏览器中登录sso。随后,tidb-login从sso provider获取token,验证token后,tidb-login为该token生成对应的数据库用户名与密码,并记录。删除该条记录时,一并撤销该数据库账号的权限。仅能在该token有效期内通过该用户名与密码登录数据库。整个流程如下图所示:

若用户选择使用tidb-login cli连接数据库,tidb-login会自动打开浏览器,用户可以登录进sso provider。类似下图。(若已在其他地方登录sso,则该认证过程将会自动跳过,用户无需反复输入。)

image.png

验证完成后,tidb-login为用户(token)生成对应的数据库user/pass并返回给cli。cli使用这个user/pass来执行sql。tidb-login会将此次 用户+token+user/pass 写进自己的存储里。同一用户再次登录且token相同时,会先从存储中拿user/pass,如token变动,则会软删除之前用户对应token记录,再去创建新的user/pass。如果员工离职,则在tidb-login中软删除该员工对应token和user/pass记录即可。

sso-provider使用keycloak。

主要功能:

  • 自动创建与发放临时数据库账号:该服务自动为sso登录用户创建临时数据库账号,自动发放。省去人工操作。
  • 自动续期功能:与sso的自动续期同步,保存 access_tokenrefresh_token,在用户使用期间自动续期,使用户仍能正常使用已创建的临时数据库账号。
  • 动态密码功能:当用户使用sso登录后,tidb-login为此用户生成一个临时的动态密码(等同于数据库密码),可以设置其有效期,用户通过tidb-login发放的数据库用户名+动态密码登录。这种方式可以限制用户所持有数据库账号的时间。
  • 数据库权限控制功能:支持创建不同数据库权限的用户。支持调用外部接口来根据角色权限创建数据库用户。

存储表设计

CREATE TABLE `tidb_login`.`tidb_user_record` (
  `id` INT NOT NULL,
  `user` VARCHAR(45) NULL,
  `access_token` VARCHAR(256) NULL,
  `refresh_token` VARCHAR(256) NULL,
  `tidb_user` VARCHAR(45) NULL,
  `tidb_pass` VARCHAR(45) NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `user_UNIQUE` (`user` ASC) VISIBLE,
  UNIQUE INDEX `tidb_user_UNIQUE` (`tidb_user` ASC) VISIBLE,
  UNIQUE INDEX `token_UNIQUE` (`token` ASC) VISIBLE,
  UNIQUE INDEX `tidb_pass_UNIQUE` (`tidb_pass` ASC) VISIBLE);
user 登录sso的用户名
access_token sso的token
refresh_token sso的刷新token,供自动续期使用
tidb_user 为该用户创建的临时数据库用户
tidb_pass 为该用户创建的临时数据库密码

接口设计

/tidb-login/tidb-login:获取token与数据库账号

接口URL

http://0.0.0.0:8840/login

请求方式

POST

Content-Type

json

请求Body参数

{
    "user": "abc123",
    "pass": "abc123123"
}

成功响应示例

{
	"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxeHUwdTZxNHh5Rk8tWkFRVTVIazBBMThDZi1xUnFzaUdvWkZjYXh4Vm5rIn0.eyJleHAiOjE2NjUxNTI1MTMsImlhdCI6MTY2NTE1MjIxMywianRpIjoiMmU0OTFlMTMtMmRiZC00M2UwLTgyMzYtZjNiNjM2ZTJmODc3IiwiaXNzIjoiaHR0cDovLzAuMC4wLjA6ODg5OS9yZWFsbXMvdGlkYiIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiI5MDM5NDg2OC05MmQ1LTQ2ODktYjgxZC00Nzc0NjgzOTRiMzYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0aWRiLWxvZ2luIiwic2Vzc2lvbl9zdGF0ZSI6Ijk1YTJkMDBmLTIzNjEtNGU0Ni1iOGJiLThhNGQ1YzZmZmU0ZCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy10aWRiIiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsInNpZCI6Ijk1YTJkMDBmLTIzNjEtNGU0Ni1iOGJiLThhNGQ1YzZmZmU0ZCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoidGlkYnVzZXIiLCJnaXZlbl9uYW1lIjoiIiwiZmFtaWx5X25hbWUiOiIifQ.G6JYnNKdRCs4W_3BtUSYrSx_dRRdzNieuTKdhAiPcrAhFIJ4Wo7ul9VvQedXS3l5Q3J8GZaN8QlfDQlRGGcYBxKU0cy4J69QkWkEzFKDf3kG8TFxbcw1wZ3Y-BNlB5v1sf8E6cuOyjddeIpOnTeu5_Y0164E3MdyBecsA-x7mOVACMVb6nFPT_RgRggj6P5ruASBCwIqxBKXgkjwC5AM0cySkwnUcPinasKSGG3952oIMEFvq4n5VIa13ZfzBpWjw5V9vm5mULiP_t3lzFzMmt6cwrffbWPWloUXCWbK_zHmQYn_kTvhpopSj3tuz7Y0BdO4C_XgqKBHoJ5WRBhPkA",
	"expires_in": 300,  # 过期前多少秒使用refresh_token重新请求获得新的token 
	"not-before-policy": 0,
	"refresh_expires_in": 1800,
	"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiOWJlOWU2MC0xMDBjLTQ0NWItYjE1OC05MzllMTBmOTQ0MGMifQ.eyJleHAiOjE2NjUxNTQwMTMsImlhdCI6MTY2NTE1MjIxMywianRpIjoiZDE2NjEzMTMtY2VlYy00MTU0LTlkZTItZTFjNDRkOGYwODIzIiwiaXNzIjoiaHR0cDovLzAuMC4wLjA6ODg5OS9yZWFsbXMvdGlkYiIsImF1ZCI6Imh0dHA6Ly8wLjAuMC4wOjg4OTkvcmVhbG1zL3RpZGIiLCJzdWIiOiI5MDM5NDg2OC05MmQ1LTQ2ODktYjgxZC00Nzc0NjgzOTRiMzYiLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoidGlkYi1sb2dpbiIsInNlc3Npb25fc3RhdGUiOiI5NWEyZDAwZi0yMzYxLTRlNDYtYjhiYi04YTRkNWM2ZmZlNGQiLCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJzaWQiOiI5NWEyZDAwZi0yMzYxLTRlNDYtYjhiYi04YTRkNWM2ZmZlNGQifQ.EGBVn_iqJCIvATHXS1UloiYVlIPL-BvSLKmp5FX2sQg",
	"scope": "profile email",
	"session_state": "95a2d00f-2361-4e46-b8bb-8a4d5c6ffe4d",
	"token_type": "Bearer",
  "username": "tidb-user-name",
  "password": "tidb-password"
}

/tidb-login/transit:转发sql

接口URL

http://0.0.0.0:8840/transit

请求方式

POST

Content-Type

json

请求Body参数

{
  "dbname":"tidb_teest",
  "table_name":"instance",
  "sql_text":"select * from instance;",
  "cluster_name":"tidb_cluster"
}

成功响应示例

{
	"code": 0,
	"msg": "success",
	"data": {
		"tableData": [
			{
				"id": "1",
				"created_at": "2022-10-08 18:25:25",
				"updated_at": "2022-10-08 18:25:25",
				"deleted_at": "NULL",
				"filed1": "texttext",
				"filed2": "testtest2"
			},
      {
				"id": "2",
				"created_at": "2022-10-08 18:25:25",
				"updated_at": "2022-10-08 18:25:25",
				"deleted_at": "NULL",
				"filed1": "texttext2",
				"filed2": "testtest22",
      }
		],
		"tableColumn": [
			{
				"name": "id",
				"width": "120"
			},
			{
				"name": "created_at",
				"width": "120"
			},
			{
				"name": "updated_at",
				"width": "120"
			},
			{
				"name": "deleted_at",
				"width": "120"
			},
			{
				"name": "filed1",
				"width": "240"
			},
			{
				"name": "filed2",
				"width": "120"
			}
		]
	}
}

目标成果:

  • 一个tidb-login服务,存储sso登录的token与数据库临时用户名/密码映射。提供自动续期、通知提醒、动态密码等功能。从用户端获取token,转换为临时user:pass登录数据库,这个过程转换过程用户不可见。对于用户来说,就像是直接利用sso登录数据库。同时,该服务提供转发sql的接口。
  • 给出一个语言(如golang)实现的demo,该demo使用sso来进行数据库登录认证,最终不直接使用用户名密码操作数据库。
  • 提供一个客户端demo:使用客户端执行sql,跳出浏览器sso登录后,成功执行sql。
  • 提供一个网页demo:通过sso登录后进入mysql执行平台。如图:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment