Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSL certificates are unset inside devbox shell #177

Closed
lucasrla opened this issue Sep 25, 2022 · 1 comment · Fixed by #178
Closed

SSL certificates are unset inside devbox shell #177

lucasrla opened this issue Sep 25, 2022 · 1 comment · Fixed by #178
Assignees
Labels
bug Something isn't working

Comments

@lucasrla
Copy link

lucasrla commented Sep 25, 2022

Hello, Nix's SSL certificates are not working properly within devbox shell.

Here's a trivial example (Devbox 0.0.6 on macOS Monterey):

devbox init

devbox add python310

devbox shell

/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/bin/python
  Python 3.10.5 (main, Jul 29 2022, 22:05:50) [Clang 11.1.0 ] on darwin
  Type "help", "copyright", "credits" or "license" for more information.
  >>> import urllib.request
  >>> urllib.request.urlopen("https://github.com/jetpack-io/devbox")
  Traceback (most recent call last):
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/urllib/request.py", line 1348, in do_open
      h.request(req.get_method(), req.selector, req.data, headers,
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/http/client.py", line 1282, in request
      self._send_request(method, url, body, headers, encode_chunked)
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/http/client.py", line 1328, in _send_request
      self.endheaders(body, encode_chunked=encode_chunked)
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/http/client.py", line 1277, in endheaders
      self._send_output(message_body, encode_chunked=encode_chunked)
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/http/client.py", line 1037, in _send_output
      self.send(msg)
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/http/client.py", line 975, in send
      self.connect()
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/http/client.py", line 1454, in connect
      self.sock = self._context.wrap_socket(self.sock,
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/ssl.py", line 513, in wrap_socket
      return self.sslsocket_class._create(
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/ssl.py", line 1071, in _create
      self.do_handshake()
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/ssl.py", line 1342, in do_handshake
      self._sslobj.do_handshake()
  ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)

  During handling of the above exception, another exception occurred:

  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/urllib/request.py", line 216, in urlopen
      return opener.open(url, data, timeout)
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/urllib/request.py", line 519, in open
      response = self._open(req, data)
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/urllib/request.py", line 536, in _open
      result = self._call_chain(self.handle_open, protocol, protocol +
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/urllib/request.py", line 496, in _call_chain
      result = func(*args)
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/urllib/request.py", line 1391, in https_open
      return self.do_open(http.client.HTTPSConnection, req,
    File "/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/lib/python3.10/urllib/request.py", line 1351, in do_open
      raise URLError(err)
  urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
  >>> exit()

Investigating it a bit further:

# still inside that devbox shell

/nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/bin/python
  Python 3.10.5 (main, Jul 29 2022, 22:05:50) [Clang 11.1.0 ] on darwin
  Type "help", "copyright", "credits" or "license" for more information.  
  >>> import ssl
  >>> ssl.OPENSSL_VERSION
  'OpenSSL 1.1.1q  5 Jul 2022'
  >>> ssl.get_default_verify_paths()
  DefaultVerifyPaths(cafile=None, capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/nix/store/f6rqri950vqprx12r5hjaygl2v1rkcfb-openssl-1.1.1q/etc/ssl/certs')
  >>> ssl.get_default_verify_paths().openssl_cafile
  '/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt'

echo $NIX_SSL_CERT_FILE
  /no-cert-file.crt

exit

# yet, in our main shell:

echo $NIX_SSL_CERT_FILE
  /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt

So I tried the following and it did solve the issue:

# back to the devbox shell

devbox shell

NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt /nix/store/v4iwl6az3wax9nw0wl42kjpq4vfdd7j4-python3-3.10.5/bin/python
  Python 3.10.5 (main, Jul 29 2022, 22:05:50) [Clang 11.1.0 ] on darwin
  Type "help", "copyright", "credits" or "license" for more information.
  >>> import urllib.request
  >>> urllib.request.urlopen("https://github.com/jetpack-io/devbox")
  <http.client.HTTPResponse object at 0x10338bbe0>
  >>> exit()

I guess the root cause is that devbox shell relies on nix-shell --pure. Apparently it is the intended design to set $NIX_SSL_CERT_FILE to /no-cert-file.crt inside pure nix-shells.

It would be great though not to lose such a crucial env var when using a devbox shell... Or maybe at least have them somehow listed/documented somewhere? :)

For now, I'm manually editing devbox.json to make sure my shell init_hook has export NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt in there.

Thanks in advance!

@gcurtis
Copy link
Collaborator

gcurtis commented Sep 26, 2022

Thanks for the thorough investigation into this! I agree that it makes sense to leave the cert file set by default. This should be a simple change of just adding NIX_SSL_CERT_FILE to the list of env vars we tell the shell to keep. We'll aim at getting this fix in for the next release.

@gcurtis gcurtis self-assigned this Sep 26, 2022
@gcurtis gcurtis added bug Something isn't working high priority labels Sep 26, 2022
gcurtis added a commit that referenced this issue Sep 26, 2022
When `NIX_SSL_CERT_FILE` and `SSL_CERT_FILE` aren't explicitly set,
`nix-shell --pure` sets them to invalid paths
(specifically "/no-cert-file.crt") to ensure that openssl doesn't use
certificates that live outside of the current Nix environment. This
causes HTTPS requests in most programs to fail. For example:

	(devbox) $ curl https://google.com
	curl: (77) error setting certificate verify locations:  CAfile: /no-cert-file.crt CApath: none

This is pretty inconvenient for development, so we want to undo those
changes when launching a devbox shell. To do that, we:

1. Keep any `NIX_SSL_CERT_FILE` and `SSL_CERT_FILE` values that are set in the parent shell.
2. Unset `NIX_SSL_CERT_FILE` or `SSL_CERT_FILE` when they're set to the "/no-cert-file.crt" value set by `nix-shell`. This causes openssl to go back to using the default paths.

NIX_SSL_CERT_FILE is used by some programs installed by Nix.
SSL_CERT_FILE is used by non-Nix programs and some Nix programs.

Fixes #177.
gcurtis added a commit that referenced this issue Sep 26, 2022
When `NIX_SSL_CERT_FILE` and `SSL_CERT_FILE` aren't explicitly set,
`nix-shell --pure` sets them to invalid paths
(specifically "/no-cert-file.crt") to ensure that openssl doesn't use
certificates that live outside of the current Nix environment. This
causes HTTPS requests in most programs to fail. For example:

	(devbox) $ curl https://google.com
curl: (77) error setting certificate verify locations: CAfile:
/no-cert-file.crt CApath: none

This is pretty inconvenient for development, so we want to undo those
changes when launching a devbox shell. To do that, we:

1. Keep any `NIX_SSL_CERT_FILE` and `SSL_CERT_FILE` values that are set
in the parent shell.
2. Unset `NIX_SSL_CERT_FILE` or `SSL_CERT_FILE` when they're set to the
"/no-cert-file.crt" value set by `nix-shell`. This causes openssl to go
back to using the default paths.

NIX_SSL_CERT_FILE is used by some programs installed by Nix.
SSL_CERT_FILE is used by non-Nix programs and some Nix programs.

Fixes #177.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

Successfully merging a pull request may close this issue.

2 participants