Skip to content

Commit 00d365b

Browse files
committed
Secure gpg entrypoint
- enable gpg protection - remove set -x to prevent logging password - add checks to prevent re-initing pass and gpg - present passphrase unlock via docker env variable - Note: gpg-agent will not expire gpg-present-passphrases - fix deb CMD to ENTRYPOINT
1 parent 044ea2b commit 00d365b

7 files changed

Lines changed: 74 additions & 38 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ tag | description
3434
To initialize and add account to the bridge, run the following command.
3535

3636
```
37-
docker run --rm -it -v protonmail:/root shenxn/protonmail-bridge init
37+
docker run --rm -it -e KEYRING_PASSPHRASE='<your_passphrase>' -v protonmail:/root shenxn/protonmail-bridge init
3838
```
3939

40-
If you want to use Docker Compose instead, you can create a copy of the provided example [docker-compose.yml](docker-compose.yml) file, modify it to suit your needs, and then run the following command:
40+
If you want to use Docker Compose instead, you can create a copy of the provided example [docker-compose.yml](docker-compose.yml) file, modify it to suit your needs (making sure KEYRING_PASSPHRASE matches what was used during intitialization), and then run the following command:
4141

4242
```
4343
docker compose run protonmail-bridge init
@@ -50,7 +50,7 @@ Wait for the bridge to startup, then you will see a prompt appear for [Proton Ma
5050
To run the container, use the following command.
5151

5252
```
53-
docker run -d --name=protonmail-bridge -v protonmail:/root -p 1025:25/tcp -p 1143:143/tcp --restart=unless-stopped shenxn/protonmail-bridge
53+
docker run -d --name=protonmail-bridge -e KEYRING_PASSPHRASE='<your_passphrase>' -v protonmail:/root -p 1025:25/tcp -p 1143:143/tcp --restart=unless-stopped shenxn/protonmail-bridge
5454
```
5555

5656
Or, if using Docker Compose, use the following command.
@@ -70,7 +70,7 @@ If you don't want to use Helm, you can also reference to the guide ([#6](https:/
7070
Please be aware that running the command above will expose your bridge to the network. Remember to use firewall if you are going to run this in an untrusted network or on a machine that has public IP address. You can also use the following command to publish the port to only localhost, which is the same behavior as the official bridge package.
7171

7272
```
73-
docker run -d --name=protonmail-bridge -v protonmail:/root -p 127.0.0.1:1025:25/tcp -p 127.0.0.1:1143:143/tcp --restart=unless-stopped shenxn/protonmail-bridge
73+
docker run -d --name=protonmail-bridge -e KEYRING_PASSPHRASE='<your_passphrase>' -v protonmail:/root -p 127.0.0.1:1025:25/tcp -p 127.0.0.1:1143:143/tcp --restart=unless-stopped shenxn/protonmail-bridge
7474
```
7575

7676
Besides, you can publish only port 25 (SMTP) if you don't need to receive any email (e.g. as a email notification service).

build/entrypoint.sh

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,49 @@
11
#!/bin/bash
22

3-
set -ex
3+
set -e
4+
5+
if [ -z "$KEYRING_PASSPHRASE" ]; then
6+
echo "KEYRING_PASSPHRASE cannot be empty"
7+
exit 1
8+
fi
9+
10+
gpg_present_phrase () {
11+
/usr/lib/gnupg2/gpg-preset-passphrase -P "$KEYRING_PASSPHRASE" \
12+
-c "$(basename "$HOME"/.gnupg/private-keys-v1.d/*.key .key)"
13+
}
14+
15+
# Start gpg-agent to force allow presetting passphrase
16+
gpg-agent --homedir "$HOME"/.gnupg --daemon --allow-preset-passphrase
417

518
# Initialize
619
if [[ $1 == init ]]; then
720

8-
# Initialize pass
9-
gpg --generate-key --batch /protonmail/gpgparams
10-
pass init pass-key
11-
21+
# Initialize GPG if no private key
22+
# While -f can't handle globs, only one key can be generated
23+
if [ ! -f "$HOME"/.gnupg/private-keys-v1.d/*.key ]; then
24+
gpg --generate-key --passphrase "$KEYRING_PASSPHRASE" --pinentry-mode loopback \
25+
--batch /protonmail/gpgparams
26+
fi
27+
28+
# Initialize pass if no password-store
29+
if [ ! -d "$HOME"/.password-store ]; then
30+
pass init pass-key
31+
fi
32+
33+
gpg_present_phrase
34+
1235
# Kill the other instance as only one can be running at a time.
1336
# This allows users to run entrypoint init inside a running conainter
1437
# which is useful in a k8s environment.
1538
# || true to make sure this would not fail in case there is no running instance.
1639
pkill protonmail-bridge || true
1740

1841
# Login
19-
/protonmail/proton-bridge --cli $@
42+
/protonmail/proton-bridge --cli
2043

2144
else
45+
# Load passphrase into gpg-agent
46+
gpg_present_phrase
2247

2348
# socat will make the conn appear to come from 127.0.0.1
2449
# ProtonMail Bridge currently expects that.
@@ -30,6 +55,6 @@ else
3055
# Fake a terminal, so it does not quit because of EOF...
3156
rm -f faketty
3257
mkfifo faketty
33-
cat faketty | /protonmail/proton-bridge --cli $@
58+
cat faketty | /protonmail/proton-bridge --cli
3459

3560
fi

build/gpgparams

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
%no-protection
21
%echo Generating a basic OpenPGP key
32
Key-Type: RSA
43
Key-Length: 2048

deb/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ RUN apt-get update \
2525
&& apt-get install -y --no-install-recommends /tmp/protonmail.deb socat pass libsecret-1-0 ca-certificates procps \
2626
&& rm -rf /var/lib/apt/lists/*
2727

28-
CMD ["bash", "/protonmail/entrypoint.sh"]
28+
ENTRYPOINT ["bash", "/protonmail/entrypoint.sh"]

deb/entrypoint.sh

100644100755
Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,49 @@
11
#!/bin/bash
22

3-
set -ex
3+
set -e
4+
5+
if [ -z "$KEYRING_PASSPHRASE" ]; then
6+
echo "KEYRING_PASSPHRASE cannot be empty"
7+
exit 1
8+
fi
9+
10+
gpg_present_phrase () {
11+
/usr/lib/gnupg2/gpg-preset-passphrase -P "$KEYRING_PASSPHRASE" \
12+
-c "$(basename "$HOME"/.gnupg/private-keys-v1.d/*.key .key)"
13+
}
14+
15+
# Start gpg-agent to force allow presetting passphrase
16+
gpg-agent --homedir "$HOME"/.gnupg --daemon --allow-preset-passphrase
417

518
# Initialize
619
if [[ $1 == init ]]; then
720

8-
# # Parse parameters
9-
# TFP="" # Default empty two factor passcode
10-
# shift # skip `init`
11-
# while [[ $# -gt 0 ]]; do
12-
# key="$1"
13-
# case $key in
14-
# -u|--username)
15-
# USERNAME="$2"
16-
# ;;
17-
# -p|--password)
18-
# PASSWORD="$2"
19-
# ;;
20-
# -t|--twofactor)
21-
# TWOFACTOR="$2"
22-
# ;;
23-
# esac
24-
# shift
25-
# shift
26-
# done
27-
28-
# Initialize pass
29-
gpg --generate-key --batch /protonmail/gpgparams
30-
pass init pass-key
21+
# Initialize GPG if no private key
22+
# While -f can't handle globs, only one key can be generated
23+
if [ ! -f "$HOME"/.gnupg/private-keys-v1.d/*.key ]; then
24+
gpg --generate-key --passphrase "$KEYRING_PASSPHRASE" --pinentry-mode loopback \
25+
--batch /protonmail/gpgparams
26+
fi
27+
28+
# Initialize pass if no password-store
29+
if [ ! -d "$HOME"/.password-store ]; then
30+
pass init pass-key
31+
fi
32+
33+
gpg_present_phrase
34+
35+
# Kill the other instance as only one can be running at a time.
36+
# This allows users to run entrypoint init inside a running conainter
37+
# which is useful in a k8s environment.
38+
# || true to make sure this would not fail in case there is no running instance.
39+
pkill protonmail-bridge || true
3140

3241
# Login
3342
protonmail-bridge --cli
3443

3544
else
45+
# Load passphrase into gpg-agent
46+
gpg_present_phrase
3647

3748
# socat will make the conn appear to come from 127.0.0.1
3849
# ProtonMail Bridge currently expects that.

deb/gpgparams

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
%no-protection
21
%echo Generating a basic OpenPGP key
32
Key-Type: RSA
43
Key-Length: 2048

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ version: '2.1'
33
services:
44
protonmail-bridge:
55
image: shenxn/protonmail-bridge
6+
environment:
7+
- KEYRING_PASSPHRASE=
68
ports:
79
- 1025:25/tcp
810
- 1143:143/tcp

0 commit comments

Comments
 (0)