iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🔏

Access Control with Client Certificates

に公開

*This article is based on partially edited and supplemented notes for my past self, so some parts may be difficult to understand. Please bear with me on that point.

Websites Accessible Only to Users with Certificates

However, there are times when you want to create a site restricted to specific people. In such cases, access restrictions are applied.

Normal websites can be viewed from all over the world as long as you have a web browser.

Basic Authentication

A typical example is access restriction using Basic Authentication. It becomes viewable by entering an ID and password into the browser.

Basic Authentication

However, authentication using only an ID/password is not highly secure these days, and there is a possibility that it can be broken by mechanical, continuous retries.

IP Address Restriction

Next is IP restriction, which allows access only from designated IP addresses.

IP restriction is still quite commonly used today. However, if you are aiming for complete security, it can sometimes be bypassed through packet spoofing. Additionally, if the source IP address changes irregularly, it takes effort to re-register it every time.

Restriction by Client Certificates

This is a method that allows only users who possess a designated certificate.

By registering a certificate distributed by an administrator in the browser, users can browse the site as long as the certificate is valid. Access without a certificate, or with an invalid certificate, will be displayed as a 400 Bad Request.

A disadvantage is that since certificate files can be duplicated, if they are leaked to someone other than the intended user, there is a possibility that an unexpected third party could browse the site.

Combining this with the previously mentioned restrictions makes it even more robust.

Client certificates are authenticated using certificate files issued by a Certificate Authority on the client-server. Since certificates have an expiration date, they cannot be used once they expire. Additionally, they may be revoked by an administrator even before expiration, in which case they can no longer be used for browsing.

_2021-04-09_9.46.58.png

Creating an Environment Restricted by Client Certificates

In this case, the construction will be based on the following configuration.

Product
Certificate Authority and Certificates OpenSSL
Web Server nginx

Creating the Certificate Authority

To issue so-called self-signed certificates, we will create a Certificate Authority (CA) and issue client certificates from it.

Here, the CSR for creating the Certificate Authority was set as follows:

Item Value
Country Name(C) JP
State or Province Name(ST) Tokyo
Locality Name(L) Chiyoda
Organization Name(O) anon5r.dev
Organization unit or division name(OU) Development
Common Name(CN) anon5r.dev
emailAddress webmaster@anon5r.dev

When written as a subject during creation, it looks like this:

C=JP/ST=Tokyo/L=Chiyoda/O=anon5r.dev/OU=Development/CN=anon5r.dev/emailAddress=webmaster@anon5r.dev
subject="/C=JP/ST=Tokyo/L=Chiyoda/O=anon5r.dev/OU=Development/CN=anon5r.dev/emailAddress=webmaster@anon5r.dev"

cd /etc/pki/CA/

openssl req -new -x509 -days $expiry -key ca-priv-anon5r-dev.key -out ca-priv-anon5r-dev.crt -subj $subject
mv ca.key ca-anon5r-dev.key

openssl req -new -x509 -days 3650 -key ca-anon5r-dev.key -out ca-anon5r-dev.crt -subj $subject
openssl ca -name CA_default -gencrl -keyfile ca.key -cert ca.crt -out ca.crl -crldays 730

openssl ca -name CA_default -gencrl -keyfile ca-anon5r-dev.key -cert ca-anon5r-dev.crt -out ca-anon5r-dev.crl -crldays 3650
diff -U0 <(openssl x509 -noout -modulus -in ca-anon5r-dev.crt) <(openssl rsa -noout -modulus -in ca-anon5r-dev.key)
diff -U0 <(openssl x509 -noout -modulus -in ca-anon5r-dev.crt) <(openssl rsa -noout -modulus -in ca-anon5r-dev.key)

Creating Client Certificates

The CSR settings for client issuance are as follows. Change the Common Name and emailAddress for each user being issued.

Item Value
Country Name(C) JP
State or Province Name(ST) Tokyo
Locality Name(L) Chiyoda
Organization Name(O) anon5r.dev
Organization unit or division name(OU) Development
Common Name(CN) user
emailAddress user@anon5r.dev

When written as the subject during creation, it looks like this:

/C=JP/ST=Tokyo/L=Chiyoda/O=anon5r.dev/OU=Development/CN=user/emailAddress=user@anon5r.dev

In this case, the output is placed under the certs directory directly inside /etc/nginx. For management purposes, directories are organized based on each user's email address, and the files are output there.

clientEmail=developer@anon5r.dev
subject="/C=JP/ST=Tokyo/L=Chiyoda/O=anon5r.dev/OU=Development/CN=anon/emailAddress=$clientEmail"
expiry=365 # Valid for 1 year

cd /etc/nginx/certs/client/anon5r.dev/
mkdir -p users/$clientEmail

openssl genrsa -out users/$clientEmail/user.key 4096
openssl req -new -key users/$clientEmail/user.key -out users/$clientEmail/user.csr -subj $subject

openssl x509 -req -days $expiry -in users/$clientEmail/user.csr -CA /etc/nginx/certs/client/anon5r.dev/ca.crt -CAkey /etc/nginx/certs/client/anon5r.dev/ca.key -CAcreateserial -CAserial ../ca.seq -out users/$clientEmail/user.crt

openssl pkcs12 -export -clcerts -in users/$clientEmail/user.crt -inkey users/$clientEmail/user.key -out users/$clientEmail/user.p12

# Restart nginx
sudo systemctl restart nginx.service

Extra

Since the output hierarchy is deep and it's an environment only I use, I created a symbolic link in the home directory so that I can quickly retrieve the issued client certificates.

ln -s /etc/nginx/certs/client/anon5r.dev/users/$clientEmail ~/client-certs
mkdir -p ~/usercerts
cp ~/client-certs/*.(crt|csr|key|p12) ~/usercerts/

Updating Client Certificates

Update the client certificate when it expires.

clientEmail=developer@anon5r.dev
expiry=365 # Valid for 1 year

openssl x509 -req -days $expiry -in users/$clientEmail/developer.csr -CA /etc/nginx/certs/client/anon5r.dev/ca.crt -CAkey /etc/nginx/certs/client/anon5r.dev/ca.key -CAcreateserial -CAserial ../ca.seq -out users/$clientEmail/user.crt
openssl pkcs12 -export -clcerts -in users/$clientEmail/user.crt -inkey users/$clientEmail/user.key -out users/$clientEmail/user.p12

# Restart nginx
sudo systemctl restart nginx.service

Afterword

This article was originally a memo from when I set up my personal development environment. I wanted to make that environment accessible via the internet, but I didn't want it to be open to everyone.

  • I want to prepare an environment that only I can use easily!
  • Logging in every time is a hassle!
  • I want to be able to use it from anywhere, not restricted by IP address!

This was a memo for creating what I thought was an optimal environment based on these selfish desires.

Reflections and Thoughts

While it may not prevent attacks on the web server itself, I think it was a fairly good choice for a personal development environment, as it can be made available to only the necessary people without much trouble and without the worry of being crawled over the internet.

However, there are challenges, such as the effort involved in issuing certificates when they expire, issuing certificates for temporary guests, and the recipient's effort to import the certificate. It is more complicated than the common, simple ID and password management.

In particular, I would like to make the process of issuing and updating client certificates a bit more streamlined.

Discussion