生成自签证书
参考文献:
1.1 自签名证书方式
除了公网可用的受信证书,在内网环境,我们需要也使用 TLS 证书保障通信安全,这时我们可能会选择自己生成证书,而不是向权威机构申请证书。 可能的原因如下:
要向权威机构申请证书,那是要给钱的。而在内网环境下,并无必要使用权威证书。
内网环境使用的可能是非公网域名(
xxx.local/xxx.lan/xxx.srv等),权威机构不签发这种域名的证书。(因为没有人唯一地拥有这个域名)
自己生成的证书有两种方类型:
自签名 TLS 证书(我签我自己):可以认为是 TLS 证书和 CA 证书都使用同一个密钥对,使用 TLS 证书对它自己进行签名。
- 测试发现这种方式得到的证书貌似不包含 SAN 属性!因此不支持多域名。
由本地 CA 证书签名的 TLS 证书:生成两个独立的密钥,一个用作 CA 证书,一个用作 TLS 证书。使用 CA 证书对 TLS 证书进行签名。
一般来说,直接生成一个泛域名的自签名证书就够了,但是它不方便拓展——客户端对每个自签名证书,都需要单独添加一次信任。 而第二种方法生成的证书就没这个问题。
总的来说,使用第一种自签名证书不方便进行拓展,未来可能会遇到麻烦。因此建议使用第二种方法
1.2 自签名生成步骤
以域名:test.local为例子
配置文件
vi openssl.cnf插入以下脚本保存
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
C = CN # Contountry
ST = <state>
L = <city>
O = <organization>
OU = <organization unit>
CN = test.local # 域名-支持泛域名
[ alt_names ]
DNS.1 = test.local #扩展域名,可以是别的域名
IP.1 = 1.2.3.4 #扩展IP
[ req_ext ]
subjectAltName = @alt_names
[ v3_ext ]
subjectAltName=@alt_names # Chrome 要求必须要有 subjectAltName(SAN)
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment,digitalSignature
extendedKeyUsage=serverAuth,clientAuth生成证书
有两种方式生成证书,一种是自签名的证书,一种是CA签名,推荐使用CA签名,导入CA签名到浏览器浏览器可识别证书,自签名浏览器无法识别
生成自签名
#生成 2048 位 的 RSA 密钥
openssl genrsa -out ssl.key 2048
#通过第一步编写的配置文件,生成证书签名请求
openssl req -new -key ssl.key -out ssl.csr -config csr.conf
#生成最终的证书,这里指定证书有效期 10000 天
##使用 server.key 进行自签名。这种方式得到的证书不包含 SAN!不支持多域名!
openssl req -x509 -sha256 -days 3650 -key server.key -in server.csr -out server.crt使用CA证书签名(推荐)
#生成 2048 位 的 RSA 密钥
openssl genrsa -out ssl.key 2048
#通过第一步编写的配置文件,生成证书签名请求
openssl req -new -key ssl.key -out ssl.csr -config csr.conf
#生成 ca 证书,并且使用 CA 证书、CA 密钥对 `csr` 文件进行签名
# ca 私钥
openssl genrsa -out ca.key 2048
# ca 公钥
openssl req -x509 -new -nodes -key ca.key -subj "/CN=test.local" -days 10000 -out ca.crt
# 签名
openssl x509 -req -in ssl.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out ssl.crt -days 10000 -extensions v3_ext -extfile csr.conf验证证书
openssl verify -CAfile ca.crt ssl.crt、转换文件
如需将crt文件换成PEM文件,则使用一下命令
openssl x509 -in ca.crt -out ca.pem -outform PEM
openssl x509 -in ssl.crt -out ssl.pem -outform PEM4.1 通过脚本一键生成
可以使用以下脚本直接生成:
vi create_cert.sh#!/bin/bash -e
# 函数:显示帮助信息
help() {
cat <<EOF
================================================================
--ssl-domain: 生成 SSL 证书需要的主域名,如不指定则默认为 test.local,如果是 IP 访问服务,则可忽略;
--ssl-trusted-ip: 一般 SSL 证书只信任域名的访问请求,有时候需要使用 IP 去访问 server,那么需要给 SSL 证书添加扩展 IP,多个 IP 用逗号隔开;
--ssl-trusted-domain: 如果想多个域名访问,则添加扩展域名(SSL_TRUSTED_DOMAIN),多个扩展域名用逗号隔开;
--ssl-size: SSL 加密位数,默认 2048;
--ssl-cn: 国家代码(2 个字母的代号),默认 CN;
使用示例:
./create_self_signed_cert.sh --ssl-domain=www.test.com --ssl-trusted-ip=1.2.3.4 --ssl-trusted-domain=www.test.com --ssl-size=2048 --ssl-date=3650
================================================================
EOF
}
# 显示帮助信息并退出
case "$1" in
-h|--help) help; exit;;
esac
# 如果没有参数,显示帮助信息并退出
if [[ -z $1 ]]; then
help
exit
fi
CMDOPTS="$*"
for OPTS in $CMDOPTS;
do
key=$(echo ${OPTS} | awk -F"=" '{print $1}' )
value=$(echo ${OPTS} | awk -F"=" '{print $2}' )
case "$key" in
--ssl-domain) SSL_DOMAIN=$value ;;
--ssl-trusted-ip) SSL_TRUSTED_IP=$value ;;
--ssl-trusted-domain) SSL_TRUSTED_DOMAIN=$value ;;
--ssl-size) SSL_SIZE=$value ;;
--ssl-date) SSL_DATE=$value ;;
--ca-date) CA_DATE=$value ;;
--ssl-cn) CN=$value ;;
esac
done
# 设置默认值
CA_DATE=${CA_DATE:-3650}
SSL_DOMAIN=${SSL_DOMAIN:-'test.local'}
SSL_DATE=${SSL_DATE:-3650}
SSL_SIZE=${SSL_SIZE:-2048}
CN=${CN:-CN}
# 定义证书文件名
SSL_KEY=ssl.key
SSL_CSR=ssl.csr
SSL_CRT=ssl.crt
SSL_PEM=ssl.pem
CA_KEY=ca.key
CA_CRT=ca.crt
CA_PEM=ca.pem
CA_SRL=ca.srl
SSL_CONFIG=openssl.cnf
SSL_CONFIG_INIT="[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
C = CN # Contountry
ST = <state>
L = <city>
O = <organization>
OU = <organization unit>"
SSL_CONFIG_EXT="
[ v3_ext ]
subjectAltName=@alt_names # Chrome 要求必须要有 subjectAltName(SAN)
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment,digitalSignature
extendedKeyUsage=serverAuth,clientAuth"
generate_ssl_config() {
# 生成 OpenSSL 配置文件
cat > "$SSL_CONFIG" <<EOM
$SSL_CONFIG_INIT
CN = $SSL_DOMAIN
[ alt_names ]
DNS.1 = $SSL_DOMAIN
EOM
# 添加扩展域名
if [[ -n $SSL_TRUSTED_DOMAIN ]]; then
IFS=',' read -ra dns <<< "$SSL_TRUSTED_DOMAIN"
for i in "${!dns[@]}"; do
# 注意这里是i+2,因为1已经被主域名占用
echo "DNS.$((i+2)) = ${dns[$i]}" >> "$SSL_CONFIG"
done
fi
# 添加扩展ip
if [[ -n $SSL_TRUSTED_IP ]]; then
IFS=',' read -ra ip <<< "$SSL_TRUSTED_IP"
for i in "${!ip[@]}"; do
echo "IP.$((i+1)) = ${ip[$i]}" >> "$SSL_CONFIG"
done
fi
#添加扩展文件
{
echo ""
echo "[ req_ext ]"
echo "subjectAltName = @alt_names"
echo "$SSL_CONFIG_EXT"
} >> "$SSL_CONFIG"
}
# 函数:生成 SSL 证书相关文件
generate_SSL_CRT() {
# 生成 CA 私钥
if [[ ! -e $CA_KEY ]]; then
openssl genrsa -out "$CA_KEY" "$SSL_SIZE"
fi
# 生成 CA 证书
if [[ ! -e $CA_CRT ]]; then
openssl req -x509 -new -nodes -key "$CA_KEY" -days "$CA_DATE" -out "$CA_CRT" -subj "/C=$CN/CN=$SSL_DOMAIN"
fi
# 生成服务 SSL KEY
openssl genrsa -out "$SSL_KEY" "$SSL_SIZE"
# 生成服务 SSL CSR
openssl req -new -key "$SSL_KEY" -out "$SSL_CSR" -config "$SSL_CONFIG"
# 生成服务 SSL CERT
openssl x509 -req -in "$SSL_CSR" -CA "$CA_CRT" -CAkey "$CA_KEY" -CAcreateserial -out "$SSL_CRT" -days "$SSL_DATE" -extensions v3_ext -extfile "$SSL_CONFIG"
#生成 PEM文件
openssl x509 -in "$CA_CRT" -out "$CA_PEM" -outform PEM
openssl x509 -in "$SSL_CRT" -out "$SSL_PEM" -outform PEM
# 附加 CA 证书到 SSL CERT
cat "$CA_CRT" >> "$SSL_CRT"
}
# 调用函数生成 SSL 配置文件
generate_ssl_config
# 调用函数生成 SSL 证书
generate_SSL_CRT
# 新建文件夹,移动证书文件
mkdir -p "${PWD}/cert"
mv *.crt *.csr *.key *.pem *.srl "$SSL_CONFIG" "${PWD}/cert/"命令执行在上面有介绍
# 查看帮助
./create_cert.sh -h
#生成域名,--支持泛域名。有通配符最好使用引号隔开,否则可能会有影响
./create_cert.sh --ssl-domain='*.test.com'
#生成ip
./create_cert.sh --ssl-trusted-ip=192.168.1.30