Teleport Discord 访问申请插件(teleport-discord)完整指南:原理、配置与部署
2026/9/21 1:18:24 网站建设 项目流程
  • 网络安全
  • 认证鉴权
  • 运维
  • 后端

【免费下载链接】teleport

The easiest, and most secure way to access and protect all of your infrastructure.

项目地址:https://gitcode.com/gh_mirrors/tel/teleport
点击查看免费下载

导读

Teleport 的 Discord 访问申请插件(Access Request Plugin)是构建在 Teleport Access API 之上的一个简单消息插件:当用户提交访问申请(Access Request)时,它会自动向指定的 Discord 频道发送告警消息,并在申请被批准或拒绝后实时更新消息内容,从而把人工审批流程直接嵌入团队日常使用的 Discord 会话中。阅读本文后,你将掌握该插件的完整配置文件结构、CLI 命令用法、Discord 消息与审核展示机制、底层实现原理,以及从构建到运行的完整部署路径。

该插件位于仓库 integrations/access/discord 目录,文档源头为 integrations/access/discord/README.md,官方将其定位为 "a simple Discord access request plugin that sends an alert to a Discord channel when an access request is created"(当访问申请创建时向 Discord 频道发送告警的简单插件)。

插件定位与整体工作流程

Teleport 的访问申请(Access Request)机制允许用户申请临时或长期的角色权限、资源访问权。默认情况下,审批发生在tsh命令行或 Web UI 中;而接入 Discord 插件后,审批信息会被推送到聊天工具,让审批人不必时刻盯着 Teleport 控制台。

从源码结构看,整个插件的核心职责可以归纳为三件事:

  1. 监听:通过 integrations/access/common/app.go 中的通用 BaseApp 框架连接 Teleport Auth Server(走 gRPC),订阅访问申请事件;
  2. 推送:通过 bot.go 中的DiscordBot,把访问申请的标题、角色、登录名、资源、原因等信息格式化成 Discord 消息,POST到目标频道的消息接口;
  3. 更新:当访问申请被审批(批准/拒绝/过期)后,用PATCH请求原地更新已发送的消息,并通过 Discord Embed(嵌入卡片)展示每一条审核记录。

插件通过role_to_recipients映射把"角色"关联到"Discord 频道 ID",实现按角色路由通知:某个角色对应的访问申请只通知到为其配置的频道。

仓库模块速览

先浏览插件目录,便于后续对照阅读:

integrations/access/discord/ ├── cmd/teleport-discord/ │ ├── example_config.toml # 官方示例配置文件(TOML) │ ├── install # 安装脚本 │ └── main.go # CLI 入口:configure / version / start ├── testlib/ │ ├── fake_discord.go # 模拟 Discord API 的测试替身 │ ├── helpers.go │ ├── message.go │ ├── oss_integration_test.go # OSS 集成测试 │ └── suite.go ├── Makefile # 构建入口(ACCESS_PLUGIN = discord) ├── app.go # 应用组装,注册插件名 "discord" ├── bot.go # DiscordBot 消息机器人核心实现 ├── config.go # 配置解析与校验 └── types.go # Discord API 请求/响应结构体

其中 app.go 的职责非常轻量——它定义插件名常量discordPluginName = "discord",该名字用于给 GenericPluginData 打标签,并作为 Audit Log 中的 Delegator(审计日志中标记"由谁处理"的字段);然后通过common.NewApp(conf, discordPluginName)复用所有消息类访问插件共用的应用框架。

配置文件详解(example_config.toml)

插件使用 TOML 格式配置,官方在 example_config.toml 中给出了完整模板,运行teleport-discord configure命令也可以直接打印出这份模板。完整内容如下:

# Example discord plugin configuration TOML file [teleport] # Teleport Auth/Proxy Server address. # addr = "example.com:3025" # # Should be port 3025 for Auth Server and 3080 or 443 for Proxy. # For Teleport Cloud, should be in the form "your-account.teleport.sh:443". # Credentials generated with `tctl auth sign`. # # When using --format=file: # identity = "/var/lib/teleport/plugins/discord/auth_id" # Identity file # refresh_identity = true # Refresh identity file on a periodic basis. # # When using --format=tls: # client_key = "/var/lib/teleport/plugins/discord/auth.key" # Teleport TLS secret key # client_crt = "/var/lib/teleport/plugins/discord/auth.crt" # Teleport TLS certificate # root_cas = "/var/lib/teleport/plugins/discord/auth.cas" # Teleport CA certs [discord] # Discord Bot OAuth token token = "secret-token" [role_to_recipients] # Map roles to recipients. # # Provide discord channel IDs recipients for access requests for specific roles. # "*" must be provided to match non-specified roles. # # "dev" = "0987654321" # "*" = ["1234567890", "0987654321"] [log] output = "stderr" # Logger output. Could be "stdout", "stderr" or "/var/lib/teleport/discord.log" severity = "INFO" # Logger severity. Could be "INFO", "ERROR", "DEBUG" or "WARN".

各段配置说明

[teleport]——连接 Teleport 集群

  • addr:Teleport Auth/Proxy 服务器地址。Auth Server 用 3025 端口,Proxy 用 3080 或 443;Teleport Cloud 用户则填写形如your-account.teleport.sh:443的地址。
  • 凭据通过tctl auth sign生成,两种格式二选一:
    • --format=file:生成身份文件(identity),配合refresh_identity = true可让插件周期性自动刷新身份文件;
    • --format=tls:生成 TLS 私钥(client_key)、证书(client_crt)和 CA 根证书(root_cas)三个文件。

[discord]——Discord Bot 凭据

  • token:Discord Bot 的 OAuth Token。注意:源码中构造请求头时会在 token 前加上"Bot "前缀(见 config.go 第 104 行token := "Bot " + c.Discord.Token),因此这里填写的是不带Bot前缀的原始 Token。
  • 除此之外,GenericAPIConfig还支持APIURL字段(见 integrations/access/common/config.go 第 109-117 行),默认值为https://discord.com/api/(config.go 第 37 行的discordAPIUrl常量),一般无需修改,仅自建 Discord API 代理时才会用到。

[role_to_recipients]——角色到频道的路由表

  • 键为 Teleport 角色名,值为 Discord 频道 ID 或 ID 列表。
  • 通配符"*"必须提供,用于匹配所有未显式列出的角色,保证任何访问申请都能找到通知目标。
  • 例如"dev" = "0987654321"表示 dev 角色的申请通知到频道 0987654321;"*" = ["1234567890", "0987654321"]表示其余角色同时通知两个频道。

[log]——日志配置

  • output:日志输出位置,可为stdoutstderr或某个日志文件路径(如/var/lib/teleport/discord.log)。
  • severity:日志级别,可为INFOERRORDEBUGWARN

配置校验逻辑

config.go 的CheckAndSetDefaults(第 56-80 行)定义了启动时的强校验规则:

  • discord.token缺失 → 直接报错missing required value discord.token
  • role_to_recipients为空 → 报错missing required value role_to_recipients.
  • role_to_recipients["*"]为空 → 报错missing required value role_to_recipients[*].
  • APIURLLog.Output(默认stderr)、Log.Severity(默认info)缺失时自动填充默认值。

Token 文件化支持LoadDiscordConfig(第 131-152 行)在加载 TOML 后还会检查 token 是否以/开头——如果是,则将其视为文件路径,通过lib.ReadPassword从文件中读取真实 Token(典型的做法是把 Token 放进权限受限的文件,避免出现在命令行或配置明文里)。

CLI 命令与启动方式

插件入口在 cmd/teleport-discord/main.go,基于 kingpin 框架提供三个子命令:

命令作用
teleport-discord configure打印示例 TOML 配置(内嵌的 example_config.toml)
teleport-discord version打印插件版本(teleport.Version 与 Gitref)并退出
teleport-discord start启动插件主进程

start子命令支持两个 flag:

  • -c/--config:指定 TOML 配置文件路径,默认/etc/teleport-discord.toml
  • -d/--debug:开启 verbose 日志输出到 stderr(等价于把日志级别强制设为 debug)。

启动流程(run函数,第 74-99 行)依次为:加载并校验配置 → 初始化日志 → 通过discord.NewApp(conf)组装应用 →lib.ServeSignals挂接信号处理(实现优雅关闭)→app.Run(ctx)进入主循环。日志中会输出版本信息:

Starting Teleport Access Discord Plugin version=... git_ref=...

消息机器人实现原理(bot.go 深度解析)

bot.go 定义了DiscordBot,它持有三个关键字段:client(resty HTTP 客户端)、clusterName(集群名,用于消息展示)和webProxyURL(Web Proxy 地址,用于在消息中生成申请详情链接)。

HTTP 客户端与健康检查

NewBot(config.go 第 93-126 行)创建 resty 客户端时设置了几个值得注意的参数:

  • Timeout: 10 * time.SeconddiscordHTTPTimeout);
  • 每个 Host 最大连接数 100(discordMaxConns);
  • 使用http.ProxyFromEnvironment,即支持通过环境变量配置 HTTP 代理;
  • 自动附加请求头:Content-Type: application/jsonAccept: application/jsonAuthorization: Bot <token>

插件的健康检查(CheckHealth,第 101-110 行)会调用 Discord API 的GET /users/@me——如果 Token 无效,该请求必然失败,因此错误信息直接提示 "health check failed, probably invalid token"。

申请消息的发送与更新

发送申请消息走BroadcastAccessRequestMessage(第 125-148 行):对recipients列表中的每个频道逐一POST /channels/{channelID}/messages,请求体是DiscordMsg{Msg: {Channel: ...}, Text: ...},并记录返回的message_id用于后续更新。单个频道失败不会中断整体,所有错误最终通过trace.NewAggregate聚合返回。

当访问申请状态变化时,UpdateMessages(第 161-178 行)对每个已发送消息执行PATCH /channels/{channelID}/messages/{messageID},用最新状态文本 + 审核 Embed 列表整体替换原消息。

消息文本组装

消息正文由三个函数拼接而成(discordMsgText,第 215-219 行),定义在共享模块 integrations/access/accessrequest/message.go:

  • MsgTitle:标题。根据申请是否包含资源,显示 "You have a new Role Request" 或 "You have a new Resource Request";长时访问(long-term access)会追加(long-term access)后缀;
  • MsgFields:字段明细,按序输出 ID、Cluster、User、每个角色的 Role/Login(s)(角色与登录名均排序后输出)、Resource(s)、Request reason 等,所有用户输入都会经过lib.MarkdownEscape转义,防止 Discord Markdown 注入;
  • MsgStatusText:状态行,带 emoji——⏳ PENDING(未处理)、✅ APPROVED(已批准)、❌ DENIED(已拒绝)、⌛ EXPIRED(已过期),并附带审批理由(Resolution reason)。

审核记录的 Embed 卡片

discordEmbeds(第 180-213 行)把每条AccessReview渲染成一张 Discord Embed 卡片:

  • 批准(RequestState_APPROVED)→ 标题 "Approved request at <时间>",颜色discordGreenColor(数值 2328611);
  • 拒绝(RequestState_DENIED)→ 标题 "Denied request at <时间>",颜色discordRedColor(数值 13771309,注释中标注为 0xD2222D);
  • 卡片包含作者(审批人)、描述("Reason: ..."),审核理由同样会经过转义并受长度限制。

能力边界(源码中明确"未实现"的部分)

源码注释和实现明确标注了以下限制,部署前务必知悉:

  • FetchRecipient仅支持频道 ID(第 221-232 行):Discord Bot 权限无法解析邮箱地址,而按频道名解析需要缓存(该接口返回全量频道且受速率限制),因此当前只支持把"接收者"直接当作 Discord Channel ID 使用;
  • PostReviewReply为空实现(第 150-153 行):Discord 没有线程化回复机制,审核信息统一通过更新原消息的 Embeds 展示;
  • NotifyUser未实现:不会向申请用户发送私信通知;
  • SendReviewReminders未实现:Access List 的定期审核提醒功能尚未支持;
  • FetchOncallUsers未实现:不支持按注解拉取 on-call 用户。

SupportedApps(第 113-117 行)可以看出,当前机器人只注册了accessrequest.NewApp()一个应用,即专注访问申请通知这一个场景。

运行状态上报与错误处理

插件通过common.StatusSink上报自身健康状态。onAfterResponseDiscord(bot.go 第 59-80 行)是 resty 的响应后置钩子:每次请求完成后,先把 HTTP 状态码换算成插件状态(common.StatusFromStatusCode)推送给 StatusSink——即使请求失败也会上报,这样外部监控能感知"插件目前处于故障"状态。

上报时特意使用context.Background()配合 10 秒超时(discordStatusUpdateTimeout),因为 resty 请求自带的 context 可能已被取消,无法用于上报故障状态。

错误处理方面:当 Discord API 返回非 2xx 时,插件尝试解析DiscordResponse{code, message},定义在 types.go),优先返回message (code: X, status: Y)形式的错误,否则回退为原始响应体 + 状态码。

构建与部署

构建

插件构建走共享 Makefile 体系。Makefile 内容极简:

ACCESS_PLUGIN = discord include ../common.mk

即通过设置ACCESS_PLUGIN = discord复用 integrations/access/common.mk 中的通用构建规则,产物名称为teleport-discordcmd/teleport-discord/install脚本则用于安装到目标系统(通常配合 systemd 作为服务运行)。

部署步骤概述

综合配置文件注释与入口代码,一套典型的部署流程为:

  1. 创建 Discord Bot:在 Discord 开发者后台创建应用并生成 Bot OAuth Token(配置中的discord.token),将 Bot 邀请进目标服务器,取得目标频道的 Channel ID;
  2. 生成 Teleport 凭据:在 Teleport 集群上用tctl auth sign --format=file(或--format=tls)为插件生成专用身份,配置[teleport]段;
  3. 编写配置文件:参照上文example_config.toml,填写addr、凭据路径、discord.tokenrole_to_recipients路由表,保存到/etc/teleport-discord.toml(或自定义路径);
  4. 启动:执行teleport-discord start,通过-d开启 debug 日志排查问题;
  5. 验证:提交一个测试访问申请,观察对应频道是否收到消息;审批后再确认原消息是否被更新为含审核 Embed 的新状态。

测试体系

插件自带一套基于 fake 后端的测试设施(testlib):

  • fake_discord.go:模拟 Discord API 的测试替身,让集成测试无需真实 Discord 账号即可验证消息发送与更新逻辑;
  • oss_integration_test.go+suite.go:OSS 版本集成测试套件,覆盖从访问申请创建、消息广播到状态更新的完整链路。

这与插件主代码形成了闭环验证:BroadcastAccessRequestMessage/UpdateMessages的请求构造、discordMsgText的消息格式、Embed 颜色与标题规则,都有对应的自动化测试守护。

总结

Teleport Discord 访问申请插件是一个轻量但完整的"访问申请 → Discord 通知 → 聊天内审批展示"闭环实现:它复用integrations/access/common的通用插件框架,仅用少量业务代码(bot.go 约 240 行)就完成了 Discord 消息的格式化、发送、更新与健康上报。对于希望把 Teleport 审批流嵌入 Discord 的团队而言,只需准备一个 Bot Token、若干频道 ID 和一份 TOML 配置即可上线;同时也要注意其能力边界——接收者目前仅支持频道 ID,且不支持私信通知与 Access List 审核提醒。

若需在自托管 Teleport 环境中进一步查阅官方部署文档,可在 Access Requests with Discord 页面(该链接由原 README.md 提供)获取详细配置说明;本文所有实现细节均以当前仓库源码为准。

  • 网络安全
  • 认证鉴权
  • 运维
  • 后端

【免费下载链接】teleport

The easiest, and most secure way to access and protect all of your infrastructure.

项目地址:https://gitcode.com/gh_mirrors/tel/teleport
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询