{ "info": { "author": "Malte Swart", "author_email": "mswart@devtation.de", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: System Administrators", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3 :: Only", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Security :: Cryptography", "Topic :: System :: Networking", "Topic :: System :: Systems Administration", "Topic :: Utilities" ], "description": "ACME Management Server (ACMEMS)\n===============================\n\n[![Build Status](https://img.shields.io/travis/mswart/acme-mgmtserver/master.svg)](https://travis-ci.org/mswart/acme-mgmtserver) [![Build Status](https://img.shields.io/pypi/v/acme-mgmtserver.svg)](https://pypi.python.org/pypi/acme-mgmtserver) [![Python Versions](https://img.shields.io/pypi/pyversions/acme-mgmtserver.svg)](https://pypi.python.org/pypi/acme-mgmtserver) [![PyPi Status](https://img.shields.io/pypi/status/acme-mgmtserver.svg)](https://pypi.python.org/pypi/acme-mgmtserver)\n\n\n[LetsEncrypt](https://letsencrypt.org) supports issuing free certificates by communication via ACME - the Automatically Certificate Management Evaluation protocol.\n\nThis tools is yet another ACME client ... but as a client/server model.\n\n\n## Why yet another ACME client\n\nSome aspects are special:\n\n* **ACME handling can be put into own VM / container ...**: The server can be placed into an own VM, container, network segment to limit the security risk on compromised systems.\n* **Only the server requires all the ACME dependencies**: The clients require only a SSL tool like OpenSSL and a HTTP client like wget or curl, no python, no build tools. Python with python-acme and its dependencies (PyOpenSSL, Cryptography, ...) is only needed for the server.\n* **Supports distributed web servers**: All `.well-known/acme-challenges` requests for all domains can be served directly by the server. This makes it easy to validate domains when using multiple web server in distributed or fail-over fashion by forwarding all `.well-known/acme-challenges` requests.\n* **Only the server needs the ACME account information**: It is not that security relevant, but only the ACME Management Server needs access to the account information / key for the ACME server like LetsEncrypt.\n* **Caching CSR signs**: The returned signed certificate of a CSR is cached until the certificate is nearly expired (per default two week). If two machines have manual shared a key and CSR and they reusing both, they will both get from ACMEMS the same certificate back.\n\n\n## Domain Validations / Challenges.\n\n### HTTP01\n\nThe normal webserver must be adjusted to forward `.well-known/acme-challenges` requests to the ACME Management Server - this is a prerequirement and will not be checked/enforced/configured by this tool.\n\n#### Nginx\n\n```\nupstream acme-mgmtserver {\n server ...;\n}\nserver {\n # ...\n location /.well-known/acme-challenge {\n proxy_set_header Host $http_host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_pass http://acme-mgmtserver;\n # to support multiple acme mgmt server check challenge on all upstream server:\n proxy_next_upstream error timeout http_404;\n }\n # ...\n}\n```\n\nThis passes all ACME challenges to the management server. `proxy_next_upstream http_404;` can be used to support multiple ACME management servers and search for the response on all servers.\n\n#### Apache\n\nUp to you - I am happy to accept a PR to complete this.\n\n### TLSNI01\n\n`TLSNI01` is currently not supported, but there are few things are missing. Feel free to open a PR or talk to me if you have use for this challenge type.\n\n### DNS01\n\nACMEMS can instrument DNS servers to serve the needed `TXT` records to validate domain names via `DNS01` challenge. The DNS servers will be updated vis DNS update. Currently there is no security for the updates implemented. We expect that the zone name managed by the name server are second-level domain name (like `example.org`).\n\n\n## Installation\n\n### Debian Packages\n\nMy preferred installation method are distribution packages. I try to published a packaged version in my own [PPA](https://launchpad.net/~malte.swart/+archive/ubuntu/acme). To goal is to support the current LTS version and the previous version for a upgrade period. The software dependencies should be directly available as distribution packages.\n\n### PyPI\n\nThe server and all its dependencies are available on PyPi and can be installed by Python package manager like pip e.g. inside a virtualenv.\n\n\n## Configuration\n\nThe configuration is a basic INI file, with multiple key support. The main parts are the blocks to define the account directory, listen information for the http interfaces and the configuration which client is allowed to request certificates for which domains.\n\n```bash\n[account]\n# the ACME server to talk to; I recommend to first test\n# against the staging system\nacme-server = https://acme-staging.api.letsencrypt.org/directory\n# account dir; contains\n# account.pem - private key to identify against the ACME server\n# registration.json - the registration resource as JSON dump\ndir = /etc/acmems/account/\n\n[mgmt]\n# Management interface itself, the clients needs to talk to this\nmgmt=192.0.2.13:1313\n# maximal size for CSR (in bytes)\nmax-size = 4k\n# define which verification block is used by default\ndefault-verification = http\n# should signed certificates be cached? if yes, how?\ndefault-storage = file\n\n# Define verification blocks\n[verification \"http\"]\n# the challenge type has to be defined first!\ntype = http01\n# listen for HTTP challenge check requests (e.g. from Nginx)\nlistener=192.0.2.80:1380\nlistener=198.51.100.80:1380\nlistener=[fe80::80%eth0]:1380\n\n[verification \"dns\"]\n# the challenge type has to be defined first!\ntype = dns01-dnsUpdate\n# which name server needs to be updated now\ndns-server=192.0.2.53\n# time-to-live for the new entries\nttl=5\n# timeout for dns update requests\ntimeout=30\n\n# Storages\n[storage \"none\"]\n# this stores nothing and it is the default storage\ntype = none\n\n[storage \"file\"]\n# caching on disk, the directory must be writeable for the daemon\ntype = file\ndirectory=/etc/acmems/storage\n# cached certificates will be treated outdated if their expire date is less \n# than $renew-within$ days away. A new certificate will be issued for the \n# passed CSR, stored and returned in subsequencial requests\n# defaults to 14 days - around 30 days is recommended by letsencrypt\nrenew-within=14\n\n# Define multiple authentification blocks\n# a CSR must fulfil all listed authentication methods and must\n# only contains listed domains (checks against globs)\n[auth \"mail\"]\n# TCP connection must come from one of this IPs\nip=192.0.2.0/24\nip=198.51.100.21\ndomain=mail.example.org\ndomain=mail.example.com\n\n# an additional auth block\n[auth \"ext\"]\nip=198.51.100.128/28\ndomain=*.test.example.org\n\n# CSR must also be signed by HMAC (via a the secret key)\n[auth \"mail-secure\"]\n# use special verification and storage\nverification = dns\nstorage = file\nip=198.51.100.21\nhmac_type=sha256\nhmac_key=A1YP67armNf3cBrecyJHdb035\ndomain=mail?.example.org\ndomain=mail.example.com\n```\n\n\n## Registration\n\nThe executable `acme-register` supports to register at the ACME server. This will not be done automatically, you have to call it manually before the first use of the server itself.\n\nPlease have a look at the help output for further instructions `acme-register --help`.\n\nA registration could look like this:\n\n```bash\n> bin/acme-register --gen-key --register --email test@example.org configs/integration.ini\nGenerate private key ... done\nInitialize ACME client ... done\nRegister ... done\nYou need to accept the terms of service at http://127.0.0.1:4001/terms/v1\n> bin/acme-register --accept-terms-of-service=http://127.0.0.1:4001/terms/v1 configs/integration.ini\nLoad private key ... done\nInitialize ACME client ... done\nRefreshing current registration ... done\nYou need to accept the terms of service at http://127.0.0.1:4001/terms/v1\nAccepting ToS at http://127.0.0.1:4001/terms/v1 ... done\n```\n\n\n## Example Client Usage\n\n```\n# generate domain private key (once!)\nopenssl genrsa 4096 > domain.key\n\n# generate csr to create/renew your certificate\n# please generate a new csr for to renew your certificate\nopenssl req -new -sha256 -key domain.key -subj \"/CN=example.org\" > domain-201512.csr\n# or\nopenssl req -new -sha256 -key domain.key -subj \"/CN=example.org\" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf \"[SAN]\\nsubjectAltName=DNS:example.org,DNS:www.example.org\")) > domain-201512.csr\n\n# upload sign csr with shared key\nwget --post-file=domain-201512.csr --header=\"`openssl dgst -sha256 -hmac '$KEY' domain-201512.csr | sed -e 's/HMAC-\\(.*\\)(.*)= *\\(.*\\)/Authentication: hmac name=\\L\\1\\E, hash=\\2/'`\" http://acmese:1313/sign > domain-201512.pem\n# upload csr with out sign\nwget --post-file=domain-201512.csr http://acmese:1313/sign > domain-201512.pem\n```\n\n\n## HTTP interface\n\n### Client request\n\nOnly POST requests to `/sign` are supported.\n\nThe body must be a CSR as PEM format; `Content-Length` header is required, `Content-Type` is currently not evaluated.\n\nTo authentication the CSR via HMAC, add a header like:\n\n```\nAuthentication: hmac name=sha256 hash=47d5066525a214c759300d884bdd19d8f461a0ad24a2a0b7b705caee6c912228\n```\n\nA complete request could look like:\n\n```\nPOST /sign HTTP/1.1\nHost: 127.0.0.1:4005\nContent-Length: 1586\nAuthentication: hmac name=sha256, hash=47d5066525a214c759300d884bdd19d8f461a0ad24a2a0b7b705caee6c912228\n\n-----BEGIN CERTIFICATE REQUEST-----\nMIIEWjCCAkICAQAwFTETMBEGA1UEAwwKZ28uZHh0dC5kZTCCAiIwDQYJKoZIhvcN\nAQEBBQADggIPADCCAgoCggIBAOWXle7/dEo7l/h9O14w2ndsoKmzpHXcfosSyZnK\nqrMoJLSKQImm0Y0ACRggs+c4oTbGeyUgm44RmmPjBoFxdL41CHTp5YHOytaYQHUz\nA1wCitOzEMuPgRqvLUc4SqgjC7fOk1EP0bUX1YIrGNz40sYy5AsVINp4ZzKFfMoR\nKtGrx4j1OrkMOfQNV6f/P8wUyOzoSSN5/XUoxcQ44aeJcfeVY6jHqZtL4BDV3EDq\noFnkHHKNGndYA6e0ov/WxHtXqxKrmsp7IN99sCvtwcoi8Kuf2OWE8/MuebsDRUCI\nfhCXCsGU+2+99qan70fL7o+VmZTwBGr3GHtjJ5+QthJ92oH6uXsS+AamyhyLpp1V\n3CRi1BO2G746QCIDpMmnXHe4uV49igZsOX75kl8i4dpXkzMe4lvgj4jL2nftFYGy\nlv0LOwiiIUovRoTeVJlmD2RIgWz85MdxgHKFHpgBmgbmSoOlM1Uad4yY7WbsvtpT\naoSjbuG6NGa77YJBZ8eAF0FEfhvYpEAN1+3pRtHWiGsHEZ0tbQU8bpy+hOXYCMkv\niwpjyd+kTMBH9oCSeM3pQ8S74grpDV0L/wlfRoii2bImJDNurcRY22RJmPSQSSia\n3KDHGZDzKW+uJs07FTa5y9RbavnCNQDrK6oyMMDZW876cQWHrj76U/f/8yuoeIuJ\nNdZtAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAOK5sq1dtr8SxSxbhaib+b/hz\nF8F0xYpMBLrLpFfoAtoLWXp0a9AM3vqaHN+iPVTkwGri9c2Hi+E3VFltH39i+Ml1\nU6I2KtiN1YB5/ARpQXCMT/29c31lPpvR3FfdKjOa078inacY+3bB7qwu3mC5qjrz\nZzkJxMf5c7iQTWhp18ISD0zw2jN9I0OeyFZVfrQleGtlhVBSYemEyuurPu2vlwlq\nXm0WpJ1wZlxNDolGTJ525HjIJEPJhGMnIwGSDKvN8INurfDzcPy1dUlRzxmoeRIs\n23xu5D0DTfIPaMFT1yZaCF45nZLCcbNyUbbLK21+TABNwwAlm2UDz1RGsUK8h94x\nKeHJunfvtmQ7DB/Y7IfYkGJYt20RovuUniv/ruZtc8xPxcs3Sv8H93ISrKJ1ElmO\nHvj45TYRjKC1Hl4YB30Yi/MQJJgN32Td48miTgyK5Sloc+v60CGWWsxfXC4zrUd9\nCxzpbR5AeEOlsrjWBUJx3V1Ri5die1J+j0cutSC42BnFXkL3/W5JGpaiIpqlK1Ha\njTC+FnojbcxDDW+SJpI3HI/Bzv3qAbMJS2WcyVGiN//sX5iuOW5r6fJECFQhCDzE\n3f0YiD2Wh6N4xcf41bOVE7gA+TjmlShzSwZQPsEwUO4brRiBErnCbwpgK/T9vCV8\nA3IlV6YS/4SoAHraTLA=\n-----END CERTIFICATE REQUEST-----\n```\n\n\n### Server response\n\nError code:\n\n* **200**: CSR was signed. Response body contains the certificate and the intermediate certificate in PEM form.\n* **403**: Signing is denied, have a look at your auth blocks / authentication methods; are you missing an `Authentication` header?\n* **413**: CSR request is too long. You might increase the `max-size` setting.\n* **415**: CSR could not be parsed.\n* **421**: Challenge validation failed (temporarily)\n* **429**: Rated limited (currently only based on ACME upstream errors)\n* **500**: Internal exception - take a look at the log and report the bug.\n\n\n## Testing\n\nThe server is tested by unit tests, integration tests against test ACME servers ([Boulder](https://github.com/letsencrypt/boulder) and [Pebble](https://github.com/letsencrypt/boulder)) and with end-to-end tests. All major features should be covered like authentication, HTTP requests, validation methods (HTTP01, DNS01), different CSR and certificate algorithms (RSA and EC).\n\nThe test are exectued by `py.test`. `docker-compose` is used to run the ACME servers. Take a look at `tests/scripts` to inspect the commands, that are run on TravisCI.\n\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (git checkout -b my-new-feature)\n3. Add tests for your feature.\n4. Add your feature.\n5. Commit your changes (git commit -am 'Add some feature')\n6. Push to the branch (git push origin my-new-feature)\n7. Create new Pull Request\n\n\n## License\n\nGPL License\n\nCopyright (c) 2015-2019, Malte Swart", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/mswart/acme-mgmtserver", "keywords": "acme server client proxy letsencrypt", "license": "GPL", "maintainer": "", "maintainer_email": "", "name": "acme-mgmtserver", "package_url": "https://pypi.org/project/acme-mgmtserver/", "platform": "", "project_url": "https://pypi.org/project/acme-mgmtserver/", "project_urls": { "Homepage": "https://github.com/mswart/acme-mgmtserver" }, "release_url": "https://pypi.org/project/acme-mgmtserver/0.4.1/", "requires_dist": null, "requires_python": "", "summary": "Basic Python Server to execute ACME instead of dump clients", "version": "0.4.1" }, "last_serial": 5986667, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "6f14d80f043e9dce7ba98b6b94180bf6", "sha256": "890c96d62f6f387cd25b69b6e70cb099ec96ab498eaa61ccf75399abbc8c68fb" }, "downloads": -1, "filename": "acme-mgmtserver-0.1.0.tar.gz", "has_sig": false, "md5_digest": "6f14d80f043e9dce7ba98b6b94180bf6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21387, "upload_time": "2015-12-16T13:33:54", "url": "https://files.pythonhosted.org/packages/c6/f3/32ed8895efde7b42c8dd17e90c09082ba5ae86b16ae38bd5a6f0623b7a62/acme-mgmtserver-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "eacd3d1f6d21165f37f2f9c2203b9f34", "sha256": "61471c9ed0d1a4212626dccd10c324eb4b06826ae4dcb07eb828461b719076fb" }, "downloads": -1, "filename": "acme-mgmtserver-0.1.1.tar.gz", "has_sig": false, "md5_digest": "eacd3d1f6d21165f37f2f9c2203b9f34", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16540, "upload_time": "2015-12-17T00:30:24", "url": "https://files.pythonhosted.org/packages/da/57/c4d810b19945b9ac86e9bb7e9bf3cc95b3109eeee848efc80b3800bd4110/acme-mgmtserver-0.1.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "2a9a04ec67d246848cc0050a97885156", "sha256": "939a36ca7e997e47eee0ba2bd85b7404b6c450488e3b51dfe5dc21e4570856e0" }, "downloads": -1, "filename": "acme-mgmtserver-0.2.0.tar.gz", "has_sig": false, "md5_digest": "2a9a04ec67d246848cc0050a97885156", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19988, "upload_time": "2016-03-16T02:41:19", "url": "https://files.pythonhosted.org/packages/27/b4/a03d5bdd3713c2cd96bfb809dcd822df21d29260e7ce52e5c62c5b89205f/acme-mgmtserver-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "4784fe4951e5cd2429ec57b0182f453d", "sha256": "96a72e980f953cd420ade5cb21f675d4c59ec219ee99ce2d7b6ac8b2df78c65a" }, "downloads": -1, "filename": "acme-mgmtserver-0.3.0.tar.gz", "has_sig": false, "md5_digest": "4784fe4951e5cd2429ec57b0182f453d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20777, "upload_time": "2016-12-01T12:09:59", "url": "https://files.pythonhosted.org/packages/fa/42/4ed81dee072f795bad8dbb6cf90d09535da0ad25f1fc360eaf40b5434f68/acme-mgmtserver-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "645bacbd9e3856038bdda4aabf80fffd", "sha256": "70be04b7a2c892b74026b45f3d04d75fe486b94af16a9fe4a13b19c3360a29bd" }, "downloads": -1, "filename": "acme-mgmtserver-0.3.1.tar.gz", "has_sig": false, "md5_digest": "645bacbd9e3856038bdda4aabf80fffd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20575, "upload_time": "2016-12-13T00:59:17", "url": "https://files.pythonhosted.org/packages/3e/c1/c0afec55a33ef55583cde8343572106de9612936b84c6b2ba6ba9e914233/acme-mgmtserver-0.3.1.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "4c054c6ed37b280aa2d1ab109afa9adb", "sha256": "0af1de048cfbcb2ebdcc466017f30cebd85ce34fee0cae549103a2a3ce8ec0d4" }, "downloads": -1, "filename": "acme-mgmtserver-0.4.1.tar.gz", "has_sig": false, "md5_digest": "4c054c6ed37b280aa2d1ab109afa9adb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24004, "upload_time": "2019-10-16T22:25:28", "url": "https://files.pythonhosted.org/packages/0e/83/e97f578abeda44b4a77501a0d8e00c5cd865113fd01f62809f99d0ea332a/acme-mgmtserver-0.4.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4c054c6ed37b280aa2d1ab109afa9adb", "sha256": "0af1de048cfbcb2ebdcc466017f30cebd85ce34fee0cae549103a2a3ce8ec0d4" }, "downloads": -1, "filename": "acme-mgmtserver-0.4.1.tar.gz", "has_sig": false, "md5_digest": "4c054c6ed37b280aa2d1ab109afa9adb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24004, "upload_time": "2019-10-16T22:25:28", "url": "https://files.pythonhosted.org/packages/0e/83/e97f578abeda44b4a77501a0d8e00c5cd865113fd01f62809f99d0ea332a/acme-mgmtserver-0.4.1.tar.gz" } ] }