414 lines
9.8 KiB
Markdown
414 lines
9.8 KiB
Markdown
### 一、安装CFSSL工具
|
||
|
||
CFSSL(CloudFlare's PKI Toolkit)是一个开源的PKI工具集,可用于创建私有CA和证书。
|
||
|
||
1. **Linux/macOS**:
|
||
```bash
|
||
# 下载cfssl和cfssljson工具
|
||
curl -o cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
|
||
curl -o cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
|
||
chmod +x cfssl cfssljson
|
||
sudo mv cfssl cfssljson /usr/local/bin/
|
||
```
|
||
|
||
2. **Windows**:
|
||
- 从 [CFSSL Releases](https://github.com/cloudflare/cfssl/releases) 下载对应版本的 `cfssl.exe` 和 `cfssljson.exe`
|
||
- 将可执行文件添加到系统PATH路径
|
||
|
||
### 二、创建私有CA
|
||
|
||
#### 1. 配置CA证书
|
||
创建一个名为 `ca-config.json` 的文件,定义证书的有效期和使用策略:
|
||
```json
|
||
{
|
||
"signing": {
|
||
"default": {
|
||
"expiry": "87600h" // 10年有效期
|
||
},
|
||
"profiles": {
|
||
"server": {
|
||
"expiry": "87600h",
|
||
"usages": ["signing", "key encipherment", "server auth"]
|
||
},
|
||
"client": {
|
||
"expiry": "87600h",
|
||
"usages": ["signing", "key encipherment", "client auth"]
|
||
},
|
||
"peer": {
|
||
"expiry": "87600h",
|
||
"usages": ["signing", "key encipherment", "server auth", "client auth"]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. 创建CA证书签名请求(CSR)配置
|
||
创建 `ca-csr.json` 文件:
|
||
```json
|
||
{
|
||
"CN": "My Private CA",
|
||
"key": {
|
||
"algo": "rsa",
|
||
"size": 4096
|
||
},
|
||
"names": [
|
||
{
|
||
"C": "CN",
|
||
"ST": "Shanghai",
|
||
"L": "Shanghai",
|
||
"O": "My Organization",
|
||
"OU": "IT Department"
|
||
}
|
||
],
|
||
"ca": {
|
||
"expiry": "87600h" // CA证书有效期10年
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3. 生成CA证书和私钥
|
||
执行以下命令生成自签名CA证书:
|
||
```bash
|
||
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
|
||
```
|
||
这将生成三个文件:
|
||
- `ca.pem`:CA公钥证书
|
||
- `ca-key.pem`:CA私钥(妥善保管,不要泄露)
|
||
- `ca.csr`:CA证书签名请求
|
||
|
||
### 三、使用CA签署服务器证书
|
||
|
||
#### 1. 创建服务器证书CSR配置
|
||
创建 `server-csr.json` 文件:
|
||
```json
|
||
{
|
||
"CN": "server.example.com",
|
||
"hosts": [
|
||
"server.example.com",
|
||
"192.168.1.100",
|
||
"localhost",
|
||
"127.0.0.1"
|
||
],
|
||
"key": {
|
||
"algo": "rsa",
|
||
"size": 2048
|
||
},
|
||
"names": [
|
||
{
|
||
"C": "CN",
|
||
"ST": "Shanghai",
|
||
"L": "Shanghai",
|
||
"O": "My Organization",
|
||
"OU": "IT Department"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
> 注意:`hosts` 字段必须包含服务器的域名、IP地址以及任何需要访问的别名
|
||
|
||
#### 2. 生成服务器证书和私钥
|
||
使用CA直接签署服务器证书:
|
||
```bash
|
||
cfssl gencert \
|
||
-ca=ca.pem \
|
||
-ca-key=ca-key.pem \
|
||
-config=ca-config.json \
|
||
-profile=server \
|
||
server-csr.json | cfssljson -bare server
|
||
```
|
||
这将生成:
|
||
- `server.pem`:服务器公钥证书
|
||
- `server-key.pem`:服务器私钥
|
||
|
||
### 四、使用CA签署客户端证书
|
||
|
||
#### 1. 创建客户端证书CSR配置
|
||
创建 `client-csr.json` 文件:
|
||
```json
|
||
{
|
||
"CN": "client.example.com",
|
||
"hosts": [], // 客户端证书通常不需要指定hosts
|
||
"key": {
|
||
"algo": "rsa",
|
||
"size": 2048
|
||
},
|
||
"names": [
|
||
{
|
||
"C": "CN",
|
||
"ST": "Shanghai",
|
||
"L": "Shanghai",
|
||
"O": "My Organization",
|
||
"OU": "IT Department"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 2. 生成客户端证书和私钥
|
||
```bash
|
||
cfssl gencert \
|
||
-ca=ca.pem \
|
||
-ca-key=ca-key.pem \
|
||
-config=ca-config.json \
|
||
-profile=client \
|
||
client-csr.json | cfssljson -bare client
|
||
```
|
||
这将生成:
|
||
- `client.pem`:客户端公钥证书
|
||
- `client-key.pem`:客户端私钥
|
||
|
||
### 五、证书验证
|
||
|
||
#### 1. 验证服务器证书
|
||
```bash
|
||
openssl verify -CAfile ca.pem server.pem
|
||
```
|
||
如果输出 `server.pem: OK`,则证书有效
|
||
|
||
#### 2. 验证客户端证书
|
||
```bash
|
||
openssl verify -CAfile ca.pem client.pem
|
||
```
|
||
|
||
### 六、证书使用示例
|
||
|
||
#### 1. 在HTTPS服务器中使用
|
||
将 `server.pem` 和 `server-key.pem` 配置到你的Web服务器(如Nginx、Apache):
|
||
```nginx
|
||
server {
|
||
listen 443 ssl;
|
||
server_name server.example.com;
|
||
|
||
ssl_certificate /path/to/server.pem;
|
||
ssl_certificate_key /path/to/server-key.pem;
|
||
ssl_client_certificate /path/to/ca.pem; # 客户端证书验证(可选)
|
||
ssl_verify_client on; # 启用客户端证书验证(可选)
|
||
|
||
# 其他配置...
|
||
}
|
||
```
|
||
|
||
#### 2. 在客户端应用中使用
|
||
在需要验证服务器证书的客户端应用中,导入 `ca.pem` 作为信任的根证书。例如,使用curl访问HTTPS服务器:
|
||
```bash
|
||
curl --cacert ca.pem https://server.example.com
|
||
```
|
||
|
||
### 七、安全注意事项
|
||
|
||
1. **私钥保护**:
|
||
- `ca-key.pem`、`server-key.pem` 和 `client-key.pem` 是敏感文件,应存储在安全位置
|
||
- 限制访问权限:`chmod 400 *.key.pem`
|
||
|
||
2. **证书备份**:
|
||
- 定期备份CA证书和私钥
|
||
- 考虑使用硬件安全模块(HSM)存储CA私钥
|
||
|
||
3. **证书撤销**:
|
||
- 如需撤销证书,可使用CFSSL生成证书撤销列表(CRL)
|
||
- 更新 `ca-config.json` 添加CRL配置
|
||
|
||
通过以上步骤,你已成功创建了一个有效期10年的私有CA,并使用它签署了服务器和客户端证书。
|
||
|
||
### 八、附快速签发脚本
|
||
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
# 证书快速签发脚本
|
||
# 依赖: cfssl, cfssljson 已安装并初始化好CA证书
|
||
|
||
# 颜色定义
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[0;33m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# 默认配置
|
||
CA_KEY="/root/ckw/cfssl/ca/ca-ecdsa-key.pem"
|
||
CA_CERT="/root/ckw/cfssl/ca/ca-ecdsa.pem"
|
||
CA_CONFIG="/root/ckw/cfssl/ca/ca-config.json"
|
||
OUTPUT_DIR="certs"
|
||
MERGE_CA="true" # 默认合并根证书
|
||
|
||
# 使用帮助
|
||
function show_help {
|
||
echo -e "${GREEN}证书快速签发脚本${NC}"
|
||
echo "用法: $0 [选项]"
|
||
echo "选项:"
|
||
echo " -h, --help 显示此帮助信息"
|
||
echo " -n, --name NAME 证书名称 (必填)"
|
||
echo " -t, --type TYPE 证书类型: server, client, peer (默认: server)"
|
||
echo " -c, --ca CA_CERT CA证书路径 (默认: $CA_CERT)"
|
||
echo " -k, --ca-key CA_KEY CA私钥路径 (默认: $CA_KEY)"
|
||
echo " -C, --ca-config CONF CA配置文件路径 (默认: $CA_CONFIG)"
|
||
echo " -o, --output DIR 输出目录 (默认: $OUTPUT_DIR)"
|
||
echo " -d, --domains LIST 域名列表 (逗号分隔)"
|
||
echo ""
|
||
echo "示例:"
|
||
echo " $0 -n server1 -d example.com,www.example.com "
|
||
}
|
||
|
||
# 参数解析
|
||
NAME=""
|
||
TYPE="server"
|
||
DOMAINS=""
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
-h|--help)
|
||
show_help
|
||
exit 0
|
||
;;
|
||
-n|--name)
|
||
NAME="$2"
|
||
shift 2
|
||
;;
|
||
-t|--type)
|
||
TYPE="$2"
|
||
shift 2
|
||
;;
|
||
-c|--ca)
|
||
CA_CERT="$2"
|
||
shift 2
|
||
;;
|
||
-k|--ca-key)
|
||
CA_KEY="$2"
|
||
shift 2
|
||
;;
|
||
-C|--ca-config)
|
||
CA_CONFIG="$2"
|
||
shift 2
|
||
;;
|
||
-o|--output)
|
||
OUTPUT_DIR="$2"
|
||
shift 2
|
||
;;
|
||
-d|--domains)
|
||
DOMAINS="$2"
|
||
shift 2
|
||
;;
|
||
--no-merge-ca)
|
||
MERGE_CA="false"
|
||
shift
|
||
;;
|
||
*)
|
||
echo -e "${RED}未知参数: $1${NC}" >&2
|
||
show_help
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# 验证必填参数
|
||
if [[ -z "$NAME" ]]; then
|
||
echo -e "${RED}错误: 必须指定证书名称 (-n/--name)${NC}" >&2
|
||
show_help
|
||
exit 1
|
||
fi
|
||
|
||
# 验证证书类型
|
||
if [[ "$TYPE" != "server" && "$TYPE" != "client" && "$TYPE" != "peer" ]]; then
|
||
echo -e "${RED}错误: 证书类型必须是 server, client 或 peer${NC}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# 验证文件是否存在
|
||
for file in "$CA_CERT" "$CA_KEY" "$CA_CONFIG"; do
|
||
if [[ ! -f "$file" ]]; then
|
||
echo -e "${RED}错误: 文件 $file 不存在${NC}" >&2
|
||
exit 1
|
||
fi
|
||
done
|
||
|
||
# 当类型为server且未指定域名时,默认将name作为域名
|
||
if [[ "$TYPE" == "server" && -z "$DOMAINS" ]]; then
|
||
DOMAINS="$NAME"
|
||
echo -e "${YELLOW}注意: 证书类型为server且未指定域名,默认添加 ${NAME} 作为域名${NC}"
|
||
fi
|
||
|
||
|
||
# 创建证书单独目录
|
||
CERT_DIR="$OUTPUT_DIR/$NAME"
|
||
mkdir -p "$CERT_DIR" || { echo -e "${RED}无法创建证书目录: $CERT_DIR${NC}"; exit 1; }
|
||
|
||
# 生成证书签名请求配置
|
||
CSR_CONFIG="$CERT_DIR/${NAME}-csr.json"
|
||
cat > "$CSR_CONFIG" <<EOF
|
||
{
|
||
"CN": "$NAME",
|
||
"key": {
|
||
"algo": "ecdsa",
|
||
"size": 256
|
||
},
|
||
"names": [
|
||
{
|
||
"C": "CN",
|
||
"ST": "Beijing",
|
||
"L": "Beijing",
|
||
"O": "CUA",
|
||
"OU": "IT"
|
||
}
|
||
]
|
||
}
|
||
EOF
|
||
|
||
# 生成SAN列表
|
||
SAN_LIST=""
|
||
if [[ -n "$DOMAINS" ]]; then
|
||
SAN_LIST+="$DOMAINS,"
|
||
fi
|
||
|
||
# 移除末尾逗号
|
||
SAN_LIST="${SAN_LIST%,}"
|
||
|
||
# 根据证书类型选择profile
|
||
case "$TYPE" in
|
||
server)
|
||
PROFILE="server"
|
||
;;
|
||
client)
|
||
PROFILE="client"
|
||
;;
|
||
peer)
|
||
PROFILE="peer"
|
||
;;
|
||
esac
|
||
|
||
# 生成证书
|
||
echo -e "${YELLOW}正在生成 $TYPE 证书: $NAME${NC}"
|
||
echo -e "${YELLOW}SAN列表: $SAN_LIST${NC}"
|
||
|
||
cfssl gencert \
|
||
-ca="$CA_CERT" \
|
||
-ca-key="$CA_KEY" \
|
||
-config="$CA_CONFIG" \
|
||
-profile="$PROFILE" \
|
||
${SAN_LIST:+-hostname="$SAN_LIST"} \
|
||
"$CSR_CONFIG" | cfssljson -bare "$CERT_DIR/$NAME"
|
||
|
||
# 验证生成结果
|
||
if [[ -f "$CERT_DIR/${NAME}.pem" && -f "$CERT_DIR/${NAME}-key.pem" ]]; then
|
||
echo -e "${GREEN}证书生成成功!${NC}"
|
||
echo -e "${GREEN}证书路径: ${CERT_DIR}/${NAME}.pem${NC}"
|
||
echo -e "${GREEN}私钥路径: ${CERT_DIR}/${NAME}-key.pem${NC}"
|
||
echo -e "${GREEN}证书签名请求: ${CSR_CONFIG}${NC}"
|
||
|
||
# 合并根证书
|
||
if [[ "$MERGE_CA" == "true" ]]; then
|
||
FULL_CHAIN="${CERT_DIR}/${NAME}-fullchain.pem"
|
||
cat "$CERT_DIR/${NAME}.pem" "$CA_CERT" > "$FULL_CHAIN"
|
||
echo -e "${GREEN}合并后的完整证书链: ${FULL_CHAIN}${NC}"
|
||
fi
|
||
|
||
# 显示证书信息
|
||
echo -e "\n${YELLOW}证书信息:${NC}"
|
||
openssl x509 -noout -text -in "$CERT_DIR/${NAME}.pem" | grep -A 5 "Subject Alternative Name"
|
||
else
|
||
echo -e "${RED}证书生成失败!${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
``` |