如何在 Ubuntu 14.04 上使用 Reprepro 创建安全软件包仓库

介绍包和存储库

我们都去过那里 - 需要一个程序 - 和我们做什么?我们大多数人只是 apt-get安装postfix和 presto! 我们神奇地安装了Postfix。

虽然这不是真正的魔法,但是. apt-get 包管理器为您搜索,下载和安装该包. 这非常方便,但如果 apt-get 无法在其标准库列表中找到所需的程序? 幸运的是, apt-get 允许用户指定自定义下载位置(称为库)。

在本教程中,我们将通过设置自己的安全存储库并使其公开用于其他人使用,我们将在Ubuntu 14.04 LTS Droplet上创建存储库,并测试来自同一分布的另一个Droplet的下载。

要充分利用本指南,请查看我们的教程 管理 apt-get 的包

前提条件

两个 Ubuntu 14.04 LTS片段

在指南结束时,你将有:

  • 准备并发布了存储库签名密钥
  • 使用 Reprepro 设置一个存储库,存储库管理器
  • 使用 Web 服务器 Nginx 使存储库公开 * 在另一台服务器上添加了存储库

准备和发布一个签名密钥

首先,我们需要一个有效的包签名密钥. 此步骤对于一个安全的存储库至关重要,因为我们将数字签名所有包。

在本节中,您将通过以下步骤生成加密的主公共密钥和签名子密钥:

  • 生成主密钥
  • 生成包签名子密钥
  • 分离主密钥从主密钥

创建一个主密钥

这个密钥应该保持安全和安全,因为这就是人们会信任的。

在我们开始之前,让我们安装 rng-tools 虽然 apt-get:

1apt-get install rng-tools

GPG 需要随机数据,称为 entropi,以生成键。 Entropy 通常是由 Linux 内核随着时间的推移而生成的,并存储在一个池中。然而,在云服务器(如 Droplets)上,内核可能会遇到问题来生成 GPG 所需的 Entropy 量。 为了帮助内核,我们安装了 rngd 程序(在 rng-tools 包中找到)。 这个程序会要求主机服务器(在那里 Droplets 位居)进行 Entropy。 一旦获取,‘rngd’ 会将数据添加到 Entropy 池中,用于其他应用,如 GPG。

如果你收到這樣的訊息:

1Trying to create /dev/hwrng device inode...
2Starting Hardware RNG entropy gatherer daemon: (failed).
3invoke-rc.d: initscript rng-tools, action "start" failed.

手动启动 rngd daemon:

1rngd -r /dev/urandom

默认情况下,rngd 正在寻找一个特殊的设备来从 /dev/hwrng 获取体。 一些 Droplets 没有这个设备。 为了补偿,我们使用假冒随机设备 /dev/urandom 通过指定 -r 指令。 有关更多信息,您可以查看我们的教程: 如何设置额外体

现在我们有一个池,我们可以生成主密钥. 这样做是通过召唤 gpg 命令. 你会看到一个类似于以下的提示:

1gpg --gen-key
 1gpg (GnuPG) 1.4.16; Copyright (C) 2013 Free Software Foundation, Inc.
 2This is free software: you are free to change and redistribute it.
 3There is NO WARRANTY, to the extent permitted by law.
 4
 5Please select what kind of key you want:
 6   (1) RSA and RSA (default)
 7   (2) DSA and Elgamal
 8   (3) DSA (sign only)
 9   (4) RSA (sign only)
10Your selection? 1

指定第一个选项,RSA和RSA(默认)``1,在提示中。选择此将有 gpg首先生成一个签名密钥,然后是加密子密钥(使用RSA算法)。

点击Enter,你将被提示为一个键大小:

1RSA keys may be between 1024 and 4096 bits long.
2What keysize do you want? (2048) 4096

密钥大小与您想要主密钥的安全性直接相关。比特大小越高,密钥的安全性越大。 Debian 项目建议使用 4096 位的任何签名密钥,所以我会在这里指定 4096 位。

按 Enter 以获取 expire prompt。

1Please specify how long the key should be valid.
2         0 = key does not expire
3      <n>  = key expires in n days
4      <n>w = key expires in n weeks
5      <n>m = key expires in n months
6      <n>y = key expires in n years
7Key is valid for? (0) 0

主密钥通常没有到期日期,但将此值设置为您预期使用此密钥的时间。

您将被要求生成一个用户ID,这些信息将被其他人和您自己用来识别这个密钥 - 因此使用真实的信息!

 1You need a user ID to identify your key; the software constructs the user ID
 2from the Real Name, Comment and Email Address in this form:
 3    "Heinrich Heine (Der Dichter) <[email protected]>"
 4
 5Real name: Mark Lopez
 6Email address: mark.lopez@example.com
 7Comment: 
 8You selected this USER-ID:
 9    "Mark Lopez <[email protected]>"
10
11Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o

如果信息是正确的,点击O和Enter,我们需要添加密码,以确保只有您可以访问这个密钥,请确保 记住这个密码,因为没有办法恢复gpg密码(一件好事)。

1You need a Passphrase to protect your secret key.
2
3Enter passphrase: (hidden)
4Repeat passphrase: (hidden)

现在一些魔法(数学)会发生,这可能需要一段时间,所以坐下来或喝一杯你最喜欢的饮料。

 1We need to generate a lot of random bytes. It is a good idea to perform
 2some other action (type on the keyboard, move the mouse, utilize the
 3disks) during the prime generation; this gives the random number
 4generator a better chance to gain enough entropy.
 5
 6Not enough random bytes available. Please do some other work to give
 7the OS a chance to collect more entropy! (Need 300 more bytes)
 8+++++
 9................+++++
10We need to generate a lot of random bytes. It is a good idea to perform
11some other action (type on the keyboard, move the mouse, utilize the
12disks) during the prime generation; this gives the random number
13generator a better chance to gain enough entropy.
14..+++++
15+++++
16gpg: /root/.gnupg/trustdb.gpg: trustdb created
17gpg: key 10E6133F marked as ultimately trusted
18public and secret key created and signed.
19
20gpg: checking the trustdb
21gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
22gpg: depth: 0 valid:   1 signed:   0 trust: 0-, 0q, 0n, 0m, 0f, 1u
23pub 4096R/10E6133F 2014-08-16
24      Key fingerprint = 1CD3 22ED 54B8 694A 0975 7164 6C1D 28A0 10E6 133F
25uid Mark Lopez <[email protected]>
26sub 4096R/7B34E07C 2014-08-16

现在我们有一个主密钥. 输出显示,我们创建了一个主密钥来签名(`0E6133F在上面 pub 行)。 你的密钥将有不同的ID。 请注意你的签名密钥的ID(示例使用10E6133F)。

生成包签名的子密钥

现在我们将创建第二个签名密钥,以便我们在这个服务器上不需要主密钥。 把主密钥当作赋予子密钥权限的根权威。

在终端执行:

「gpg --edit-key 10E6133F」

代替示例 ID 以您的密钥 ID. 此命令将我们输入 gpg 环境. 在这里,我们可以编辑我们的新密钥并添加子密钥. 你会看到以下输出:

 1gpg (GnuPG) 1.4.16; Copyright (C) 2013 Free Software Foundation, Inc.
 2This is free software: you are free to change and redistribute it.
 3There is NO WARRANTY, to the extent permitted by law.
 4
 5Secret key is available.
 6
 7pub 4096R/10E6133F created: 2014-08-16 expires: never usage: SC
 8                     trust: ultimate validity: ultimate
 9sub 4096R/7B34E07C created: 2014-08-16 expires: never usage: E
10[ultimate] (1). Mark Lopez <[email protected]>
11
12gpg>

addkey键入:

1addkey

点击 Enter. GPG 将提示您的密码. 输入您用来加密此密钥的密码。

1Key is protected.
2
3You need a passphrase to unlock the secret key for
4user: "Mark Lopez <[email protected]>"
54096-bit RSA key, ID 10E6133F, created 2014-08-16
6
7gpg: gpg-agent is not available in this session
8Enter passphrase: <hidden>

您将看到以下键类型提示。

1Please select what kind of key you want:
2   (3) DSA (sign only)
3   (4) RSA (sign only)
4   (5) Elgamal (encrypt only)
5   (6) RSA (encrypt only)
6Your selection? 4

我们想创建一个 signing 子密钥,所以选择RSA (仅签名) 4. RSA 对于客户端来说更快,而 DSA 对于服务器来说更快。

我们再次被提示为一个关键尺寸。

1RSA keys may be between 1024 and 4096 bits long.
2What keysize do you want? (2048) 4096

此教程使用 4096 以增加安全性。

1Please specify how long the key should be valid.
2         0 = key does not expire
3      <n>  = key expires in n days
4      <n>w = key expires in n weeks
5      <n>m = key expires in n months
6      <n>y = key expires in n years
7Key is valid for? (0) 1y

我们已经有一个主密钥,所以子密钥的到期时间不那么重要,一年是一个很好的时间框架。

点击 Enter,然后键入 y (是) 两次为下一个两个提示. 一些数学将产生另一个密钥。

 1We need to generate a lot of random bytes. It is a good idea to perform
 2some other action (type on the keyboard, move the mouse, utilize the
 3disks) during the prime generation; this gives the random number
 4generator a better chance to gain enough entropy.
 5............+++++
 6.+++++
 7
 8pub 4096R/10E6133F created: 2014-08-16 expires: never usage: SC
 9                     trust: ultimate validity: ultimate
10sub 4096R/7B34E07C created: 2014-08-16 expires: never usage: E
11sub 4096R/A72DB3EF created: 2014-08-16 expires: 2015-08-16 usage: S
12[ultimate] (1). Mark Lopez <[email protected]>
13
14gpg>

以快速节约为类型。

1save

在上面的输出中,我们的主密钥的SC告诉我们,密钥仅用于签名和认证。E意味着密钥只能用于加密。

记住你的新签名密钥的ID(示例表明A72DB3EF在上面的第二个子行)。

输入保存以返回终端并保存您的新密钥。

1save

Detach 主键从 Subkey 中获取

创建子密钥的重点是,我们不需要主密钥在我们的服务器上,这使得它更安全。现在我们将将我们的主密钥从我们的子密钥中分离出来。

首先,让我们使用 --export-secret-key 和 --export 命令来导出整个密钥。

1gpg --export-secret-key 10E6133F > private.key
2gpg --export 10E6133F >> private.key

默认情况下, --export-secret-key 和 --export 将打印到我们的控制台的密钥,所以我们会将输出导向一个新的文件(private.key)。

**重要:将 private.key 文件复制到安全的地方(不是在服务器上)。 可能的位置是在闪存磁盘或 USB 驱动器上. 此文件包含您的私钥、公共钥匙、加密子钥和签名子钥匙。

** 将此文件备份到安全位置后,** 删除该文件:

1#back up the private.key file before running this# rm private.key

请确保更改标识符以匹配您生成的主密钥和第二个子密钥(不要使用第一个子密钥)。

1gpg --export 10E6133F > public.key
2gpg --export-secret-subkeys A72DB3EF > signing.key

现在我们有我们的密钥的备份,我们可以从我们的服务器中删除我们的主密钥。

1gpg --delete-secret-key 10E6133F

只重新导入我们的签名子密钥。

1gpg --import public.key signing.key

检查我们不再在我们的服务器上拥有主密钥:

1gpg --list-secret-keys
1sec#  4096R/10E6133F 2014-08-16
2uid Mark Lopez <[email protected]>
3ssb 4096R/7B34E07C 2014-08-16
4ssb 4096R/A72DB3EF 2014-08-16

注意 **#**在 sec之后,这意味着我们的主密钥没有安装,服务器只包含我们的签名子密钥。

清理你的钥匙:

1rm public.key signing.key

你需要做的最后一件事是发布你的签名密钥。

1gpg --keyserver keyserver.ubuntu.com --send-key 10E6133F

这个命令将你的密钥发布到一个公共的密钥存储库 - 在这种情况下是Ubuntu自己的密钥服务器,这允许其他人下载你的密钥并轻松验证你的包。

创建使用 Reprepro 的存储库

现在让我们来谈谈这个教程:创建一个 apt-get 存储库. Apt-get 存储库不是最容易管理的事情. 幸运的是,R. Bernhard(https://packages.qa.debian.org/r/reprepro.html)创建了 Reprepro,他曾经生产、管理和同步 Debian 包的本地存储库(也称为 Mirrorer)。

安装和配置 Reprepro

Reprepro 可以从默认的 Ubuntu 存储库中安装。

1apt-get update
2apt-get install reprepro

Reprepro 的配置是 repository 特定的,这意味着如果您创建多个 repositories,您可以有不同的配置。

为此存储库创建一个专用文件夹并移动到它。

1mkdir -p /var/repositories/
2cd /var/repositories/

创建配置目录。

1mkdir conf
2cd conf/

创建两个空的配置文件(选项和分布)。

1touch options distributions

在您最喜欢的文本编辑器中打开选项文件(Nano是默认安装的)。

1nano options

此文件包含 Reprepro 的选项,每次 Reprepro 运行时都会读到。

在您的文本编辑器中,添加以下内容。

1ask-passphrase

如果我们不将此添加到选项中,如果我们的密钥被加密(它是)。

Ctrl + x 然后 y 和 Enter 将保存我们的更改并返回控制台。

打开分布式文件。

1nano distributions

这个文件有四个必要的指令. 将这些添加到文件中。

1Codename: trusty
2Components: main
3Architectures: i386 amd64
4SignWith: A72DB3EF

代码名称指令直接与发布的 Debian 发行版的代码名称有关,并且是必需的。这是将下载包的发行版的代码名称,并且不一定与该服务器的发行版相匹配。例如,Ubuntu 14.04 LTS 发行版被称为 trusty,Ubuntu 12.04 LTS 被称为 precise,而 Debian 7.6 被称为 wheezy

Components 字段是必需的,这只是一个简单的存储库,所以在这里设置main。还有其他名称空间,如non−freecontrib – 请参阅 apt-get 以获取适当的命名方案。

Architectures 是另一个需要的字段. 此字段列出了此存储库中的二进制架构,分隔为空间。 此存储库将为 32 位和 64 位服务器托管包,所以 i386 amd64 设置在这里。

要指定其他计算机将如何验证我们的包,我们使用 SignWith 指令. 这是一个可选的指令,但需要签名。 在本示例中早些时候的签名密钥具有 ID A72DB3EF,所以它在这里设置。

使用 Ctrl + `x 保存和退出文件,然后 y 和 Enter。

您现在已经为 Reprepro 设置了所需的结构。

添加一个带 Reprepro 的包

首先,让我们将目录更改为临时位置。

1mkdir -p /tmp/debs
2cd /tmp/debs

我们需要一些示例包来工作 - wget他们与:

1wget https://github.com/Silvenga/examples/raw/master/example-helloworld_1.0.0.0_amd64.deb
2wget https://github.com/Silvenga/examples/raw/master/example-helloworld_1.0.0.0_i386.deb

这些包是纯粹为本指南而制作的,并包含一个简单的bash脚本来证明我们的存储库的功能。

运行程序ls应该给我们这个布局:

1ls
1example-helloworld_1.0.0.0_amd64.deb example-helloworld_1.0.0.0_i386.deb

我们现在有两个示例包:一个用于32位(i386)计算机,另一个用于64位(amd64)计算机。

1reprepro -b /var/repositories includedeb trusty example-helloworld_1.0.0.0_*

-b 参数指定了存储库的(b)ase目录.包括eb 命令需要两个参数 - <分布代码名称 > 和 < 文件路径(s) >

1Exporting indices...
2C3D099E3A72DB3EF Mark Lopez <[email protected]> needs a passphrase
3Please enter passphrase: < hidden >
4C3D099E3A72DB3EF Mark Lopez <[email protected]> needs a passphrase
5Please enter passphrase: < hidden >

成功!

列出和删除

我们可以列出管理的包以列表命令,然后是代码名称。

1reprepro -b /var/repositories/ list trusty
2
3trusty|main|i386: example-helloworld 1.0.0.0
4trusty|main|amd64: example-helloworld 1.0.0.0

要删除一个包,请使用删除命令. 删除命令需要包的代码名称和包名称。

1reprepro -b /var/repositories/ remove trusty example-helloworld

让库存公开

接下来,我们将安装 Nginx 作为 Web 服务器,以使此库公开。

安装 Nginx

1apt-get update
2apt-get install nginx

Nginx 安装了默认示例配置,以便在其他时间查看该文件。

1mv /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak
2touch /etc/nginx/sites-available/default

现在我们有一个空的配置文件,我们可以开始配置我们的 Nginx 服务器来托管我们的新的存储库。

使用您最喜欢的文本编辑器打开配置文件。

1nano /etc/nginx/sites-available/default

并添加以下配置指令:

 1server {
 2
 3    ## Let your repository be the root directory
 4    root		/var/repositories;
 5    
 6    ## Always good to log
 7    access_log 	/var/log/nginx/repo.access.log;
 8    error_log 	/var/log/nginx/repo.error.log;
 9
10    ## Prevent access to Reprepro's files
11    location ~ /(db|conf) {
12    	deny 		all;
13    	return 		404;
14    }
15}

Nginx 有一些很好的默认功能,我们需要配置的只是根目录,同时拒绝访问 Reprepro 的文件。

重新启动 Nginx 服务以加载这些新配置。

1service nginx restart

您的公共Ubuntu存储库已准备好使用!

您需要您的 Droplet 的 IP 地址,以便用户知道存储库的位置. 如果您不知道您的 Droplet 的公共地址,您可以使用 ifconfig 找到它。

1ifconfig eth0
1eth0 Link encap:Ethernet HWaddr 04:01:23:f9:0e:01
2          inet addr:198.199.114.168 Bcast:198.199.114.255 Mask:255.255.255.0
3          inet6 addr: fe80::601:23ff:fef9:e01/64 Scope:Link
4          UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
5          RX packets:16555 errors:0 dropped:0 overruns:0 frame:0
6          TX packets:16815 errors:0 dropped:0 overruns:0 carrier:0
7          collisions:0 txqueuelen:1000
8          RX bytes:7788170 (7.7 MB)  TX bytes:3058446 (3.0 MB)

在上面的示例中,服务器的地址是198.199.114.168。

使用您的 Reprepro 服务器的 IP 地址,您现在可以将此存储库添加到任何其他适当的服务器中。

从我们的新仓库中安装一个包

如果你还没有,请用Ubuntu 14.04 LTS创建另一个Droplet,这样你就可以从新的存储库中进行测试安装。

在新服务器上,下载您的公共密钥来验证您的存储库中的软件包. 请记住,您已将密钥发布到 keyserver.ubuntu.com。

这是用 apt-key 命令完成的。

1apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 10E6133F

这个命令下载了指定的密钥并将密钥添加到 apt-get 数据库中。 adv 命令告诉 apt-key 使用 GPG 来下载密钥. 其他两个参数被直接传递到 GPG。 自从您将密钥上传到 keyserver.ubuntu.com 之后,使用 --keyserver keyserver.ubuntu.com 指令将密钥从同一个位置转移。

现在为 apt-get 添加存储库的地址来查找,您将需要从上一步获取存储库服务器的 IP 地址。

1add-apt-repository "deb http://198.199.114.168/ trusty main"

请注意我们给 add-apt 存储库的字符串,大多数 Debian 存储库可以用以下一般格式添加:

1deb (repository location) (current distribution code name)  (the components name)

我们有一个 HTTP 服务器,所以协议是 http://. 示例的位置是 198.199.114.168. 我们的服务器的代码名称是 trusty. 这是一个简单的存储库,所以我们称该组件为

添加库后,请确保运行 apt-get 更新. 此命令将检查所有已知库的更新和更改(包括您刚刚做的库)。

1apt-get update

更新 apt-get 后,您现在可以从存储库中安装示例包。

1apt-get install example-helloworld

如果一切顺利,你现在可以执行例子 - helloworld 并看到:

1Hello, World!
2This package was successfully installed!

恭喜您!您刚刚从您创建的存储库中安装了一个软件包!

若要移除示例包,请运行此命令:

1apt-get remove example-helloworld

这将删除您刚刚安装的示例包。

结论

在本指南中,你开始创建一个安全的APT存储库,你已经学会了如何创建一个安全的密钥来签署包;如何使用Reprepro创建和管理一个存储库;以及如何将这个存储库添加到另一个服务器上。

Published At
Categories with 技术
comments powered by Disqus