< Previous | Contents | Next >
10.3.3. Creating a Package Repository for APT
Now that you have a custom package, you can distribute it through an APT package repository. Use reprepro to create the desired repository and to fill it. This tool is rather powerful and its manual page is certainly worth reading.
A package repository is typically hosted on a server. To properly separate it from other services running on the server, it is best to create a user dedicated to this service. In the dedicated user account, you will be able to host the repository files and also the GnuPG key that will be used to sign the package repository:
# apt install reprepro gnupg
[...]
# adduser --system --group pkgrepo
Adding system user ‘pkgrepo’ (UID 136) ... Adding new group ‘pkgrepo’ (GID 142) ...
Adding new user ‘pkgrepo’ (UID 136) with group ‘pkgrepo’ ... Creating home directory ‘/home/pkgrepo’ ...
# chown pkgrepo $(tty)
# su - -s /bin/bash pkgrepo
$ gpg --gen-key
gpg (GnuPG) 2.1.11; Copyright (C) 2016 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gpg: directory ’/home/pkgrepo/.gnupg’ created
gpg: new configuration file ’/home/pkgrepo/.gnupg/dirmngr.conf’ created gpg: new configuration file ’/home/pkgrepo/.gnupg/gpg.conf’ created gpg: keybox ’/home/pkgrepo/.gnupg/pubring.kbx’ created
Note: Use ”gpg --full-gen-key” for a full featured key generation dialog. GnuPG needs to construct a user ID to identify your key.
Real name: Offensive Security Repository Signing Key
Email address: repoadmin@offsec.com
You selected this USER-ID:
”Offensive Security Repository Signing Key <repoadmin@offsec.com>”
# apt install reprepro gnupg
[...]
# adduser --system --group pkgrepo
Adding system user ‘pkgrepo’ (UID 136) ... Adding new group ‘pkgrepo’ (GID 142) ...
Adding new user ‘pkgrepo’ (UID 136) with group ‘pkgrepo’ ... Creating home directory ‘/home/pkgrepo’ ...
# chown pkgrepo $(tty)
# su - -s /bin/bash pkgrepo
$ gpg --gen-key
gpg (GnuPG) 2.1.11; Copyright (C) 2016 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gpg: directory ’/home/pkgrepo/.gnupg’ created
gpg: new configuration file ’/home/pkgrepo/.gnupg/dirmngr.conf’ created gpg: new configuration file ’/home/pkgrepo/.gnupg/gpg.conf’ created gpg: keybox ’/home/pkgrepo/.gnupg/pubring.kbx’ created
Note: Use ”gpg --full-gen-key” for a full featured key generation dialog. GnuPG needs to construct a user ID to identify your key.
Real name: Offensive Security Repository Signing Key
Email address: repoadmin@offsec.com
You selected this USER-ID:
”Offensive Security Repository Signing Key <repoadmin@offsec.com>”
Change (N)ame, (E)mail, or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy.
[...]
gpg: /home/pkgrepo/.gnupg/trustdb.gpg: trustdb created gpg: key B4EF2D0D marked as ultimately trusted
gpg: directory ’/home/pkgrepo/.gnupg/openpgp-revocs.d’ created
gpg: revocation certificate stored as ’/home/pkgrepo/.gnupg/openpgp-revocs.d/
➥ F8FE22F74F1B714E38DA6181B27F74F7B4EF2D0D.rev’
public and secret key created and signed.
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: PGP
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u pub rsa2048/B4EF2D0D 2016-06-17 [S]
Key fingerprint = F8FE 22F7 4F1B 714E 38DA 6181 B27F 74F7 B4EF 2D0D
uid [ultimate] Offensive Security Repository Signing Key <repoadmin@offsec.com> sub rsa2048/38035F38 2016-06-17 []
Change (N)ame, (E)mail, or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy.
[...]
gpg: /home/pkgrepo/.gnupg/trustdb.gpg: trustdb created gpg: key B4EF2D0D marked as ultimately trusted
gpg: directory ’/home/pkgrepo/.gnupg/openpgp-revocs.d’ created
gpg: revocation certificate stored as ’/home/pkgrepo/.gnupg/openpgp-revocs.d/
➥ F8FE22F74F1B714E38DA6181B27F74F7B4EF2D0D.rev’
public and secret key created and signed.
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: PGP
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u pub rsa2048/B4EF2D0D 2016-06-17 [S]
Key fingerprint = F8FE 22F7 4F1B 714E 38DA 6181 B27F 74F7 B4EF 2D0D
uid [ultimate] Offensive Security Repository Signing Key <repoadmin@offsec.com> sub rsa2048/38035F38 2016-06-17 []
Note that when you are prompted for a passphrase, you should enter an empty value (and confirm that you don’t want to protect your private key) as you want to be able to sign the repository non- interactively. Note also that gpg requires write access to the terminal to be able to securely prompt for a passphrase: that is why you changed the ownership of the virtual terminal (which is owned by root since you initially connected as that user) before starting a shell as pkgrepo.
Now you can start setting up the repository. A dedicated directory is necessary for reprepro and inside that directory you have to create a conf/distributions file documenting which distribu- tions are available in the package repository:
$ mkdir -p reprepro/conf
$ cd reprepro
$ cat >conf/distributions <<END Codename: offsec-internal AlsoAcceptFor: unstable
Origin: Offensive Security
Description: Offsec’s Internal packages Architectures: source amd64 i386 Components: main
SignWith: F8FE22F74F1B714E38DA6181B27F74F7B4EF2D0D END
$ mkdir -p reprepro/conf
$ cd reprepro
$ cat >conf/distributions <<END Codename: offsec-internal AlsoAcceptFor: unstable
Origin: Offensive Security
Description: Offsec’s Internal packages Architectures: source amd64 i386 Components: main
SignWith: F8FE22F74F1B714E38DA6181B27F74F7B4EF2D0D END
The required fields are Codename, which gives the name of the distribution, Architectures, which indicates which architectures will be available in the distribution (and accepted on the input side), and Components, which indicates the various components available in the distribution (com-
ponents are a sort of sub-section of the distribution, which can be enabled separately in APT’s sources.list). The Origin and Description fields are purely informative and they are copied as-is in the Release file. The SignWith field asks reprepro to sign the repository with the GnuPG key whose identifier is listed (put the full fingerprint here to ensure you use the correct key, and not another one colliding on the short identifier). The AlsoAcceptFor setting is not required but makes it possible to process .changes files whose Distribution field has a value listed here (without this, it would only accept the distribution’s codename in that field).
With this basic setup in place, you can let reprepro generate an empty repository:
$ reprepro export
Exporting indices...
$ find .
.
./db
./db/version
./db/references.db
./db/contents.cache.db
./db/checksums.db
./db/packages.db
./db/release.caches.db
./conf
./conf/distributions
./dists
./dists/offsec-internal
./dists/offsec-internal/Release.gpg
./dists/offsec-internal/Release
./dists/offsec-internal/main
./dists/offsec-internal/main/source
./dists/offsec-internal/main/source/Release
./dists/offsec-internal/main/source/Sources.gz
./dists/offsec-internal/main/binary-amd64
./dists/offsec-internal/main/binary-amd64/Packages
./dists/offsec-internal/main/binary-amd64/Release
./dists/offsec-internal/main/binary-amd64/Packages.gz
./dists/offsec-internal/main/binary-i386
./dists/offsec-internal/main/binary-i386/Packages
./dists/offsec-internal/main/binary-i386/Release
./dists/offsec-internal/main/binary-i386/Packages.gz
./dists/offsec-internal/InRelease
$ reprepro export
Exporting indices...
$ find .
.
./db
./db/version
./db/references.db
./db/contents.cache.db
./db/checksums.db
./db/packages.db
./db/release.caches.db
./conf
./conf/distributions
./dists
./dists/offsec-internal
./dists/offsec-internal/Release.gpg
./dists/offsec-internal/Release
./dists/offsec-internal/main
./dists/offsec-internal/main/source
./dists/offsec-internal/main/source/Release
./dists/offsec-internal/main/source/Sources.gz
./dists/offsec-internal/main/binary-amd64
./dists/offsec-internal/main/binary-amd64/Packages
./dists/offsec-internal/main/binary-amd64/Release
./dists/offsec-internal/main/binary-amd64/Packages.gz
./dists/offsec-internal/main/binary-i386
./dists/offsec-internal/main/binary-i386/Packages
./dists/offsec-internal/main/binary-i386/Release
./dists/offsec-internal/main/binary-i386/Packages.gz
./dists/offsec-internal/InRelease
As you can see, reprepro created the repository meta-information in a dists sub-directory. It also initialized an internal database in a db sub-directory.
It is now time to add your first package. First, copy the files generated by the build of the offsec- defaults package (offsec-defaults_1.0.dsc, offsec-defaults_1.0.tar.xz,
offsec-defaults_1.0_all.deb, and offsec-defaults_1.0_amd64.changes) into /tmp
on the server hosting the package repository and ask reprepro to include the package:
$ reprepro include offsec-internal /tmp/offsec-defaults_1.0_amd64.changes
Exporting indices...
$ find pool pool pool/main pool/main/o
pool/main/o/offsec-defaults
pool/main/o/offsec-defaults/offsec-defaults_1.0.dsc pool/main/o/offsec-defaults/offsec-defaults_1.0.tar.xz pool/main/o/offsec-defaults/offsec-defaults_1.0_all.deb
$ reprepro include offsec-internal /tmp/offsec-defaults_1.0_amd64.changes
Exporting indices...
$ find pool pool pool/main pool/main/o
pool/main/o/offsec-defaults
pool/main/o/offsec-defaults/offsec-defaults_1.0.dsc pool/main/o/offsec-defaults/offsec-defaults_1.0.tar.xz pool/main/o/offsec-defaults/offsec-defaults_1.0_all.deb
As you can see, it added the files into its own package pool in a pool sub-directory.
The dists and pool directories are the two directories that you need to make (publicly) available over HTTP to finish the setup of your APT repository. They contain all the files that APT will want to download.
Assuming that you want to host this on a virtual host named pkgrepo.offsec.com, you could cre- ate the following Apache configuration file, save it to /etc/apache2/sites-available/pkgrepo. offsec.com.conf, and enable it with a2ensite pkgrepo.offsec.com):
<VirtualHost *:80>
ServerName pkgrepo.offsec.com ServerAdmin repoadmin@offsec.com
ErrorLog /var/log/apache2/pkgrepo.offsec.com-error.log
CustomLog /var/log/apache2/pkgrepo.offsec.com-access.log ”%h %l %u %t \”%r\” %>s %O” DocumentRoot /home/pkgrepo/reprepro
<Directory ”/home/pkgrepo/reprepro”>
Options Indexes FollowSymLinks MultiViews Require all granted
AllowOverride All
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName pkgrepo.offsec.com ServerAdmin repoadmin@offsec.com
ErrorLog /var/log/apache2/pkgrepo.offsec.com-error.log
CustomLog /var/log/apache2/pkgrepo.offsec.com-access.log ”%h %l %u %t \”%r\” %>s %O” DocumentRoot /home/pkgrepo/reprepro
<Directory ”/home/pkgrepo/reprepro”>
Options Indexes FollowSymLinks MultiViews Require all granted
AllowOverride All
</Directory>
</VirtualHost>
And the corresponding sources.list entry to add on machines that need packages from this repository would look like this:
deb http://pkgrepo.offsec.com offsec-internal main
# Enable next line if you want access to source packages too
# deb-src http://pkgrepo.offsec.com offsec-internal main
deb http://pkgrepo.offsec.com offsec-internal main
# Enable next line if you want access to source packages too
# deb-src http://pkgrepo.offsec.com offsec-internal main
Your package is now published and should be available to your networked hosts.
Although this has been a lengthy setup, the “heavy lifting” is now completed. You can boot your networked machines via PXE, install a customized version of Kali Linux without interaction thanks to a network-delivered preseed, configure SaltStack to manage your configurations (and control minions!), create forked custom packages, and distribute those packages through your own pack- age repository. This provides centralized management and enterprise-level control over multiple Kali Linux installations. In short, you can now quickly deploy highly secure Kali systems precon- figured for your specific needs and keep them synchronized thanks to Kali’s (semi-automatic) in- stallation of all package updates.