Sewer is a programmatic Lets Encrypt(ACME) client
Project description
Sewer
Codacy Badge CircleCI codecov Code style: black
Check the CHANGELOG for news about changes. See also what’s new in 0.8.2 for a description of the many changes in this release.
Features
Obtain or renew SSL/TLS certificates from Let’s Encrypt
Supports acme version 2 (current RFC).
Support for SAN certificates.
Supports wildcard certificates.
Bundling certificates.
Supports DNS and HTTP challenges.
sewer is both a command-line program and a Python library for customization
Well written(if I have to say so myself):
DNS services supported
Installation
pip3 install sewer
# with All DNS Provider support, include aliyun, Hurricane Electric, Aurora, ACME ...
# pip3 install sewer[alldns]
# with Cloudflare support
# pip3 install sewer[cloudflare]
# with Aliyun support
# pip3 install sewer[aliyun]
# with HE DNS(Hurricane Electric DNS) support
# pip3 install sewer[hurricane]
# with Aurora DNS Support
# pip3 install sewer[aurora]
# with ACME DNS Support
# pip3 install sewer[acmedns]
# with Rackspace DNS Support
# pip3 install sewer[rackspace]
# with DNSPod DNS Support
# pip3 install sewer[dnspod]
# with DuckDNS DNS Support
# pip3 install sewer[duckdns]
# with ClouDNS DNS Support
# pip3 install sewer[cloudns]
# with AWS Route 53 DNS Support
# pip3 install sewer[route53]
# with PowerDNS DNS Support
# pip3 install sewer[powerdns]
sewer(since version 0.5.0) is now python3 only. To install the (now unsupported) python2 version, run;
pip install sewer==0.3.0
Sewer is in active development and it’s API [STRIKEOUT:may] will change in backward incompatible ways. https://pypi.python.org/pypi/sewer
Usage
import sewer
dns_class = sewer.CloudFlareDns(CLOUDFLARE_EMAIL='example@example.com',
CLOUDFLARE_API_KEY='nsa-grade-api-key')
# 1. to create a new certificate:
client = sewer.Client(domain_name='example.com',
dns_class=dns_class)
certificate = client.cert()
certificate_key = client.certificate_key
account_key = client.account_key
print("your certificate is:", certificate)
print("your certificate's key is:", certificate_key)
print("your letsencrypt.org account key is:", account_key)
# NB: your certificate_key and account_key should be SECRET.
# keep them very safe.
# you can write these out to individual files, eg::
with open('certificate.crt', 'w') as certificate_file:
certificate_file.write(certificate)
with open('certificate.key', 'w') as certificate_key_file:
certificate_key_file.write(certificate_key)
with open('account_key.key', 'w') as account_key_file:
account_key_file.write(account_key)
# 2. to renew a certificate:
import sewer
dns_class = sewer.CloudFlareDns(CLOUDFLARE_EMAIL='example@example.com',
CLOUDFLARE_API_KEY='nsa-grade-api-key')
with open('account_key.key', 'r') as account_key_file:
account_key = account_key_file.read()
client = sewer.Client(domain_name='example.com',
dns_class=dns_class,
account_key=account_key)
certificate = client.renew()
certificate_key = client.certificate_key
with open('certificate.crt', 'w') as certificate_file:
certificate_file.write(certificate)
with open('certificate.key', 'w') as certificate_key_file:
certificate_key_file.write(certificate_key)
# 3. You can also request/renew wildcard certificates:
import sewer
dns_class = sewer.CloudFlareDns(CLOUDFLARE_EMAIL='example@example.com',
CLOUDFLARE_API_KEY='nsa-grade-api-key')
client = sewer.Client(domain_name='*.example.com',
dns_class=dns_class)
certificate = client.cert()
certificate_key = client.certificate_key
account_key = client.account_key
CLI
To get certificate, run:
CLOUDFLARE_EMAIL=example@example.com \
CLOUDFLARE_API_KEY=api-key \
sewer \
--dns cloudflare \
--domain example.com \
--action run
To renew a certificate, run:
CLOUDFLARE_EMAIL=example@example.com \
CLOUDFLARE_API_KEY=api-key \
sewer \
--account_key /path/to/your/account.key \
--dns cloudflare \
--domain example.com \
--action renew
To see help:
sewer --help
usage: sewer [-h] [--version] [--account_key ACCOUNT_KEY]
[--certificate_key CERTIFICATE_KEY] --dns
{cloudflare,aurora,acmedns,aliyun,hurricane} --domain DOMAIN
[--alt_domains [ALT_DOMAINS [ALT_DOMAINS ...]]]
[--bundle_name BUNDLE_NAME] [--endpoint {production,staging}]
[--email EMAIL] --action {run,renew} [--out_dir OUT_DIR]
[--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}]
Sewer is a Let's Encrypt(ACME) client.
optional arguments:
-h, --help show this help message and exit
--version The currently installed sewer version.
--account_key ACCOUNT_KEY
The path to your letsencrypt/acme account key. eg:
--account_key /home/myaccount.key
--certificate_key CERTIFICATE_KEY
The path to your certificate key. eg:
--certificate_key /home/mycertificate.key
--dns {cloudflare,aurora,acmedns,aliyun,hurricane}
The name of the dns provider that you want to use.
--domain DOMAIN The domain/subdomain name for which you want to
get/renew certificate for. wildcards are also
supported eg: --domain example.com
--alt_domains [ALT_DOMAINS [ALT_DOMAINS ...]]
A list of alternative domain/subdomain name/s(if any)
for which you want to get/renew certificate for. eg:
--alt_domains www.example.com blog.example.com
--bundle_name BUNDLE_NAME
The name to use for certificate certificate key and
account key. Default is name of domain.
--endpoint {production,staging}
Whether to use letsencrypt/acme production/live
endpoints or staging endpoints. production endpoints
are used by default. eg: --endpoint staging
--email EMAIL Email to be used for registration and recovery. eg:
--email me@example.com
--action {run,renew} The action that you want to perform. Either run (get a
new certificate) or renew (renew a certificate). eg:
--action run
--out_dir OUT_DIR The dir where the certificate and keys file will be
stored. default: The directory you run sewer command.
eg: --out_dir /data/ssl/
--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}
The log level to output log messages at. eg:
--loglevel DEBUG
The cerrtificate, certificate key and account key will be saved in the directory that you run sewer from.
The commandline interface(app) is called sewer or alternatively you could use, sewer-cli.
Bring your own DNS provider
import sewer
import boto3
class AWSroute53Dns(sewer.BaseDns):
def __init__(self,
HostedZoneId,
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY):
self.dns_provider_name = 'AWS_route53'
self.HostedZoneId = HostedZoneId
self.boto_client = boto3.client(
'route53', aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
super(AWSroute53Dns, self).__init__()
def create_dns_record(self,
domain_name,
domain_dns_value):
"""
AWS route53 with boto3 documentation;
https://boto3.readthedocs.io/en/latest/reference/services/route53.html#Route53.Client.change_resource_record_sets
"""
# do whatever is necessary for your particular DNS provider to create a TXT DNS record
# eg for AWS route53, it will be something like::
self.boto_client.change_resource_record_sets(
HostedZoneId=self.HostedZoneId,
ChangeBatch={
'Changes': [
{
'Action': 'CREATE',
'ResourceRecordSet': {
'Name': '_acme-challenge' + '.' + domain_name + '.',
'Type': 'TXT',
'TTL': 123,
'ResourceRecords': [
{
'Value': "{0}".format(domain_dns_value)},
]}},
]})
def delete_dns_record(self,
domain_name,
domain_dns_value):
# do whatever is necessary for your particular DNS provider to delete a TXT DNS record
# eg for AWS route53, it will be something like::
self.boto_client.change_resource_record_sets(
HostedZoneId=self.HostedZoneId,
ChangeBatch={
'Changes': [
{
'Action': 'DELETE',
'ResourceRecordSet': {
'Name': '_acme-challenge' + '.' + domain_name + '.',
'Type': 'TXT',
'TTL': 123,
'ResourceRecords': [
{
'Value': "{0}".format(domain_dns_value)},
]}},
]})
custom_route53_dns_class = AWSroute53Dns(
HostedZoneId='my-zone', AWS_ACCESS_KEY_ID='access-key',
AWS_SECRET_ACCESS_KEY='secret-access-key')
# create a new certificate:
client = sewer.Client(domain_name='example.com',
dns_class=custom_route53_dns_class)
certificate = client.cert()
certificate_key = client.certificate_key
account_key = client.account_key
print("certificate::", certificate)
print("certificate's key::", certificate_key)
Bring your own HTTP provider
import os
import sewer
class CertbotishProvider(sewer.BaseHttp):
def __init__(self, nginx_root="/path/to/www/html/"):
super(CertbotishProvider, self).__init__("http-01")
self.nginx_root = nginx_root
def create_challenge_file(self, domain_name, token, acme_keyauthorization):
with open(f"{self.nginx_root}/{domain_name}/.well-known/{token}", "w") as fp:
fp.write(acme_keyauthorization)
def delete_challenge_file(self, domain_name, token):
os.unlink(f"{self.nginx_root}/{domain_name}/.well-known/{token}")
Development setup
see the how to contribute documentation
TODO
support more DNS providers
FAQ
Why another ACME client? I wanted an ACME client that I could use to programmatically(as a library) acquire/get certificates. However I could not find anything satisfactory for use in Python code.
Why is it called Sewer? I really like the Kenyan hip hop artiste going by the name of Kitu Sewer.
Here’s the ouput of running sewer using the cli app:
CLOUDFLARE_EMAIL=example@example.com \
CLOUDFLARE_API_KEY=nsa-grade-api-key \
sewer \
--endpoint staging \
--dns cloudflare \
--domain subdomain.example.com \
--action run
2018-03-06 18:08.41 chosen_dns_provider message=Using cloudflare as dns provider.
2018-03-06 18:08.46 acme_register acme_server=https://acme-staging... domain_names=['subdomain.example.com'] sewer_version=0.5.0b
2018-03-06 18:08.52 acme_register_response acme_server=https://acme-staging... domain_names=['subdomain.example.com']
2018-03-06 18:08.52 apply_for_cert_issuance acme_server=https://acme-staging... domain_names=['subdomain.example.com'] sewer_version=0.5.0b
2018-03-06 18:09.01 apply_for_cert_issuance_response acme_server=https://acme-staging... domain_names=['subdomain.example.com']
2018-03-06 18:09.08 create_dns_record dns_provider_name=CloudFlareDns
2018-03-06 18:09.16 create_cloudflare_dns_record_response dns_provider_name=CloudFlareDns status_code=200
2018-03-06 18:09.36 send_csr acme_server=https://acme-staging... domain_names=['subdomain.example.com'] sewer_version=0.5.0b
2018-03-06 18:09.45 send_csr_response acme_server=https://acme-staging... domain_names=['subdomain.example.com']
2018-03-06 18:09.45 download_certificate acme_server=https://acme-staging... domain_names=['subdomain.example.com'] sewer_version=0.5.0b
2018-03-06 18:09.50 download_certificate_response acme_server=https://acme-staging... domain_names=['subdomain.example.com']
2018-03-06 18:09.54 the_end message=Certificate Succesfully issued. The certificate, certificate key and account key have been saved in the current directory
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file sewer-0.8.2.tar.gz
.
File metadata
- Download URL: sewer-0.8.2.tar.gz
- Upload date:
- Size: 38.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.6.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1618103de07aff54665c5e557c8340ab98db6a7bf5d6f777a47beaa754fcd34a |
|
MD5 | 4a274d1a47d77d225881a8f063dad28e |
|
BLAKE2b-256 | 15cda6b5daf3f002e34549127b6f3fb302a27ac1e6f4f8083d4988baf6952f8e |
File details
Details for the file sewer-0.8.2-py3-none-any.whl
.
File metadata
- Download URL: sewer-0.8.2-py3-none-any.whl
- Upload date:
- Size: 42.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.6.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ed804dde380719d6c2cd1b44aedce14a4ce2a44049ae49a1ef9092f4717c1089 |
|
MD5 | 377588f4d9f659dd681eb1d31d82b020 |
|
BLAKE2b-256 | cce9dbf272fe9004f87704de69f037dd713c30a7942b8556b13f227351c9485b |