歡迎光臨
每天分享高質量文章

自己成為一個證書頒發機構(CA) | Linux 中國

為你的微服務架構或者整合測試建立一個簡單的內部 CA。

— Moshe Zadka

 

傳輸層安全(TLS)模型(有時也稱它的舊名稱 SSL)基於證書頒發機構certificate authoritie(CA)的概念。這些機構受到瀏覽器和作業系統的信任,從而簽名伺服器的的證書以用於驗證其所有權。

但是,對於內部網路,微服務架構或整合測試,有時候本地 CA更有用:一個只在內部受信任的 CA,然後簽名本地伺服器的證書。

這對整合測試特別有意義。獲取證書可能會帶來負擔,因為這會佔用伺服器幾分鐘。但是在程式碼中使用“忽略證書”可能會被引入到生產環境,從而導致安全災難。

CA 證書與常規伺服器證書沒有太大區別。重要的是它被原生代碼信任。例如,在 Python requests 庫中,可以透過將 REQUESTS_CA_BUNDLE 變數設定為包含此證書的目錄來完成。

在為整合測試建立證書的例子中,不需要長期的證書:如果你的整合測試需要超過一天,那麼你應該已經測試失敗了。

因此,計算昨天明天作為有效期間隔:

  1. >>> import datetime
  2. >>> one_day = datetime.timedelta(days=1)
  3. >>> today = datetime.date.today()
  4. >>> yesterday = today - one_day
  5. >>> tomorrow = today - one_day

現在你已準備好建立一個簡單的 CA 證書。你需要生成私鑰,建立公鑰,設定 CA 的“引數”,然後自簽名證書:CA 證書總是自簽名的。最後,匯出證書檔案以及私鑰檔案。

  1. from cryptography.hazmat.primitives.asymmetric import rsa
  2. from cryptography.hazmat.primitives import hashes, serialization
  3. from cryptography import x509
  4. from cryptography.x509.oid import NameOID
  5. private_key = rsa.generate_private_key(
  6. public_exponent=65537,
  7. key_size=2048,
  8. backend=default_backend()
  9. )
  10. public_key = private_key.public_key()
  11. builder = x509.CertificateBuilder()
  12. builder = builder.subject_name(x509.Name([
  13. x509.NameAttribute(NameOID.COMMON_NAME, 'Simple Test CA'),
  14. ]))
  15. builder = builder.issuer_name(x509.Name([
  16. x509.NameAttribute(NameOID.COMMON_NAME, 'Simple Test CA'),
  17. ]))
  18. builder = builder.not_valid_before(yesterday)
  19. builder = builder.not_valid_after(tomorrow)
  20. builder = builder.serial_number(x509.random_serial_number())
  21. builder = builder.public_key(public_key)
  22. builder = builder.add_extension(
  23. x509.BasicConstraints(ca=True, path_length=None),
  24. critical=True)
  25. certificate = builder.sign(
  26. private_key=private_key, algorithm=hashes.SHA256(),
  27. backend=default_backend()
  28. )
  29. private_bytes = private_key.private_bytes(
  30. encoding=serialization.Encoding.PEM,
  31. format=serialization.PrivateFormat.TraditionalOpenSSL,
  32. encryption_algorithm=serialization.NoEncrption())
  33. public_bytes = certificate.public_bytes(
  34. encoding=serialization.Encoding.PEM)
  35. with open("ca.pem", "wb") as fout:
  36. fout.write(private_bytes + public_bytes)
  37. with open("ca.crt", "wb") as fout:
  38. fout.write(public_bytes)

通常,真正的 CA 會需要證書簽名請求(CSR)來簽名證書。但是,當你是自己的 CA 時,你可以制定自己的規則!可以徑直簽名你想要的內容。

繼續整合測試的例子,你可以建立私鑰並立即簽名相應的公鑰。註意 COMMON_NAME 需要是 https URL 中的“伺服器名稱”。如果你已配置名稱查詢,你需要伺服器能響應對 service.test.local 的請求。

  1. service_private_key = rsa.generate_private_key(
  2. public_exponent=65537,
  3. key_size=2048,
  4. backend=default_backend()
  5. )
  6. service_public_key = service_private_key.public_key()
  7. builder = x509.CertificateBuilder()
  8. builder = builder.subject_name(x509.Name([
  9. x509.NameAttribute(NameOID.COMMON_NAME, 'service.test.local')
  10. ]))
  11. builder = builder.not_valid_before(yesterday)
  12. builder = builder.not_valid_after(tomorrow)
  13. builder = builder.public_key(public_key)
  14. certificate = builder.sign(
  15. private_key=private_key, algorithm=hashes.SHA256(),
  16. backend=default_backend()
  17. )
  18. private_bytes = service_private_key.private_bytes(
  19. encoding=serialization.Encoding.PEM,
  20. format=serialization.PrivateFormat.TraditionalOpenSSL,
  21. encryption_algorithm=serialization.NoEncrption())
  22. public_bytes = certificate.public_bytes(
  23. encoding=serialization.Encoding.PEM)
  24. with open("service.pem", "wb") as fout:
  25. fout.write(private_bytes + public_bytes)

現在 service.pem 檔案有一個私鑰和一個“有效”的證書:它已由本地的 CA 簽名。該檔案的格式可以給 Nginx、HAProxy 或大多數其他 HTTPS 伺服器使用。

透過將此邏輯用在測試指令碼中,只要客戶端配置信任該 CA,那麼就可以輕鬆建立看起來真實的 HTTPS 伺服器。

已同步到看一看
贊(0)

分享創造快樂