企业内常常需要构建一个PKI公钥体系(内部的,不需要外部信任的),用来对内部用户、应用、服务、设备等进行身份验证,或者对代码进行签名。然而没有硬件加密模块(HSM)的软实现CA均存在各种各样的安全问题。

亚马逊云科技Amazon Certificate Manager在大部分Region均提供了Private CA服务(中国区域目前没有提供),由于亚马逊云科技维护CA的私钥(类似于HSM),私钥时不会泄露,ACM PCA便可以用来构建安全的企业内PKI公钥体系。

本文主要使用CLI创建根CA (RootCA) 中级CA (Intermediate CA)以及一个终端实体证书(End-Entity Cert),通过这个过程大家可以了解PKI公钥体系是如何构成的。

需要注意的是:

  1. 为了简化,我们在此会采用S3公开访问的形式托管CRL,但是基于目前的最佳实践,在生产环境中我们仍然建议使用CloudFront + OAI的形式访问阻止S3公开访问的形式托管CRL;
  2. 一个Private CA月费是400美金,本例会创建两个CA以构成一个体系,这样在月租上就会有800美金的支出(万幸第一个月你可以减免一个CA的费用)。除此之外,你签发证书还有一个一次性费用,这个就比较少了,这部分具体可以参考https://aws.amazon.com/certificate-manager/pricing/。

首先我们来聊一聊我们将要创建的CA的层次结构。PCA支持最多五级的层次结构,良好的层次结构可以对每个CA做到精细控制,可以有更高的安全性。我们在本文中会使用两级CA,Root CA – Subordinate CA (通常也叫做Intermediate CA),则示意如下。

Image

一般实践中我们并不会使用Root CA来给终端实体来签发证书,Root CA一般会用来签发其他CA。而Intermediate CA则用来批量签发终端实体证书。

所有证书(包含CA证书),都需要进行签名,不同的是Root CA是自签名的,而次一级的证书(或者CA证书)都需要上一级的CA来签名。按照这个思路,我们开始CA的构建过程。

1) 创建Root CA,我们首先创建Root CA配置文件,存储为rca_config.json

{
   "KeyAlgorithm":"RSA_2048",
   "SigningAlgorithm":"SHA256WITHRSA",
   "Subject":{
      "Country":"CN",
      "Organization":"Xi'an Goldendata IT Co., Ltd.",
      "OrganizationalUnit":"IT Dept.",
      "State":"Shaanxi",
      "Locality":"Xi'an",
      "CommonName":"XA Goldendata Root CA"
   }
}

然后执行

$ aws acm-pca create-certificate-authority \
    --certificate-authority-configuration file://rca_config.json \
    --certificate-authority-type "ROOT" \
    --idempotency-token root-ca-demo

可以得到返回

{
    "CertificateAuthorityArn": "arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161"
}

我们这时通过控制台看一看ACM的状态

Image

可以发现,此时尚未对Root CA实施自签名,所以我们首先要拿到CSR证书请求

$ aws acm-pca get-certificate-authority-csr \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161 \
  --output text > rca.csr

然后我们使用Root CA对该CSR签名,即自签名,由于是Root CA,我们一般会给比较久的有效期

$ aws acm-pca issue-certificate \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161 \
  --csr fileb://rca.csr \
  --signing-algorithm SHA256WITHRSA \
  --template-arn arn:aws:acm-pca:::template/RootCACertificate/V1 \
  --validity Value=3650,Type=DAYS

可以得到Root CA的证书

{
    "CertificateArn": "arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161/certificate/2da5b4a6dfb0fef5ed8c38f3de015aae"
}

我们需要将这个证书导出

$ aws acm-pca get-certificate \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161 \
  --certificate-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161/certificate/2da5b4a6dfb0fef5ed8c38f3de015aae \
  --output text > rca_cert.pem

然后将这个证书导入(安装)到ACM

$ aws acm-pca import-certificate-authority-certificate \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161 \
  --certificate fileb://rca_cert.pem

这时,我们再检查一下控制台,可以确认Root CA已经生效了,可以用来做下一步动作。

Image

需要注意的是,Root CA并不需要CRL。

2) 创建Intermediate CA,本流程其实类似于Root CA的创建过程,我们依然是首先要创建Intermediate CA的配置文件

{
   "KeyAlgorithm":"RSA_2048",
   "SigningAlgorithm":"SHA256WITHRSA",
   "Subject":{
      "Country":"CN",
      "Organization":"Xi'an Goldendata IT Co., Ltd.",
      "OrganizationalUnit":"R&D",
      "State":"Shaanxi",
      "Locality":"Xi'an",
      "CommonName":"XA Goldendata R&D CA"
   }
}

不同的是,我们需要创建一个CRL配置文件,当进行证书有效性检查时,会对CRL做检查(对于S3桶及权限的部分,我们在此不做赘述,具体可以参考https://docs.aws.amazon.com/acm-pca/latest/userguide/PcaCreateCa.html#s3-policies)

{
    "CrlConfiguration":{
       "Enabled":true,
       "ExpirationInDays":7,
       "S3BucketName":"pki-demo-sean"
    }
 }

如同之前备注的,生产环境中建议使用CloudFront+OAI的方式,我们在此为了简单,使用了默认(可公共读)

然后执行创建CA,我们目前创建的并不是Root CA,注意CA类型

$ aws acm-pca create-certificate-authority \
        --certificate-authority-configuration file://ica_config.json \
        --revocation-configuration file://ica_revoke.json \
        --certificate-authority-type "SUBORDINATE" \
        --idempotency-token ica-demo

得到CA返回

{
    "CertificateAuthorityArn": "arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/9a526f96-f417-49dc-886a-a5e268e7ef4d"
}

同样获取CSR

aws acm-pca get-certificate-authority-csr \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/9a526f96-f417-49dc-886a-a5e268e7ef4d
  --output text > ica.csr

这时要注意,我们要使用第一步创建的Root CA签发这个CA证书,同时证书模板要选用SubordinateCACertificate_PathLen0/V1,pathlen为0表示这个CA不能签发CA,只能签发终端实体

aws acm-pca issue-certificate \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161 \
  --csr fileb://ica.csr \
  --signing-algorithm SHA256WITHRSA \
  --template-arn arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen0/V1 \
  --validity Value=1095,Type=DAYS

我们得到它的证书返回

{
    "CertificateArn": "arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161/certificate/c0af427d7d48c7d756f688c26e6e8a4a"
}

同样获取证书,也要注意这个证书是Root CA签发的,对应的参数不要搞错

aws acm-pca get-certificate \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161 \
  --certificate-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/235f40bc-427f-43fc-93e5-bb27c402e161/certificate/c0af427d7d48c7d756f688c26e6e8a4a \
  --output text > ica_cert.pem

需要整理ica_cert.pem,删除Root CA的证书部分。

最后安装证书,这个证书将安装到Intermediate CA上

$ aws acm-pca import-certificate-authority-certificate \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/9a526f96-f417-49dc-886a-a5e268e7ef4d \
  --certificate fileb://ica_cert.pem \
  --certificate-chain fileb://rca_cert.pem

Root CA的证书做为证书链,在命令中引用。这时我们可以在控制台确认

Image

顺带一提,当这个CA有效时,S3的桶也写入了一个测试文件,如图

Image

我们也可以将这个CA证书的内容通过工具解码,有如下内容

Image

到此,两级的CA已经搭建完成了,下一步我们将使用这个CA签发终端实体证书,如果你有一个内部门户网站,通过证书做双向验证无疑是最安全的方式之一。

3) 创建终端实体证书

类似于一切证书创建流程,我们首先需要创建私钥,然后需要根据具体的内容来创建对应的CSR,然后使用Intermediate CA签发证书。

$ openssl req -new -nodes -newkey rsa:2048 -keyout end_entity.key -out end_entity.csr \
  -subj "/C=CN/ST=Shaanxi/L=Xi'an/O=Xi'an Goldendata IT Co., Ltd./OU=R&D/CN=Sean Chang/emailAddress=sean@jinshuju.net"

然后我们使用Intermediate  CA来签发

aws acm-pca issue-certificate \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/9a526f96-f417-49dc-886a-a5e268e7ef4d \
  --csr fileb://end_entity.csr \
  --signing-algorithm SHA256WITHRSA \
  --template-arn arn:aws:acm-pca:::template/EndEntityCertificate/V1 \
  --validity Value=365,Type=DAYS
{
    "CertificateArn": "arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/9a526f96-f417-49dc-886a-a5e268e7ef4d/certificate/3e5e4a71e0ba7c82238093fc1588a131"
}

获取证书

$ aws acm-pca get-certificate \
  --certificate-authority-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/9a526f96-f417-49dc-886a-a5e268e7ef4d \
  --certificate-arn arn:aws:acm-pca:ap-east-1:xxxxxx:certificate-authority/9a526f96-f417-49dc-886a-a5e268e7ef4d/certificate/3e5e4a71e0ba7c82238093fc1588a131 \
  --output text > end_entity.pem

然后我们合成p12文件

$ openssl pkcs12 -export -in end_entity.pem -inkey end-entity.key -out certificate.pfx -certfile ica_cert.pem

我们尝试在终端上打开,可以有以下截图

Image

同时我们可以注意到,证书中也包含了CRL列表,以供确认证书是否被吊销。

Image

总结

需要注意的是,现阶段ACM PCA只是一个CA的管理工具,其本身并不会展示签发的证书列表(这个和ACM证书管理的功能不同),所以当你想查看签发记录或者吊销证书时,你需要

1) 生成审计报告,报告中会列出CA所签发的证书,生成的报告会存储在S3中,生成过程可以通过控制台或者CLI

2) 通过命令行吊销证书,参数是证书序号,这个可以参考https://docs.aws.amazon.com/cli/latest/reference/acm-pca/revoke-certificate.html

希望本文的流程拆解可以帮助你更好的了解PKI以及PCA。