Created
August 27, 2018 06:30
-
-
Save odg0318/2523356f3ff4e06fe59ec867732921ef to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import datetime | |
| import ipaddress | |
| from cryptography import x509 | |
| from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID | |
| from cryptography.hazmat.primitives import hashes | |
| from cryptography.hazmat.backends import default_backend | |
| from cryptography.hazmat.primitives import serialization | |
| from cryptography.hazmat.primitives.asymmetric import rsa | |
| class Base(object): | |
| def _generate_key(self, bits): | |
| return rsa.generate_private_key( | |
| public_exponent=65537, | |
| key_size=bits, | |
| backend=default_backend() | |
| ) | |
| def dump_key(self): | |
| return self.key.private_bytes( | |
| encoding=serialization.Encoding.PEM, | |
| format=serialization.PrivateFormat.TraditionalOpenSSL, | |
| encryption_algorithm=serialization.NoEncryption(), | |
| ) | |
| def dump_cert(self): | |
| return self.cert.public_bytes(serialization.Encoding.PEM) | |
| class CA(Base): | |
| def __init__(self, bits=2048): | |
| self.key = self._generate_key(bits) | |
| self.cert = self._generate_cert(self.key) | |
| def _generate_cert(self, key): | |
| name = x509.Name([ | |
| x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'MyCompany'), | |
| ]) | |
| builder = x509.CertificateBuilder() | |
| builder = builder.subject_name(name) | |
| builder = builder.issuer_name(name) | |
| builder = builder.not_valid_before(datetime.datetime.utcnow()) | |
| builder = builder.not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=3650)) | |
| builder = builder.serial_number(x509.random_serial_number()) | |
| builder = builder.public_key(key.public_key()) | |
| builder = builder.add_extension( | |
| x509.BasicConstraints(ca=True, path_length=None), critical=False, | |
| ) | |
| builder = builder.add_extension( | |
| x509.SubjectKeyIdentifier.from_public_key(key.public_key()), | |
| critical=False | |
| ) | |
| builder = builder.add_extension( | |
| x509.AuthorityKeyIdentifier.from_issuer_public_key( | |
| key.public_key() | |
| ), critical=False | |
| ) | |
| return builder.sign( | |
| private_key=key, algorithm=hashes.SHA256(), | |
| backend=default_backend() | |
| ) | |
| class LeafCertificate(Base): | |
| def __init__(self, ca, cn=None, ip=None, bits=2048): | |
| self.key = self._generate_key(bits) | |
| self.cert = self._generate_cert(self.key, ca, cn, ip) | |
| def _generate_cert(self, key, ca, cn, ip): | |
| name = x509.Name([ | |
| x509.NameAttribute(NameOID.COMMON_NAME, cn), | |
| ]) | |
| builder = x509.CertificateBuilder() | |
| builder = builder.subject_name(name) | |
| builder = builder.issuer_name(ca.cert.subject) | |
| builder = builder.not_valid_before(datetime.datetime.utcnow()) | |
| builder = builder.not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=3650)) | |
| builder = builder.serial_number(x509.random_serial_number()) | |
| builder = builder.public_key(key.public_key()) | |
| key_usage = ExtendedKeyUsageOID.CLIENT_AUTH if ip is None else ExtendedKeyUsageOID.SERVER_AUTH | |
| builder = builder.add_extension( | |
| x509.ExtendedKeyUsage( | |
| [key_usage] | |
| ), | |
| critical=False, | |
| ) | |
| if ip is not None: | |
| builder = builder.add_extension( | |
| x509.SubjectAlternativeName(x509.SubjectAlternativeName( | |
| [ | |
| x509.DNSName(ip), | |
| x509.IPAddress(ipaddress.IPv4Address(ip)), | |
| x509.IPAddress(ipaddress.IPv4Address('127.0.0.1')), | |
| ] | |
| )), | |
| critical=False | |
| ) | |
| # Ok, sign the cert. | |
| return builder.sign( | |
| private_key=ca.key, algorithm=hashes.SHA256(), | |
| backend=default_backend() | |
| ) | |
| class ServerCertificate(LeafCertificate): | |
| def __init__(self, ca, ip): | |
| super(ServerCertificate, self).__init__(ca, cn=ip, ip=ip) | |
| class ClientCertificate(LeafCertificate): | |
| def __init__(self, ca, cn): | |
| super(ClientCertificate, self).__init__(ca, cn=cn) | |
| def generate_ca(bits=2048): | |
| return CA(bits) | |
| def generate_server_certificate(ca, ip): | |
| return ServerCertificate(ca, ip) | |
| def generate_client_certificate(ca, cn='portainer'): | |
| return ClientCertificate(ca, cn) | |
| def usage(): | |
| ca = generate_ca() | |
| server = generate_server_certificate(ca, '172.16.1.5') | |
| client = generate_client_certificate(ca, 'odg0318') | |
| with open('ca.key', 'wb') as f: | |
| f.write(ca.dump_key()) | |
| with open('ca.crt', 'wb') as f: | |
| f.write(ca.dump_cert()) | |
| with open('server.key', 'wb') as f: | |
| f.write(server.dump_key()) | |
| with open('server.crt', 'wb') as f: | |
| f.write(server.dump_cert()) | |
| with open('client.key', 'wb') as f: | |
| f.write(client.dump_key()) | |
| with open('client.crt', 'wb') as f: | |
| f.write(client.dump_cert()) | |
| if __name__ == '__main__': | |
| usage() |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This python code shows how to generate certificates for protecting docker daemon socket over TLS.