
kviklet v0.9.0
类似 Pull Request 的数据库查询审批/批准流程,用于合规但顺畅的工程人员访问生产环境。
Kviklet
Kviklet.dev | 发布说明 | Discord
在不影响开发者生产力的情况下安全访问生产环境。

Kviklet(发音为 Quick-let)将四眼原则应用于生产数据库访问,为单条 SQL 语句或限时数据库会话提供类似拉取请求的审查和批准工作流。工程师可以相互审查和批准彼此的请求,而无需将每个查询都通过 DBA 或运维团队。
Kviklet 是自托管的,作为 Docker 容器运行,并使用 PostgreSQL 数据库存储应用程序状态。其 Web 界面允许你提交、审查和执行请求。可选的企业许可证可解锁 SAML 身份验证、基于角色的审查要求、角色同步和 API 密钥。请在 kviklet.dev 申请企业许可证。
支持的数据库包括 Postgres、MySQL、MariaDB、MS SQL Server 和 MongoDB。
访问模型
我们建议将 Kviklet 连接到您现有的身份提供商。Kviklet 支持通过 OIDC(Google、Keycloak 等)或 SAML(仅限企业版)进行 SSO,以及 LDAP 身份验证(Active Directory 等)。 用户随后为映射到特定数据库用户的连接创建请求。这些请求可以是:
- 单条查询:提交审查的特定 SQL 语句。
- 临时访问:限时会话,您可以在其中运行多条语句。
根据配置,请求在 Kviklet 允许执行之前会由其他用户审查和批准。
Kviklet 代表用户连接到数据库。连接的数据库密码永远不会向用户显示。
管理员可以配置哪个角色有权访问哪个连接,以及执行需要哪些审查关卡。数据库级别的访问通过底层数据库的 RBAC 机制进行管理。例如,可以为只读连接创建只读角色,并为其分配比写入连接更少的审查要求。
Kviklet 记录已执行的语句,并将其与用户和访问请求关联。为了全面覆盖手动数据库访问,请限制直接连接,并将任何手动访问都通过 Kviklet 进行路由。工程师无需接收或共享底层数据库凭据。
额外的企业版功能包括:
- SAML:支持 SAML 身份验证。
- 代理(Postgres、MariaDB、MySQL):通过已批准的临时访问会话,使用临时密码,使用您首选的数据库客户端。已执行的语句会记录在 Kviklet 的审计日志中。
- 基于角色的审查关卡:要求在执行前获得特定角色的批准。
- 角色同步:自动从您的身份提供商组同步用户角色。
- API 密钥:以编程方式访问 Kviklet API。
更多截图
请求
所有数据请求都集中在一个地方。就像您生产数据库的开放 PR:

实时会话
已批准的临时访问请求会直接在浏览器中打开一个实时 SQL 会话:

审计日志
每条已执行的语句都会被记录——无论是作为已审查的单条查询运行、在实时会话中运行,还是通过数据库代理运行:

按数据库/连接类型划分的功能
大多数功能适用于所有数据库(SSO、LDAP、RBAC、审查/批准流程、审计日志等)。但某些功能受到限制,要么是因为尚未构建,要么是因为对该特定用途没有意义。下表显示了哪些功能适用于哪种数据库类型:
| Database | Statement Review | Temporary Access | Proxy(Beta) | Explain Plan |
|---|---|---|---|---|
| Postgres | ✓ | ✓ | ✓ | ✓ |
| MySQL | ✓ | ✓ | ✓ | ✓ |
| MariaDB | ✓ | ✓ | ✓ | ✓ |
| SQL Server | ✓ | ✓ | ✗ | ✓ |
| MongoDB | ✓ | ✓ | ✗ | ✗ |
| Kubernetes | ✓ | ✗ | ✗ | ✗ |
设置
Kviklet 以简单的 docker 容器形式发布。
您可以在 Releases 下找到可用版本。我们建议定期更新您使用的版本,因为我们会继续构建新功能。
目前最新版本是 ghcr.io/kviklet/kviklet:0.8.0,您也可以使用 :main,但偶尔可能会发生我们意外合并了有问题的内容。不过我们会尽量避免这种情况。
快速开始
如果您只是想尝试一下它的工作方式:
-
以下是一个最小的 docker-compose.yaml:
点击展开 compose 内容
``` services: postgres: image: postgres:16 restart: always environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: postgres ports: - "5432:5432" volumes: - ./postgres-data:/var/lib/postgresql/data # - ./sample_data.sql:/docker-entrypoint-initdb.d/init.sqlkviklet-postgres: image: postgres:16 restart: always environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: kviklet ports: - "5433:5432" volumes: - ./kviklet-postgres-data:/var/lib/postgresql/data
kviklet: image: ghcr.io/kviklet/kviklet:main ports: - "80:8080" environment: - SPRING_DATASOURCE_URL=jdbc:postgresql://kviklet-postgres:5432/kviklet - SPRING_DATASOURCE_USERNAME=postgres - SPRING_DATASOURCE_PASSWORD=postgres - INITIAL_USER_EMAIL=[email protected] - INITIAL_USER_PASSWORD=admin depends_on: - kviklet-postgres
-
通过
docker-compose up -d运行docker-compose.yml。Kviklet 将在 80 端口启动,访问localhost即可试用。管理员登录账号为 [email protected],密码为admin。 -
docker-compose 中包含一个额外的 postgres 数据库,你可以在 Kviklet 中为其设置连接。要让该数据库包含一些数据,请取消注释以下行: ``` - ./sample_data.sql:/docker-entrypoint-initdb.d/init.sql
并创建一个 sample_data.sql 文件:
点击展开 sample_data.sql 内容
```sql CREATE TABLE Locations ( Name VARCHAR(100) NOT NULL, Address VARCHAR(255) NOT NULL, City VARCHAR(100) NOT NULL, Country VARCHAR(100) NOT NULL, PostalCode VARCHAR(20) NOT NULL );alter table public.Locations owner to postgres;
INSERT INTO public.Locations (Name, Address, City, Country, PostalCode) VALUES ('Central Park', '59th to 110th St', 'New York', 'USA', '10022'), ('Eiffel Tower', 'Champ de Mars, 5 Avenue Anatole', 'Paris', 'France', '75007'), ('Colosseum', 'Piazza del Colosseo, 1', 'Rome', 'Italy', '00184'), ('Sydney Opera House', 'Bennelong Point', 'Sydney', 'Australia', '2000'), ('Great Wall of China', 'Huairou District', 'Beijing', 'China', '101405');
</details>
### 数据库设置
Kviklet 需要自己的 postgres 数据库(或至少是 schema)来保存关于查询、连接、审批等的元数据。
你可以在这里找到官方镜像:https://hub.docker.com/_/postgres,或使用你所选云服务商提供的云端托管版本。
启动 kviklet 容器时,你需要相应地设置以下三个环境变量:```
SPRING_DATASOURCE_PASSWORD = password
SPRING_DATASOURCE_USERNAME = username
SPRING_DATASOURCE_URL = jdbc:postgresql://[host]:[port]/[database]?currentSchema=[schema]
替代身份验证方法
- IAM 身份验证:
可以使用 AWS IAM 身份验证进行数据库连接,在这种情况下,只需省略密码并设置用户名即可。
你还必须设置环境变量: ```
SPRING_DATASOURCE_IAMAUTH=true
Kviklet 将从常见位置(环境变量、实例角色等)加载凭据,并为连接生成令牌。
- 证书: 你也可以使用证书进行数据库连接,示例见此处。
初始用户
你需要一个初始管理员用户来进行配置。为此,请设置两个环境变量:
INITIAL_USER_EMAIL 和 INITIAL_USER_PASSWORD,以便你可以登录 Web 界面。之后你可以通过 UI 更改密码。
示例:```
INITIAL_USER_EMAIL=[email protected]
INITIAL_USER_PASSWORD=someverysecurepassword
我们目前将容器发布到 GitHub packages,因此完成所有设置后,你可以运行 `ghcr.io/kviklet/kviklet:main`,别忘了映射端口 `8080`,这是 Kviklet 默认启动的端口。
一个 docker run 示例可能如下所示:```
docker run \
-e SPRING_DATASOURCE_PASSWORD=postgres \
-e SPRING_DATASOURCE_USERNAME=postgres \
-e SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/Kviklet \
-e [email protected] \
-e INITIAL_USER_PASSWORD=someverysecurepassword \
--network host \
ghcr.io/kviklet/kviklet:main
通过 OIDC / OAuth2 实现 SSO
如果你想为你的 Kviklet 实例设置 SSO(这非常合理,否则你又得管理密码了)。 你需要设置这 3 个环境变量:``` KVIKLET_IDENTITYPROVIDER_CLIENTID KVIKLET_IDENTITYPROVIDER_CLIENTSECRET KVIKLET_IDENTITYPROVIDER_TYPE=google
你可以按照 Google 的说明轻松获取 google client id 和 secret:
https://developers.google.com/identity/gsi/web/guides/get-google-api-clientid
对于有效的重定向 URI,你应该配置:https://[kviklet_host]/api/login/oauth2/code/google
对于允许的来源,只需填写你托管的 kviklet url。
设置这些环境变量后,你组织中的每个人都可以通过“使用 Google 登录”按钮登录。但默认情况下他们没有任何权限,你需要在他们首次登录后为其分配角色。
#### Keycloak
如果你想改用 Keycloak 设置 SSO,则需要设置这 4 个环境变量:```
KVIKLET_IDENTITYPROVIDER_CLIENTID
KVIKLET_IDENTITYPROVIDER_CLIENTSECRET
KVIKLET_IDENTITYPROVIDER_TYPE=keycloak
KVIKLET_IDENTITYPROVIDER_ISSUERURI=http://[host]:[port]/realms/[realm]
创建 Keycloak 应用程序时,你会获得客户端 ID 和密钥。 对于有效的重定向 URI,你应该配置:https://[kviklet_host]/api/login/oauth2/code/keycloak 对于允许的来源,只需填写你托管的 kviklet URL。
设置这些环境变量后,登录页面应显示一个“使用 Keycloak 登录”按钮,该按钮会重定向到你的 Keycloak 实例。在企业版中,你可以启用角色同步,将角色从你的 Keycloak 实例自动同步到 kviklet。有关更多详细信息,请参阅 Role Sync 部分。
GitHub(Beta)
Beta: GitHub 身份验证是新功能,尚不支持角色同步——每个新用户都会获得默认角色,必须手动分配角色。
GitHub 不符合 OIDC 规范(它是纯 OAuth 2.0),因此 Kviklet 对其提供了专门支持。设置以下环境变量:``` KVIKLET_IDENTITYPROVIDER_CLIENTID KVIKLET_IDENTITYPROVIDER_CLIENTSECRET KVIKLET_IDENTITYPROVIDER_TYPE=github KVIKLET_IDENTITYPROVIDER_GITHUB_ALLOWEDORGS=your-org,another-org
在 https://github.com/settings/developers 创建一个 GitHub OAuth App 并进行配置:
- Authorization callback URL:`https://[kviklet_host]/api/login/oauth2/code/github`
- Homepage URL:你托管的 Kviklet URL
`KVIKLET_IDENTITYPROVIDER_GITHUB_ALLOWEDORGS` 是**必填项**(缺少它 Kviklet 将拒绝启动)。GitHub OAuth App 无法限制谁可以完成 OAuth 流程,因此 Kviklet 会在认证后调用 `/user/orgs`,并拒绝不属于至少一个允许列表组织的用户(不区分大小写,仅检查前 100 个组织)。
为了让组织检查能够看到用户的成员身份,用户必须在 OAuth 同意屏幕上为每个允许列表中的组织点击 **Grant**(或 **Request**)。如果该组织启用了“Restrict third-party OAuth applications”,则组织所有者还需要先批准该 OAuth 应用一次,之后任何成员的成员身份才会可见。
Kviklet 请求 `read:user`、`user:email` 和 `read:org` 权限范围。电子邮件始终从 `/user/emails` 读取,并且只接受 `primary && verified` 的条目,因此使用私密电子邮件地址的用户仍然可以成功登录。
#### 其他 OIDC 提供程序
其他符合 OIDC 的提供程序(GitLab、Auth0、Okta 等)应该与 Keycloak 类似地工作。请注意,`redirect URI` 会根据你选择的类型而变化,因此如果你选择 `gitlab`,它将是 `https://[kviklet_host]/api/login/oauth2/code/gitlab`。
如果你遇到问题,欢迎创建 issue,我们(目前)还没有尝试过所有的 OIDC 提供程序,并且实现上可能存在细微差异,可能需要 Kviklet 侧进行更新。
### LDAP
Kviklet 支持 LDAP 认证。要启用和配置 LDAP,你可以覆盖以下环境变量:```
LDAP_ENABLED=true
LDAP_URL=ldap://your-ldap-server:389
LDAP_BASE=dc=your,dc=domain,dc=com
LDAP_PRINCIPAL=cn=admin,dc=your,dc=domain,dc=com
LDAP_PASSWORD=your-admin-password
LDAP_UNIQUE_IDENTIFIER_ATTRIBUTE=uid
LDAP_EMAIL_ATTRIBUTE=mail
LDAP_FULL_NAME_ATTRIBUTE=cn
LDAP_USER_OU=people
LDAP_SEARCH_BASE=ou=people
以下是每个设置的含义:
LDAP_ENABLED:设置为true以启用 LDAP 身份验证。LDAP_URL:您的 LDAP 服务器的 URL。LDAP_BASE:用于 LDAP 搜索的基础 DN。LDAP_PRINCIPAL:用于绑定到 LDAP 服务器的管理员用户的 DN。LDAP_PASSWORD:管理员用户的密码。LDAP_UNIQUE_IDENTIFIER_ATTRIBUTE:用作唯一用户标识符的 LDAP 属性(默认值:"uid")。LDAP_EMAIL_ATTRIBUTE:包含用户电子邮件地址的 LDAP 属性(默认值:"mail")。LDAP_FULL_NAME_ATTRIBUTE:包含用户全名的 LDAP 属性(默认值:"cn")。LDAP_USER_OU:存储用户账户的组织单位(OU)(默认值:"people")。LDAP_SEARCH_BASE:允许覆盖用户搜索的基础 DN(默认值:"ou=people")。如果您使用 FreeIPA,可能需要将其设置为例如cn=users。如果设置此项,LDAP_USER_OU将被忽略。
您可以根据自己的 LDAP 架构自定义这些属性。配置 LDAP 后,用户将能够使用其 LDAP 凭据登录。LDAP 用户首次登录时,将在 Kviklet 中创建一个具有默认权限的相应用户账户。管理员需要在这些用户首次登录后为其分配适当的角色。
SAML(仅限企业版)
Kviklet 支持 SAML 2.0 身份验证。要启用 SAML,请设置以下环境变量:``` SAML_ENABLED=true SAML_ENTITYID=https://your-identity-provider.com SAML_SSOSERVICELOCATION=https://your-identity-provider.com/sso SAML_VERIFICATIONCERTIFICATE=-----BEGIN CERTIFICATE-----\nMIICmzCCAYMCBgF4...\n-----END CERTIFICATE-----
配置详情:
- `SAML_ENABLED`:设置为 `true` 以启用 SAML 身份验证
- `SAML_ENTITYID`:您的 SAML 身份提供者的实体 ID
- `SAML_SSOSERVICELOCATION`:您的身份提供者的 SSO 服务 URL
- `SAML_VERIFICATIONCERTIFICATE`:用于验证 SAML 响应的 X.509 证书(包含 BEGIN/END CERTIFICATE 行)
您可以选择性地自定义 SAML 属性映射:```
SAML_USERATTRIBUTES_EMAILATTRIBUTE=email
SAML_USERATTRIBUTES_NAMEATTRIBUTE=name
SAML_USERATTRIBUTES_IDATTRIBUTE=nameID
你的身份提供者应配置为:
- Entity ID:
https://[kviklet_host]/api/saml2/service-provider-metadata/saml - Redirect Uri:
https://[kviklet_host]/api/login/saml2/sso/saml
配置 SAML 后,用户可以通过身份提供者登录。首次登录时,会创建一个具有默认权限的用户账户。
如果你被正确重定向到 IDP,但随后遇到 cors 错误,你可以通过以下方式将你的 IDP 主机添加到 Kviklet 的允许来源中:``` CORS_ALLOWEDORIGINS=https://[idp_host]
## 配置
### 连接
启动 Kviklet 后,你首先需要配置一个数据库连接。前往 设置 -> 数据库 -> 添加连接。


在这里,你可以为每个连接配置审核要求和执行限制。详情请参阅[审核门](#review-gates)。
#### AWS IAM 认证
Kviklet 支持为 Postgres、MySQL 和 MariaDB 数据库连接使用 IAM 认证,为此在创建新连接时选择 IAM 认证。


这将移除设置密码的选项,转而使用 AWS 凭证连接到数据库。
Kviklet 使用 AWS 的 `DefaultCredentialsProvider` 来查找凭证并为连接生成令牌。这意味着所有常见的位置都应该可用(环境变量或关联的实例角色),确切的顺序在此处有文档说明:https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.html
此外,你可以提供一个 AWS 角色 ARN,Kviklet 将代入该角色,并使用这些凭证来创建临时的数据库令牌。这对于连接到与 Kviklet 不在同一 AWS 账户中的数据库特别有用。要使用此功能,只需在创建或编辑 IAM 认证连接时,在指定字段中输入角色 ARN。将该字段留空将使用默认凭证提供程序(不代入角色)。
令牌生成期间使用的 AWS 区域是从你的连接 URL 推断出来的,因此没有设置它的选项。
要了解如何为你的数据库设置 IAM 认证,请遵循 AWS 官方文档:https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html
主要的两点是:
- 创建一个启用了 IAM 认证选项并具有正确权限的数据库用户
- 创建一个 IAM 策略,允许 AWS 实体为该用户生成令牌
### 审核门
默认情况下,Kviklet 允许简单的审核数量配置。你可以配置特定连接上的请求在执行之前需要多少个批准。
请求的批准状态是根据每个审核者的最新操作计算的。如果审核者批准后又请求更改,则只有更改请求计入——其先前的批准被移除。编辑请求总是会重置所有先前的批准,确保任何更改都必须先经过审核才能执行。同样,如果执行失败(例如由于 SQL 语法错误),批准会被重置,以便请求可以被更正并重新批准,而无需创建一个新的请求。
你还可以为每个连接配置**最大执行次数**限制,以控制单个已批准的请求可以执行的频率。默认值为 1。将其设置为 0 允许无限次执行。失败的执行不计入此限制。
#### 基于角色的审核要求(企业版)
拥有 Kviklet 企业版许可证,你可以配置单个连接要求来自具有特定角色的用户的批准。这允许你例如要求来自维护给定数据库的团队的批准,或将敏感连接置于 DBA 或管理层批准的门槛之后。
**工作原理:**
每个连接都有一个**所需审核总数**计数(`numTotalRequired`),它作为一个下限——无论角色如何,所需的不同批准的最小数量。在此基础上,你可以添加**角色要求**,指定必须有多少个批准来自具有特定角色的用户(例如,“1 个来自 DBA,1 个来自安全团队”)。
只有当**两个**条件都满足时,请求才会被批准:
- 不同批准的总数达到 `numTotalRequired`
- 每个角色要求都单独满足
如果用户属于多个角色,来自该用户的单个批准会计入所有匹配的角色要求。但是,它仍然只计为总数中的一个批准。
**示例:** 一个连接需要 3 个总批准,其中包括 1 个来自 DBA 和 1 个来自安全团队。一个同时拥有 DBA 和安全团队角色的用户批准了——这满足了两个角色要求,但只计为所需的 3 个总批准中的 1 个。仍然需要来自任何用户的另外两个批准。
如果你的企业版许可证过期,现有的基于角色的审核要求仍然会被强制执行,但无法再修改。你只能移除它们,以回退到简单的总审核数配置。
### 角色
Kviklet 附带 3 个角色:默认、管理员和开发者。
- 默认角色提供对所有连接和请求的读取访问权限。此角色分配给每个用户且无法移除。但是,你可以随意更改此角色的权限。
- 管理员有权创建和编辑连接,以及添加新用户并设置其权限。
- 开发者可以创建请求,以及批准和评论请求,当然还可以执行实际的语句。
你可以自定义角色,例如,让某个角色只能访问特定连接或一组数据库连接。
这很有用,例如,如果你有不同的团队使用不同的数据库,并希望更细粒度地控制对这些数据库的访问。
#### 创建新角色
创建新角色的操作如下。前往 设置 -> 角色 -> 添加角色。


默认设置对大多数角色来说并不重要,你可以直接给用户读取和角色查看访问权限,然后就这样。
更有趣的是为连接添加单独的权限。在这里,你首先添加一个选择器来选择特定的连接。这可以是一个特定的 id,或者你使用 `*` 通配符来匹配多个连接。例如,如果你想要一个可以访问所有开发数据库的角色(以防你也用 kviklet 管理对这些数据库的访问),你可以使用像 `dev-*` 这样的选择器,并确保连接的 id 设置正确。
当然,你也可以为组织内的不同团队制定一套自己的系统。
### 角色同步(企业版)
自动从你的身份提供程序组同步用户角色。此功能需要企业版许可证。
**配置**在 设置 > 角色同步 中完成:
- **启用角色同步**:打开/关闭同步
- **同步模式**:
- **完全同步** - 用户角色与其 IdP 组映射完全匹配(加上默认角色)
- **增量** - IdP 组添加角色但不移除现有角色
- **仅首次登录** - 角色仅在首次登录时同步,之后保留手动更改
- **组属性**:包含组成员身份的 IdP 属性(默认:`groups`)
- **角色映射**:将 IdP 组名称(例如 `engineering`)映射到 Kviklet 角色
#### OIDC 设置
配置你的 OIDC 提供程序,在 ID 令牌中包含 `groups` 声明:
- **Keycloak**:
Keycloak 默认不在令牌中包含组,因此你需要为客户端添加一个映射器。
1. 在左侧菜单中导航到 **Clients**
2. 选择你的 Kviklet 客户端
3. 转到 **Client scopes** 选项卡
4. 点击专用范围(例如 `kviklet-dedicated`)
5. 转到 **Mappers** 选项卡
6. 点击 **Add mapper** → **By configuration**
7. 选择 **Group Membership**
8. 配置映射器:
| 设置 | 值 |
| ------------------- | -------- |
| Name | `groups` |
| Token Claim Name | `groups` |
| Full group path | **OFF** |
| Add to ID token | **ON** |
| Add to access token | **ON** |
| Add to userinfo | **ON** |
9. 点击 **Save**
> **重要:** “Token Claim Name”必须与 Kviklet 角色同步设置中配置的“组属性”匹配(默认:`groups`)。
- **其他 OIDC 提供程序**:添加一个组映射器/声明,在 ID 令牌中包含用户的组成员身份。这通常在提供程序的管理界面中完成。
如果你遇到问题,请随时创建一个 issue,我们还没有尝试过所有的 OIDC 提供程序(目前),并且实现上可能存在细微差异,可能需要 Kviklet 这边进行更新。
#### LDAP 设置
LDAP 角色同步使用 `memberOf` 属性:
1. 确保你的 LDAP 服务器启用了 `memberOf` overlay
2. 在 Kviklet 中将**组属性**设置为 `memberOf`
3. 然后从用户属性中的 `memberOf` 属性提取组名称。
#### SAML 设置
配置你的 SAML IdP,在断言中包含组:
1. 添加一个映射用户组成员身份的属性语句
2. 在 Kviklet 中设置**组属性**以匹配你的 SAML 属性名称
3. 然后从用户属性中的 SAML 属性提取组名称。
### 通知
你可以配置 Kviklet 向 Slack 或 Teams 中的频道发送通知。这对于通知你的团队有需要审核的新请求很有用。你可以在 设置 -> 常规 -> 通知设置 中配置。
#### Slack
要配置 Slack 通知,你需要创建一个 Slack 应用并为其启用 webhooks。你可以按照此处的说明操作:https://api.slack.com/messaging/webhooks
#### Teams
Teams 通知使用 Power Automate **工作流** webhook。Kviklet 发送一个自适应卡片,webhook 模板将其发布到你的频道。
**推荐:使用工作流模板**
1. 在 Teams 中,打开你想要接收通知的频道,点击频道名称旁边的 **...**,然后选择 **工作流**(或添加 **工作流** 应用)。
2. 搜索并创建 **“向频道发送 webhook 警报”** 模板。
3. 在提示时登录,然后选择目标团队和频道并创建工作流。
4. 打开触发器步骤并复制生成的 **HTTP POST URL**。
5. 将 URL 粘贴到 Kviklet 的 设置 -> 常规 -> 通知设置 中,然后点击保存。
**替代方案:手动构建工作流**
如果你更喜欢自己构建流程(或者模板不可用):
1. 频道 **...** -> **工作流** -> 创建一个触发器为 **“收到 Teams webhook 请求时”** 的流程。
2. 添加操作 **Microsoft Teams -> “在聊天或频道中发布卡片”**。
3. 将该操作的 **自适应卡片** 字段设置为表达式 `string(triggerBody())`,以便它发布 Kviklet 发送的卡片。
4. 选择目标团队和频道,**保存**,然后从触发器步骤复制 **HTTP POST URL**。
目前有以下通知:
- 需要批准的新请求
- 请求上的新批准
#### 基础 URL 配置
当 Kviklet 在反向代理或 Kubernetes Ingress 后面运行时,通知链接可能会使用内部 IP 地址而不是你的公共域名。Kviklet 尝试通过查看传入请求来跟踪正确的 URL,但一些反向代理没有正确设置 Forwarded 头。要解决此问题,请显式设置基础 URL:```
KVIKLET_BASE_URL=https://kviklet.example.com
这确保所有通知链接都指向正确的公共 URL。
遥测
Kviklet 会报告匿名使用统计数据,以帮助我们了解哪些功能被使用以及错误发生在何处。要关闭此功能,请设置:``` KVIKLET_TELEMETRY_ENABLED=false
Kviklet 在启动时会记录一行日志,说明遥测是否开启。
**发送的内容。** 每个事件都携带一个随机实例 ID(生成一次并存储在 Kviklet 的数据库中)、访问 Kviklet 所用的基础 URL(见上文;通常是内部主机名)以及 Kviklet 版本。用户仅通过一个限定于该实例的不透明 ID 来标识,因此可以统计唯一用户数,但绝不会发送电子邮件地址或姓名。确切的事件及其属性定义在 `backend/src/main/kotlin/dev/kviklet/kviklet/telemetry/TelemetryEvent.kt` 中。
**绝不发送的内容。** 查询、语句、结果、命令输出、错误消息、连接名称、主机名、凭据、请求标题或描述、注释以及用户或角色名称。
### 日志记录
默认情况下,Kviklet 将人类可读(美化)的日志写入 stdout,这在直接阅读或通过 `docker logs` 查看时非常方便。
如果你将日志发送到集中式系统(Elasticsearch、Loki、Datadog、CloudWatch 等),可以改用结构化的 **JSON 日志**,这样更易于索引和查询。通过环境变量设置格式:```
# One of: ecs (Elastic Common Schema), logstash, gelf (Graylog)
LOGGING_STRUCTURED_FORMAT_CONSOLE=ecs
加密
如果你不希望凭据以明文形式存储在数据库中,建议在 Kviklet postgres 数据库本身上启用数据库加密。对于大多数托管服务提供商来说,这只是一个简单的勾选框。 尽管如此,如果 Kviklet 数据库以某种方式被攻破,这将是一个巨大的安全风险。因为它包含可能你所有生产数据存储的数据库凭据。因此,你可以启用凭据的静态加密。
要做到这一点,只需设置这两个环境变量。``` ENCRYPTION_ENABLED=true ENCRYPTION_KEY_CURRENT=some-secret
Kviklet 会在启动时加密您所有现有的凭据,并将该密钥用于您之后创建的未来连接。
### 密钥轮换
如果您想轮换密钥,只需为旧密钥添加另一个变量并更改当前密钥即可:```
ENCRYPTION_KEY_PREVIOUS=some-secret
ENCRYPTION_KEY_CURRENT=another-secret
Kviklet 将在启动时重新加密所有连接,这样您之后就可以在移除先前密钥的情况下重启容器。
API 密钥
Kviklet 支持使用 API 密钥进行程序化访问。这是一项仅限企业版的功能,需要有效的许可证。您可以在 设置 -> API 密钥 部分创建 API 密钥。

按如下方式使用:```bash
curl --location '[kviklet_host]/api/connections/'
--header 'Authorization: Bearer your-api-key'
API 密钥继承创建它们的用户的权限。目前只有管理员可以管理 API 密钥,使用 API 密钥执行的所有操作都归属于创建该密钥的用户。
一些基础的 API 文档可以在 `[kviklet_host]/api/swagger-ui/index.html` 找到。但请记住,这仍在开发中,API 可能会在未来版本中发生变化。
最终,真相在代码中,所以你随时可以查看 controller 来了解 API 是如何定义的。如果你有任何问题,欢迎提交 issue。
## 实验性功能
目前有两个实验性功能。它们主要基于社区反馈构建。欢迎试用这些功能并留下你的任何意见。我们希望在未来进一步发展这些功能,并使其与核心审批流程良好配合。
### Kubernetes Exec
如果你想使用 Kubernetes Exec 功能,你需要创建一个单独的 kubernetes 连接。Kviklet 将使用部署 pod 的用户来执行命令。因此请确保该用户具有在你想访问的 pod 上执行命令所需的权限。
Kviklet 还使用 /bin/sh 来执行命令,因此你需要确保你的 pod 有一个 shell,或者至少在 /bin/sh 中有一个符号链接。如果这让你感到困扰,欢迎提交 issue,我们可能会将其设为可配置,或者找到其他解决方案。
Kubernetes 命令只等待 5 秒的输出,如果命令耗时超过这个时间,Kviklet 将等待最多一小时,然后命令超时。这是一个临时解决方案,我们正在研究使用 websockets 来使其响应更快,并有可能启用终端会话。
### 代理 - Postgres、MariaDB、MySQL(企业版)
如果你为临时访问创建请求,你可以——而不是使用 Web 界面——通过 kviklet 管理的代理运行你的查询,并使用你选择的数据库客户端。
代理是一个企业版功能:它需要有效的许可证,并且管理员还需要在 设置 -> 通用 -> 数据库代理 下将其打开。
为此,容器监听稳定的端口(默认是 5432 和 3306,可通过 `kviklet.proxy.postgres.port` 和 `kviklet.proxy.mysql.port` 配置),因此你需要暴露这些端口。
用户随后可以创建一个临时访问请求,并在请求被批准后点击“启动代理”。每个请求都会获得一个临时用户名和密码;Kviklet 通过用户名将每个连接路由到其对应的请求。使用这些凭据,他们可以连接到数据库。Kviklet 验证临时用户和密码,并将所有请求代理到数据库上的底层用户。任何执行的语句都会像通过 Web 界面运行一样记录在审计日志中。
注意:代理目前不支持结果跟踪。因此执行的语句会被记录,但结果或语句是否成功或失败不会被记录。


#### 代理 - TLS
Kviklet 终止到数据库的 TLS 连接。这意味着默认情况下,进出代理本身的任何流量都未加密。
如果你希望 kviklet 重新加密流量,你可以通过设置以下环境变量为 Kviklet 提供代理的 TLS 证书和密钥:```
PROXY_TLS_CERTIFICATE_SOURCE=env
PROXY_TLS_CERTIFICATE_CERT=your-certificate
PROXY_TLS_CERTIFICATE_KEY=your-key
或者,你也可以使用文件:``` PROXY_TLS_CERTIFICATE_SOURCE=file PROXY_TLS_CERTIFICATE_CERT_FILE=path/to/cert.pem PROXY_TLS_CERTIFICATE_KEY_FILE=path/to/key.pem
无论哪种方式,证书和密钥都必须以 [pem 格式](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail) 存储。
## 有问题?想贡献?
如果您有任何问题、想提供反馈或需要设置方面的帮助,请加入我们的 [Discord 社区](https://discord.gg/7SmPJfeP6e)。您也可以创建 [GitHub issue](https://github.com/kviklet/kviklet/issues) 来报告错误和提出功能请求。
如果您想贡献,欢迎 fork 并为小改动创建 PR。如果您计划开发较大的功能,我希望能在 GitHub issue 或 Discord 上先进行一些讨论。
您也可以通过 [email protected] 联系我。