Setuptools version not pinned in certbot - bug?

I'm trying to use the certbot acme client inside of an AWS lambda function, and so am building all the dependencies into a zip archive using something very similar to poetry export -f requirements.txt requirements.txt then pip install -r requirements.txt.

By default poetry export will include hashes in exports. However, adding certbot causes the following exception from pip.

ERROR: In --require-hashes mode, all requirements must have their versions pinned with ==. These do not:
setuptools from (from acme==1.9.0->-r requirements.txt (line 1))

Having dug around in the code I believe the issue is caused by setuptools not being pinned to a particular version in in the certbot acme client.

I was going to create an issue as a possible bug report, but noticed a few issues to do with setuptools already and so wanted to check this wasn't something intentional and that I may be missing a more obvious solution?


Welcome to the Let's Encrypt Community, Dom :slightly_smiling_face:

@bmw, @certbot-devs

I believe you guys should address this one.


I see pip and also acme==1.9.0
Anyone care for some snaps?

READERS: Get involved. Be heard. Do your part, it starts with: If you read something you like; then like it :heart: !

1 Like

I'm sorry I don't understand your reply. Please could you elaborate? If your reply is related to the the Ubuntu snap system, I would appreciate some direction on how this is related. The environment I am experiencing this error in is a CircleCI python:3.8.6 container.

This is the first time I have used the certbot library, and so appreciate the effort and respect shown by all those assisting.

1 Like

I'm sorry for my (intended) humor.
[if you have to explain the joke... it's never funny]

Anywho, did you install certbot from snapd?
If not (which is most likely the case), can you?

Otherwise, the joke may be on me, if you already did.
[not that there was ever any joke on you - I do so often get misunderstood...]

READERS: Get involved. Be heard. Do your part, it starts with: If you read something you like; then like it :heart: !

1 Like

Ah I see - ha yes, humour is always so hard crossing borders and with the limitations of technical forms! Thank-you for taking the time to look at my issue and offer assistance.

No, I did not use snapd to install certbot. I am installing certbot through a standard pip install based on a requirements.txt file exported by poetry, in a standard python docker container pulled from Docker Hub. The pip install is failing because the calculated dependency graph does not pin a version of setuptools, and so installing from pip with hashes fails because I don't have hashes for setuptools, unless I --allow-unsafe. Should I install certbot some other way and if so which C-libs etc. do I need to copy into my lambda environment? I just want to use the acme client in a python script in a small lambda function, so minimal install is preferable and I don't want to think too much about shims and so on.

I've noticed pytz is also not pinned (again, realise with the 3.9 release this may be a deliberate decision/moving towards obsolescence), so realise the error may be something deeper/different (or that pytz will be the next error after solving this one).


I can't say that I know with certainty how that should best be installed within CircleCI.
And it seems we are not alone on this, and I can see why you came looking for help here; when the only thing returned for certbot on their help forum is more than three years old and completely un-helpful:

That said, there are some very clever people in this community (which will undoubtedly chime in on this given adequate time - it is Sunday afternoon in the states now - where most of them live) like @_az, @certbot-devs

I'm thinking 1.9.0 may not be the most adequate version for that system, but I'll leave the advice for the experts (thou exact CircleCI proficiency may hard to find it might be similar enough to, or based on, some other .well-known system).

READERS: Get involved. Be heard. Do your part, it starts with: If you read something you like; then like it :heart: !

1 Like

I think that the setuptools situation is a bit complicated, and to make things worse, it's currently undergoing changes. I think bmw or adferrand should be able to answer in more detail.

As a guide, you can look at how Certbot can be deployed from pip by looking at certbot-auto.

In particular, the embedded pipstrap snippet is responsible for installing a pinned version of setuptools.

certbot-auto is also responsible for installing relevant C libraries like libssl, libffi, libaugeas etc.

In general, if I were to look at running something ACME-related in Lambda, I would probably choose something with less dependencies (or a zero dependency static binary, such as lego). It would also probably save you a decent bit of money, as the memory usage and runtime duration would be a lot lower.


Thanks for everybody's help. @_az - I would definitely prefer to use an acme client with fewer dependencies, do you know if lego has a python wrapper? The only thin ACME client I've found it acme-tiny which looks relatively specific to a few use cases, and makes me think it would be easier to write my own client, which I am very keen not to do.

I could also --allow-unsafe inside my CI script, but fear this would just lead to the deployment breaking again in the future with new releases (because I can't pin to particular versions etc.).


_az would definitely know better than me, but I believe that is written purely in script/shell and should have much less in the way of dependencies. I'm currently modifying my own thin client that is pure PHP, but I think your circumstances might be beyond that.

Perhaps this is of value about

Purely written in Shell with no dependencies on python or the official Let's Encrypt client

1 Like

Ah, I think I misunderstood your original post: You are using the acme module in your Python Lambda function, rather than using the Certbot application proper. So you wouldn't be requiring the certbot module at all.

FWIW poetry add acme && poetry export && pip install --require-hashes works alright for me in that environment:

$ sudo docker run -v $(pwd):/app --rm -it python:3.8.6 /bin/bash
root@138be024046e:/# cd /app
root@138be024046e:/app# ls
poetry.lock  pyproject.toml  requirements.txt
root@138be024046e:/app# pip install --require-hashes -r requirements.txt
Collecting acme==1.9.0
  Downloading acme-1.9.0-py2.py3-none-any.whl (42 kB)
    |████████████████████████████████| 42 kB 895 kB/s
Collecting certifi==2020.6.20
  Downloading certifi-2020.6.20-py2.py3-none-any.whl (156 kB)
    |████████████████████████████████| 156 kB 5.3 MB/s
Collecting cffi==1.14.3
  Downloading cffi-1.14.3-cp38-cp38-manylinux1_x86_64.whl (410 kB)
    |████████████████████████████████| 410 kB 10.6 MB/s
Collecting chardet==3.0.4
  Downloading chardet-3.0.4-py2.py3-none-any.whl (133 kB)
    |████████████████████████████████| 133 kB 16.1 MB/s
Collecting cryptography==3.1.1
  Downloading cryptography-3.1.1-cp35-abi3-manylinux2010_x86_64.whl (2.6 MB)
    |████████████████████████████████| 2.6 MB 12.6 MB/s
Collecting idna==2.10
  Downloading idna-2.10-py2.py3-none-any.whl (58 kB)
    |████████████████████████████████| 58 kB 8.2 MB/s
Collecting josepy==1.4.0
  Downloading josepy-1.4.0-py2.py3-none-any.whl (57 kB)
    |████████████████████████████████| 57 kB 7.9 MB/s
Collecting pycparser==2.20
  Downloading pycparser-2.20-py2.py3-none-any.whl (112 kB)
    |████████████████████████████████| 112 kB 15.5 MB/s
Collecting pyopenssl==19.1.0
  Downloading pyOpenSSL-19.1.0-py2.py3-none-any.whl (53 kB)
    |████████████████████████████████| 53 kB 4.9 MB/s
Collecting pyrfc3339==1.1
  Downloading pyRFC3339-1.1-py2.py3-none-any.whl (5.7 kB)
Collecting pytz==2020.1
  Downloading pytz-2020.1-py2.py3-none-any.whl (510 kB)
    |████████████████████████████████| 510 kB 13.1 MB/s
Collecting requests-toolbelt==0.9.1
  Downloading requests_toolbelt-0.9.1-py2.py3-none-any.whl (54 kB)
    |████████████████████████████████| 54 kB 3.8 MB/s
Collecting requests==2.24.0
  Downloading requests-2.24.0-py2.py3-none-any.whl (61 kB)
    |████████████████████████████████| 61 kB 836 kB/s
Collecting six==1.15.0
  Downloading six-1.15.0-py2.py3-none-any.whl (10 kB)
Collecting urllib3==1.25.11
  Downloading urllib3-1.25.11-py2.py3-none-any.whl (127 kB)
    |████████████████████████████████| 127 kB 15.2 MB/s
Requirement already satisfied: setuptools in /usr/local/lib/python3.8/site-packages (from acme==1.9.0->-r requirements.txt (line 1)) (50.3.2)
Installing collected packages: six, pytz, chardet, urllib3, idna, certifi, requests, requests-toolbelt, pycparser, cffi, cryptography, pyopenssl, pyrfc3339, josepy, acme
Successfully installed acme-1.9.0 certifi-2020.6.20 cffi-1.14.3 chardet-3.0.4 cryptography-3.1.1 idna-2.10 josepy-1.4.0 pycparser-2.20 pyopenssl-19.1.0 pyrfc3339-1.1 pytz-2020.1 requests-2.24.0 requests-toolbelt-0.9.1 six-1.15.0 urllib3-1.25.11

I'm not too sure why pip would be complaining about setuptools in this instance, but like I said, one of the senior maintainers should be able to help out tomorrow(ish).


Thanks for your help - I've switched my dependency to acme = "^1.9.0" rather than certbot. However, I'm still getting the error in Circle. Please could you share the poetry.lock and pyproject.toml generated in the container above to assist me debugging this (probably tomorrow morning - it's getting late in the UK!).

Again, really can't thank everyone enough for their help.


Sure, these are the files generated by poetry 1.1.4.

I also tried in the circleci/python:3.8.6 container and it worked there as well.


It's in Node.js rather than in Python, but I put together an ACME renewal process in Lambda as a hobby project if you're interested in getting some ideas from it that at least worked for me:


Thanks for your help everyone - I intend to investigate the issue with hashes as a bug in my build process, however to check the feasibility of what I'm doing, I've added --without-hashes to my export, and am testing the ACME API process.

However, I'm now getting:

[ERROR] KeyError: 'Directory field "new-reg" not found'
Traceback (most recent call last):
  File "/var/task/tls_manager/certgen/", line 50, in handler
    reg = acme.register()
  File "/var/task/acme/", line 279, in register
    response = self._post([new_reg], new_reg)
  File "/var/task/acme/", line 255, in __getitem__
    raise KeyError('Directory field "' + self._canon_key(name) + '" not found')

I'm using the ACME v2 endpoint, but this looks like an issue with a v1 client trying to use a v2 endpoint. Am I right to assume that acme==1.9.0 is an ACME v2 RFC 8555 client? Am I missing something?

1 Like

What was the exact endpoint URL you used?

And are you using either BackwardsCompatibleClientV2 or ClientV2?