<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged ssl</title>
<link>https://coderlegion.com/tag/ssl</link>
<description>Powered by Question2Answer</description>
<item>
<title>Bash Script to Automatically Renew and Reload SSL Certificates</title>
<link>https://coderlegion.com/13256/bash-script-to-automatically-renew-and-reload-ssl-certificates</link>
<description>&lt;p&gt;Keeping your website secure isn’t optional anymore. Users expect it, browsers enforce it, and search engines reward it. SSL certificates are a core part of that security, but managing them manually can quickly become a headache, especially when they expire every 90 days.&lt;/p&gt;
&lt;p&gt;If you’ve ever had a site go down or show a &quot;Not Secure&quot; warning because of an expired certificate, you know how frustrating it can be.&lt;/p&gt;
&lt;p&gt;The good news is that you can automate the entire process. In this post, you’ll learn how to use a simple Bash script to automatically renew your SSL certificates and reload your web server without any downtime.&lt;/p&gt;
&lt;h3 id=&quot;why-automating-ssl-renewal-matters&quot;&gt;Why Automating SSL Renewal Matters&lt;/h3&gt;
&lt;p&gt;Let’s start with the obvious. SSL certificates expire. If you’re using Let’s Encrypt, they typically last 90 days. That’s great for security, but it means you need a reliable renewal process.&lt;/p&gt;
&lt;p&gt;Manual renewal comes with risks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You forget to renew on time&lt;/li&gt;
&lt;li&gt;You renew but forget to reload your server&lt;/li&gt;
&lt;li&gt;Your site goes offline unexpectedly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Automation solves all of this. Once set up, your system quietly handles renewals in the background.&lt;/p&gt;
&lt;p&gt;You get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Continuous HTTPS protection&lt;/li&gt;
&lt;li&gt;Zero manual effort&lt;/li&gt;
&lt;li&gt;No surprise outages&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-this-script-does&quot;&gt;What This Script Does&lt;/h3&gt;
&lt;p&gt;The Bash script we’re working with handles three main tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Renews SSL certificates using Certbot&lt;/li&gt;
&lt;li&gt;Checks if renewal was successful&lt;/li&gt;
&lt;li&gt;Reloads your web server (like Nginx or Apache) to apply changes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s simple, efficient, and reliable.&lt;/p&gt;
&lt;h3 id=&quot;the-bash-script&quot;&gt;The Bash Script&lt;/h3&gt;
&lt;p&gt;Here’s a clean version of the script:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash

LOG_FILE=&quot;/var/log/ssl_renewal.log&quot;
DATE=$(date '+%Y-%m-%d %H:%M:%S')

echo &quot;[$DATE] Starting SSL renewal process...&quot; &amp;gt;&amp;gt; $LOG_FILE

# Renew certificates
certbot renew --quiet

# Check if renewal was successful
if [ $? -eq 0 ]; then
    echo &quot;[$DATE] SSL certificates renewed successfully.&quot; &amp;gt;&amp;gt; $LOG_FILE
    
    # Reload web server
    systemctl reload nginx
    
    if [ $? -eq 0 ]; then
        echo &quot;[$DATE] Nginx reloaded successfully.&quot; &amp;gt;&amp;gt; $LOG_FILE
    else
        echo &quot;[$DATE] Failed to reload Nginx.&quot; &amp;gt;&amp;gt; $LOG_FILE
    fi
else
    echo &quot;[$DATE] SSL renewal failed.&quot; &amp;gt;&amp;gt; $LOG_FILE
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;breaking-it-down&quot;&gt;Breaking It Down&lt;/h3&gt;
&lt;p&gt;If you’re not deeply familiar with Bash, here’s what’s happening in plain terms.&lt;/p&gt;
&lt;h4 id=&quot;logging-activity&quot;&gt;Logging Activity&lt;/h4&gt;
&lt;p&gt;The script logs everything to a file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;LOG_FILE=&quot;/var/log/ssl_renewal.log&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is useful for troubleshooting. If something goes wrong, you can check the log.&lt;/p&gt;
&lt;h4 id=&quot;running-certbot&quot;&gt;Running Certbot&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;certbot renew --quiet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command attempts to renew any certificates that are close to expiration. The &lt;code&gt;--quiet&lt;/code&gt; flag keeps things clean unless there’s an error.&lt;/p&gt;
&lt;h4 id=&quot;checking-success&quot;&gt;Checking Success&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;if [ $? -eq 0 ];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This checks whether the previous command worked. A return value of &lt;code&gt;0&lt;/code&gt; means success.&lt;/p&gt;
&lt;h4 id=&quot;reloading-the-server&quot;&gt;Reloading the Server&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This applies the new certificates without restarting the server, which means no downtime.&lt;/p&gt;
&lt;p&gt;If you’re using Apache instead, you’d replace that with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;automating-with-cron&quot;&gt;Automating with Cron&lt;/h3&gt;
&lt;p&gt;The script is only useful if it runs automatically. That’s where cron jobs come in.&lt;/p&gt;
&lt;p&gt;Open your crontab:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;crontab -e
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add this line to run the script daily at 2:30 AM:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;30 2 * * * /path/to/your/script.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure your script is executable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;chmod +x /path/to/your/script.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it. Your server now handles SSL renewal on its own.&lt;/p&gt;
&lt;h3 id=&quot;best-practices-for-ssl-automation&quot;&gt;Best Practices for SSL Automation&lt;/h3&gt;
&lt;p&gt;To keep things running smoothly, follow a few simple guidelines:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Test your setup&lt;/strong&gt;&lt;br&gt;
Run the script manually before relying on automation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;./script.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. Use staging mode first&lt;/strong&gt;&lt;br&gt;
If you’re testing renewal logic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;certbot renew --dry-run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. Monitor logs&lt;/strong&gt;&lt;br&gt;
Check your log file occasionally:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cat /var/log/ssl_renewal.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;4. Set up alerts (optional)&lt;/strong&gt;&lt;br&gt;
For production systems, consider email alerts if renewal fails.&lt;/p&gt;
&lt;h3 id=&quot;common-issues-to-watch-for&quot;&gt;Common Issues to Watch For&lt;/h3&gt;
&lt;p&gt;Even with automation, things can go wrong. Here are a few common problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Port 80/443 blocked&lt;/strong&gt;: Certbot needs access for validation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Incorrect domain configuration&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server reload failures due to config errors&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If renewal fails, the logs will usually point you in the right direction.&lt;/p&gt;
&lt;h3 id=&quot;seo-benefits-of-ssl-yes-it-matters-&quot;&gt;SEO Benefits of SSL (Yes, It Matters)&lt;/h3&gt;
&lt;p&gt;Beyond security, SSL certificates also impact your search rankings from the eyes of a developer.&lt;/p&gt;
&lt;p&gt;Google uses HTTPS as a ranking signal. Sites without SSL may:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rank lower in search results&lt;/li&gt;
&lt;li&gt;Show &quot;Not Secure&quot; warnings in browsers&lt;/li&gt;
&lt;li&gt;Lose user trust&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Automating SSL renewal helps maintain both your security and your SEO performance.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;Automating SSL certificate renewal with a Bash script is one of those small improvements that pays off constantly. It saves time, prevents downtime, and keeps your site secure without ongoing effort.&lt;/p&gt;
&lt;p&gt;Once you set it up, you can forget about expiration dates and focus on what actually matters, like building and growing your site.&lt;/p&gt;
&lt;p&gt;If you manage multiple servers or websites, this approach becomes even more valuable.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you found this helpful, consider sharing it with someone who manages servers or websites. It might save them from their next &quot;certificate expired&quot; panic.&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/13256/bash-script-to-automatically-renew-and-reload-ssl-certificates</guid>
<pubDate>Fri, 20 Mar 2026 10:34:54 +0000</pubDate>
</item>
<item>
<title>The SSL Handshake Failed: Debugging the &quot;Invisible Wall&quot; in Monoliths and Microservices</title>
<link>https://coderlegion.com/10306/the-ssl-handshake-failed-debugging-the-invisible-wall-in-monoliths-and-microservices</link>
<description>&lt;p&gt;We’ve all been there. The logs say &lt;code&gt;Connection Refused&lt;/code&gt; or the dreaded &lt;code&gt;javax.net.ssl.SSLHandshakeException&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The network team swears the firewall is open. The platform team says the certificates are valid. The application team says &quot;it works on my machine.&quot; And yet, your traffic is hitting an invisible wall.&lt;/p&gt;
&lt;p&gt;I used to treat SSL/TLS errors as a &quot;black box&quot; mystery—restart the server and pray. But after years of debugging secure connections in enterprise integration (webMethods, Java, and now microservices), I’ve realized that the handshake isn't random. It’s a precise, step-by-step negotiation that fails for predictable reasons.&lt;/p&gt;
&lt;p&gt;In this deep dive, I break down:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Anatomy of the Fail:&lt;/strong&gt; Where exactly the &quot;Client Hello&quot; or &quot;Server Hello&quot; dies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Certificate Chain of Trust:&lt;/strong&gt; Why your root CA might be the silent killer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Debug Tools:&lt;/strong&gt; How to use &lt;code&gt;openssl&lt;/code&gt; and JVM flags to see what’s actually happening on the wire.&lt;/p&gt;
&lt;p&gt;Stop guessing. Here is how you actually debug the invisible wall.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.webmethodman.com/p/the-ssl-handshake-failed-now-what&quot;&gt;The SSL Handshake Failed. Now What?&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/10306/the-ssl-handshake-failed-debugging-the-invisible-wall-in-monoliths-and-microservices</guid>
<pubDate>Thu, 22 Jan 2026 21:48:04 +0000</pubDate>
</item>
<item>
<title>How to update SSL certificates through file upload in SafeLine WAF</title>
<link>https://coderlegion.com/8109/how-to-update-ssl-certificates-through-file-upload-in-safeline-waf</link>
<description>&lt;p&gt;Some users find it cumbersome to manually upload certificates through the interface when using Safeline WAF's SSL Cert feature. &lt;/p&gt;
&lt;p&gt;They want to store certificate files in a fixed directory and have Safeline automatically detect and update them after overwriting, allowing the entire process to be completed through automation tools. Related issues include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine/issues/782&quot;&gt;[Suggestion] Add path import method for certificates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine/issues/733&quot;&gt;[Bug] After manually updating certificate files and restarting the container, the expiration time in the [Certificate Management] interface is not synchronized&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine/issues/362&quot;&gt;Suggestions for combining acme.sh for automatic certificate deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine/issues/1205&quot;&gt;[Suggestion] Allow loading wildcard certificate from file system&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To solve or optimize the above issues, Safeline Community Edition launched the automatic certificate reading and updating feature in &lt;code&gt;version 7.2.0&lt;/code&gt;. Below is an introduction to how to use this feature.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;WAF version &amp;gt;= 7.2.0&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;upload-certificate-once&quot;&gt;Upload Certificate Once&lt;/h3&gt;
&lt;p&gt;To let the WAF know that there are certificates that need periodic updates, you need to upload the certificate once in the WAF.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1boud7sgemty8vexo37j.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;get-certificate-path&quot;&gt;Get Certificate Path&lt;/h3&gt;
&lt;p&gt;By default, certificates are saved in &lt;code&gt;/data/safeline/resources/nginx/certs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ls /data/safeline/resources/nginx/certs/ -lh
total 8.0K
-rw-r--r-- 1 root root 1.4K Nov 22 18:15 cert_1.crt
-rw-r--r-- 1 root root 1.7K Nov 22 18:15 cert_1.key
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;update-certificates-using-files&quot;&gt;Update Certificates Using Files&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You can use tools like certbot to apply for free certificates&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After obtaining the certificates, simply overwrite the above files&lt;/p&gt;
&lt;h3 id=&quot;waf-automatic-updates&quot;&gt;WAF Automatic Updates&lt;/h3&gt;
&lt;p&gt;WAF refreshes certificate content every hour by default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SafeLine Resources:&lt;/strong&gt;&lt;br&gt;
SafeLine Website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://ly.safepoint.cloud/ShZAy9x&quot;&gt;https://ly.safepoint.cloud/ShZAy9x&lt;/a&gt;&lt;br&gt;
Live Demo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://demo.waf.chaitin.com:9443/statistics&quot;&gt;https://demo.waf.chaitin.com:9443/statistics&lt;/a&gt;&lt;br&gt;
Discord: &lt;a rel=&quot;nofollow&quot; href=&quot;https://discord.gg/dy3JT7dkmY&quot;&gt;https://discord.gg/dy3JT7dkmY&lt;/a&gt;&lt;br&gt;
Doc: &lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.waf.chaitin.com/en/home&quot;&gt;https://docs.waf.chaitin.com/en/home&lt;/a&gt;&lt;br&gt;
Github: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/chaitin/SafeLine&quot;&gt;https://github.com/chaitin/SafeLine&lt;/a&gt;&lt;/p&gt;
</description>
<category>Getting Started</category>
<guid isPermaLink="true">https://coderlegion.com/8109/how-to-update-ssl-certificates-through-file-upload-in-safeline-waf</guid>
<pubDate>Wed, 03 Dec 2025 03:49:25 +0000</pubDate>
</item>
<item>
<title>PostgreSQL Client Certificate Authentication: Complete Setup Guide</title>
<link>https://coderlegion.com/4373/postgresql-client-certificate-authentication-complete-setup-guide</link>
<description>&lt;p&gt;Client certificate authentication in PostgreSQL provides a secure, passwordless way to authenticate users. Instead of relying on passwords, clients present valid X.509 certificates to prove their identity.&lt;/p&gt;
&lt;h3 id=&quot;what-to-configure&quot;&gt;What to Configure&lt;/h3&gt;
&lt;h4 id=&quot;server-side-requirements&quot;&gt;Server-Side Requirements&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SSL certificates&lt;/strong&gt;: Server certificate + client certificates&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PostgreSQL SSL settings&lt;/strong&gt;: Enable SSL and configure certificate paths&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authentication rules&lt;/strong&gt;: Configure &lt;code&gt;pg_hba.conf&lt;/code&gt; for certificate-based auth&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User mapping&lt;/strong&gt;: Link certificate Common Names to database users&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;client-side-requirements&quot;&gt;Client-Side Requirements&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Client certificate&lt;/strong&gt;: Valid X.509 certificate for the user&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private key&lt;/strong&gt;: Matching private key for the certificate&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Root certificate&lt;/strong&gt;: Server's certificate for verification&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connection parameters&lt;/strong&gt;: Proper SSL mode and certificate paths&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-to-configure&quot;&gt;How to Configure&lt;/h3&gt;
&lt;h4 id=&quot;1-generate-ssl-certificates&quot;&gt;1. Generate SSL Certificates&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Create SSL directory
mkdir -p /var/lib/postgresql/17/main/ssl
cd /var/lib/postgresql/17/main/ssl

# Generate server certificate
openssl genrsa -out server.key 4096
openssl req -new -key server.key -out server.csr \
  -subj &quot;/C=US/ST=State/L=City/O=Org/OU=OrgUnit/CN=localhost&quot;
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

# Generate client certificate for user 'appuser'
openssl genrsa -out appuser.key 4096
openssl req -new -key appuser.key -out appuser.csr \
  -subj &quot;/C=US/ST=State/L=City/O=Org/OU=OrgUnit/CN=appuser&quot;
openssl x509 -req -days 365 -in appuser.csr \
  -CA server.crt -CAkey server.key -CAcreateserial -out appuser.crt

# Set permissions
chown postgres:postgres *.crt *.key
chmod 600 *.key
chmod 644 *.crt
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;2-configure-postgresql-ssl-settings&quot;&gt;2. Configure PostgreSQL SSL Settings&lt;/h4&gt;
&lt;p&gt;Add to &lt;code&gt;postgresql.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;# SSL Configuration
ssl = on
ssl_cert_file = '/var/lib/postgresql/17/main/ssl/server.crt'
ssl_key_file = '/var/lib/postgresql/17/main/ssl/server.key'
ssl_ca_file = '/var/lib/postgresql/17/main/ssl/server.crt'
ssl_prefer_server_ciphers = on
ssl_min_protocol_version = 'TLSv1.2'
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;3-configure-authentication-rules&quot;&gt;3. Configure Authentication Rules&lt;/h4&gt;
&lt;p&gt;Update &lt;code&gt;pg_hba.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# SSL connections require client certificate authentication
hostssl all             all             0.0.0.0/0               cert clientcert=verify-full
hostssl all             all             ::/0                    cert clientcert=verify-full

# Non-SSL connections require password authentication
hostnossl all           all             0.0.0.0/0               scram-sha-256
hostnossl all           all             ::/0                    scram-sha-256
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;4-create-database-user&quot;&gt;4. Create Database User&lt;/h4&gt;
&lt;p&gt;The database user must match the certificate's Common Name(&lt;strong&gt;CN&lt;/strong&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE USER appuser WITH LOGIN;
GRANT CONNECT ON DATABASE mydb TO appuser;
-- Grant additional permissions as needed
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;how-to-connect-from-client&quot;&gt;How to Connect from Client&lt;/h3&gt;
&lt;h4 id=&quot;critical-connection-parameters&quot;&gt;Critical Connection Parameters&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Parameter     &lt;/th&gt;&lt;th&gt;Self-Managed Value            &lt;/th&gt;&lt;th&gt;RDS Value                           &lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sslmode&lt;/code&gt;     &lt;/td&gt;&lt;td&gt;&lt;code&gt;require&lt;/code&gt; or &lt;code&gt;verify-full&lt;/code&gt;    &lt;/td&gt;&lt;td&gt;&lt;code&gt;require&lt;/code&gt; or &lt;code&gt;verify-full&lt;/code&gt;          &lt;/td&gt;&lt;td&gt;Force SSL connection&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sslcert&lt;/code&gt;     &lt;/td&gt;&lt;td&gt;&lt;code&gt;/path/to/client.crt&lt;/code&gt;         &lt;/td&gt;&lt;td&gt;N/A (not supported)                 &lt;/td&gt;&lt;td&gt;Client certificate file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sslkey&lt;/code&gt;      &lt;/td&gt;&lt;td&gt;&lt;code&gt;/path/to/client.key&lt;/code&gt;         &lt;/td&gt;&lt;td&gt;N/A (not supported)                 &lt;/td&gt;&lt;td&gt;Client private key file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sslrootcert&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;/path/to/server.crt&lt;/code&gt;         &lt;/td&gt;&lt;td&gt;&lt;code&gt;./global-bundle.pem&lt;/code&gt;               &lt;/td&gt;&lt;td&gt;Server certificate for verification&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;host&lt;/code&gt;        &lt;/td&gt;&lt;td&gt;&lt;code&gt;localhost&lt;/code&gt; or custom         &lt;/td&gt;&lt;td&gt;&lt;code&gt;instance.region.rds.amazonaws.com&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Database server endpoint&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;password&lt;/code&gt;    &lt;/td&gt;&lt;td&gt;Not required with client cert &lt;/td&gt;&lt;td&gt;Required (or IAM token)             &lt;/td&gt;&lt;td&gt;Authentication credential&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;connection-examples&quot;&gt;Connection Examples&lt;/h4&gt;
&lt;h5 id=&quot;self-managed-postgresql-with-client-certificates&quot;&gt;Self-Managed PostgreSQL with Client Certificates&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# psql - No password required
psql &quot;host=localhost port=5432 dbname=mydb user=appuser \
      sslmode=require \
      sslcert=./certs/appuser.crt \
      sslkey=./certs/appuser.key \
      sslrootcert=./certs/server.crt&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// .NET - Client certificate authentication
var connectionString = &quot;Host=localhost;Port=5432;Database=mydb;Username=appuser;&quot; +
                      &quot;SSL Mode=Require;&quot; +
                      &quot;Client Certificate=./certs/appuser.crt;&quot; +
                      &quot;Client Key=./certs/appuser.key;&quot; +
                      &quot;Root Certificate=./certs/server.crt;&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Python - Client certificate authentication
import psycopg2
conn = psycopg2.connect(
    host=&quot;localhost&quot;,
    port=5432,
    database=&quot;mydb&quot;,
    user=&quot;appuser&quot;,
    sslmode=&quot;require&quot;,
    sslcert=&quot;./certs/appuser.crt&quot;,
    sslkey=&quot;./certs/appuser.key&quot;,
    sslrootcert=&quot;./certs/server.crt&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;// Java JDBC - Client certificate authentication
String url = &quot;jdbc:postgresql://localhost:5432/mydb&quot; +
            &quot;?ssl=true&quot; +
            &quot;&amp;amp;sslmode=require&quot; +
            &quot;&amp;amp;sslcert=./certs/appuser.crt&quot; +
            &quot;&amp;amp;sslkey=./certs/appuser.key&quot; +
            &quot;&amp;amp;sslrootcert=./certs/server.crt&quot; +
            &quot;&amp;amp;user=appuser&quot;;

Connection conn = DriverManager.getConnection(url);
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;aws-rds-postgresql-with-ssl-password-required-&quot;&gt;AWS RDS PostgreSQL with SSL (Password Required)&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# psql - Password required, verify server certificate
psql &quot;host=mydb.cluster-xyz.us-east-1.rds.amazonaws.com \
      port=5432 dbname=postgres user=myuser password=mypassword \
      sslmode=verify-full sslrootcert=./global-bundle.pem&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;// .NET - RDS with SSL verification
var connectionString = &quot;Host=mydb.cluster-xyz.us-east-1.rds.amazonaws.com;&quot; +
                      &quot;Port=5432;Database=postgres;Username=myuser;Password=mypassword;&quot; +
                      &quot;SSL Mode=Require;Root Certificate=./global-bundle.pem;&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Python - RDS with SSL verification  
import psycopg2
conn = psycopg2.connect(
    host=&quot;mydb.cluster-xyz.us-east-1.rds.amazonaws.com&quot;,
    port=5432,
    database=&quot;postgres&quot;,
    user=&quot;myuser&quot;,
    password=&quot;mypassword&quot;,
    sslmode=&quot;verify-full&quot;,
    sslrootcert=&quot;./global-bundle.pem&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;// Java JDBC - RDS with SSL verification
String url = &quot;jdbc:postgresql://mydb.cluster-xyz.us-east-1.rds.amazonaws.com:5432/postgres&quot; +
            &quot;?ssl=true&quot; +
            &quot;&amp;amp;sslmode=verify-full&quot; +
            &quot;&amp;amp;sslrootcert=./global-bundle.pem&quot; +
            &quot;&amp;amp;user=myuser&quot; +
            &quot;&amp;amp;password=mypassword&quot;;

Connection conn = DriverManager.getConnection(url);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;server-configuration-vs-client-parameters&quot;&gt;Server Configuration vs Client Parameters&lt;/h3&gt;
&lt;h4 id=&quot;server-side-pg-hba-conf-&quot;&gt;Server Side (&lt;code&gt;pg_hba.conf&lt;/code&gt;)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Authentication method MUST be 'cert'
hostssl all all 0.0.0.0/0 cert clientcert=verify-full
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;client-side-connection-string-&quot;&gt;Client Side (Connection String)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# SSL mode MUST be 'require' or 'verify-full'
sslmode=require
# All three certificate files MUST be provided
sslcert=./client.crt
sslkey=./client.key  
sslrootcert=./server.crt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;common-pitfalls&quot;&gt;Common Pitfalls&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Certificate CN mismatch&lt;/strong&gt;: Client certificate CN must match database username&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Missing clientcert=verify-full&lt;/strong&gt;: Server won't require client certificates&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wrong SSL mode&lt;/strong&gt;: &lt;code&gt;sslmode=disable&lt;/code&gt; or &lt;code&gt;prefer&lt;/code&gt; may skip certificate auth&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File permissions&lt;/strong&gt;: Private keys must be readable only by the client process&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Certificate expiration&lt;/strong&gt;: Monitor and rotate certificates before expiry&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;security-benefits&quot;&gt;Security Benefits&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No password transmission&lt;/strong&gt;: Eliminates password-based attacks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strong authentication&lt;/strong&gt;: Based on cryptographic proof of identity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Non-repudiation&lt;/strong&gt;: Certificate-based audit trails&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mutual authentication&lt;/strong&gt;: Both client and server verify each other&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;aws-rds-postgresql-configuration&quot;&gt;AWS RDS PostgreSQL Configuration&lt;/h3&gt;
&lt;h4 id=&quot;rds-limitations-for-client-certificates&quot;&gt;RDS Limitations for Client Certificates&lt;/h4&gt;
&lt;p&gt;AWS RDS PostgreSQL has &lt;strong&gt;limited support&lt;/strong&gt; for client certificate authentication compared to self-managed PostgreSQL:&lt;/p&gt;
&lt;h5 id=&quot;what-s-not-available-in-rds&quot;&gt;What's NOT Available in RDS&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Custom client certificate generation&lt;/strong&gt;: You cannot upload custom client certificates&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full &lt;code&gt;cert&lt;/code&gt; authentication method&lt;/strong&gt;: RDS doesn't support the &lt;code&gt;cert&lt;/code&gt; method in &lt;code&gt;pg_hba.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct certificate file access&lt;/strong&gt;: No access to &lt;code&gt;/var/lib/postgresql/&lt;/code&gt; directory&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;what-is-available-in-rds&quot;&gt;What IS Available in RDS&lt;/h5&gt;
&lt;h4 id=&quot;1-rds-ssl-server-certificates-amp-configuration&quot;&gt;1. RDS SSL Server Certificates &amp;amp; Configuration&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Download RDS CA certificate bundle
wget https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem

# Enable SSL in RDS parameter group
aws rds modify-db-parameter-group \
    --db-parameter-group-name mygroup \
    --parameters &quot;ParameterName=ssl,ParameterValue=1,ApplyMethod=immediate&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;2-alternative-iam-database-authentication&quot;&gt;2. Alternative: IAM Database Authentication&lt;/h4&gt;
&lt;p&gt;For passwordless authentication in RDS, use IAM database authentication:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Create IAM-enabled database user
CREATE USER iamuser;
GRANT rds_iam TO iamuser;
GRANT CONNECT ON DATABASE postgres TO iamuser;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Connect using IAM token (Python example)
import boto3
import psycopg2

rds_client = boto3.client('rds', region_name='us-east-1')
token = rds_client.generate_db_auth_token(
    DBHostname='mydb.xyz.us-east-1.rds.amazonaws.com',
    Port=5432,
    DBUsername='iamuser'
)

conn = psycopg2.connect(
    host=&quot;mydb.xyz.us-east-1.rds.amazonaws.com&quot;,
    port=5432,
    database=&quot;postgres&quot;,
    user=&quot;iamuser&quot;,
    password=token,  # IAM token as password
    sslmode=&quot;require&quot;,
    sslrootcert=&quot;./global-bundle.pem&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;3-hybrid-approach-alb-client-certificates-rds&quot;&gt;3. Hybrid Approach: ALB + Client Certificates + RDS&lt;/h4&gt;
&lt;p&gt;For applications requiring client certificate authentication with RDS:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;[Client with Client Cert] → [ALB with SSL termination] → [App Server] → [RDS with IAM Auth]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ALB handles client certificate verification&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application validates certificates in code&lt;/strong&gt;  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RDS connection uses IAM authentication&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;summary-amp-verification&quot;&gt;Summary &amp;amp; Verification&lt;/h3&gt;
&lt;h4 id=&quot;self-managed-vs-aws-rds-comparison&quot;&gt;Self-Managed vs AWS RDS Comparison&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Feature                     &lt;/th&gt;&lt;th&gt;Self-Managed          &lt;/th&gt;&lt;th&gt;AWS RDS&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Client Certificate Auth     &lt;/td&gt;&lt;td&gt;✅ Full support        &lt;/td&gt;&lt;td&gt;❌ Not supported&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Server SSL Certificates     &lt;/td&gt;&lt;td&gt;✅ Custom certificates &lt;/td&gt;&lt;td&gt;✅ AWS-managed certificates&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Passwordless Authentication &lt;/td&gt;&lt;td&gt;✅ Client certificates &lt;/td&gt;&lt;td&gt;✅ IAM authentication&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Certificate Management      &lt;/td&gt;&lt;td&gt;❌ Manual rotation     &lt;/td&gt;&lt;td&gt;✅ Automatic rotation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SSL Configuration Control   &lt;/td&gt;&lt;td&gt;✅ Full control        &lt;/td&gt;&lt;td&gt;❌ Limited parameters&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&quot;verification-commands&quot;&gt;Verification Commands&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Verify SSL is enabled
SHOW ssl;

-- Check active SSL connections with certificate details
SELECT datname, usename, client_addr, ssl, ssl_version, ssl_cipher,
       client_dn, issuer_dn
FROM pg_stat_ssl 
JOIN pg_stat_activity ON pg_stat_ssl.pid = pg_stat_activity.pid 
WHERE ssl = true;
-- Example output
pid|ssl |version|cipher                |bits|client_dn                                                      |client_serial                                   |issuer_dn                                                   |datid|datname       |pid|leader_pid|usesysid|usename       |application_name|client_addr|client_hostname|client_port|backend_start                |xact_start|query_start                  |state_change                 |wait_event_type|wait_event|state|backend_xid|backend_xmin|query_id           |query                                                                                                                        |backend_type  |
---+----+-------+----------------------+----+---------------------------------------------------------------+------------------------------------------------+------------------------------------------------------------+-----+--------------+---+----------+--------+--------------+----------------+-----------+---------------+-----------+-----------------------------+----------+-----------------------------+-----------------------------+---------------+----------+-----+-----------+------------+-------------------+-----------------------------------------------------------------------------------------------------------------------------+--------------+
754|true|TLSv1.3|TLS_AES_256_GCM_SHA384| 256|/C=US/ST=State/L=City/O=Organization/OU=OrgUnit/CN=redgatemonit|608692775915102986323080169170088721995325147053|/C=US/ST=State/L=City/O=Organization/OU=OrgUnit/CN=localhost|16384|redgatemonitor|754|          |   16385|redgatemonitor|psql            |10.88.0.1  |               |      59168|2025-07-30 09:43:20.240 +0100|          |2025-07-30 09:43:58.869 +0100|2025-07-30 09:43:58.870 +0100|Client         |ClientRead|idle |           |            |8885888923103386772|SELECT datname, usename, client_addr, ssl,* FROM pg_stat_ssl JOIN pg_stat_activity ON pg_stat_ssl.pid = pg_stat_activity.pid;|client backend|
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Self-managed PostgreSQL&lt;/strong&gt;: Use client certificates for true passwordless authentication&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS RDS&lt;/strong&gt;: Combine IAM authentication with SSL encryption for secure connections&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hybrid approach&lt;/strong&gt;: Use ALB for client certificate verification with RDS backend&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Both approaches provide enterprise-grade security with different trade-offs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Client certificate authentication in PostgreSQL provides enterprise-grade security without the overhead of password management, making it ideal for automated systems and high-security environments.&lt;/p&gt;
&lt;h4 id=&quot;references&quot;&gt;References&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.postgresql.org/docs/current/ssl-tcp.html&quot;&gt;https://www.postgresql.org/docs/current/ssl-tcp.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/4373/postgresql-client-certificate-authentication-complete-setup-guide</guid>
<pubDate>Fri, 01 Aug 2025 12:50:19 +0000</pubDate>
</item>
</channel>
</rss>