180 lines
6.4 KiB
Text
180 lines
6.4 KiB
Text
|
|
:experimental:
|
|
|
|
[[chap-Defensive_Coding-Tasks-Packaging]]
|
|
=== RPM Packaging
|
|
|
|
This chapter deals with security-related concerns around RPM
|
|
packaging. It has to be read in conjunction with
|
|
distribution-specific packaging guidelines.
|
|
|
|
[[sect-Defensive_Coding-Tasks-Packaging-Certificates]]
|
|
==== Generating X.509 Self-signed Certificates during
|
|
Installation
|
|
|
|
Some applications need X.509 certificates for authentication
|
|
purposes. For example, a single private/public key pair could
|
|
be used to define cluster membership, enabling authentication
|
|
and encryption of all intra-cluster communication. (Lack of
|
|
certification from a CA matters less in such a context.) For
|
|
such use, generating the key pair at package installation time
|
|
when preparing system images for use in the cluster is
|
|
reasonable. For other use cases, it is necessary to generate
|
|
the key pair before the service is started for the first time,
|
|
see <<sect-Defensive_Coding-Tasks-Packaging-Certificates-Service>>,
|
|
and link:++https://fedoraproject.org/wiki/Packaging:Initial_Service_Setup#Generating_Self-Signed_Certificates++[Packaging:Initial Service Setup].
|
|
|
|
[IMPORTANT]
|
|
====
|
|
|
|
The way the key is generated may not be suitable for key
|
|
material of critical value. ([command]`openssl
|
|
genrsa` uses, but does not require, entropy from a
|
|
physical source of randomness, among other things.) Such keys
|
|
should be stored in a hardware security module if possible,
|
|
and generated from random bits reserved for this purpose
|
|
derived from a non-deterministic physical source.
|
|
|
|
====
|
|
|
|
In the spec file, we define two RPM variables which contain the
|
|
names of the files used to store the private and public key, and
|
|
the user name for the service:
|
|
|
|
[source,bash]
|
|
----
|
|
# Name of the user owning the file with the private key
|
|
%define tlsuser %{name}
|
|
# Name of the directory which contains the key and certificate files
|
|
%define tlsdir %{_sysconfdir}/%{name}
|
|
%define tlskey %{tlsdir}/%{name}.key
|
|
%define tlscert %{tlsdir}/%{name}.crt
|
|
----
|
|
|
|
These variables likely need adjustment based on the needs of the
|
|
package.
|
|
|
|
Typically, the file with the private key needs to be owned by
|
|
the system user which needs to read it,
|
|
`%{tlsuser}` (not `root`). In
|
|
order to avoid races, if the *directory*
|
|
`%{tlsdir}` is *owned by the services
|
|
user*, you should use the code in <<ex-Defensive_Coding-Packaging-Certificates-Owned>>.
|
|
The invocation of [application]*su* with the
|
|
[option]`-s /bin/bash` argument is necessary in case the
|
|
login shell for the user has been disabled.
|
|
|
|
[[ex-Defensive_Coding-Packaging-Certificates-Owned]]
|
|
.Creating a key pair in a user-owned directory
|
|
====
|
|
|
|
[source,bash]
|
|
----
|
|
%post
|
|
if [ $1 -eq 1 ] ; then
|
|
if ! test -e %{tlskey} ; then
|
|
su -s /bin/bash \
|
|
-c "umask 077 && openssl genrsa -out %{tlskey} 2048 2>/dev/null" \
|
|
%{tlsuser}
|
|
fi
|
|
if ! test -e %{tlscert} ; then
|
|
cn="Automatically generated certificate for the %{tlsuser} service"
|
|
req_args="-key %{tlskey} -out %{tlscert} -days 7305 -subj \"/CN=$cn/\""
|
|
su -s /bin/bash \
|
|
-c "openssl req -new -x509 -extensions usr_cert $req_args" \
|
|
%{tlsuser}
|
|
fi
|
|
fi
|
|
|
|
%files
|
|
%dir %attr(0755,%{tlsuser},%{tlsuser]) %{tlsdir}
|
|
%ghost %attr(0600,%{tlsuser},%{tlsuser}) %config(noreplace) %{tlskey}
|
|
%ghost %attr(0644,%{tlsuser},%{tlsuser}) %config(noreplace) %{tlscert}
|
|
----
|
|
|
|
====
|
|
|
|
The files containing the key material are marked as ghost
|
|
configuration files. This ensures that they are tracked in the
|
|
RPM database as associated with the package, but RPM will not
|
|
create them when the package is installed and not verify their
|
|
contents (the `%ghost`), or delete the files
|
|
when the package is uninstalled (the
|
|
`%config(noreplace)` part).
|
|
|
|
If the *directory*
|
|
`%{tlsdir}` *is owned by*
|
|
`root`, use the code in <<ex-Defensive_Coding-Packaging-Certificates-Unowned>>.
|
|
|
|
[[ex-Defensive_Coding-Packaging-Certificates-Unowned]]
|
|
.Creating a key pair in a `root`-owned directory
|
|
====
|
|
|
|
[source,bash]
|
|
----
|
|
%post
|
|
if [ $1 -eq 1 ] ; then
|
|
if ! test -e %{tlskey} ; then
|
|
(umask 077 && openssl genrsa -out %{tlskey} 2048 2>/dev/null)
|
|
chown %{tlsuser} %{tlskey}
|
|
fi
|
|
if ! test -e %{tlscert} ; then
|
|
cn="Automatically generated certificate for the %{tlsuser} service"
|
|
openssl req -new -x509 -extensions usr_cert \
|
|
-key %{tlskey} -out %{tlscert} -days 7305 -subj "/CN=$cn/"
|
|
fi
|
|
fi
|
|
|
|
%files
|
|
%dir %attr(0755,root,root]) %{tlsdir}
|
|
%ghost %attr(0600,%{tlsuser},%{tlsuser}) %config(noreplace) %{tlskey}
|
|
%ghost %attr(0644,root,root) %config(noreplace) %{tlscert}
|
|
----
|
|
|
|
====
|
|
|
|
In order for this to work, the package which generates the keys
|
|
must require the [application]*openssl* package. If
|
|
the user which owns the key file is generated by a different
|
|
package, the package generating the certificate must specify a
|
|
`Requires(pre):` on the package which creates
|
|
the user. This ensures that the user account will exist when it
|
|
is needed for the [application]*su* or
|
|
[application]*chmod* invocation.
|
|
|
|
[[sect-Defensive_Coding-Tasks-Packaging-Certificates-Service]]
|
|
==== Generating X.509 Self-signed Certificates before Service Start
|
|
|
|
An alternative way to automatically provide an X.509 key pair is
|
|
to create it just before the service is started for the first
|
|
time. This ensures that installation images which are created
|
|
from installed RPM packages receive different key material.
|
|
Creating the key pair at package installation time (see <<sect-Defensive_Coding-Tasks-Packaging-Certificates>>)
|
|
would put the key into the image, which may or may not make
|
|
sense.
|
|
|
|
[IMPORTANT]
|
|
====
|
|
|
|
The caveats about the way the key is generated in <<sect-Defensive_Coding-Tasks-Packaging-Certificates>>
|
|
apply to this procedure as well.
|
|
|
|
====
|
|
|
|
Generating key material before service start may happen very
|
|
early during boot, when the kernel randomness pool has not yet
|
|
been initialized. Currently, the only way to check for the
|
|
initialization is to look for the kernel message
|
|
`random: nonblocking pool is initialized`, or
|
|
ensure that the application used for generating the keys
|
|
is utilizing the `getrandom()` system call.
|
|
|
|
In theory, it is also possible to use an application which reads from
|
|
`/dev/random` while generating the key
|
|
material (instead of `/dev/urandom`), but
|
|
this can block not just during the boot process, but also much
|
|
later at run time, and generally results in a poor user
|
|
experience.
|
|
|
|
The requirements for generating such keys is documented at
|
|
link:++https://fedoraproject.org/wiki/Packaging:Initial_Service_Setup#Generating_Self-Signed_Certificates++[Packaging:Initial Service Setup].
|