Cert Based Authentication
Configure NGINX to verify client certifcate before responding to requests. This provides another security layer to NGINX enabling only known certificates access to make requests for the proxy. Generally, these should be considered machine certificates as they do not identify a particular user, just a machine with a certificate.
See Certificate Authority for instructions on setting up required certificates used here. An excellent reference for basic certificate usage and should be well understood before proceeding.
Nginx Configuration
If the default_server
is set to not require cert-based authentication and
additional server blocks do, clients that do not support it will fall back to
the default_server
and be able to make valid requests. Therefore the
default server should act as a catch all for non-cert based requests and
specifically respond to those requests. In this case we will respond immediately
with a 403
.
Danger
You are entering a dangerous space. Once a client has a valid SSL connection, certificate validation needs to be explicitly enforced; otherwise a client can access other SSL areas (due to a pre-existing valid SSL connection).
ALWAYS explicitly check for valid client certificates and do penetration testing to verify your assumptions.
server {
# Security-related headers (cross-site/domain, referrer)
# https://geekflare.com/http-header-implementation/
# https://geekflare.com/nginx-webserver-security-hardening-guide/
# https://www.cyberciti.biz/tips/linux-unix-bsd-nginx-webserver-security.html
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
# Enable basic SSL security settings.
ssl_certificate /etc/nginx/ssl/letsencrypt-fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/letsencrypt-privkey.pem;
ssl_trusted_certificate /etc/nginx/ssl/letsencrypt-chain.pem;
ssl_dhparam /etc/nginx/ssl/letsencrypt-ssl-dhparams.pem;
# Enable OCSP stapling https://en.wikipedia.org/wiki/OCSP_stapling.
ssl_stapling on;
ssl_stapling_verify on;
# make client certificate verification optional, so we can display a 403
# message to those who fail authentication. All loctions **must** explicitly
# validate ssl_client_verify for restricted access to work. Alternatively the
# ``on`` option will force client auth for all connections, including error
# pages.
ssl_client_certificate /etc/nginx/auth/ca-chain.cert.pem;
ssl_crl /etc/nginx/auth/ca-chain.crl.pem;
ssl_verify_client optional;
# One error page for everything. Does not require client cert.
root /www;
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 /error.html;
location = /error.html {
allow all;
internal;
root /www;
}
# If no cert auth is used, 403.
location /secured_site {
# Disable client certificate authentication for a specific host. See geo
# module for catching subnets.
if ($remote_addr = 10.10.10.10) {
proxy_pass http://some-backend;
break;
}
if ($ssl_client_verify != SUCCESS) {
return 403;
break;
}
proxy_pass http://some-backend;
}
}
This provices Authentication (authn) See Certificate Authorization (authz) for authorization setup.
If
statements should only be used to forrewrite
andreturn
(proxy_pass
is arewrite
statement). See If is Evil.Access can be provided based on client certificate presented as well (e.g. specific access for specific certificates).
Disabling for a specific host may be required for backend hosts communicating with each other via the proxy. Most backend services do not support client authentication. The address here should be the proxy
gateway
address as that is where those proxied requests will be coming from. This will only allow traffic originating from the proxy through, not proxied requests from clients. Always be sure to enforce client verification and test assumptions.The Certificate Revocation List must include all CRL’s up to the Root CA for the CRL to work, otherwise all CRL checks will be invalid and block access even for valid clients.
Proxy-specific Client Certificate
For cases where a backend requires a certificate but the client using the proxy does not have one. This is dangerous if used without layering additional security measures. Explicitly specify a certificate that the proxy will use to authenticate to backends for requests.
server {
proxy_ssl_certificate /etc/nginx/auth/nginx.crt.pem;
proxy_ssl_certificate_key /etc/nginx/auth/nginx.key.pem;
proxy_ssl_trusted_certificate /etc/nginx/auth/{BACKEND}.crt.pem;
}
Git Configuration
Accessing a https based git repository behind a NGINX proxy requiring client certificate authentication is supported both locally and via URI matching.
Git Cert Auth for Repo Site
[http "https://git.example.com"]
sslCert = /home/user/{MACHINE}.crt.pem
sslKey = /home/user/{MACHINE}.key.pem
Git Cert Auth for Specific Repo
git config --local http.sslCert "/home/user/{MACHINE}.crt.pem"
git config --local http.sslKey "/home/user/{MACHINE}.key.pem"
Note
--global
will force certification authentication for all repositories.
This is probably not what you want to do.
Chrome Client Certificate
Setup chrome to auto present correct certificate when challenged by proxy server.
Import Client Certificate to Chrome
chrome://settings › Settings › Advanced › Privacy and security › Manage certificates › Import
☐
Enable strong private key protection
☐
Mark this key as exportable
☑
Include all extended properties
☑ Place all certificates in the following store
Personal
Updated: None
Note
Use export password to decrypt and import.
Restart Chrome. Nagivate to a proxied site and the certificate prompt should appear to select which cert to authenticate with. If NGINX has been reloaded and setup, then this should allow you to passthrough.
Auto-select Client Certificate
Auto selecting the correct certificate will enable transparent authentication for proxied sites. Enabled via Group Policy or Registry.
Auto-select Client Certificate (Windows)
1
incremental counter for which matching patterns to apply. If using multiple certificates this will represent the resolution order.O
is used to match the Organizational Name of the server CA{SERVER}
. This will use this certificate for all{SERVER}
cert auth requests.If using a reg file, ensure proper escaping:
"1"="{\"pattern\":\"https://[*.]example.com\",\"filter\":{\"ISSUER\":{\"O\":\"{SERVER}\"}}}"
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\AutoSelectCertificateForUrls
1
SZ
{“pattern”:”https://[\*.]example.com”,”filter”:{“ISSUER”:{“O”:”{SERVER}”}}}
Updated: 2021-12-29 Reference
Auto-select Client Certificate (Linux)
All directories should be readable by other
.
{
"AutoSelectCertificateForUrls": [
"{\"pattern\":\"https://[*.]example.com\",\"filter\":{\"ISSUER\":{\"O\":\"{SERVER}\"}}}"
]
}
Restarting chrome will pickup the configuration changes.
Firefox Client Certificate
Setup Firefox to auto present correct certificate when challenged by proxy server.
Import Client Certificate to Firefox
about:preferences#privacy › Certificates › OSCP › View Certificates › Your Certificates › Import
Updated: None
Note
Use export password to decrypt and import.
Disable client certificate sync’ing.
about:config › Accept the Risk and Continue › services.sync.prefs.sync.security.default_personal_cert
{false}
Updated: None Reference
Restart Firefox. Nagivate to a proxied site and the certificate prompt should appear to select which cert to authenticate with. If NGINX has been reloaded and setup, then this should allow you to passthrough. Remember decision to prevent additional certificate prompts on revisit.