传输层安全 (TLS) 模型,有时也称为较旧的名称 SSL,是基于证书颁发机构 (CA) 的概念。 这些机构受到浏览器和操作系统的信任,反过来签署服务器的证书以验证其所有权。
然而,对于内网、微服务架构或集成测试,有时拥有一个本地 CA 非常有用:一个仅在内部受信任,并反过来签署本地服务器证书的 CA。
这对于集成测试尤其有意义。 获取证书可能是一个负担,因为服务器将运行几分钟。 但是,在代码中设置“忽略证书”选项可能会使其在生产环境中被激活,从而导致安全灾难。
CA 证书与常规服务器证书没有太大区别; 重要的是它受到本地代码的信任。 例如,在 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 会期望收到证书签名请求 (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 服务器的格式。
通过将此逻辑应用于测试脚本,可以轻松创建看起来像真实的 HTTPS 服务器的服务器,只要客户端配置为信任正确的 CA 即可。
2 条评论