Kevin K
Kevin K

Reputation: 438

gpgp key request fails in dockerfile but not bash

I have an issue in that my attempts to receive a gpg key fails when building my docker container. The command that I am providing works correctly when executed at the command line.

In /etc/systemd/system/docker.service.d/http-proxy.conf:

[Service]
Environment="HTTP_PROXY=http://<corporate proxy>/" "HTTPS_PROXY="<corporate proxy>/" "NO_PROXY=localhost,127.0.0.1,.domain.local,.corp"

I use a build.sh shell script to build the image:

#/bin/bash
docker build -t hgk/test-container .

The shell script is in the same location as my Dockerfile. These are the only two things in that directory.

FROM openjdk:8
ARG KEYSERV=hkp://p80.pool.sks-keyservers.net:80
ARG THEPROXY=<my corporate proxy>

# grab gosu for easy step-down from root
# (see docker-sonarqube pull request #115)
RUN set -x \
    && wget -e https_proxy=$THEPROXY -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.10/gosu-$(dpkg --print-architecture)" \
    && wget -e https_proxy=$THEPROXY-O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/1.10/gosu-$(dpkg --print-architecture).asc" \
    && export GNUPGHOME="$(mktemp -d)" \
    && gpg --version \
    && gpg -vv --keyserver $KEYSERV --keyserver-options http-proxy=$THEPROXY --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
    && gpg --list-keys \
    && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
    && rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc \
    && chmod +x /usr/local/bin/gosu \
    && gosu nobody true

The two wget commands work correctly and they retrieve the files. The first gpg command eventually times out:

+ mktemp -d
+ export GNUPGHOME=/tmp/tmp.LJ1EVFQmpO
+ gpg --version
gpg (GnuPG) 2.1.18
libgcrypt 1.7.6-beta
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
<https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /tmp/tmp.LJlEVFQmpO
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
+ gpg -vv --keyserver hkp://p80.pool.sks-keyservers.net:80 --keyserver-options http-proxy=<corp proxy> --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4
gpg: keybox '/tmp/tmp.LJlEVFQmpO/pubring.kbx' created
gpg: no running Dirmngr - starting '/usr/bin/dirmngr'
gpg: waiting for the dirmngr to come up ... (5s)
gpg: connection to the dirmngr established

[[I am hung here - It just waits for ... something? I'll update the question if anything prints after this]] 

I put the gpg --list-keys command in the Dockerfile to see if we got past there. However, if I run it via the command line, it successfully retrieves the key:

[root@me foo]# printenv | grep proxy
[root@me foo]# gpg --keyserver hkp://p80.pool.sks-keyservers.net:80 --
keyserver-options http-proxy=<corp proxy> --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4
gpg: keyring `/root/.gnupg/pubring.gpg' created
gpg: requesting key BF357DD4 from hkp server p80.pool.sks-keyservers.net
Version: SKS 1.1.6
gpg: armor header:
Comment: Hostname: sks.okoyono.de
gpg: armor header:
gpg: pub  4096R/BF357DD4 2014-02-28  Tianon Gravi <[email protected]>
gpg: key BF357DD4: removed multiple subkey binding
gpg: key BF357DD4: removed multiple subkey binding
gpg: /tmp/tmp.DIX6yQQf25/trustdb.gpg: trustdb created
gpg: using PGP trust model
gpg: key BF357DD4: public key "Tianon Gravi <[email protected]>" imported
gpg: 1 keys cached (126 signatures)
gpg: 0 keys processed (0 validity counts cleared)
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

[root@me foo]# gpg --list-keys
/root/.gnupg/pubring.gpg
------------------------
pub   4096R/BF357DD4 2014-02-28 [expires: 2019-07-06]
uid                  Tianon Gravi <[email protected]>
uid                  Tianon Gravi <[email protected]>
uid                  Tianon Gravi <[email protected]>
uid                  Andrew Page (tianon) <[email protected]>
uid                  Andrew Page (tianon) <[email protected]>
uid                  Andrew Page (Tianon Gravi) <[email protected]>
uid                  Tianon Gravi (Andrew Page) <[email protected]>
sub   4096R/769826E6 2014-02-28 [expires: 2019-07-06]

I've tried different sks-keyservers (ubuntu, MIT, and other sks) with the same behavior - correct from bash, wrong from Docker.

Any thoughts/tips/suggestions?

Update: My "openjdk:8" version had not been updated in a while (since 8u121). I found I was running gpg v1.4.18. I did a docker image pull openjdk:8 which brought me up to 8u151 and gpg 2.1.18. The version of gpg on the CentOS 7 machine is 2.0.22.

Upvotes: 2

Views: 2548

Answers (2)

Jens Erat
Jens Erat

Reputation: 38682

Your systemd unit file's environment variables are not passed into a container when building Docker images. Instead, make use of the --build-arg parameter for passing the proxy values:

docker build --build-arg=HTTP_PROXY=http://<corporate proxy>/ --build-arg=HTTPS_PROXY=http://<corporate proxy>/ -t hgk/test-container .

You should not bake runtime options like proxy variables into the Dockerfile, always pass configuration through environment variables (or this build argument parameter).

Additional hint: most applications rely on http_proxy and https_proxy -- while most environment variables are indeed all-caps, the proxy variables have a more wide-spread lower-case usage.

Upvotes: 1

Kevin K
Kevin K

Reputation: 438

My solution to the problem (whether it is the right solution or not is up for debate) was to add the http_proxy and https_proxy environment variables to the Dockerfile.

FROM openjdk:8
ARG KEYSERV=hkp://p80.pool.sks-keyservers.net:80
ARG THEPROXY=<my corporate proxy>
ENV http_proxy $THEPROXY
ENV https_proxy $THEPROXY

# grab gosu for easy step-down from root
# (see docker-sonarqube pull request #115)
RUN set -x \
    && wget -e https_proxy=$THEPROXY -O /usr/local/bin/gosu 
"https://github.com/tianon/gosu/releases/download/1.10/gosu-$(dpkg --print-architecture)" \
    && wget -e https_proxy=$THEPROXY-O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/1.10/gosu-$(dpkg --print-architecture).asc" \
    && export GNUPGHOME="$(mktemp -d)" \
    && gpg --version \
    && gpg -vv --keyserver $KEYSERV --keyserver-options http-proxy=$THEPROXY --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
    && gpg --list-keys \
    && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
    && rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc \
    && chmod +x /usr/local/bin/gosu \
    && gosu nobody true

My interpretation of this fix is that gpg spins up dirmngr. dirmngr "is a server for managing and downloading certificate revocation lists (CRLs) for X.509 certificates and for downloading the certificates themselves." This hints at some form of network connectivity being necessary. Reading the [dirmngr options][2] page, there is a --http-proxy argument that does not seem to get passed to the startup arguments for dirmngr.

Somehow, adding the http_proxy to the environment allows dirmngr to do it's job successfully.

I'm not sure if this is a bug (there's an --honor-http-proxy option that appears to be set to 0 by default in the gnupg source code, so I'm not sure why it's picking up the http_proxy, but my solution is working and meets my needs. I'll try to read the source code a little more in detail this weekend, but this isn't a high priority any more for me and my team.

Upvotes: 0

Related Questions