---
author: Moshe Zadka
category: 软件开发
comments_data: []
count:
  commentnum: 0
  favtimes: 0
  likes: 0
  sharetimes: 0
  viewnum: 7260
date: '2019-05-31 09:10:51'
editorchoice: false
excerpt: 为你的微服务架构或者集成测试创建一个简单的内部 CA。
fromurl: https://opensource.com/article/19/4/certificate-authority
id: 10921
islctt: true
largepic: /images/p/201905/31/091023sg9s0ss11rsoseqg.jpg
permalink: /article-10921-1.html
pic: /images/p/201905/31/091023sg9s0ss11rsoseqg.jpg.thumb.jpg
related: []
reviewer: wxy
selector: lujun9972
summary: 为你的微服务架构或者集成测试创建一个简单的内部 CA。
tags:
- CA
- 证书
thumb: false
title: 自己成为一个证书颁发机构（CA）
titlepic: true
translator: geekpi
updated: '2019-05-31 09:10:51'
---


> 
> 为你的微服务架构或者集成测试创建一个简单的内部 CA。
> 
> 
> 


![](/images/p/201905/31/091023sg9s0ss11rsoseqg.jpg)


传输层安全（[TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security)）模型（有时也称它的旧名称 SSL）基于<ruby> <a href="https://en.wikipedia.org/wiki/Certificate_authority">  证书颁发机构 </a> <rt>  certificate authoritie </rt></ruby>（CA）的概念。这些机构受到浏览器和操作系统的信任，从而*签名*服务器的的证书以用于验证其所有权。


但是，对于内部网络，微服务架构或集成测试，有时候*本地 CA*更有用：一个只在内部受信任的 CA，然后签名本地服务器的证书。


这对集成测试特别有意义。获取证书可能会带来负担，因为这会占用服务器几分钟。但是在代码中使用“忽略证书”可能会被引入到生产环境，从而导致安全灾难。


CA 证书与常规服务器证书没有太大区别。重要的是它被本地代码信任。例如，在 Python `requests` 库中，可以通过将 `REQUESTS_CA_BUNDLE` 变量设置为包含此证书的目录来完成。


在为集成测试创建证书的例子中，不需要*长期的*证书：如果你的集成测试需要超过一天，那么你应该已经测试失败了。


因此，计算**昨天**和**明天**作为有效期间隔：



```
>>> import datetime
>>> one_day = datetime.timedelta(days=1)
>>> today = datetime.date.today()
>>> yesterday = today - one_day
>>> tomorrow = today - one_day
```

现在你已准备好创建一个简单的 CA 证书。你需要生成私钥，创建公钥，设置 CA 的“参数”，然后自签名证书：CA 证书*总是*自签名的。最后，导出证书文件以及私钥文件。



```
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes, serialization
from cryptography import x509
from cryptography.x509.oid import NameOID


private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)
public_key = private_key.public_key()
builder = x509.CertificateBuilder()
builder = builder.subject_name(x509.Name([
    x509.NameAttribute(NameOID.COMMON_NAME, 'Simple Test CA'),
]))
builder = builder.issuer_name(x509.Name([
    x509.NameAttribute(NameOID.COMMON_NAME, 'Simple Test CA'),
]))
builder = builder.not_valid_before(yesterday)
builder = builder.not_valid_after(tomorrow)
builder = builder.serial_number(x509.random_serial_number())
builder = builder.public_key(public_key)
builder = builder.add_extension(
    x509.BasicConstraints(ca=True, path_length=None),
    critical=True)
certificate = builder.sign(
    private_key=private_key, algorithm=hashes.SHA256(),
    backend=default_backend()
)
private_bytes = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.TraditionalOpenSSL,
    encryption_algorithm=serialization.NoEncrption())
public_bytes = certificate.public_bytes(
    encoding=serialization.Encoding.PEM)
with open("ca.pem", "wb") as fout:
    fout.write(private_bytes + public_bytes)
with open("ca.crt", "wb") as fout:
    fout.write(public_bytes)
```

通常，真正的 CA 会需要[证书签名请求](https://en.wikipedia.org/wiki/Certificate_signing_request)（CSR）来签名证书。但是，当你是自己的 CA 时，你可以制定自己的规则！可以径直签名你想要的内容。


继续集成测试的例子，你可以创建私钥并立即签名相应的公钥。注意 `COMMON_NAME` 需要是 `https` URL 中的“服务器名称”。如果你已配置名称查询，你需要服务器能响应对 `service.test.local` 的请求。



```
service_private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)
service_public_key = service_private_key.public_key()
builder = x509.CertificateBuilder()
builder = builder.subject_name(x509.Name([
   x509.NameAttribute(NameOID.COMMON_NAME, 'service.test.local')
]))
builder = builder.not_valid_before(yesterday)
builder = builder.not_valid_after(tomorrow)
builder = builder.public_key(public_key)
certificate = builder.sign(
    private_key=private_key, algorithm=hashes.SHA256(),
    backend=default_backend()
)
private_bytes = service_private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.TraditionalOpenSSL,
    encryption_algorithm=serialization.NoEncrption())
public_bytes = certificate.public_bytes(
    encoding=serialization.Encoding.PEM)
with open("service.pem", "wb") as fout:
    fout.write(private_bytes + public_bytes)
```

现在 `service.pem` 文件有一个私钥和一个“有效”的证书：它已由本地的 CA 签名。该文件的格式可以给 Nginx、HAProxy 或大多数其他 HTTPS 服务器使用。


通过将此逻辑用在测试脚本中，只要客户端配置信任该 CA，那么就可以轻松创建看起来真实的 HTTPS 服务器。




---


via: <https://opensource.com/article/19/4/certificate-authority>


作者：[Moshe Zadka](https://opensource.com/users/moshez/users/elenajon123) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出