agenix
是一个小巧便捷的 Nix 库,用于使用常见的公钥-私钥 SSH 密钥对安全地管理和部署机密:
你可以在源机器上使用多个公共 SSH 密钥加密一个机密(密码、访问令牌等),
然后将该加密的机密部署到任何拥有与这些公钥之一对应的私有 SSH 密钥的目标机器上。
该项目包含两个部分:
agenix
命令行应用程序(CLI),用于将机密加密为可复制到 Nix 存储的安全 .age
文件。agenix
NixOS 模块,方便地
.age
文件)添加到 Nix 存储中,以便可以像任何其他 Nix 包一样使用 nixos-rebuild
或类似工具部署。/run/agenix/...
)以供使用。Nix 存储中的所有文件都可以被任何系统用户读取,因此不适合包含明文机密。许多现有工具(如 NixOps deployment.keys)与 nixos-rebuild
分开部署机密,这使得部署、缓存和审计更加困难。带外机密管理也不太可重现。
agenix
通过使用您预先存在的 SSH 密钥基础设施和 age
将机密加密到 Nix 存储中来解决这些问题。机密在 NixOS 系统激活期间使用 SSH 主机私钥解密。
ssh-keyscan
获取系统公钥首先将其添加到 niv:
$ niv add ryantm/agenix
然后在 configuration.nix
的 imports
列表中添加以下内容:
{ imports = [ "${(import ./nix/sources.nix).agenix}/modules/age.nix" ]; }
要安装 agenix
二进制文件:
</details> <details> <summary>{ environment.systemPackages = [ (pkgs.callPackage "${(import ./nix/sources.nix).agenix}/pkgs/agenix.nix" {}) ]; }
以 root 身份运行:
$ sudo nix-channel --add https://github.com/ryantm/agenix/archive/main.tar.gz agenix $ sudo nix-channel --update
然后在 configuration.nix
的 imports
列表中添加以下内容:
{ imports = [ <agenix/modules/age.nix> ]; }
要安装 agenix
二进制文件:
</details> <details> <summary>{ environment.systemPackages = [ (pkgs.callPackage <agenix/pkgs/agenix.nix> {}) ]; }
在您的 configuration.nix 中添加以下内容:
{ imports = [ "${builtins.fetchTarball "https://github.com/ryantm/agenix/archive/main.tar.gz"}/modules/age.nix" ]; }
或者使用固定版本:
{ imports = let # 将此替换为实际的提交 ID 或标签 commit = "298b235f664f925b433614dc33380f0662adfc3f"; in [ "${builtins.fetchTarball { url = "https://github.com/ryantm/agenix/archive/${commit}.tar.gz"; # 从 nix build 输出更新哈希值 sha256 = ""; }}/modules/age.nix" ]; }
要安装 agenix
二进制文件:
</details> <details> <summary>{ environment.systemPackages = [ (pkgs.callPackage "${builtins.fetchTarball "https://github.com/ryantm/agenix/archive/main.tar.gz"}/pkgs/agenix.nix" {}) ]; }
{ inputs.agenix.url = "github:ryantm/agenix"; # 可选,模块不需要 #inputs.agenix.inputs.nixpkgs.follows = "nixpkgs"; # 可选,选择不下载 darwin 依赖项(在 Linux 上节省一些资源) #inputs.agenix.inputs.darwin.follows = ""; outputs = { self, nixpkgs, agenix }: { # 将 `yourhostname` 更改为您的实际主机名 nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem { # 更改为您的系统: system = "x86_64-linux"; modules = [ ./configuration.nix agenix.nixosModules.default ]; }; }; }
您可以临时运行 CLI 工具而无需安装:
nix run github:ryantm/agenix -- --help
但您也可以将其永久添加到 NixOS 模块中 (将系统 "x86_64-linux" 替换为您的系统):
{ environment.systemPackages = [ agenix.packages.x86_64-linux.default ]; }
例如,在您的 flake.nix
文件中:
</details>{ inputs.agenix.url = "github:ryantm/agenix"; # ... outputs = { self, nixpkgs, agenix }: { # 将 `yourhostname` 更改为您的实际主机名 nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ # ... { environment.systemPackages = [ agenix.packages.${system}.default ]; } ]; }; }; }
您要部署机密的系统应该已经存在并运行 sshd
,以便它在 /etc/ssh/
中生成了 SSH 主机密钥。
创建一个目录来存储机密和 secrets.nix
文件,用于列出机密及其公钥:
$ mkdir secrets $ cd secrets $ touch secrets.nix
这个 secrets.nix
文件不会导入到您的 NixOS 配置中。
它只用于 agenix
CLI 工具(示例如下)以了解用于加密的公钥。
将公钥添加到您的 secrets.nix
文件中:
let user1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL0idNvgGiucWgup/mP78zyC23uFjYq0evcWdjGQUaBH"; user2 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILI6jSq53F/3hEmSs+oq9L4TwOo1PrDMAgcA1uo1CCV/"; users = [ user1 user2 ];
system1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJDyIr/FSz1cJdcoW69R+NrWzwGK/+3gJpqD1t8L2zE"; system2 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKzxQgondgEYcLpcPdJLrTdNgZ2gznOHCAxMdaceTUT1"; systems = [ system1 system2 ]; in { "secret1.age".publicKeys = [ user1 system1 ]; "secret2.age".publicKeys = users ++ systems; }
这些是稍后能够使用其对应私钥解密 `.age` 文件的用户和系统。
你可以从以下方式获取公钥:
* 通常在本地计算机的 `~/.ssh` 目录下,例如 `~/.ssh/id_ed25519.pub`。
* 从运行中的目标机器使用 `ssh-keyscan`:
```ShellSession
$ ssh-keyscan <ip-地址>
... ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKzxQgondgEYcLpcPdJLrTdNgZ2gznOHCAxMdaceTUT1
...
创建一个秘密文件:
$ agenix -e secret1.age
它将在你的 $EDITOR 环境变量配置的应用程序中打开一个临时文件。
当你保存该文件时,其内容将使用 secrets.nix
文件中提到的所有公钥进行加密。
将秘密添加到 NixOS 模块配置中:
{ age.secrets.secret1.file = ../secrets/secret1.age; }
当 age.secrets
属性集包含一个秘密时,agenix
NixOS 模块稍后会自动解密并将该秘密挂载到默认路径 /run/agenix/secret1
下。
这里 secret1.age
文件成为你的 NixOS 部署的一部分,即移动到 Nix store 中。
在你的配置中引用秘密的挂载路径:
{ users.users.user1 = { isNormalUser = true; passwordFile = config.age.secrets.secret1.path; }; }
你可以在其他配置中已经引用(稍后)未加密秘密的挂载路径。
所以默认情况下 config.age.secrets.secret1.path
将包含路径 /run/agenix/secret1
。
像往常一样使用 nixos-rebuild
或其他部署工具。
secret1.age
文件将像任何其他 Nix 包一样被复制到目标机器。
然后它将被解密并按照先前描述的方式挂载。
编辑秘密文件:
$ agenix -e secret1.age
它假设你的 SSH 私钥在 ~/.ssh/
中。
为了解密并打开一个 .age
文件进行编辑,你需要用于加密该文件的公钥之一对应的私钥。你可以使用 -i
明确传递你想使用的私钥,例如
$ agenix -e secret1.age -i ~/.ssh/id_ed25519
age
模块参考age.secrets
age.secrets
是秘密的属性集。你总是需要使用这个配置选项。默认为 {}
。
age.secrets.<name>.file
age.secrets.<name>.file
是此秘密的加密 .age
文件的路径。这是唯一必需的秘密选项。
示例:
{ age.secrets.monitrc.file = ../secrets/monitrc.age; }
age.secrets.<name>.path
age.secrets.<name>.path
是秘密解密后的路径。默认为 /run/agenix/<name>
(config.age.secretsDir/<name>
)。
定义不同路径的示例:
{ age.secrets.monitrc = { file = ../secrets/monitrc.age; path = "/etc/monitrc"; }; }
对于许多服务,你不需要设置这个。相反,在你的配置中使用 config.age.secrets.<name>.path
引用解密路径。
引用路径的示例:
{ users.users.ryantm = { isNormalUser = true; passwordFile = config.age.secrets.passwordfile-ryantm.path; }; }
{ # 不要这样做! config.password = builtins.readFile config.age.secrets.secret1.path; }
这可能会导致明文被放置到全局可读的 Nix store 中。相反,让你的服务在运行时读取明文路径。
age.secrets.<name>.mode
age.secrets.<name>.mode
是解密后的秘密的权限模式,格式为 chmod 可以理解的格式。通常,你只需要与 age.secrets.<name>.owner
和 age.secrets.<name>.group
结合使用。
示例:
{ age.secrets.nginx-htpasswd = { file = ../secrets/nginx.htpasswd.age; mode = "770"; owner = "nginx"; group = "nginx"; }; }
age.secrets.<name>.owner
age.secrets.<name>.owner
是解密文件所有者的用户名。通常,你只需要与 age.secrets.<name>.mode
和 age.secrets.<name>.group
结合使用。
示例:
{ age.secrets.nginx-htpasswd = { file = ../secrets/nginx.htpasswd.age; mode = "770"; owner = "nginx"; group = "nginx"; }; }
age.secrets.<name>.group
age.secrets.<name>.group
是解密文件的组名。通常,你只需要与 age.secrets.<name>.owner
和 age.secrets.<name>.mode
结合使用。
示例:
{ age.secrets.nginx-htpasswd = { file = ../secrets/nginx.htpasswd.age; mode = "770"; owner = "nginx"; group = "nginx"; }; }
age.secrets.<name>.symlink
age.secrets.<name>.symlink
是一个布尔值。如果为 true(默认值),秘密将被符号链接到 age.secrets.<name>.path
。如果为 false,秘密将被复制到 age.secrets.<name>.path
。通常,你希望保持为 true,因为它可以安全地清理不再使用的秘密。(符号链接仍然存在,但它将是断开的。)如果为 false,你需要负责在停止使用秘密后自行清理。
一些程序不喜欢跟随符号链接(例如 Java 程序如 Elasticsearch)。
示例:
{ age.secrets."elasticsearch.conf" = { file = ../secrets/elasticsearch.conf.age; symlink = false; }; }
age.secrets.<name>.name
age.secrets.<name>.name
是解密后文件的名称字符串。默认为属性路径中的 <name>
,但如果你希望文件名与属性名不同,可以单独设置。
一个秘密名称与其属性路径不同的示例:
{ age.secrets.monit = { name = "monitrc"; file = ../secrets/monitrc.age; }; }
age.ageBin
age.ageBin
是 age
二进制文件路径的字符串。通常,你不需要更改这个。默认为 age/bin/age
。
覆盖 age.ageBin
的示例:
{pkgs, ...}:{ age.ageBin = "${pkgs.age}/bin/age"; }
age.identityPaths
age.identityPaths
是一个尝试用于解密秘密的接收者密钥路径列表。默认情况下,它是 config.services.openssh.hostKeys
中的 rsa
和 ed25519
密钥,在 NixOS 上你通常不需要更改这个。列表项应该是字符串("/path/to/id_rsa""),而不是 nix 路径(
../path/to/id_rsa),因为后者会将你的私钥复制到 nix store 中,这正是
agenix设计用来避免的情况。在运行时,至少一个文件路径必须存在并能够解密相关的秘密。覆盖
age.identityPaths` 的示例:
{ age.identityPaths = [ "/var/lib/persistent/ssh_host_ed25519_key" ]; }
age.secretsDir
age.secretsDir
是默认情况下秘密被符号链接到的目录。通常情况下,你不需要更改这个设置。默认值为 /run/agenix
。
覆盖 age.secretsDir
的示例:
{ age.secretsDir = "/run/keys"; }
age.secretsMountPoint
age.secretsMountPoint
是在秘密被符号链接之前创建秘密世代的目录。通常情况下,你不需要更改这个设置。默认值为 /run/agenix.d
。
覆盖 age.secretsMountPoint
的示例:
{ age.secretsMountPoint = "/run/secret-generations"; }
agenix - 编辑和重新加密 age 秘密文件
agenix -e 文件 [-i 私钥]
agenix -r [-i 私钥]
选项:
-h, --help 显示帮助
-e, --edit 文件 使用 $EDITOR 编辑文件
-r, --rekey 使用指定的接收者重新加密所有秘密
-d, --decrypt 文件 将文件解密到标准输出
-i, --identity 解密时使用的身份
-v, --verbose 详细输出
文件 一个 age 加密的文件
私钥 用于解密文件的 SSH 私钥路径
EDITOR 环境变量,用于指定编辑文件时使用的编辑器
如果标准输入不是交互式的,EDITOR 将被设置为 "cp /dev/stdin"
RULES 环境变量,包含指定接收者公钥的 Nix 文件路径。
默认为 './secrets.nix'
如果你更改了 secrets.nix
中的公钥,你应该重新加密你的秘密:
$ agenix --rekey
要重新加密一个秘密,你必须能够解密它。由于 age
加密算法中的随机性,即使身份没有改变,文件在重新加密时也总是会发生变化。(这最终可以通过从 age 文件中读取身份来改进。)
agenix 命令行界面默认使用 age
作为其 age 实现,你可以使用 Flakes 来使用 rage
实现,如下所示:
{pkgs,agenix,...}:{ environment.systemPackages = [ (agenix.packages.x86_64-linux.default.override { ageBin = "${pkgs.rage}/bin/rage"; }) ]; }
支持和开发讨论可以在 GitHub 上进行,也可以通过 Matrix 进行。
本项目尚未经过安全专业人员的审核。
不熟悉 age
的人可能会惊讶地发现秘密没有经过身份验证。这意味着每个拥有秘密文件写入权限的攻击者都可以修改秘密,因为公钥是公开的。这乍看之下似乎不是问题,因为更改配置本身就可以轻易暴露秘密。然而,审查配置更改比审查随机秘密(例如,4096 位 RSA 密钥)更容易。这个问题可以通过使用消息认证码(MAC)来解决,就像其他实现(如 GPG 或 sops)那样,但为了简单起见,age
中省略了这一功能。
此外,你应该只加密那些在未来被解密时你能够使其失效的秘密,并准备定期轮换它们,因为 age 在 2024 年 6 月 19 日之前不是后量子安全的。因此,如果威胁行为者可以访问你加密的密钥(例如通过在公共仓库中使用),他们可以利用现在收集,以后解密的策略来存储你的密钥,以便日后解密,包括发现重大漏洞导致秘密暴露的情况。详情请参见 https://github.com/FiloSottile/age/issues/578。
nix fmt
来格式化 nix 代码你可以使用以下命令运行测试:
nix flake check
你可以以交互模式运行集成测试,如下所示:
nix run .#checks.x86_64-linux.integration.driverInteractive
启动后,输入 run_tests()
来运行测试。
本项目基于 Mic92 创建的 sops-nix。感谢 Mic92 的灵感和建议。
AI辅助编程,代码自动修复
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。
AI小说写作助手,一站式润色、改写、扩写
蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。
全能AI智能助手,随时解答生活与工作的多样问题
问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。
实时语音翻译/同声传译工具
Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。
一键生成PPT和Word,让学习生活更轻松
讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。
深度推理能力全新升级,全面对标OpenAI o1
科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。
一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型
Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。
AI助力,做PPT更简单!
咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。
选题、配图、成文,一站式创作,让内容运营更高效
讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。
专业的AI公文写作平台,公文写作神器
AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。
最新AI工具、AI资讯
独家AI资源、AI项目落地
微信扫一扫关注公众号