Wednesday, April 1, 2015

Build packages in poudriere without OpenSSL in the base jail


Goals: Use poudriere to build clean packages which are guaranteed to not depend on openssl from base (by forcing it to be missing).  Provide details on what I encountered and how I worked around it to save other people time if they wish to continue on my path.  Encourage discussion about why these steps are needed in the first place and what can/will be done to properly solve some. 

This procedure is not meant as a full guide to using poudriere or a full guide to using libressl in ports.  It mentions many steps towards setting up poudriere but doesn't make an effort to entirely integrate with any poudriere set up you may already have.  I'm leaving that up to you.  This procedure is also not about creating a running system without openssl in base, but just a build jail for packages.

This procedure is mostly for people who already know how to setup poudriere and for people who already know how to make ports use libressl, but wish to ensure poudriere packages are not compiled against openssl from base.  It will leverage existing knowledge of poudriere and experience patching local ports for libressl compat where needed.  See Bernard's excellent work at https://wiki.freebsd.org/LibreSSL

This procedure is based on FreeBSD 10.1-RELEASE source code as a common reference point for compile options and patches, although newer builds can be used with less workarounds (noted below where known).

I cannot guarantee you will get perfect results with the ports you decide to package with this procedure.  I had to patch a few myself, and avoid some others like the EXAMPLES option of ldns, or ldns as a dep of openssh-portable.  The primary purpose is to make sure all built packages (except pkg itself) do not depend on openssl from base.  The secondary purpose is to expose some (but not all) ports that ideally need fixes to honor WITH_OPENSSL_PORT=yes properly.  The fact that a port compiles is not good enough because I've found packages resulting in things like this:

root@cacti:~ # lsof | grep libssl
httpd   22748    root  txt     VREG     186,2270822501             393456 249397 /usr/local/lib/libssl.so.30.0.0
httpd   22748    root  txt     VREG     186,2270822501             438864 224016 /usr/lib/libssl.so.7
httpd   22749     www  txt     VREG     186,2270822501             393456 249397 /usr/local/lib/libssl.so.30.0.0
httpd   22749     www  txt     VREG     186,2270822501             438864 224016 /usr/lib/libssl.so.7

Worse yet, my Apache 2.2 would crash at start.

Some of this is surely caused by net-mgmt/net-snmp trying to use openssl from base, then getting pulled in to apache through php.

This procedure should also be applicable to using openssl from ports, although I worked with libressl here.  Just remove OPENSSL_PORT= security/libressl from 10amd64-nossl-make.conf.

I am using the result for production packages on my systems.  Some of the steps may have to be manually redone like compiling pkg when a new version comes out.  Some of the other alterations I hope can be fixed in ports or the source tree so less workarounds are required.




Install poudriere if it isn't:
pkg install poudriere

Now we need to build a custom poudriere jail without openssl in base.  It is not yet as simple as WITHOUT_OPENSSL=yes, but as FreeBSD improves compilation options, this will get easier in the future.  I started with WITHOUT_OPENSSL=yes and made several iterations finding out which components to disable and how.  Most of them do not affect package building at all, such as iSCSI support in the package building jail.  Compiling libfetch without SSL support DOES affect poudriere somewhat since it uses fetch from inside the jail and won't be able to reach any https-only mirrors.  Fortunately many distfiles are still available without SSL.  If I run into a https-only distfile, I might just fetch it manually from outside the jail, but eventually fetch will need a workaround or a replacement in this setup.


Put these in /usr/local/etc/poudriere.d/10amd64-nossl-src.conf
to enable compile options for our build jail in poudriere:

# WITHOUT_OPENSSL=yes automatically causes a number of
# buildworld components to compile without SSL support
# or skip compiling at all.
WITHOUT_OPENSSL=yes
#
# Disable other things that will not presently compile
# with WITHOUT_OPENSSL=yes. The need to do this in
# addition to WITHOUT_OPENSSL=yes can be considered a bug.
WITHOUT_LDNS=yes
WITHOUT_LDNS_UTILS=yes
WITHOUT_PKGBOOTSTRAP=yes
WITHOUT_SVNLITE=yes
# 10.1-RELEASE needs this, newer builds don't such as r276751
WITHOUT_BSNMP=yes

# libfetch mostly supports WITHOUT_OPENSSL=yes but
# there is a small bug encountered when compiling it.
# This is handled as part of buildworld-nossl.diff.
# See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=191951

# We still want to compile libfetch because pkg
# requires it and fetch uses it. Our resulting
# fetch and libfetch will not support SSL, but
# maybe poudriere can use something else instead
# of fetch for getting distfiles from https:// sites.

# When the below options exist, hopefully they are
# automatically conditional on WITHOUT_OPENSSL=yes.
# If not, that is a bug.

# WITHOUT_BSDINSTALL exists in 10-STABLE as of
# 20150213 r278713 but this is after 10.1-RELEASE.
# We'll patch usr.sbin/Makefile instead for now.
#
# WITHOUT_CTLD=yes does not exist yet in any version
# as of 20150324. We'll patch usr.sbin/Makefile instead
# for now.
#
# WITHOUT_ISCSI exists in 10-STABLE as of
# 20150211 r278555 but this is after 10.1-RELEASE.
# We'll patch usr.sbin/Makefile instead for now.


Some of the above options are not sufficient to complete buildworld. Below we'll use /root/buildworld-nossl.diff to patch a bug in libfetch when built with WITHOUT_OPENSSL=yes, and manually disable bsdinstall, ctld, iscsi as noted above. See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=191951 for the libfetch bug:



Fetch some patches we'll need:
cd /root
fetch http://www.egr.msu.edu/~mcdouga9/nossl-patches/buildworld-nossl.diff
fetch http://www.egr.msu.edu/~mcdouga9/nossl-patches/patch-emulators-virtualbox-libressl
fetch http://www.egr.msu.edu/~mcdouga9/nossl-patches/patch-lang-python27-libressl


In /usr/local/etc/poudriere.conf I've only changed:
ZPOOL=rpool

This is to match the name of my zpool.



Build a new poudriere jail for 10.1-RELEASE from source while applying buildworld-nossl.diff:

poudriere jail -c -j 10amd64-nossl -v release/10.1.0 -a amd64 -m svn -P /root/buildworld-nossl.diff


Put this content in /usr/local/etc/poudriere.d/10amd64-nossl-make.conf
to set up some port changes to fix some port compiles in poudriere:

WITH_OPENSSL_PORT=yes
OPENSSL_PORT= security/libressl
# ldns examples subdir does not link with openssl properly
dns_ldns_UNSET=EXAMPLES
ftp_curl_SET=GSSAPI_NONE
ftp_curl_UNSET=GSSAPI_BASE TLS_SRP
#
.if ${.CURDIR:M*/lang/python27}
EXTRA_PATCHES+= /distfiles/custom/patch-lang-python27-libressl
.endif
#
.if ${.CURDIR:M*/emulators/virtualbox-ose}
USE_OPENSSL=    yes
CONFIGURE_ARGS+= --with-openssl-dir=/usr/local
EXTRA_PATCHES+= /distfiles/custom/patch-emulators-virtualbox-libressl
.endif
#
.if ${.CURDIR:M*/security/p5-Crypt-SSLeay}
CONFIGURE_ENV=  OPENSSL_INCLUDE="/usr/local/include"
.endif
#
.if ${.CURDIR:M*/security/ca_root_nss}
USE_OPENSSL=    yes
.endif




Prepare storage for some custom port patches:

ln -s /usr/local/poudriere/ports/default /usr/ports
mkdir -p /usr/local/poudriere/ports/default/distfiles/custom
cp /root/patch-emulators-virtualbox-libressl /usr/local/poudriere/ports/default/distfiles/custom/
cp /root/patch-lang-python27-libressl /usr/local/poudriere/ports/default/distfiles/custom/
rm /usr/local/poudriere/ports/default/net-mgmt/net-snmp/files/patch-agent_Makefile.in

Note about net-snmp patch delete:
/usr/ports/net-mgmt/net-snmp/files/patch-agent_Makefile.in causes snmp to link against libpkg apparently so snmp can report package information.  Since our libpkg is compiled against openssl which is not present in the jail, linking against libpkg will fail.  This may be complicated to fix properly, however since I do not use snmp in this manner, I found it was pretty trivial to avoid linking with libpkg.



Temporarily copy openssl in so pkg can compile.  It is not ready to link against libressl and it would be complicated when no other ports are installed.  It dynamically links against openssl for the 'pkg' command which is okay for systems that install our package of pkg because those systems will have openssl in base, but it also statically links against openssl and libfetch for 'pkg-static' which poudriere uses for compiles.

cp /usr/bin/openssl /usr/local/poudriere/jails/10amd64-nossl/usr/bin/
cp -Rp /usr/local/include/openssl/ /usr/local/poudriere/jails/10amd64-nossl/usr/include/openssl/
cp /usr/lib/libssl* /usr/local/poudriere/jails/10amd64-nossl/usr/lib/
cp /usr/lib/libcrypto* /usr/local/poudriere/jails/10amd64-nossl/usr/lib/
zfs destroy rpool/poudriere/jails/10amd64-nossl@clean
zfs snap rpool/poudriere/jails/10amd64-nossl@clean

Compile pkg only:

poudriere bulk -j 10amd64-nossl ports-mgmt/pkg



Delete temporary openssl:

rm /usr/local/poudriere/jails/10amd64-nossl/usr/bin/openssl
rm -r /usr/local/poudriere/jails/10amd64-nossl/usr/include/openssl/
rm /usr/local/poudriere/jails/10amd64-nossl/usr/lib/libcrypto*
rm /usr/local/poudriere/jails/10amd64-nossl/usr/lib/libssl*
zfs destroy rpool/poudriere/jails/10amd64-nossl@clean
zfs snap rpool/poudriere/jails/10amd64-nossl@clean


Now compile some sample packages:
poudriere bulk -j 10amd64-nossl emulators/virtualbox-ose ftp/curl net-mgmt/php56-snmp \
net/p5-SOAP-Lite www/apache24 mail/postfix security/openssh-portable

I've compiled over 1400 packages successfully using the methods above plus other patches just for libressl.

Additional notes:
x11/xscreensaver would not compile because 'bc' was missing from base. 'bc' is a wrapper for 'dc' which was also not built because it uses openssl for a math library. It may be possible to modify 'dc' to use a simpler math library, or make/find a 'bc' workalike from ports and make xscreensaver depend on it, even if it needs libressl, or find a different way for xscreensaver to do math. I wasn't actually using xscreensaver for anything, I'm more likely to use xlockmore which does build.

devel/android-tools-adb would not compile... I didn't look at why since I don't use it. May or may not be simple to fix.

dns/ldns has a subdirectory of examples with it's own Makefile, but it does not seem to look for openssl in /usr/local/. I spent some time trying to fix this but lost interest in favor of making everything else a usable solution.

ports-mgmt/pkg links against openssl from base which is understandable, non-trivial to extract, and unlikely to switch to an ssl library from ports. Because of this, you'll have to copy openssl back into your build root any time pkg needs to be built, build pkg, then remove openssl again. Perhaps it could switch to a bundled ssl library or equivalent replacement? Fortunately pkg version bumps are not extremely frequent and you can't forget to fix it because the compile will fail which will remind you.