创建自签名的 SSL 证书

2024-09-20#SSL证书#Nginx

SSL 证书是一种数字证书,用于在客户端和服务器之间建立安全的加密连接,确保数据在传输过程中不被窃取或篡改。在互联网上,通常由权威的证书颁发机构(CA)给用户颁发证书。通常可以利用云服务厂商提供的证书管理服务获取证书(可能是付费的),也可以向 Let's Encrypt 这个免费、自动化且开放的证书颁发机构申请证书。除此之外,对于内部应用,还可以自行创建证书。本文介绍创建自签名的SSL证书的方式。

任务 🔗

my.internal 域名创建自签名的证书。

工具 🔗

本文使用 openssl 的命令行工具创建证书。MacOS 和大部分的 Linux 发行版,应该都内置了这个工具。

步骤 🔗

创建文件结构 🔗

创建两个目录:camy.internal 分别保存 CA 和 my.internal 的相关文件:

mkdir ca && make my.internal

创建根证书 🔗

根证书(Root certificate)是信任的源头。在数字证书体系中,它处于最顶层的位置。浏览器、操作系统等软件在出厂时会预装一些受信任的根证书。当用户访问一个使用了由受信任的根证书颁发机构(CA)所颁发的 SSL 证书的网站时,软件会通过信任链的验证机制,从该网站的证书追溯到根证书,如果根证书是受信任的,那么就认为该网站的证书也是可信的,从而建立起安全的连接。

以下操作在 ca 目录下操作。

创建根证书的密钥 🔗

openssl genrsa -des3 -out ca.key 2048

创建证书配置 🔗

创建证书配置文件 ca.conf,内容如下:

[ca]
default_ca = CA_default

[CA_default]
default_days = 3650

[req]
default_bits = 2048
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no

[req_distinguished_name]
C = (此处写国家,比如CN)
ST = (此处填写省)
L = (此处填写城市)
O = (此处填写 Orgnisation)
OU = (此处填写 Orgnisation Unit)
CN = (此处填写证书名称,比如MyRoot CA)

[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

创建根证书 🔗

openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -config ca.conf

生成的根证书文件为 ca.crt

颁发证书 🔗

以下操作在 my.internal 目录下操作。

创建密钥 🔗

一些 HTTP 服务器无法使用有密码保护的私密。因此在创建密钥时,直接生成 RSA 密钥:

openssl genrsa -out private_key.pem 2048

创建证书配置 🔗

与CA证书类似,创建配置文件 openssl.conf,内容如下:

[req]
default_bits = 2048
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no

[req_distinguished_name]
C = (此处写国家,比如CN)
ST = (此处填写省)
L = (此处填写城市)
O = (此处填写 Orgnisation)
OU = (此处填写 Orgnisation Unit)
CN = my.internal

[v3_req]
basicConstraints = CA:false
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.0 = localhost
DNS.1 = my.internal

创建证书签名请求 🔗

接下来生成“证书签名请求”,即 Certificate Signing Request (CSR)。

openssl req -new -key private_key.pem -out csr.pem -config openssl.conf

对证书进行签名 🔗

使用根证书、根证书密钥,对证书签名请求进行签名:

openssl x509 -req -days 365 -in csr.pem -CA ../ca/ca.crt -CAkey ../ca/ca.key -CAcreateserial -out certificate.pem

生成的证书文件为 certificate.pem

在 HTTP 服务器部署证书 🔗

my.internal 目录下的 certificate.pemprivate_key.pem 上传到 HTTP 服务器。以 Nginx 为例,将它们上传到 /etc/nginx/conf.d/my.internal 目录下(注意设定合适的文件权限,或者文件所有者)。假定后端的服务位于本机的 8000 端口。那么服务器配置如下(可放在 /etc/nginx/conf.d/my.internal.conf 文件中):

server {
    server_name my.internal;
    listen 443 ssl;
    ssl_certificate /etc/nginx/conf.d/my.internal/certificate.pem;
    ssl_certificate_key /etc/nginx/conf.d/my.internal/private_key.pem;
    location / {
    	proxy_pass http://localhost:8000;
    }
}

在客户端电脑上安装根证书 🔗

此时使用 curl 访问站点:

curl -H "Host: 127.0.0.1" https://my.internal

curl 会给出证书错误的消息。这是因为系统还没有“信任”这个证书。为此,可以让系统“信任”根证书,那么就会信任这个根证书颁发的所有证书。

在 macOS 上,可以打开 Keychain Access(密钥串访问) 程序。在 loginSystem 密钥串中,选择 Certificates 选项卡,然后将根证书文件(即 ca/ca.cert)拖动到窗口中,然后双击根证书项,打开详情后,点击 Trust,将 When using this certificate 设置为 Always Trust。如图所示:

RootCA

此时,回到密钥串列表里,如下图所示:

keychain

验证配置 🔗

使用 curl 访问站点:

curl -H "Host: 127.0.0.1" https://my.internal

确保没有证书错误。

使用浏览器访问站点 🔗

由于 my.internal 是内部域名,因此需要修改本地 DNS 才可以访问。为此,修改 /etc/hosts,添加记录:

127.0.0.1 my.internal

然后使用浏览器访问 https://my.internal。此时,Chrome 和 Firefox 浏览器依然会将站点标记为Not Secure(不安全)。

其中, Firefox 给出的提示是:

Someone could be trying to impersonate the site and you should not continue.
 
Websites prove their identity via certificates. Firefox does not trust my.internal because its certificate issuer is unknown, the certificate is self-signed, or the server is not sending the correct intermediate certificates.
 
Error code: SEC_ERROR_UNKNOWN_ISSUER
 
View Certificate

点击 Accept the Risk and Continue 才可以继续访问站点。


加载中...