Nginx-ல் mTLS மற்றும் Client Certificate அமைப்பது எப்படி?
OpenSSL மூலம் சொந்தமாக CA உருவாக்கி, Nginx-ல் mTLS மூலம் admin panel-ஐப் பாதுகாப்பது எப்படி என்பதை அறிக. சரியான certificate இல்லாத பயனர்களை நிராகரிக்கும் முறையை விளக்குகிறோம்.
mTLS-ன் செயல்பாடுகள்
Mutual TLS, பொதுவாக mTLS என்று அழைக்கப்படுகிறது. இது ஒவ்வொரு client-மிடமிருந்தும் ஒரு certificate-ஐக் கேட்கும்படி Nginx-ஐக் கட்டாயப்படுத்துகிறது. அந்த certificate விடுபட்டிருந்தாலோ அல்லது நீங்கள் நிர்வகிக்கும் certificate authority (CA) மூலம் வழங்கப்படாமல் இருந்தாலோ, Nginx அந்த request-ஐ நிராகரித்துவிடும். இந்தச் சரிபார்ப்பு TLS (transport layer security) handshake-ன் போதே நடைபெறுகிறது. எனவே, சரியான client certificate இல்லாத ஒரு caller, உங்கள் application-ஐ ஒருபோதும் சென்றடைய முடியாது. இதுவே இதன் முக்கிய ஈர்ப்பு: ஒரு admin panel அல்லது metrics endpoint-ஐ, login பக்கம் இல்லாமலேயே public internet-ல் வைக்க முடியும்; bot-கள் எதையும் ஊகிக்க முடியாது.
இதன் கட்டமைப்பு சிறியது. openssl மூலம் உருவாக்கப்பட்ட ஒரு private CA, ஒவ்வொரு நபருக்கும் ஒரு certificate, மற்றும் Nginx server block-ல் மூன்று directives மட்டுமே தேவை. இது ஓராண்டுக்கும் மேலாகச் சிறப்பாகச் செயல்படுமா என்பதைத் தீர்மானிப்பது அதன் செயல்பாட்டு மேலாண்மைதான். எனவே, இந்த வழிகாட்டியின் பெரும்பகுதி certificate-ன் ஆயுட்காலம், revocation, தனிநபர் certificates, மற்றும் ஒரு client நிராகரிக்கப்படும்போது அதற்கான காரணத்தைக் கண்டறியும் முறைகள் ஆகியவற்றைப் பற்றி விளக்குகிறது.
இரண்டு சங்கிலிகள், ஒன்றல்ல
mTLS அமைப்பில் இரண்டு சான்றிதழ் சங்கிலிகள் (certificate chains) உள்ளன, அவற்றுக்கும் ஒன்றுக்கொன்று எந்தத் தொடர்பும் இல்லை. அவற்றை ஒன்றாகக் குழப்பிக்கொள்வதுதான் அனைவரும் செய்யும் முதல் தவறு.
முதல் சங்கிலி server-க்குரியது. உங்கள் VPS, Let's Encrypt போன்ற பொதுவான CA வழங்கிய admin.example.com சான்றிதழை browser-க்குக் காட்டும்; operating system-உடன் வரும் root store-ஐ வைத்து browser அதைச் சரிபார்க்கும். mTLS-ல் இந்த பாதியில் எந்த மாற்றமும் இல்லை. certbot இன்று அந்தச் சான்றிதழை வழங்கினால், அதை அப்படியே வைத்திருங்கள்: certbot மூலம் nginx-க்கு Let's Encrypt சான்றிதழ் வழங்குதல் என்பதைப் பார்க்கவும்.
இரண்டாவது சங்கிலி client-க்குரியது. நீங்களே ஒரு சிறிய CA-வை உருவாக்கி, உள்ளே நுழைய வேண்டிய ஒவ்வொரு நபருக்கும் ஒரு சான்றிதழில் கையொப்பமிடுங்கள். client-களைச் சரிபார்க்கும்போது அந்த CA-வை மட்டும் நம்புமாறு nginx-க்குக் கட்டளையிடுங்கள். எந்தப் பொதுவான root store-க்கும் உங்கள் CA தெரியாது, அது தெரிய வேண்டிய அவசியமும் இல்லை. ssl_client_certificate கோப்பு மூலம் nginx மட்டுமே அதை நம்பினால் போதுமானது.
எனவே, ssl_client_certificate என்பது nginx காட்டும் சான்றிதழை ஒருபோதும் பாதிக்காது, மேலும் Let's Encrypt சங்கிலி எந்த client-கள் உள்ளே அனுமதிக்கப்பட வேண்டும் என்பதைப் பாதிக்காது. ssl_client_certificate-ஐ fullchain.pem-க்குச் சுட்டிக்காட்டுவது பார்ப்பதற்குச் சரியாகத் தெரிந்தாலும், அது அப்படிச் செயல்படாது: அந்த directive, ஒரு client சான்றிதழ் எந்த issuers-இடமிருந்து வரலாம் என்பதை மட்டுமே குறிப்பிடுகிறது, அது இணைப்பின் மறுமுனையாகும். server-ன் சொந்த வெளிச்செல்லும் (outbound) பணிகளுக்காக உங்கள் CA-வை நம்ப வைப்பது ஒரு தனி வேலை, அது Ubuntu trust store-ல் உங்கள் சொந்த CA-வைச் சேர்த்தல் பகுதியில் விளக்கப்பட்டுள்ளது. client-ஐச் சரிபார்க்கும்போது nginx வாசிப்பது system trust store அல்ல.
openssl மூலம் சொந்தமாக client CA உருவாக்குதல்
CA-வை web server அல்லாத வேறொரு இடத்தில் உருவாக்கவும். nginx-க்கு CA-வின் public certificate மட்டுமே தேவை. CA private key புதிய client certificate-களை கையொப்பமிடுவதால், அதை இணையத்துடன் இணைக்கப்பட்ட server-ல் வைப்பது ஆபத்தானது. ஒருமுறை server ஊடுருவப்பட்டால், தாக்குதல் நடத்துபவர் தனக்குத் தேவையான செல்லுபடியாகும் client certificate-களை உருவாக்க முடியும்.
mkdir -p ~/client-ca/certs ~/client-ca/newcerts ~/client-ca/private ~/client-ca/csr
cd ~/client-ca
chmod 700 private
touch index.txt
echo 1000 > serial
echo 1000 > crlnumberindex.txt, serial மற்றும் crlnumber ஆகியவை CA database-ஆகச் செயல்படுகின்றன. இவை இல்லையெனில் openssl ca இயங்க மறுக்கும். இவை பிற்காலத்தில் certificate-களை ரத்து செய்ய (revocation) அவசியமானவை. ஒரு revocation list-ல் serial number-கள் குறிப்பிடப்படுவதால், எந்த serial number யாருக்கு வழங்கப்பட்டது என்பதை CA நினைவில் வைத்திருக்க வேண்டும்.
~/client-ca/openssl.cnf-ஐ உருவாக்கவும். openssl ca ஆனது ~-ஐ விரிவுபடுத்தாது என்பதால், dir-ல் அந்த directory-ன் முழுமையான பாதையை (real path) குறிப்பிடவும்.
[ ca ]
default_ca = client_ca
[ client_ca ]
dir = /home/you/client-ca
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/ca.crt
private_key = $dir/private/ca.key
serial = $dir/serial
crlnumber = $dir/crlnumber
default_md = sha256
default_days = 365
default_crl_days = 30
policy = policy_loose
rand_serial = no
unique_subject = no
email_in_dn = no
[ policy_loose ]
commonName = supplied
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
emailAddress = optional
[ client_ext ]
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuerஇப்போது CA key மற்றும் அதன் self-signed certificate-ஐ உருவாக்கவும்:
openssl genrsa -aes256 -out private/ca.key 4096
chmod 600 private/ca.key
openssl req -x509 -new -key private/ca.key -sha256 -days 3650 \
-subj "/O=Example Ops/CN=Example Ops Client CA" \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
-addext "keyUsage=critical,keyCertSign,cRLSign" \
-out ca.crt-aes256 ஆனது CA key-க்கு ஒரு passphrase-ஐ அமைக்கிறது, எனவே ஒவ்வொரு முறை கையொப்பமிடும்போதும் அது கேட்கப்படும். இதுவே அதன் நோக்கம். நீங்கள் உருவாக்கியதைச் சரிபார்க்கவும்:
openssl x509 -in ca.crt -noout -subject -dates -ext basicConstraintsSubject உங்கள் CA-வாக இருக்க வேண்டும் மற்றும் அதன் செல்லுபடியாகும் காலம் பத்து ஆண்டுகளாக இருக்க வேண்டும். extension வரியில் CA:TRUE, pathlen:0 என்று இருக்க வேண்டும். pathlen:0 என்பது இந்த CA இறுதி certificate-களை மட்டுமே கையொப்பமிட முடியும், மற்றொரு CA-வை கையொப்பமிட முடியாது என்பதைக் குறிக்கிறது. இது certificate சங்கிலியை (chain) ஒரே நிலையில் வைத்திருப்பதோடு, ssl_verify_depth-ஐ மாற்றாமல் இருக்கவும் உதவுகிறது.
ஒவ்வொரு நபருக்கும் தனிப்பட்ட client certificate வழங்குதல்
ஒவ்வொரு நபருக்கும் ஒரு certificate மட்டுமே வழங்க வேண்டும். ஒரு குழுவிற்குப் பொதுவான certificate-ஐ ஒருபோதும் பயன்படுத்த வேண்டாம். ஏனெனில், பொதுவான certificate-ஐத் திரும்பப் பெற்றால் (revoke) அனைவரின் அணுகலும் துண்டிக்கப்படும்; மேலும், யார் அந்தச் சேவையை அழைத்தார்கள் என்பதை அறிய முடியாது.
openssl genrsa -out private/alice.key 2048
openssl req -new -key private/alice.key -out csr/alice.csr \
-subj "/O=Example Ops/CN=alice"
openssl ca -config openssl.cnf -extensions client_ext \
-days 365 -notext -in csr/alice.csr -out certs/alice.crtopenssl ca தான் கையொப்பமிடப்போகும் certificate-ஐக் காட்டும், CA passphrase-ஐக் கேட்கும், உறுதிப்படுத்த இருமுறை கேட்கும், பின்னர் index.txt-ல் ஒரு வரியைச் சேர்க்கும். நீங்கள் script மூலம் இதைச் செய்யும்போது -batch-ஐச் சேர்க்கவும். client_ext பகுதி முக்கியமானது, ஏனெனில் அதில் உள்ள ஒரு வரி: extendedKeyUsage = clientAuth. client authentication-க்குத் தகுதியற்றதாகக் கருதப்படும் serverAuth-ஐ மட்டும் கொண்ட extended key usage உள்ள certificate நிராகரிக்கப்படும், எனவே ஊகிப்பதற்குப் பதிலாக நோக்கத்தைத் தெளிவாகக் குறிப்பிடவும்.
எதையும் ஒப்படைக்கும் முன், CA-வுடன் அந்த இணையைச் சரிபார்க்கவும்:
openssl verify -CAfile ca.crt certs/alice.crtஇது certs/alice.crt: OK என்பதை அச்சிடும். வேறு ஏதேனும் வெளியீடு வந்தால், certificate-ம் CA-வும் பொருந்தவில்லை என்று பொருள்; எந்த nginx configuration-உம் இதைச் சரிசெய்ய முடியாது.
Browser-ல் இறக்குமதி செய்யக்கூடிய வகையில் key மற்றும் certificate-ஐ ஒரே கோப்பாக இணைக்கவும்:
openssl pkcs12 -export -inkey private/alice.key -in certs/alice.crt \
-name "alice at example ops" -out alice.p12இந்த ஏற்றுமதி (export) ஒரு கடவுச்சொல்லைக் கேட்கும், இது பரிமாற்றத்தின் போது கோப்பைப் பாதுகாக்கும். கோப்பையும் கடவுச்சொல்லையும் வெவ்வேறு வழிகளில் அனுப்பவும், பயனர்களுக்கு வெறும் .key-ஐக் கொடுப்பதற்குப் பதிலாக .p12-ஐ வழங்கவும். CA-வை bundle-ல் சேர்க்க நீங்கள் -certfile ca.crt-ஐப் பயன்படுத்தலாம், ஆனால் nginx-க்கு அது தேவையில்லை: nginx ஏற்கனவே ca.crt-ஐக் கொண்டுள்ளது, எனவே அந்த CA-வால் நேரடியாகக் கையொப்பமிடப்பட்ட certificate தானாகவே சரிபார்க்கப்படும்.
Ubuntu 24.04-ல் உள்ள OpenSSL 3, தற்போதைய encryption முறையைப் பயன்படுத்தி PKCS#12 கோப்புகளை உருவாக்குகிறது. ஆகஸ்ட் 2026 நிலவரப்படி பயன்பாட்டில் உள்ள browsers மற்றும் operating systems இவற்றை வாசிக்கும். பழைய இறக்குமதி கருவி (importer) கோப்பை ஏற்கவில்லை என்றால், -legacy-ஐச் சேர்த்து மீண்டும் ஏற்றுமதி செய்யவும்; இது அந்த இறக்குமதி கருவி எதிர்பார்க்கும் பழைய algorithms-க்குத் திரும்பும். அந்த flag-ஐப் பயன்படுத்துவதற்கு முன், இறக்குமதி கருவி காட்டும் செய்தியைப் படிக்கவும்.
ssl_client_certificate மற்றும் ssl_verify_client கொண்டு nginx-ஐ உள்ளமைத்தல்
CA certificate-ஐ மட்டும் server-க்கு நகலெடுக்கவும்.
scp ca.crt user@admin.example.com:/tmp/client-ca.crt
ssh user@admin.example.com \
'sudo install -o root -g root -m 644 /tmp/client-ca.crt /etc/nginx/client-ca.crt'இங்கு 644 முறைமை (mode) சரியானது. CA certificate என்பது பொதுவான தகவலாகும். CA key உங்கள் பணிநிலையத்திலேயே (workstation) இருக்க வேண்டும்.
பிறகு, ஏற்கனவே TLS termination செய்யும் server block-ல் மூன்று directives-ஐச் சேர்க்கவும்:
server {
listen 443 ssl;
server_name admin.example.com;
ssl_certificate /etc/letsencrypt/live/admin.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/admin.example.com/privkey.pem;
ssl_client_certificate /etc/nginx/client-ca.crt;
ssl_verify_client on;
ssl_verify_depth 1;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}ssl_verify_depth 1 என்பது nginx-ன் இயல்புநிலை (default) அமைப்பாகும். இது client certificate-ஐ அந்த கோப்பில் உள்ள CA நேரடியாக கையொப்பமிட்டிருக்க வேண்டும் என்று கூறுகிறது. நீங்கள் intermediate certificate-ஐச் சேர்த்தால் மட்டுமே இதை அதிகரிக்கவும். handshake-ன் போது, ssl_client_certificate-ல் உள்ள subject பெயர்களை nginx client-க்கு அனுப்பும். இதன் மூலமே எந்த certificate-ஐ வழங்க வேண்டும் என்று browser-க்குத் தெரியும். இந்த செயல்பாட்டிற்காகவே ssl_trusted_certificate-க்கு பதிலாக ssl_client_certificate பயன்படுத்தப்படுகிறது; ssl_trusted_certificate அதே முறையில் சரிபார்த்தாலும், எந்தப் பட்டியலையும் அனுப்பாது.
Ubuntu 24.04-ல் nginx 1.24 உள்ளது, இதில் HTTP/2 என்பது listen வரியில் listen 443 ssl http2; என்று குறிப்பிடப்படுகிறது. nginx 1.25.1 மற்றும் அதற்குப் பிந்தைய பதிப்புகளில் இந்த வடிவம் நீக்கப்பட்டு (deprecated), HTTP/2-க்கு எனத் தனி directive-ஆக http2 on; உள்ளது. இதில் எதைப் பயன்படுத்தினாலும் certificate சரிபார்ப்பில் மாற்றம் இருக்காது.
Reload செய்து முடிவைப் பார்க்கவும்:
sudo nginx -t && sudo systemctl reload nginx
curl -i https://admin.example.com/nginx -t கட்டளையானது syntax is ok மற்றும் test is successful ஆகியவற்றை அச்சிடும். curl அழைப்பில் எந்த certificate-ம் இல்லை என்பதால், அது 400 Bad Request என்ற பதிலையும் No required SSL certificate was sent என்ற உடற்பகுதியையும் (body) தர வேண்டும். இது nginx தனது நுழைவாயிலிலேயே மறுப்பதாகும்; அதாவது உள்ளமைப்பு (configuration) செயல்பாட்டில் உள்ளது, application-க்கு எந்தக் கோரிக்கையும் செல்லவில்லை என்று பொருள். இப்போது சரியாக முயற்சி செய்யவும்:
curl --cert certs/alice.crt --key private/alice.key https://admin.example.com/இது உங்கள் application வழங்கும் தகவலைத் திருப்பித் தர வேண்டும்.
ஏன் gate-ஐ server block-க்குள் வைக்க வேண்டும்
TLS handshake-ன் போது, nginx ஒரு request line-ஐ வாசிப்பதற்கு முன்பே certificate பரிமாறப்படுகிறது. எனவே, அந்த நேரத்தில் எந்த location-ல் அந்த request சேரும் என்பது nginx-க்குத் தெரியாது. ssl_verify_client on;-ஐ ஒரு location-க்குள் வைப்பது, connection-ன் பாதியிலேயே client-ஐ மீண்டும் negotiate செய்யக் கோருகிறது. TLS 1.3 renegotiation-ஐ நீக்கிவிட்டது, HTTP/2 அதைத் தடை செய்கிறது. எனவே, தற்போதைய stack-ல் அந்த முறை, prompt செய்வதற்குப் பதிலாகத் தோல்வியடைகிறது.
scoping-ஐ நீங்களே கையாளுங்கள். server மட்டத்தில் certificate-ஐக் கோருங்கள், பிறகு ஒவ்வொரு location-க்கும் முடிவு செய்யுங்கள்:
ssl_verify_client optional;
location /metrics {
if ($ssl_client_verify != SUCCESS) { return 403; }
proxy_pass http://127.0.0.1:9090;
}
location /healthz {
proxy_pass http://127.0.0.1:8080;
}$ssl_client_verify-ல் SUCCESS இருக்கும், அல்லது client எதையும் அனுப்பவில்லை என்றால் NONE இருக்கும், அல்லது ஒரு காரணத்துடன் FAILED: இருக்கும். optional மூலம், nginx ஒரு certificate-ஐக் கோருகிறது மற்றும் அது வந்தால் மட்டுமே சரிபார்க்கிறது. இதுவே மேலே உள்ள பொதுவான /healthz path இயங்கவும், அதே சமயம் /metrics மூடப்பட்டிருக்கவும் உதவுகிறது. அனுப்பப்பட்டு, சரிபார்ப்பில் தோல்வியடையும் ஒரு certificate-ஐ nginx அந்த நிலையிலேயே நிராகரித்துவிடும். அதற்குப் பதிலாக, தோல்வியடையும் certificate-ஐ நீங்களே ஆய்வு செய்ய விரும்பினால், அது optional_no_ca ஆகும்; அப்போது உங்கள் சொந்த சோதனை, SUCCESS தவிர மற்ற அனைத்து மதிப்புகளையும் நிராகரிப்பாகக் கருத வேண்டும்.
இதற்காக nginx-ல் தரமற்ற status codes உள்ளன. error_page மூலம் அவற்றை நீங்கள் பிடிக்கலாம், இதனால் நிராகரிக்கப்பட்ட visitor-க்கு வெறும் 400 error-க்கு பதிலாக ஒரு விளக்கம் கிடைக்கும்:
error_page 495 496 = @needcert;
location @needcert {
default_type text/plain;
return 200 "This host requires a client certificate. Ask ops for one.\n";
}495 என்பது client certificate சரிபார்ப்பில் தோல்வியடைந்தது என்று பொருள். 496 என்பது client எந்த certificate-ஐயும் சமர்ப்பிக்கவில்லை என்று பொருள். அந்தப் பக்கத்தை plain text-ஆக வைத்திருங்கள், ஏனெனில் அதைப் படிக்கும் நபருக்கு session-ம் இருக்காது, account-ம் இருக்காது.
Browser-ல் client certificate-ஐ எவ்வாறு நிறுவுவது?
Firefox தனக்கென தனி certificate store-ஐப் பயன்படுத்துகிறது: Settings, பின் Privacy and Security, அதன்பின் View Certificates, பிறகு Your Certificates tab, இறுதியாக Import என்பதைத் தேர்வு செய்து, .p12-ஐத் தேர்ந்தெடுத்து அதன் கடவுச்சொல்லை உள்ளிடவும்.
Chrome மற்றும் Edge ஆகியவை Windows மற்றும் macOS-ல் இயங்குதளத்தின் (OS) certificate store-ஐப் பயன்படுத்துகின்றன. எனவே, .p12 கோப்பைத் திறந்தால், கணினியின் import wizard தொடங்கும். Linux-ல், Chrome உங்கள் home directory-ல் உள்ள தனி NSS (network security services) database-ஐப் படிக்கிறது. இதற்கு command line கருவியைப் பயன்படுத்துவதே நம்பகமான வழியாகும்:
sudo apt install -y libnss3-tools
pk12util -d sql:$HOME/.pki/nssdb -i alice.p12இதன்பின் தளத்தை ஏற்றினால், எந்த certificate-ஐ அனுப்ப வேண்டும் என்று browser கேட்கும். அந்த browser session முடியும் வரை Chrome இந்தத் தேர்வை நினைவில் வைத்திருக்கும். எனவே, மீண்டும் கேட்கப்பட வேண்டும் எனில், browser-ஐ restart செய்யவும். ஒரு certificate ஒரு கணினியின் ஒரு browser profile-ல் மட்டுமே இருக்கும். எனவே, Firefox-ல் import செய்யப்பட்ட certificate Chrome-க்குத் தெரியாது; இவை இரண்டுமே உங்கள் தொலைபேசிக்குத் தெரியாது.
curl --cert மூலம் சோதனை செய்தல்
curl என்ன செய்தது என்பதை அதுவே தெரிவிக்கும் என்பதால், அதை வைத்து பிழைத்திருத்தம் (debug) செய்யவும்.
curl -v --cert certs/alice.crt --key private/alice.key https://admin.example.com/நீங்கள் certificate மற்றும் key-ஐ ஒரே PEM கோப்பாக இணைத்து, அதை --cert alice.pem மூலம் வழங்கலாம். key-க்கு passphrase இருந்தால், curl அதைக் கேட்கும். இது --cert alice.pem:passphrase-ஐயும் ஏற்கும், ஆனால் அது உங்கள் shell history-ல் பதிவாகிவிடும் என்பதால், prompt வரும்போது உள்ளிடுவது சிறந்தது.
nginx-ஐக் குறை கூறுவதற்கு முன் இரண்டு சோதனைகளைச் செய்வது அவசியம். முதலாவதாக, certificate மற்றும் key ஆகியவை இணையாக இருக்க வேண்டும்:
openssl x509 -noout -pubkey -in certs/alice.crt | openssl sha256
openssl pkey -pubout -in private/alice.key | openssl sha256இரண்டு hashes-ம் ஒன்றாக இருந்தால், அந்த கோப்புகள் ஒன்றுக்கொன்று தொடர்புடையவை. hashes வேறாக இருந்தால், நீங்கள் இரண்டு வெவ்வேறு கோப்புகளைக் கலந்துவிட்டீர்கள் என்று அர்த்தம்; எந்த client-ம் இந்த காரணத்தை உங்களுக்குத் தெளிவாகச் சொல்லாது.
இரண்டாவதாக, server உங்கள் CA-ஐக் கேட்க வேண்டும்:
openssl s_client -connect admin.example.com:443 -servername admin.example.com </dev/nullவெளியீட்டில் Acceptable client certificate CA names தொகுதியைத் தேடவும், அதில் உங்கள் CA-ன் subject உள்ளதா என்று பார்க்கவும். அந்த தொகுதி முற்றிலும் இல்லை என்றால், பதிலளித்த server block-ல் nginx certificate-ஐக் கேட்கவில்லை என்று அர்த்தம்; எனவே, உங்கள் directives வேறு ஒரு server block-ல் (பெரும்பாலும் default server-ல்) அமர்ந்துள்ளன.
client CN-ஐ application-க்கு அனுப்புதல்
Certificate யார் அழைப்பு விடுத்தார் என்பதைத் தெரிவிக்கிறது, ஆனால் proxy-க்கு பின்னால் உள்ள application-ஆல் TLS layer-ஐப் பார்க்க முடியாது. எனவே, nginx அந்தப் பெயரைத் தொடர்ந்து அனுப்ப வேண்டும்.
map $ssl_client_s_dn $client_cn {
default "";
"~,?CN=(?<cn>[^,]+)" $cn;
}$ssl_client_s_dn, subject distinguished name-ஐ RFC 2253 வடிவத்தில் வைத்திருக்கும், இது CN=alice,O=Example Ops போலத் தோன்றும். இந்த map, CN field-ஐ $client_cn-க்குள் கொண்டு வருகிறது. CN-ஐ ஒரு சாதாரண username-ஆக வைத்திருக்கவும், ஏனெனில் அந்த வடிவத்தில் CN-க்குள் இருக்கும் கமா (comma) escape செய்யப்படும், மேலும் மேலே உள்ள சிறிய regular expression அந்த escape-ஐக் கையாளாது.
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Client-Cert-CN $client_cn;
proxy_set_header X-Client-Cert-Serial $ssl_client_serial;
}proxy_set_header, அழைப்பாளர் அனுப்பிய அதே பெயரிலான எந்தவொரு header-ஐயும் மாற்றீடு செய்கிறது, எனவே யாரும் இந்த location வழியாக X-Client-Cert-CN-ஐப் போலியாக உருவாக்க முடியாது. இரண்டு நிபந்தனைகள் இதை உறுதிப்படுத்துகின்றன. உட்புற நிலையில் எந்த header-உம் வரையறுக்கப்படாதபோது மட்டுமே, வெளிப்புற நிலையிலிருந்து proxy_set_header-ஐ nginx பெற்றுக்கொள்கிறது. எனவே, ஒரு proxy_set_header வரியைக் கொண்ட இரண்டாவது location, அதற்கு மேலே அமைக்கப்பட்ட அனைத்து header-களையும் அமைதியாக இழந்துவிடும், இதில் இதுவும் அடங்கும். மேலும், nginx வழியாக மட்டுமே application-ஐ அணுக முடியும் என்பதை உறுதிப்படுத்த வேண்டும். அதாவது, அதை 0.0.0.0-க்கு பதிலாக 127.0.0.1-ல் bind செய்ய வேண்டும், ஏனெனில் public port-ல் உள்ள ஒரு app, இணையத்திலிருந்து நேரடியாகப் போலியான header-ஐப் படித்துவிடும். அதன் proxy பக்கம் nginx reverse proxy configuration ஒவ்வொன்றாக விளக்கப்பட்டுள்ளது என்பதில் விவரிக்கப்பட்டுள்ளது. ஒருவேளை application-க்கு பெயருக்குப் பதிலாக முழு certificate-உம் தேவைப்பட்டால், $ssl_client_escaped_cert அதை URL-encoded வடிவில் header-க்குள் பாதுகாப்பாகக் கொண்டு செல்லும்.
ஒரு client certificate-ஐ எவ்வாறு ரத்து செய்வது?
ஒருவர் பணியிலிருந்து விலகினாலோ அல்லது மடிக்கணினி தொலைந்து போனாலோ, அந்த ஒரு certificate-ஐ மட்டும் நீங்கள் ரத்து செய்யலாம். மற்றவர்களின் அணுகல் பாதிக்கப்படாது; ஒவ்வொரு நபருக்கும் தனித்தனி certificate வழங்குவதன் நோக்கமே இதுதான்.
cd ~/client-ca
openssl ca -config openssl.cnf -revoke certs/alice.crt
openssl ca -config openssl.cnf -gencrl -out crl.pemமுதல் கட்டளை, index.txt கோப்பில் அந்த serial எண்ணின் வரியை V என்பதிலிருந்து R என மாற்றும். இரண்டாவது கட்டளை, ரத்து செய்யப்பட்ட serial எண்களைக் கொண்ட, கையொப்பமிடப்பட்ட Certificate Revocation List (CRL) கோப்பை உருவாக்கும். இந்தக் கோப்பை server-க்கு அனுப்பி, nginx-ல் உள்ள பிற directives-களுடன் சேர்த்து ssl_crl /etc/nginx/client-ca.crl; மூலம் அதைச் சுட்டிக்காட்டவும்.
scp crl.pem user@admin.example.com:/tmp/client-ca.crl
ssh user@admin.example.com 'sudo install -m 644 /tmp/client-ca.crl /etc/nginx/client-ca.crl && sudo nginx -t && sudo systemctl reload nginx'இங்கேதான் அனைவரின் அணுகலையும் தடுக்கும் ஒரு சிக்கல் உள்ளது. ஒரு CRL கோப்பு nextUpdate தேதியைக் கொண்டிருக்கும்; இது default_crl_days மூலம் நிர்ணயிக்கப்படுகிறது (மேலே உள்ள configuration-ல் இது 30 நாட்கள்). அந்தத் தேதி கடந்தவுடன், OpenSSL அந்தப் பட்டியலைப் பழையதாகக் கருதி, ரத்து செய்யப்பட்ட certificate-க்கு மட்டுமல்லாமல், அனைத்து client certificate-களுக்கும் CRL has expired பிழையைக் காட்டி சரிபார்ப்பைத் தோல்வியடையச் செய்யும். nginx தனது configuration-ஐ ஏற்றும்போதுதான் இந்தக் கோப்பைப் படிக்கும் என்பதால், வட்டில் புதிய CRL கோப்பை வைத்தாலும், service-ஐ reload செய்யும் வரை மாற்றம் நடைமுறைக்கு வராது. எனவே, 30 நாட்கள் காலாவதிக்கு முன்னதாகவே, வாரந்தோறும் CRL-ஐப் புதுப்பித்து reload செய்யவும். கோப்பை நகலெடுக்கும் முன் தேதிகளைச் சரிபார்க்கவும்:
openssl crl -in crl.pem -noout -lastupdate -nextupdateகுறைந்த எண்ணிக்கையிலான பயனர்களுக்கு ஒரு எளிய வழி உள்ளது. CA உங்களுடையது என்பதால், CRL முறையைத் தவிர்த்துவிட்டு, nginx மூலமாகவே ஒரு குறிப்பிட்ட serial எண்ணை நேரடியாக நிராகரிக்க முடியும்:
map $ssl_client_serial $revoked {
default 0;
"1002" 1;
}இதனுடன் location block-ல் if ($revoked) { return 403; } என்பதைச் சேர்க்கவும். இதற்கு மறக்கக்கூடிய காலாவதி தேதி கிடையாது. மேலும், இது அந்த server-ல் மட்டுமே இருக்கும் என்பதால், உங்கள் CA-வை நம்பும் பிற அமைப்புகளுக்கு இந்தத் தகவல் தெரியாது. ஒரு application-க்கு முன்னால் ஒரே ஒரு nginx மட்டும் இருக்கும் சூழலுக்கு இதுவே எளிமையான மற்றும் சரியான தீர்வாகும். ஒன்றுக்கும் மேற்பட்ட நுழைவு வாயில்கள் (gates) இருக்கும்போது மட்டும் CRL முறைக்கு மாறவும்.
Client certificates எவ்வளவு காலம் செல்லுபடியாகும் வகையில் இருக்க வேண்டும்?
Client certificates-க்கு ஒரு வருடம் அல்லது அதைவிடக் குறைவான கால அவகாசம் வழங்கவும்; மீண்டும் வழங்குவதற்கான வேலைகளை உங்களால் கையாள முடிந்தால் குறைவான காலமே சிறந்தது. இதில் காலாவதியாதல் என்பது அமைதியான தோல்வியாகும், ஏனெனில் இது குறித்து பயனருக்கு முன்கூட்டியே எந்த எச்சரிக்கையும் கிடைக்காது. ஒரு நாள் காலை அவர்கள் panel-ஐத் திறக்கும்போது, nginx இணைப்பை மறுக்கும்; browser-ம் தனது சொந்த மொழியில் அந்த மறுப்பைக் காட்டும், அதில் அரிதாகவே 'expired' என்ற வார்த்தை இடம்பெறும். CA-வின் காலாவதி தேதியை 10 ஆண்டுகளாக வைத்துக்கொள்ளுங்கள், அதை நீங்கள் அடிக்கடி பார்க்கும் இடத்தில் குறித்து வையுங்கள். ஏனெனில் CA certificate காலாவதியாகும் நாளில், அதன் கீழ் உள்ள அனைத்து certificate-களும் சரிபார்ப்பை நிறுத்திவிடும்.
பின்வரும் இரண்டு கட்டளைகள் உங்களை முன்கூட்டியே எச்சரிக்கையாக வைத்திருக்க உதவும்:
openssl x509 -in certs/alice.crt -noout -subject -serial -enddate
awk -F'\t' '{print $1, $2, $4}' ~/client-ca/index.txtindex.txt-ன் முதல் நெடுவரிசை (column) நிலையைத் தெரிவிக்கும்: V என்பது செல்லுபடியாகும் (valid), R என்பது ரத்து செய்யப்பட்டது (revoked), E என்பது காலாவதியானது (expired). இரண்டாவது நெடுவரிசை YYMMDDHHMMSSZ வடிவத்தில் காலாவதி தேதியையும், நான்காவது நெடுவரிசை serial எண்ணையும் குறிக்கும். அந்த file மட்டுமே யாரிடம் எந்த certificate உள்ளது என்பதற்கான ஒரே ஆவணம், எனவே அதை CA key-யுடன் சேர்த்து backup எடுத்துக்கொள்ளுங்கள்; இரண்டையும் ரகசியமாகப் பாதுகாக்கவும்.
புதுப்பித்தல் (renewal) என்பது புதிய certificate-ஐ உருவாக்குவதே தவிர, பழையதை நீட்டிப்பது அல்ல. புதிய key மற்றும் CSR (certificate signing request)-ஐ உருவாக்கி, அதை sign செய்து, பயனரிடம் ஒப்படையுங்கள். புதியது சரியாகச் செயல்படுவதை பயனர் உறுதி செய்த பிறகு, பழைய certificate-ஐ revoke செய்யவும்.
mTLS எவற்றிலிருந்து பாதுகாக்கிறது, எவற்றிலிருந்து பாதுகாக்காது
இது அங்கீகரிக்கப்படாத அணுகலை நீக்குகிறது. உங்கள் hostname-ஐக் கண்டறியும் ஒரு scanner, handshake-ன் போதே நிராகரிக்கப்படும். எனவே, அது ஒரு HTTP request-ஐ அனுப்பாது, login form-ஐப் பார்க்காது, திருடப்பட்ட கடவுச்சொல்லைப் பயன்படுத்தி நுழையவும் முடியாது. Credential stuffing தாக்குதலுக்கு இங்கே இடமில்லை. சான்றிதழ் இல்லாத எவராலும் application-ன் login flow-ல் உள்ள பாதிப்புகளை அணுக முடியாது. இது chat-ல் பகிரப்படும் shared secret சிக்கலையும் நீக்குகிறது, ஏனெனில் private key என்பது தற்செயலாகப் பகிர முடியாத ஒரு கோப்பு.
பாதிக்கப்பட்ட client-ஐப் பொறுத்தவரை இது எந்தப் பாதுகாப்பையும் வழங்காது. ஒரு laptop-ல் உள்ள malware-க்கு அந்த key கோப்பு தெரியும், உரிமையாளர் passphrase-ஐத் தட்டச்சு செய்தவுடன் அதுவும் கிடைத்துவிடும். ஒரு சான்றிதழ் என்பது கோப்பின் இருப்பைத்தான் உறுதிப்படுத்துமே தவிர, நபரின் இருப்பை அல்ல. எனவே, அந்த attacker ஒரு முறையான பயனர் போலவே server-க்குத் தெரிவார். .p12 கடவுச்சொல் மற்றும் முழு வட்டு குறியாக்கம் (full disk encryption) ஆகியவை தொடர்ந்து முக்கியத்துவம் பெறுகின்றன.
இது authorization-ம் அல்ல. நீங்கள் $client_cn-ஐச் சரிபார்த்து அதற்கேற்ப செயல்படாவிட்டால், செல்லுபடியாகும் சான்றிதழ் கொண்ட எவரும் அந்த server block-ல் உள்ள அனைத்தையும் அணுக முடியும். இயல்பாக, இரண்டு சான்றிதழ் வைத்திருப்பவர்களுக்கும் ஒரே மாதிரியான அணுகல் உரிமையே இருக்கும்.
மேலும், இது nginx வழியாக வரும் பாதையை மட்டுமே பாதுகாக்கிறது. உங்கள் application பொதுவான port-ல் இயங்கினால், அதற்கு முன்னால் உள்ள mTLS வெறும் அலங்காரம் மட்டுமே: application-ஐ 127.0.0.1-ல் bind செய்து, அதன் port-க்கான firewall-ஐ மூடி வைக்கவும். அதே server-க்குள் நுழைய மற்றொரு வழி SSH, அதற்கு hardening SSH access on your VPS-ல் விவரிக்கப்பட்டுள்ள அதே கவனம் தேவை.
இறுதியாக ஒரு வரம்பு உள்ளது, இதை நீங்கள் செயல்படுத்தும் நாளிலேயே இது பாதிப்பை ஏற்படுத்தும். சான்றிதழை வழங்க முடியாத எவையும் செயல்படாது: uptime monitor, payment provider-ன் webhook, RSS reader, அல்லது சான்றிதழ் சேமிப்பகம் இல்லாத mobile app போன்றவை இதில் அடங்கும். ssl_verify_client on-ஐ அமைப்பதற்கு முன்பே இவற்றை முடிவு செய்யுங்கள், ஏனெனில் இதன் தோல்வி முழுமையானது மற்றும் அந்தத் தரப்பில் எந்த அறிவிப்பும் இருக்காது.
கிளையண்ட் நிராகரிக்கப்படும்போது, அது என்ன பிழைச் செய்தியைக் காட்டுகிறது என்பதைப் பார்க்கவும்
ஒரு கிளையண்ட் நிராகரிக்கப்படும்போது காட்டப்படும் செய்தி, பயன்படுத்தப்படும் browser, curl-ன் பதிப்பு மற்றும் அதன் பின்னணியில் உள்ள TLS library ஆகியவற்றைப் பொறுத்து மாறுபடும். எனவே, எங்கோ எழுதப்பட்டிருக்கும் ஒரு செய்தியுடன் ஒப்பிட்டுப் பார்ப்பதை விட, உங்கள் கிளையண்ட் என்ன செய்தியைக் காட்டுகிறது என்பதைப் படியுங்கள். பயனுள்ள விவரங்கள் server-ல் தான் இருக்கும்.
sudo tail -n 50 /var/log/nginx/error.logநிராகரிக்கப்பட்ட certificate, client SSL certificate verify error என்ற வரியையும், அதைத் தொடர்ந்து OpenSSL வழங்கிய காரணத்தையும் log-ல் பதிவு செய்யும். அந்த காரணத்தின் அடிப்படையிலேயே நீங்கள் நடவடிக்கை எடுக்க வேண்டும். பொதுவாக இது சில குறிப்பிட்ட காரணங்களால் நிகழ்கிறது. ssl_client_certificate-ல் குறிப்பிடப்பட்டுள்ள கோப்பில் உள்ள CA-விடமிருந்து அந்த certificate பெறப்பட்டிருக்காது. அல்லது, அந்த certificate-ன் செல்லுபடியாகும் காலம் முடிந்திருக்கலாம். server-ல் உள்ள CRL அதன் nextUpdate-ஐக் கடந்துவிட்டதால், அது ஒரு கிளையண்ட்டை மட்டும் நிராகரிக்காமல், அனைத்து கிளையண்ட்டுகளையும் நிராகரிக்கத் தொடங்கும்.
browser எந்தவொரு certificate-ஐயும் வழங்கவில்லை என்றால், சிக்கல் சரிபார்ப்புக்கு (verification) முன்பே நடக்கிறது என்று அர்த்தம். handshake-ன் போது nginx ஏற்றுக்கொள்ளக்கூடிய issuer பெயர்களை அனுப்பும். browser-ன் store-ல் அதனுடன் பொருந்தக்கூடிய எதுவும் இல்லாததால், அது உங்களுக்கு எதையும் வழங்கவில்லை. நீங்கள் உண்மையில் பயன்படுத்தும் profile-ல் .p12-ஐ மீண்டும் import செய்யவும்.
குறிப்பிடத்தக்க மற்றொரு சூழல் இது: உங்கள் CA கையொப்பமிட்ட certificate-க்கு பதிலாக, நீங்களே கையொப்பமிட்ட (self-signed) கிளையண்ட் certificate-ஐ வைத்துச் சோதித்தால், சரிபார்ப்பு வெற்றிபெறாது. ஏனெனில், nginx அந்த கையொப்பத்தை CA கோப்புடன் ஒப்பிட்டுச் சரிபார்க்கும், ஆனால் self-signed certificate அதில் இருக்காது. certificate-ஐ உருவாக்கும் முறை Ubuntu-வில் self-signed certificate உருவாக்குதல் என்பதில் உள்ளதைப் போன்றே இருக்கும். mTLS-க்கு உங்கள் CA மூலம் கையொப்பமிடும் கூடுதல் படிநிலை மட்டுமே தேவைப்படும்.
FAQ
mTLS பயன்படுத்தினாலும் எனக்கு Let's Encrypt certificate தேவையா?
ஆம். இந்த இரண்டு சான்றிதழ்களுக்கும் தொடர்பில்லை. உங்கள் server தனது சொந்த சான்றிதழை வழங்குவதால், browser அந்த hostname-ஐ நம்புகிறது; இதற்கு browser ஏற்கனவே அறிந்த ஒரு CA-விடமிருந்து சான்றிதழ் பெறப்பட வேண்டும். உங்கள் client CA என்பது ஒரு தனிப்பட்ட private chain ஆகும், இது யார் இணைக்கிறார்கள் என்பதைச் சரிபார்க்க மட்டுமே பயன்படுகிறது. ssl_client_certificate-ஐ அமைப்பது nginx வழங்கும் சான்றிதழில் எந்த மாற்றத்தையும் ஏற்படுத்தாது, மேலும் அது உங்கள் Let's Encrypt chain-ஐக் குறிப்பிடக்கூடாது.
எனது browser ஏன் என்னிடம் சான்றிதழைத் தேர்ந்தெடுக்கக் கேட்கவில்லை?
handshake-ன் போது, ssl_client_certificate-ல் உள்ள கோப்பிலிருந்து பெறப்பட்ட, ஏற்கத்தக்க issuers-ன் பட்டியலை nginx அனுப்புகிறது. அந்தப் பட்டியலில் உள்ள issuer-ன் சான்றிதழ்களை மட்டுமே browser வழங்கும். எனவே, prompt வரவில்லை என்றால், உங்கள் CA-வின் சான்றிதழ் browser-ல் இல்லை என்று பொருள்: அது வேறு ஒரு browser profile-ல் இறக்கப்பட்டிருக்கலாம், அல்லது server-ல் நிறுவப்பட்ட CA-விடமிருந்து வேறுபட்ட CA-வால் அந்தச் சான்றிதழ் கையொப்பமிடப்பட்டிருக்கலாம். openssl s_client -connect admin.example.com:443-ஐ இயக்கி, output-ல் உள்ள ஏற்கத்தக்க client certificate CA பெயர்களைப் பார்த்து, server எந்த CA-வைக் கேட்கிறது என்பதை உறுதிப்படுத்தவும்.
ஒரு குறிப்பிட்ட URL-க்கு மட்டும் client certificate-ஐக் கட்டாயமாக்க முடியுமா?
location-க்குள் ssl_verify_client on-ஐப் பயன்படுத்தி இதைச் செய்ய முடியாது. TLS 1.3-ல் renegotiation வசதி நீக்கப்பட்டுவிட்டது மற்றும் HTTP/2-ல் இது தடைசெய்யப்பட்டுள்ளது, எனவே handshake-ன் போதே (request path-ஐ nginx அறிவதற்கு முன்பே) சான்றிதழ் பரிமாற்றம் நடைபெறுகிறது. server block-ல் ssl_verify_client optional;-ஐ அமைக்கவும், பின்னர் ஒவ்வொரு protected location-லும் $ssl_client_verify-ஐச் சோதித்து, அது SUCCESS-ஆக இல்லாதபோது 403 error-ஐத் திருப்பவும்.
ஒரு நபருக்கான அணுகலை நான் எவ்வாறு ரத்து செய்வது?
openssl ca -revoke மூலம் அந்தச் சான்றிதழை ரத்து செய்யவும், openssl ca -gencrl மூலம் பட்டியலை மீண்டும் உருவாக்கவும், அதை server-க்கு நகலெடுத்து, புதிய கோப்பை வாசிக்க nginx-ஐ reload செய்யவும். ஒவ்வொரு நபரும் பகிரப்பட்ட சான்றிதழுக்குப் பதிலாகத் தனித்தனிச் சான்றிதழ்களை வைத்திருந்தால் மட்டுமே, மற்றவர்கள் பாதிக்கப்படாமல் இது செயல்படும். CRL-ன் nextUpdate தேதியைக் கவனிக்கவும், ஏனெனில் CRL காலாவதியானால், ரத்து செய்யப்பட்டவர்கள் மட்டுமல்லாமல் அனைத்து client-களின் சரிபார்ப்பும் தோல்வியடையும்.
mTLS ஒரு login page-க்கு மாற்றாகுமா?
அணுகல் கட்டுப்பாட்டிற்கு, ஆம்: சான்றிதழ் இல்லாமல் application-ஐ அணுக முடியாது, எனவே தாக்குதல் நடத்த படிவமோ (form) அல்லது ஊகிக்க கடவுச்சொல்லோ (password) இருக்காது. ஆனால் application-க்குள் அடையாளத்தை உறுதிப்படுத்த, இல்லை. ஒரு சான்றிதழ், அழைப்பவர் ஒரு key file-ஐ வைத்திருக்கிறார் என்பதை மட்டுமே உறுதிப்படுத்துகிறது, எனவே திருடப்பட்ட laptop-ம் ஒரு செல்லுபடியாகும் பயனராகவே கருதப்படும். CN-ஐ upstream-க்கு அனுப்பவும், application-ல் ஏற்கனவே உள்ள கணக்குகள் மற்றும் அனுமதிகளைத் தக்கவைக்கவும், சான்றிதழை அவற்றுக்கு முன்னால் உள்ள ஒரு நுழைவாயிலாக மட்டும் பயன்படுத்தவும்.