Skip to content

Commit 74958ce

Browse files
committed
Docker certificate generation and GPG signing issues
- Change entrypoint to require manual cert generation (not auto-gen) - Add --entrypoint '' flag to bypass validation when generating certs - Fix GPG_TTY and stderr redirect for passphrase prompts in onboard - Update DOCKER.md with clearer 3-step deployment process - Simplify generate-mtls-certs.sh DNS SAN prompting - Fix sed -i portability for Alpine/BusyBox - Update erl_gpg dependency to use primary key fingerprints Docker deployments now require explicit certificate generation step before starting server, ensuring DNS SANs can be configured properly.
1 parent 5d2e6e5 commit 74958ce

File tree

5 files changed

+61
-26
lines changed

5 files changed

+61
-26
lines changed

bin/cryptic-onboard

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,10 @@ EOF
578578
CSR_DATA=${CSR_DATA%x}
579579
# Use fingerprint with ! suffix to force exact key match
580580
# Sign the exact CSR data we're going to send
581-
GPG_SIG=$(printf '%s' "$CSR_DATA" | gpg --armor --detach-sign --local-user "${GPG_FP}!" 2>/dev/null)
581+
# Set GPG_TTY so pinentry knows which terminal to use for passphrase prompt
582+
export GPG_TTY=$(tty)
583+
# Redirect stderr to terminal (not /dev/null) so passphrase prompts appear
584+
GPG_SIG=$(printf '%s' "$CSR_DATA" | gpg --armor --detach-sign --local-user "${GPG_FP}!" 2>/dev/tty)
582585
if [ $? -ne 0 ]; then
583586
echo ""
584587
error "Failed to sign CSR with GPG key.\n\nFingerprint: $GPG_FP\nUID: $GPG_EMAIL\n\nMake sure you have the private key and it's not expired."

docs/DOCKER.md

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,26 @@ docker run -it --rm --name cryptic-client \
3737
--add-host=cryptic-server:host-gateway \
3838
ghcr.io/etnt/cryptic-tui:latest sh -c 'cryptic --onboard'
3939

40-
# Start the Cryptic client with your username (e.g `franz`)
40+
# Start the Cryptic client with your username (e.g `bob`)
4141
# You'll be prompted for a Passphrase which is used to encrypt your local DB
4242

4343
# Method 1: Using environment variables
4444
docker run -it --rm --name cryptic-client \
4545
-v ~/.cryptic:/home/cryptic/.cryptic \
4646
-v ~/.cryptic-gpg:/home/cryptic/.gnupg \
4747
--add-host=cryptic-server:host-gateway \
48-
-e CRYPTIC_USERNAME=franz \
48+
-e CRYPTIC_USERNAME=bob \
4949
-e CRYPTIC_ENABLE_DB=true \
5050
ghcr.io/etnt/cryptic-tui:latest
5151

52-
# Method 2: Using command-line flags
52+
# Method 2: Using command-line flags
53+
# (but here also increase log output details)
5354
docker run -it --rm --name cryptic-client \
5455
-v ~/.cryptic:/home/cryptic/.cryptic \
5556
-v ~/.cryptic-gpg:/home/cryptic/.gnupg \
5657
--add-host=cryptic-server:host-gateway \
57-
ghcr.io/etnt/cryptic-tui:latest sh -c 'cryptic -u franz --enable-db --tui'
58+
-e CRYPTIC_DEBUG=true \
59+
ghcr.io/etnt/cryptic-tui:latest sh -c 'cryptic -u bob --enable-db --tui'
5860
```
5961

6062
**Run the latest server image:**
@@ -64,27 +66,28 @@ docker run -it --rm --name cryptic-client \
6466
docker pull ghcr.io/etnt/cryptic:latest
6567

6668
# Create a directory for storing all Cryptic server data
67-
mkdir ~/.cryptic_server
69+
mkdir -p ~/.cryptic_server
6870
cd ~/.cryptic_server
6971

70-
# Setup the server certificates (one-time step)
71-
# Creates ca.crt, ca.key, server.crt, server.key in ./priv/ssl/
72+
# Step 1: Generate CA and server certificates (one-time setup)
73+
# This will prompt for optional DNS Subject Alternative Names (SANs)
7274
docker run -it --rm \
75+
--entrypoint '' \
7376
-v $(pwd):/opt/cryptic/server_data \
7477
-e CRYPTIC_SERVER_DIR=/opt/cryptic/server_data \
7578
ghcr.io/etnt/cryptic:latest \
76-
sh -c 'DIR=${CRYPTIC_SERVER_DIR}/priv/ssl generate-mtls-certs.sh'
79+
sh -c 'DIR="${CRYPTIC_SERVER_DIR}/priv/ssl" generate-mtls-certs.sh'
7780

78-
# Bootstrap the first admin user BEFORE starting the server
79-
# Step 1: Generate a GPG key on your host (if you don't have one)
80-
# No passphrase needed - it's only used for signing CSRs
81+
# Step 2: Bootstrap the first admin user
82+
# Generate a GPG key on your host (if you don't have one)
83+
# No passphrase needed - it's only used for signing CSRs
8184
gpg --quick-generate-key 'alice <alice@cryptic.local>' rsa4096
8285

83-
# Step 2: Export your GPG public key to the bootstrap directory
86+
# Export your GPG public key to the bootstrap directory
8487
mkdir -p priv/ca/bootstrap
8588
gpg --armor --export alice@cryptic.local > priv/ca/bootstrap/alice.gpg
8689

87-
# Run the server with single directory mount
90+
# Step 3: Run the server
8891
# All server data (priv/, logs/, data/) will be in ~/.cryptic_server/
8992
# Note: Mount to /opt/cryptic/server_data (not /opt/cryptic which contains the Erlang release)
9093
# For debug log output, add: -e CRYPTIC_DEBUG=true
@@ -96,13 +99,30 @@ docker run -d \
9699
-e CRYPTIC_SERVER_DIR=/opt/cryptic/server_data \
97100
ghcr.io/etnt/cryptic:latest
98101

99-
# Check server logs
102+
# Check server logs (you'll see certificate information on first start)
100103
docker logs -f cryptic-server
101104

102105
# Stop the server and remove the container
103106
docker stop cryptic-server && docker rm cryptic-server
104107
```
105108

109+
### Manual Certificate Generation (Optional)
110+
111+
The Quick Deployment section above includes certificate generation as Step 1.
112+
If you need to regenerate certificates or add additional DNS SANs later:
113+
114+
```bash
115+
cd ~/.cryptic_server
116+
117+
# Run certificate generation interactively (will prompt for DNS SANs)
118+
docker run -it --rm \
119+
--entrypoint '' \
120+
-v $(pwd):/opt/cryptic/server_data \
121+
-e CRYPTIC_SERVER_DIR=/opt/cryptic/server_data \
122+
ghcr.io/etnt/cryptic:latest \
123+
sh -c 'DIR="${CRYPTIC_SERVER_DIR}/priv/ssl" generate-mtls-certs.sh'
124+
```
125+
106126
## The Client
107127

108128
The Cryptic TUI (Terminal User Interface) client can run in Docker to

rebar.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.16.0">>},0},
44
{<<"erl_gpg">>,
55
{git,"https://github.com/etnt/erl_gpg.git",
6-
{ref,"adea5da8a7f78964d84b50c8a921a44ffa7af3e1"}},
6+
{ref,"ce79a49bb40557698ea6d596c2b69f1328fcd8f4"}},
77
0},
88
{<<"esqlite">>,
99
{git,"https://github.com/mmzeeman/esqlite.git",

scripts/docker-entrypoint.sh

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,19 @@ echo " ${CRYPTIC_SERVER_DIR}/priv/ca/bootstrap/*.gpg - Bootstrap GPG keys"
2525
echo " ${CRYPTIC_SERVER_DIR}/data/ - Database files"
2626
echo " ${CRYPTIC_SERVER_DIR}/logs/ - Log files"
2727

28-
# Check if CA certificates exist, generate if missing
28+
# Check if CA certificates exist
2929
if [ ! -f "${CRYPTIC_SERVER_DIR}/priv/ssl/ca.crt" ] || [ ! -f "${CRYPTIC_SERVER_DIR}/priv/ssl/ca.key" ]; then
30-
echo "INFO: CA certificates not found, generating..."
31-
DIR="${CRYPTIC_SERVER_DIR}/priv/ssl" /usr/local/bin/generate-mtls-certs.sh
30+
echo "ERROR: CA certificates not found!"
31+
echo "Please generate certificates before starting the server:"
32+
echo ""
33+
echo " docker run -it --rm \\"
34+
echo " --entrypoint '' \\"
35+
echo " -v \$(pwd):/opt/cryptic/server_data \\"
36+
echo " -e CRYPTIC_SERVER_DIR=/opt/cryptic/server_data \\"
37+
echo " <image-name> \\"
38+
echo " sh -c 'DIR=\"\${CRYPTIC_SERVER_DIR}/priv/ssl\" generate-mtls-certs.sh'"
39+
echo ""
40+
exit 1
3241
else
3342
echo "INFO: CA certificates found"
3443
fi
@@ -45,10 +54,10 @@ if [ "${CRYPTIC_DEBUG}" = "true" ]; then
4554
ls -ld "${CRYPTIC_SERVER_DIR}/data/ca"
4655
echo "DEBUG: ${CRYPTIC_SERVER_DIR}/data/ca contents:"
4756
ls -la "${CRYPTIC_SERVER_DIR}/data/ca/" || echo "Directory empty or not readable"
48-
57+
4958
echo "DEBUG: ${CRYPTIC_SERVER_DIR}/priv contents:"
5059
ls -laR "${CRYPTIC_SERVER_DIR}/priv" 2>/dev/null || echo "Directory not readable"
51-
60+
5261
echo "DEBUG: Environment variables:"
5362
echo " CRYPTIC_SERVER_DIR=${CRYPTIC_SERVER_DIR}"
5463
echo " CRYPTIC_CA_DB_FILE=${CRYPTIC_CA_DB_FILE}"

scripts/generate-mtls-certs.sh

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ if [ ! -f "${DIR}/serial" ]; then
2222
fi
2323

2424
DNS_SANS=""
25-
echo "Enter DNS Subject Alternative Name (SAN) (unless localhost only) - press Enter to skip:"
26-
printf "DNS names (comma-separated): " ; read DNS_SANS
25+
printf "Enter DNS Subject Alternative Name (SAN) - press Enter to skip\nDNS names (comma-separated): "
26+
read DNS_SANS
2727

2828
# Build SAN string for OpenSSL config file format (DNS.3 = hostname, DNS.4 = hostname, ...)
2929
SAN_LINES=""
@@ -38,7 +38,7 @@ if [ -n "$DNS_SANS" ]; then
3838
if [ -n "$name" ]; then
3939
if [ -n "$SAN_LINES" ]; then
4040
SAN_LINES="${SAN_LINES}
41-
DNS.$INDEX = $name"
41+
DNS.$INDEX = $name"
4242
else
4343
SAN_LINES="DNS.$INDEX = $name"
4444
fi
@@ -79,11 +79,13 @@ echo "Using OpenSSL config: $OPENSSL_CNF"
7979

8080
# Create temporary config file with SAN extension
8181
TEMP_CONFIG="/tmp/openssl_san_server.cnf"
82+
rm -f "$TEMP_CONFIG"
8283
cp "$OPENSSL_CNF" "$TEMP_CONFIG"
8384

8485
# Update the dir path in the config to match our $DIR
8586
# This replaces "dir = priv/ssl" (or similar) with the actual DIR path
86-
sed -i "s|^dir[[:space:]]*=.*|dir = $DIR|" "$TEMP_CONFIG"
87+
# Use temporary file for POSIX compatibility (Alpine/BusyBox doesn't support sed -i the same way)
88+
sed "s|^dir[[:space:]]*=.*|dir = $DIR|" "$TEMP_CONFIG" > "$TEMP_CONFIG.tmp" && mv "$TEMP_CONFIG.tmp" "$TEMP_CONFIG"
8789

8890
# Add SAN to the [ alt_names_server ] section after DNS.2 line
8991
if [ -n "$SAN_LINES" ]; then
@@ -113,7 +115,8 @@ openssl ca -config ${CONFIG_FILE} -extensions v3_server -batch -notext \
113115

114116

115117
# Clean up temporary files
116-
rm ${DIR}/server.csr
118+
rm -f ${DIR}/server.csr
119+
rm -f "$TEMP_CONFIG"
117120

118121
# Set appropriate permissions
119122
chmod 600 ${DIR}/*.key ${DIR}/*.pem

0 commit comments

Comments
 (0)