Skip to content

Commit faa85e9

Browse files
committed
ensure that proper flags are passed after tls is enabled
ensure that order of ops is respected re: mongod.conf
1 parent fafcec8 commit faa85e9

File tree

7 files changed

+125
-33
lines changed

7 files changed

+125
-33
lines changed

README.md

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,24 +162,83 @@ The provision_ssl script configures MongoDB to use pre-generated private CA cert
162162

163163
Replace `/path/to/your/certificate.pem` and `/path/to/your/ca_certificate.pem` with the actual paths to your certificate files.
164164

165-
2. **Run the TLS provisioning script**:
165+
2. **Generate a client certificate** (required for connecting to MongoDB):
166+
167+
You'll need to create a client certificate signed by the same CA that signed your server certificate. If you're using the certificate generation script from the repository, you can add a function to generate client certificates:
168+
169+
```javascript
170+
const generate_client_certificate = (client_name) => {
171+
const ca_key = 'ca.key';
172+
const ca_crt = 'ca.crt';
173+
const client_key = `${client_name}.key`;
174+
const client_csr = `${client_name}.csr`;
175+
const client_crt = `${client_name}.crt`;
176+
const client_pem = `${client_name}.pem`;
177+
178+
// Generate client key
179+
execSync(`openssl genrsa -out ${client_key} 2048`);
180+
181+
// Generate CSR
182+
execSync(`openssl req -new -key ${client_key} -out ${client_csr} -subj "/CN=${client_name}"`);
183+
184+
// Sign with CA
185+
execSync(`openssl x509 -req -in ${client_csr} -CA ${ca_crt} -CAkey ${ca_key} -CAcreateserial -out ${client_crt} -days 7300 -sha256`);
186+
187+
// Create combined PEM file
188+
const crtContent = fs.readFileSync(client_crt);
189+
const keyContent = fs.readFileSync(client_key);
190+
fs.writeFileSync(client_pem, Buffer.concat([crtContent, keyContent]));
191+
192+
return client_pem;
193+
};
194+
```
195+
196+
3. **Run the TLS provisioning script**:
166197

167198
```bash
168199
./provision_ssl.sh
169200
```
170201

171-
3. **What the provision_ssl script does**:
202+
4. **What the provision_ssl script does**:
172203
- Checks for the existence of the certificate files
173204
- Updates the MongoDB configuration to use TLS with proper settings
174205
- Configures MongoDB to allow connections from outside the server (bindIp: 0.0.0.0)
206+
- Adds the replica set configuration
207+
- Initializes the replica set using the domain name from config.json
175208
- Restarts MongoDB with the new TLS configuration
176209

177-
3. **Verify TLS is working**:
210+
5. **Connecting to MongoDB with client certificates**:
211+
212+
After running provision_ssl.sh, you must use client certificates to connect:
213+
214+
```bash
215+
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p your_password --authenticationDatabase admin
216+
```
217+
218+
Ensure the client certificate exists at `/etc/ssl/mongodb/client.pem`.
219+
220+
**For GUI tools like Studio 3T**:
221+
222+
You'll need to configure the connection to use:
223+
- TLS/SSL enabled
224+
- CA file: `/etc/ssl/mongodb/certificate_authority.pem`
225+
- Client certificate: Your generated client.pem file
226+
- Authentication: Username/Password with admin database
178227

179-
The script will verify that MongoDB is running with TLS. You can also check manually:
228+
**For application connections**:
229+
230+
In your application code, you'll need to specify both the CA file and client certificate:
231+
232+
```
233+
mongodb://admin:[email protected]:27017/?tls=true&tlsCAFile=/etc/ssl/mongodb/certificate_authority.pem&tlsCertificateKeyFile=/etc/ssl/mongodb/client.pem&authSource=admin
234+
```
235+
236+
6. **Verify TLS is working**:
237+
238+
The script will attempt to verify that MongoDB is running with TLS. You can also check manually, but remember you'll need to use your client certificate:
180239

181240
```bash
182-
sudo mongosh --host your-domain.com --port $MONGO_PORT --tls -u admin -p your_password --authenticationDatabase admin --eval "db.adminCommand({ getParameter: 1, tlsMode: 1 })"
241+
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p your_password --authenticationDatabase admin --eval "db.adminCommand({ getParameter: 1, tlsMode: 1 })"
183242
```
184243

185244
Replace `$MONGO_PORT` with the port you specified in config.json.
@@ -304,7 +363,7 @@ Example output:
304363
],
305364
"tls_enabled": true,
306365
"replica_set": "rs0",
307-
"connection_string": "mongodb://admin:[email protected]:27017,mdb2.example.com:27017/?tls=true&authSource=admin&replicaSet=rs0"
366+
"connection_string": "mongodb://admin:[email protected]:27017,mdb2.example.com:27017/?tls=true&tlsCAFile=/etc/ssl/mongodb/certificate_authority.pem&tlsCertificateKeyFile=/etc/ssl/mongodb/client.pem&authSource=admin&replicaSet=rs0"
308367
}
309368
```
310369

@@ -315,10 +374,10 @@ For security best practices, you should regularly rotate the MongoDB admin passw
315374
1. **Connect to the primary node**:
316375

317376
```bash
318-
mongosh --host your-domain.com --port $MONGO_PORT --tls -u admin -p current_password --authenticationDatabase admin
377+
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p current_password --authenticationDatabase admin
319378
```
320379

321-
Replace `$MONGO_PORT` with the port you specified in config.json, and `current_password` with your current password.
380+
Replace `$MONGO_PORT` with the port you specified in config.json and `current_password` with your current password.
322381

323382
2. **Change the admin user's password**:
324383

@@ -341,9 +400,9 @@ For security best practices, you should regularly rotate the MongoDB admin passw
341400
4. **Verify the new password**:
342401

343402
```bash
344-
mongosh --host your-domain.com --port $MONGO_PORT --tls -u admin -p new_secure_password --authenticationDatabase admin --eval "db.adminCommand('ping')"
403+
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p new_secure_password --authenticationDatabase admin --eval "db.adminCommand('ping')"
345404
```
346-
405+
347406
You should see a successful response with `{ ok: 1 }`.
348407

349408
5. **Password Rotation Schedule**:
@@ -408,7 +467,7 @@ If you encounter issues during the setup process, here are some common troublesh
408467
4. **Test MongoDB connection with TLS**:
409468

410469
```bash
411-
sudo mongosh --host your-domain.com --port $MONGO_PORT --tls -u admin -p your_password --authenticationDatabase admin
470+
mongosh --host your-domain.com --port $MONGO_PORT --tls --tlsCAFile /etc/ssl/mongodb/certificate_authority.pem --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u admin -p your_password --authenticationDatabase admin
412471
```
413472

414473
Replace `$MONGO_PORT` with the port you specified in config.json and `your-domain.com` with your actual domain name.

bootstrap.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ net:
9191
bindIp: 127.0.0.1
9292
EOF
9393

94+
# Ensure MongoDB can resolve its own domain name
95+
echo "Checking if domain is in /etc/hosts..."
96+
if ! grep -q "$DOMAIN" /etc/hosts; then
97+
echo "Adding $DOMAIN to /etc/hosts..."
98+
echo "127.0.1.1 $DOMAIN" | sudo tee -a /etc/hosts
99+
echo "Added $DOMAIN to /etc/hosts"
100+
else
101+
echo "Domain $DOMAIN already in /etc/hosts"
102+
fi
103+
94104
# Store the replica set name for provision_ssl.sh to use later
95105
echo "$REPLICA_SET" > /tmp/mongodb_replica_set
96106

connection_info.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ rm $TEMP_FILE
9898

9999
# Build connection string
100100
if [ "$TLS_ENABLED" = true ]; then
101-
CONNECTION_STRING="mongodb://$DB_USERNAME:$DB_PASSWORD@$(echo $HOSTS_JSON | jq -r 'map(.hostname + ":" + .port) | join(",")' || echo "$CONNECTION_DOMAIN:$MONGO_PORT")/?tls=true&authSource=admin&replicaSet=$REPLICA_SET"
101+
CONNECTION_STRING="mongodb://$DB_USERNAME:$DB_PASSWORD@$(echo $HOSTS_JSON | jq -r 'map(.hostname + ":" + .port) | join(",")' || echo "$CONNECTION_DOMAIN:$MONGO_PORT")/?tls=true&tlsCAFile=$CA_FILE&tlsCertificateKeyFile=/etc/ssl/mongodb/client.pem&authSource=admin&replicaSet=$REPLICA_SET"
102+
echo "NOTE: The connection string includes client certificate path."
103+
echo " Ensure the client certificate exists at /etc/ssl/mongodb/client.pem"
102104
else
103105
CONNECTION_STRING="mongodb://$DB_USERNAME:$DB_PASSWORD@$(echo $HOSTS_JSON | jq -r 'map(.hostname + ":" + .port) | join(",")' || echo "$CONNECTION_DOMAIN:$MONGO_PORT")/?authSource=admin&replicaSet=$REPLICA_SET"
104106
fi

provision_ssl.sh

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ if [ -f "$MONGO_CONF" ]; then
4848
else
4949
# Check if net section already exists
5050
if grep -q "net:" "$MONGO_CONF" && ! grep -q " tls:" "$MONGO_CONF"; then
51-
# Add TLS configuration under existing net section
51+
# Add TLS configuration under existing net section (requiring client certificates)
5252
echo "Adding TLS configuration to existing net section..."
5353
sudo sed -i '/net:/a\ tls:\n mode: requireTLS\n certificateKeyFile: '"$CERT_FILE"'\n CAFile: '"$CA_FILE"'' "$MONGO_CONF"
5454

@@ -124,7 +124,9 @@ fi
124124

125125
# Verify MongoDB is running with TLS
126126
echo "Waiting for MongoDB to start completely..."
127-
sleep 5
127+
128+
sleep 10
129+
128130
if sudo systemctl is-active --quiet mongod; then
129131
echo "✅ MongoDB restarted successfully with TLS configuration"
130132

@@ -138,14 +140,20 @@ if sudo systemctl is-active --quiet mongod; then
138140
MONGO_PORT=$(jq -r '.mongo_port' "$CONFIG_FILE")
139141

140142
if command -v mongosh &> /dev/null; then
141-
# Try with localhost
142-
echo "Attempting to verify TLS using localhost"
143-
if sudo mongosh --host localhost --port $MONGO_PORT --tls -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval "db.adminCommand({ getParameter: 1, tlsMode: 1 })" 2>/dev/null | grep -q "requireTLS"; then
144-
echo "✅ MongoDB TLS mode verified using localhost: requireTLS is active"
143+
# Try with domain name and client certificate
144+
echo "Attempting to verify TLS using domain name"
145+
if mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval "db.adminCommand({ getParameter: 1, tlsMode: 1 })" 2>/dev/null | grep -q "requireTLS"; then
146+
echo "✅ MongoDB TLS mode verified using domain name: requireTLS is active"
145147
else
146148
echo "⚠️ WARNING: MongoDB is running but TLS mode could not be verified."
147-
echo "Please check manually with:"
148-
echo "mongosh --host localhost --port $MONGO_PORT --tls -u $DB_USERNAME -p <password> --authenticationDatabase admin --eval \"db.adminCommand({ getParameter: 1, tlsMode: 1 })\""
149+
echo "This is expected because client certificates are required."
150+
echo ""
151+
echo "IMPORTANT: To connect to MongoDB, you will need:"
152+
echo "1. A client certificate signed by your CA"
153+
echo "2. Connect using the domain name that matches your server certificate"
154+
echo ""
155+
echo "Example connection command:"
156+
echo "mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p <password> --authenticationDatabase admin"
149157
fi
150158
else
151159
echo "⚠️ mongosh not available to verify TLS configuration."
@@ -204,12 +212,12 @@ if [ -f "$CONFIG_FILE" ]; then
204212
fi
205213

206214
# Check if the node is already initialized (part of a replica set)
207-
if mongosh --host localhost --port $MONGO_PORT -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "JSON.stringify(rs.status())" 2>/dev/null | grep -q '"ok":1'; then
215+
if mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "JSON.stringify(rs.status())" 2>/dev/null | grep -q '"ok":1'; then
208216
IS_INITIALIZED=true
209217
echo "This node is already initialized as part of a replica set."
210218

211219
# Now check if it's primary
212-
if mongosh --host localhost --port $MONGO_PORT -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "JSON.stringify(rs.isMaster())" 2>/dev/null | grep -q '"ismaster":true'; then
220+
if mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "JSON.stringify(rs.isMaster())" 2>/dev/null | grep -q '"ismaster":true'; then
213221
IS_PRIMARY=true
214222
echo "This node is the primary."
215223
else
@@ -226,7 +234,7 @@ if [ -f "$CONFIG_FILE" ]; then
226234
echo "Initializing replica set with domain name..."
227235

228236
# Initialize the replica set with the domain name instead of localhost
229-
if mongosh --host localhost --port $MONGO_PORT $TLS_ARGS -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval "
237+
if mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval "
230238
rs.initiate({
231239
_id: '$REPLICA_SET',
232240
members: [{ _id: 0, host: '$DOMAIN:$MONGO_PORT' }]
@@ -236,25 +244,25 @@ if [ -f "$CONFIG_FILE" ]; then
236244

237245
# Verify the initialization
238246
echo "Verifying replica set configuration..."
239-
mongosh --host localhost --port $MONGO_PORT $TLS_ARGS -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "rs.conf().members.forEach(function(m) { print(m.host); })"
247+
mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "rs.conf().members.forEach(function(m) { print(m.host); })"
240248
else
241249
echo "❌ ERROR: Failed to initialize replica set. You may need to initialize it manually."
242250
echo "Manual initialization command:"
243-
echo "mongosh --host localhost --port $MONGO_PORT $TLS_ARGS -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval \"rs.initiate({ _id: '$REPLICA_SET', members: [{ _id: 0, host: '$DOMAIN:$MONGO_PORT' }] })\""
251+
echo "mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval \"rs.initiate({ _id: '$REPLICA_SET', members: [{ _id: 0, host: '$DOMAIN:$MONGO_PORT' }] })\""
244252
fi
245253
elif [ "$IS_INITIALIZED" = true ]; then
246254
# This is an already initialized primary node, check if we need to update the configuration
247255
echo "Checking if replica set configuration needs to be updated..."
248256

249257
# Get current replica set configuration
250258
TEMP_FILE=$(mktemp)
251-
if mongosh --host localhost --port $MONGO_PORT $TLS_ARGS -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "JSON.stringify(rs.conf())" > $TEMP_FILE 2>/dev/null; then
259+
if mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "JSON.stringify(rs.conf())" > $TEMP_FILE 2>/dev/null; then
252260
# Check if any member is using localhost
253261
if grep -q "localhost" $TEMP_FILE; then
254262
echo "Found localhost in replica set configuration. Updating to use domain name..."
255263

256264
# Update replica set configuration to use domain name
257-
if mongosh --host localhost --port $MONGO_PORT $TLS_ARGS -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval "
265+
if mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval "
258266
var config = rs.conf();
259267
for (var i = 0; i < config.members.length; i++) {
260268
if (config.members[i].host.includes('localhost')) {
@@ -268,11 +276,11 @@ if [ -f "$CONFIG_FILE" ]; then
268276

269277
# Verify the update
270278
echo "Verifying updated configuration..."
271-
mongosh --host localhost --port $MONGO_PORT $TLS_ARGS -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "rs.conf().members.forEach(function(m) { print(m.host); })"
279+
mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --quiet --eval "rs.conf().members.forEach(function(m) { print(m.host); })"
272280
else
273281
echo "⚠️ WARNING: Failed to update replica set configuration. You may need to update it manually."
274282
echo "Manual update command:"
275-
echo "mongosh --host localhost --port $MONGO_PORT $TLS_ARGS -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval \"var config = rs.conf(); config.members[0].host = '$DOMAIN:$MONGO_PORT'; rs.reconfig(config);\""
283+
echo "mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p $DB_PASSWORD --authenticationDatabase admin --eval \"var config = rs.conf(); config.members[0].host = '$DOMAIN:$MONGO_PORT'; rs.reconfig(config);\""
276284
fi
277285
else
278286
echo "Replica set configuration already using domain name. No update needed."
@@ -309,4 +317,11 @@ fi
309317

310318
echo "✅ TLS configuration complete"
311319
echo "MongoDB is now configured to use TLS with the certificate at $CERT_FILE"
312-
echo "Clients will need to connect using TLS"
320+
echo ""
321+
echo "IMPORTANT: Client certificates are required for connections"
322+
echo "To connect to MongoDB, you will need:"
323+
echo "1. A client certificate signed by your CA"
324+
echo "2. Connect using the domain name that matches your server certificate"
325+
echo ""
326+
echo "Example connection command:"
327+
echo "mongosh --host $DOMAIN --port $MONGO_PORT --tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem -u $DB_USERNAME -p <password> --authenticationDatabase admin"

utils/create_backup.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ create_backup() {
4646

4747
# Use the exact command that works
4848
if [ "$tls_enabled" = "true" ]; then
49-
TLS_ARG="--ssl"
49+
TLS_ARG="--ssl --sslCAFile $CA_FILE --sslPEMKeyFile /etc/ssl/mongodb/client.pem"
50+
echo "NOTE: Client certificates are required for connections."
51+
echo " Ensure the client certificate exists at /etc/ssl/mongodb/client.pem"
5052
else
5153
TLS_ARG=""
5254
fi

utils/replica_sets.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ TLS_ARGS=""
2222

2323
if [ -f "$CERT_FILE" ] && grep -q "tls:" /etc/mongod.conf && grep -q "mode: requireTLS" /etc/mongod.conf; then
2424
echo "MongoDB TLS is enabled. Using TLS connection..."
25-
TLS_ARGS="--tls"
25+
echo "NOTE: Client certificates are required for connections."
26+
TLS_ARGS="--tls --tlsCAFile $CA_FILE --tlsCertificateKeyFile /etc/ssl/mongodb/client.pem"
27+
echo "IMPORTANT: Ensure the client certificate exists at /etc/ssl/mongodb/client.pem"
2628
elif grep -q "ssl:" /etc/mongod.conf && grep -q "mode: requireSSL" /etc/mongod.conf; then
2729
# For backward compatibility with older configurations
2830
echo "MongoDB SSL is enabled. Using SSL connection..."

utils/restore_backup.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ restore_backup() {
5151

5252
# Use the exact command that works
5353
if [ "$tls_enabled" = "true" ]; then
54-
TLS_ARG="--ssl"
54+
TLS_ARG="--ssl --sslCAFile $CA_FILE --sslPEMKeyFile /etc/ssl/mongodb/client.pem"
55+
echo "NOTE: Client certificates are required for connections."
56+
echo " Ensure the client certificate exists at /etc/ssl/mongodb/client.pem"
5557
else
5658
TLS_ARG=""
5759
fi

0 commit comments

Comments
 (0)