2 个版本 (1 个稳定版)
1.0.0 | 2020 年 8 月 28 日 |
---|---|
0.5.0 | 2020 年 8 月 28 日 |
#2220 在 密码学
89KB
1.5K SLoC
Caramel 客户端 Rust
Rust Caramel 客户端和库
这是什么
Caramel 是一个简单的证书颁发机构 (CA),允许用户设置自己的根 CA,签名客户端和服务器,从而使用 TLS(传输层安全性)和客户端证书身份验证来识别机器。
这是一个 客户端,与 Caramel 服务器 进行通信。
它负责
- 生成私钥
- 创建 CSR(证书签名请求)
- 将 CSR 发布到 Caramel 服务器
- 从 Caramel 服务器获取已签名的证书
为什么使用它
我们用它进行机器对机器的身份验证。通过为机器添加 systemd 服务或 cron-job 来创建和维护用于与其他机器进行身份验证的私钥和证书,我们消除了计算机账户和服务密码的需求。
我们的一些常见用例
- 服务器到服务器的日志上传
- 客户端应用程序到数据库服务器的身份验证
- 部署监控服务(Zabbix)的密钥和证书
- Web 应用程序到 API 的身份验证
许可证
根据您的选择,许可协议为以下之一
- Apache 许可证 2.0 版,(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
。
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交的任何贡献,都应如上所述双许可,不附加任何额外条款或条件。
用户故事
对于开发者来说,以下是一些这个包应该能够满足的基本场景,无论是作为独立应用程序,还是作为嵌入在其他软件中的库。
日志客户端证书与密钥处理
在我们的基础设施中,我们希望使用 TLS 和客户端证书通过 TLS 验证上传日志文件到日志服务器。
为此,我们为日志基础设施设置了单独的 CA,并希望在提交日志的所有机器上部署一个工具。
该工具由 systemd 服务和计时器启动,以保持证书的更新。
[Unit]
Description=Refresh Caramel Certificate for %i
After=network.target
Wants=network-online.target
[Service]
Type=oneshot
Environment=CARAMEL_CA=ca.example.com
Environment=CARAMEL_CN=service.example.com
Environment=CARAMEL_CERT_DIR=/var/lib/example/tls/
WorkingDirectory=/var/lib/example/tls/
ExecStart=/usr/local/bin/caramel-client $CARAMEL_CA $CARAMEL_CN
然后,该服务由计时器触发,或通过简单的插入文件由其他服务依赖。
上述单元将确保在 /var/lib/example/tls/ 目录中存在一个CA证书文件、私钥文件以及其他应用程序使用的已签名的证书文件。
在此用例中,caramel-client生成私钥、证书签名请求,然后继续轮询服务器以获取已签名的证书,只有当CA已经签署了请求后,才会最终成功退出。
这是因为以下服务需要证书才能继续成功运行,因此它们应该等待收到证书。因此,客户端最简单的模式是无限循环等待服务器签署请求,这需要管理员手动操作。
由于服务器有管理员在监视,没有必要自动尝试从错误情况中恢复,对于管理员能够跟踪应用程序状态来说,重要的是要有良好的错误信息。
嵌入式客户端应用程序
在嵌入式固件中,我们不希望分发大量公钥CA证书,并且想保护我们免受MITM/中间人攻击和其他有趣的问题,因此我们将CA证书与硬件一起嵌入。
对于此用例,客户端由其他应用程序调用,这意味着通过返回码表示密钥的状态,并且永远不会阻塞或循环。
在这些情况下,没有管理员可以访问或调试,因此客户端需要能够自动恢复,通常是通过在Caramel服务器返回某些错误码的情况下“从头开始”。
在此,应用程序使用硬件的“知名”序列号或设备的MAC地址作为它们的客户端ID。
与上面的命令行客户端不同,CA证书应该能够使用别处指定的证书,私钥和证书存储在单个知名文件中,具有特定的所有权和权限。
为了避免并发调用引起麻烦,在处理密钥和/或CSR请求时,密钥文件会被flock
(独占,如果另一个进程正在进行,则返回未指定的错误码)锁定,因此如果在程序并发启动时,会导致错误码退出,因为多个不同的工具将各自尝试启动知名“确保我们有密钥”应用程序,如果不存在密钥。
为了便于调试和监控,客户端ID是用户代理中此操作模式的一部分。
并且为了进一步提供身份验证,如果客户端认为它有一个可用的CA证书,它默认会将客户端证书传递给服务器。
此客户端还会比较服务器端和本地证书的时间戳,如果它没有被更新,则不会获取新文件,以节省计费连接的带宽。
正在使用的状态码
- 成功请求:0
- 未更改的文件:0
- 锁定文件:1
- 挂起签名:69
- 其他错误:127
错误处理
- 拒绝:擦除密钥、CSR并重新开始
嵌入式库应用程序
在移动设备(智能手机)上,库在后台使用,以方便API连接。当应用程序第一次启动时,它生成一个新的UUID和密钥,并将其发送到后台的Caramel服务器。
Caramel服务器被配置为自动签署所有以前未见过的基于UUID的请求,因此客户端几乎可以立即获得证书。
在这个步骤中,匿名用户对于服务器来说有一个独特和可信任的身份,同时仍然能够保持匿名。
如果服务需要,可以进行适当的用户身份验证步骤,例如使用OAuth或电子邮件回调将用户身份与设备的账户关联起来。
对于这个用例,绝对不要尝试直接将文件存储到磁盘上,而应仅返回可以存储在系统密钥链或每个应用程序数据库中的文件对象。
使用容器
# podman pull registry.gitlab.com/modioab/caramel-client-rs/client:latest
# podman run -ti --rm=true -v $(pwd):/data:rw registry.gitlab.com/modioab/caramel-client-rs/client:latest CA.EXAMPLE.COM TEST-CERTIFICATE-PLEASE-IGNORE
依赖项
~10–22MB
~361K SLoC