- 团队名称:三恒诸浪
- 作者:
姓名 | 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,则该认证过程将会自动跳过,用户无需反复输入。)
验证完成后,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_token
和refresh_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 | 为该用户创建的临时数据库密码 |
接口URL
请求方式
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"
}
接口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执行平台。如图: