使用Vault搭建企业PKI系统

来源:互联网 发布:数据分析师证书含金量 编辑:程序博客网 时间:2024/05/19 03:24

静态的数据加密和传输中的数据加密,对于数据安全来说同等重要。目前最流行的用于传输中数据加密的方式就是 SSL/TLS。 对于大多数企业内部网络管理员,如果不是非用不可,一般都不会主动使用SSL/TLS,没有一个方便高效和安全的创建CA,签发证书的解决方案。

Hashicorp公司的Vault工具出现,将秘钥管理提升到了一个新水平,其中的PKI后端可以方便的帮助企业搭建一套私有的PKI体系。Vault的使用文档从功能的角度对pki后端做了详细介绍,我在此将提供一个搭建企业自建PKI的完成过程。

这篇介绍将包括以下几个部分:

1. 启动vault服务

2. 为企业创建一个根CA

3. 为企业创建一个中间CA

4. 为一个web服务颁发TLS秘钥和证书 

5. 使用NGINX测试签发的证书

需要澄清的是这篇介绍只是一个对于概念完整介绍,并不是一个最好的实践方案,在此的目的是介绍pki后端的功能。 真实实践时,Vault需要配置为HA模式,由TLS保护,不使用root token和策略,与CA和证书关联的有效期也应谨慎的根据真实的应用情况而定。

Vault作为企业内部自建CA最方便的一点就是,应用可以随时请求证书和秘钥。这就意味着可以通过基本的cron任务来更新证书,因此证书的有效期可以尽可能的短(这部分内容我会在我的另一篇博客中介绍)。但这部分功能也是Vault与我们之前习惯使用的EasyRSA或者是CFSSL的区别所在,它改变了我们管理TLS的方式。


启动 Vault

下载Vault后,创建一个目录存储相关加密数据和配置等。接下来创建一个配置文件,并启动服务:

$ mkdir vault && cd vault$ vi vault.hcldisable_mlock  = truelistener "tcp" {  address = "0.0.0.0:8200"  tls_disable = 1}backend "file" {  path = "/home/benr/vault/secrets"}$ vault server -config=vault.hcl==> Vault server configuration:                 Backend: file              Listener 1: tcp (addr: "0.0.0.0:8200", tls: "disabled")               Log Level: info                   Mlock: supported: true, enabled: false                 Version: Vault v0.6.0==> Vault server started! Log data will stream in below:
在另一个终端中初始化并解封Vault:

$ export VAULT_ADDR='http://127.0.0.1:8200'$ vault initUnseal Key 1: 811538b33c90d6f558b0296e12dc0023fc4086f5cbc424a2a3766d52dd52d7cf01Unseal Key 2: 3eb6e073249168bdef779cf0e47f5c02baf7a2260e3d531073ae40862916029302Unseal Key 3: b99b0b9a16f2f88ab83f87ddab4e6f483b15f288889bc9d1b9b2d154ad14ac8f03Unseal Key 4: c24260a579914e78f78123b7a83fc96ebd16434980fc5a003f24bd5e2ecf7fa804Unseal Key 5: 456f8b4c4bf2de4fa0c9389ae70efa243cf413e7065ac0c1f5382c8caacdd1b405Initial Root Token: d194e2e3-6483-aa23-9bf2-f1bb31b0edbb...$ vault unseal 811538b33c90d6f558b0296e12dc0023fc4086f5cbc424a2a3766d52dd52d7cf01$ vault unseal 3eb6e073249168bdef779cf0e47f5c02baf7a2260e3d531073ae40862916029302$ vault unseal b99b0b9a16f2f88ab83f87ddab4e6f483b15f288889bc9d1b9b2d154ad14ac8f03Sealed: falseKey Shares: 5Key Threshold: 3Unseal Progress: 0$ vault authToken (will be hidden): d194e2e3-6483-aa23-9bf2-f1bb31b0edbbSuccessfully authenticated! You are now logged in.token: d194e2e3-6483-aa23-9bf2-f1bb31b0edbbtoken_duration: 0token_policies: [root]
好了!到了这一步Vault已经启动并解封,可以使用了。


创建一个根CA

在Vault中,秘密信息是通过"backend"(后端)管理的,在使用之前必须被挂载。这在刚开始使用Vault时看起来非常奇怪,但这确实是合理的设计,后端可以多次挂载在不同的路径下。这个特性在我们搭建PKI时十分重要,因为Vault的一个pki后端只能代表一个CA,因此我们需要挂载两个pki后端,一个作为根CA,一个作为中间CA。这个特性使一个Vault服务可以支持多个CA,它们之间又彼此独立。

因此,我们先挂载一个pki后端,作为根CA,路径为“cuddltech”。我们在挂载时需要提供路径("path",用于访问这个特定后端的路径),描述("description"),最长有效期("maximum lease TTL"):

$ vault mount -path=cuddletech -description="Cuddletech Root CA" -max-lease-ttl=87600h pkiSuccessfully mounted 'pki' at 'cuddletech'!$ vault mountsPath         Type       Default TTL  Max TTL    Descriptioncubbyhole/   cubbyhole  n/a          n/a        per-token private secret storagecuddletech/  pki        system       315360000  Cuddletech Root CAsecret/      generic    system       system     generic secret storagesys/         system     n/a          n/a        system endpoints used for control, policy and debugging 
现在我们就可以创建我们的根CA证书和秘钥了:

$ vault write cuddletech/root/generate/internal \> common_name="Cuddletech Root CA" \> ttl=87600h \> key_bits=4096 \> exclude_cn_from_sans=trueKey             Value---             -----certificate     -----BEGIN CERTIFICATE-----MIIFKzCCAxOgAwIBAgIUDXiI3GDzP2IbQ9IatFSCv9Pq/lgwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAxMSQ3VkZGxldGVjaCBSb290IENBMB4XDTE2MDcwOTA4MTIz..axscmLdVE2HTB87W1H77iKKN8n9Xne//LUidxVX0Kg==-----END CERTIFICATE-----expiration      1783411981issuing_ca      -----BEGIN CERTIFICATE-----MIIFKzCCAxOgAwIBAgIUDXiI3GDzP2IbQ9IatFSCv9Pq/lgwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAxMSQ3VkZGxldGVjaCBSb290IENBMB4XDTE2MDcwOTA4MTIz...axscmLdVE2HTB87W1H77iKKN8n9Xne//LUidxVX0Kg==-----END CERTIFICATE-----serial_number   0d:78:88:dc:60:f3:3f:62:1b:43:d2:1a:b4:54:82:bf:d3:ea:fe:58
最后需要做的就是配置URL用于获取CA证书和CRL:

$ vault write cuddletech/config/urls issuing_certificates="http://10.0.0.22:8200/v1/cuddletechSuccess! Data written to: cuddletech/config/urls
到此,根CA就已经准备好了,接下来需要生成中间CA。


创建一个中间CA

创建中间CA的过程和创建根CA的过程类似,最大的不同是不能用一步一次生成证书和私钥。我们需要再挂载一个pki后端,在此先生成CSR和私钥,然后将CSR给根CA所在后端签名,将得到的证书导入后创建的pki后端作为中间CA的证书。

说起来有点绕,看步骤就清晰明了了。首先为中间CA再挂载一个pki后端,将它命名为Ops 中间CA:

$ vault mount -path=cuddletech_ops -description="Cuddletech Ops Intermediate CA" -max-lease-ttl=26280h pkiSuccessfully mounted 'pki' at 'cuddletech_ops'!$ vault mountsPath             Type       Default TTL  Max TTL    Descriptioncubbyhole/       cubbyhole  n/a          n/a        per-token private secret storagecuddletech/      pki        system       315360000  Cuddletech Root CAcuddletech_ops/  pki        system       94608000   Cuddletech Ops Intermediate CA
下一步生成一个中签CA的CSR:

$ vault write cuddletech_ops/intermediate/generate/internal \>  common_name="Cuddletech Operations Intermediate CA">  ttl=26280h \>  key_bits=4096 \>  exclude_cn_from_sans=trueKey     Value---     -----csr     -----BEGIN CERTIFICATE REQUEST-----MIICuDCCAaACAQAwMDEuMCwGA1UEAxMlQ3VkZGxldGVjaCBPcGVyYXRpb25zIEludGVybWVkaWF0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALt8...hD8cpHTXqjKExYWKc/rQDgjw9+RNDdb45xszDagrgFgNPqI9i0fNh9jViMmjUiTcPQTZS4XxIoRrx1/xVHJ4Qm++ntLPVCvzjMZafg==-----END CERTIFICATE REQUEST-----
复制CSR的值到一个新建的文件:cuddletech_ops.csr 这样做的原因是下一步需要将它作为参数传给根CA所在后端进行签名。

$ vault write cuddletech/root/sign-intermediate \>  csr=@cuddletech_ops.csr \>  common_name="Cuddletech Ops Intermediate CA" \>  ttl=8760hKey             Value---             -----certificate     -----BEGIN CERTIFICATE-----MIIEZDCCAkygAwIBAgIUHuIhRF3tYtfoZiAFdjcCtQpMR+cwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAxMSQ3VkZGxldGVjaCBSb290IENBMB4XDTE2MDcwOTA4Mjkz...UtI2b/AamAqf340eRKmSdEh4WypB4JR+t259YA45w2j4mS+rxREycEk4YosR/vUsjekMiq57yNq7h8eOTrnOulJxazbVrYGb-----END CERTIFICATE-----expiration      1470645002issuing_ca      -----BEGIN CERTIFICATE-----MIIFKzCCAxOgAwIBAgIUDXiI3GDzP2IbQ9IatFSCv9Pq/lgwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAxMSQ3VkZGxldGVjaCBSb290IENBMB4XDTE2MDcwOTA4MTIz..1FRGlwHUg+6IIZBVIapzivLc6pAvLFPxQlQvT5CNHPk91zwyNQ9ZX2PzatdajUndaxscmLdVE2HTB87W1H77iKKN8n9Xne//LUidxVX0Kg==-----END CERTIFICATE-----serial_number   1e:e2:21:44:5d:ed:62:d7:e8:66:20:05:76:37:02:b5:0a:4c:47:e7
现在我们就有了一个已经被根CA签名过了证书了,我们将证书内从复制粘贴到一个新建文件:cuddletech_ops.crt 我们将它导入中间CA的后端:

$ vault write cuddletech_ops/intermediate/set-signed \> certificate=@cuddletech_ops.crtSuccess! Data written to: cuddletech_ops/intermediate/set-signed
我们来验证一下:

$ curl -s http://localhost:8200/v1/cuddletech_ops/ca/pem | openssl x509 -text | head -20Certificate:    Data:        Version: 3 (0x2)        Serial Number:            76:12:53:41:be:18:98:2c:a1:51:4a:f8:f0:bd:b4:a3:44:7e:74:59    Signature Algorithm: sha256WithRSAEncryption        Issuer: CN=Cuddletech Root CA        Validity            Not Before: Jul  9 09:23:39 2016 GMT            Not After : Jul  9 09:24:09 2017 GMT        Subject: CN=Cuddletech Ops Intermediate CA ...
最后要做的就是配置获取CA和CRL的url:

$ vault write cuddletech_ops/config/urls \> issuing_certificates="http://10.0.0.22:8200/v1/cuddletech_ops/ca" \> crl_distribution_points="http://10.0.0.22:8200/v1/cuddletech_ops/crl"Success! Data written to: cuddletech_ops/config/urls

为一个Web服务申请一个证书

到这里为止,我们的CA就配置好了,接下来看看如何颁发证书。颁发证书需要两个步骤,第一步是创建一个角色,定义和限制生成证书的一些参数,例如秘钥类型和秘钥长度,证书类型等等。第二步就是颁发一个该角色的证书。

在中间CA后端中创建一个名为“web_server”类型的角色,该角色可生成的秘钥长度为2048 bits,最长有效期为1年,允许任意CN。

$ vault write cuddletech_ops/roles/web_server \> key_bits=2048 \> max_ttl=8760h \> allow_any_name=trueSuccess! Data written to: cuddletech_ops/roles/web_server
接下来就可以使用这个角色去颁发证书了。

$ vault write cuddletech_ops/issue/web_server \> common_name="ssl_test.cuddletech.com" \> ip_sans="172.17.0.2" \> ttl=720h> format=pemKey                     Value---                     -----lease_id                cuddletech_ops/issue/web_server/e03318f2-d005-8196-4ed5-a42f9cd55238lease_duration          2591999lease_renewable         falsecertificate             -----BEGIN CERTIFICATE-----MIIE7jCCAtagAwIBAgIUN+vXFuIf42v1SW+mDROUVAm+lUMwDQYJKoZIhvcNAQELBQAwKTEnMCUGA1UEAxMeQ3VkZGxldGVjaCBPcHMgSW50ZXJtZWRpYXRlIENBMB4XDTE2MDcwOTA5MzE1N1oXDTE2MDgwODA5MzIyN1owIjEgMB4GA1UEAwwXc3NsX3Rl...issuing_ca              -----BEGIN CERTIFICATE-----MIIF5DCCA8ygAwIBAgIUdhJTQb4YmCyhUUr48L20o0R+dFkwDQYJKoZIhvcNAQEL...private_key             -----BEGIN RSA PRIVATE KEY-----MIIEowIBAAKCAQEApBabDpPZIloRQUpro3tQEls0FEFvsvfraQzQJLD2dicSPZ2sCqYyT8OXMclrapG7KKTYp79AaTW8LgNg3WvCzoMGDfhLL9m0QomzrMDzoW8Q7iQO1MV4f6JXjGMbOMMXatKQlO32fLZln8m+/yJ3pOW0S6uatFzZ/N3+ed+gDuUc7eAO...private_key_type        rsaserial_number           37:eb:d7:16:e2:1f:e3:6b:f5:49:6f:a6:0d:13:94:54:09:be:95:43
我们需要将证书(certificate)和签发CA证书也就是中间CA的证书(issuing_ca)一起写入新建文件 ssl_test.cuddletech.com.crt文件中(颁发的证书在前,CA证书在后),将私钥(private_key)写入文件ssl_test.cuddletech.com.key 中。

接下来可以配置NGINX了!


在NGINX中测试证书

将上一步得到的ssl_test.cuddletech.com.crt证书文件路径写入NGINX配置文件,然后启动。
server {    listen              443 ssl;    server_name         ssl_test.cuddletech.com;    ssl_certificate     ssl_test.cuddletech.com.crt;    ssl_certificate_key ssl_test.cuddletech.com.key;    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;    ssl_ciphers         HIGH:!aNULL:!MD5;    location / {      root   /usr/share/nginx/html;      index  index.html index.htm;    }}
在NGINX启动后,用浏览器访问,这时你会看到熟悉的“Your connection is not secure”的警告,我们需要导出根CA的证书,并添加到浏览器的受信证书列表里。导出根CA证书:
$ curl -s http://localhost:8200/v1/cuddletech/ca/pem > cuddletech_ca.pem
当你将根CA导入浏览器受信列表里后,你就会体会到使用Vault来颁发内部TLS证书是如此好用,好用到飞起来:)






1 0