0

I have been using Visual Studio Code (VSC) a lot in my work recently, especially when working with Jupyter notebooks.

Someone pointed out to me that Jupyter notebooks have become the target of ransomware attacks. I would therefore like to make sure that my work with VSC and Jupyter notebooks is indeed secure (enough).

I connect to my institution from home via VPN where I connect to a central server using SSH. I then attach my VSC to a container that is running on that central server. The container launches a Jupyter notebook server upon start (CMD jupyter notebook ...) and this server uses a specific token for security.

I now also wanted to use an SSL certificate, which I created myself, to encrypt communication with the Jupyter notebook server running inside the container. I follow the instructions on how to "Connect to a remote Jupyter server" described at the bottom of this VSC webpage.

However, when opening a notebook, VSC tells me that it "failed to connect to the remote Jupyter Server". The Jupyter Logs look as follows:

Visual Studio Code (1.66.0, attached-container, desktop)
Jupyter Extension Version: 2022.3.1000901801.
Python Extension Version: 2022.4.0.
Workspace folder /path/to/my
Info 12:56:34: ZMQ install verified.
User belongs to experiment group 'jupyterTestcf'
User belongs to experiment group 'jupyterEnhancedDataViewer'
Info 12:56:35: Old kernelspecs (created by Jupyter extension) stored in directory HOME_DIR_ON_HOST/.local/share/jupyter/kernels/__old_vscode_kernelspecs
Error 12:56:35: getCondaFile, Class name = b, completed in 25ms, has a falsy return value [Error: ENOENT: no such file or directory, lstat 'HOME_DIR_ON_HOST/anaconda2/bin/conda'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'lstat',
  path: 'HOME_DIR_ON_HOST/anaconda2/bin/conda'
}
Error 12:56:35: getCondaVersion, Class name = b, completed in 28ms, has a falsy return value [Error: ENOENT: no such file or directory, lstat 'HOME_DIR_ON_HOST/anaconda2/bin/conda'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'lstat',
  path: 'HOME_DIR_ON_HOST/anaconda2/bin/conda'
}
Info 12:56:35: Checking for server existence.
Info 12:56:35: Checking for server usability.
Info 12:56:35: Starting notebook server.
Info 12:56:35: Connecting to server
Info 12:56:35: Connecting to process server
Info 12:56:35: Connecting server kernel https://0.0.0.0:8888/
Connecting to Jupyter server at https://0.0.0.0:8888/
Info 12:56:35: Creating server with settings : {"baseUrl":"https://0.0.0.0:8888/","appUrl":"","wsUrl":"wss://0.0.0.0:8888/","token":"my_notebook_server_token_0123456789","appendToken":true,"init":{"cache":"no-store","credentials":"same-origin"}}
Info 12:56:35: Connection complete server
Info 12:56:35: Server started.
Info 12:56:35: Creating server with settings : {"baseUrl":"https://0.0.0.0:8888/","appUrl":"","wsUrl":"wss://0.0.0.0:8888/","token":"my_notebook_server_token_0123456789","appendToken":true,"init":{"cache":"no-store","credentials":"same-origin"}}
Info 12:56:35: Preferred kernel connection found in cache .jvsc74a57bd0df0893f56f349688326838aaeea0de204df53a132722cbd565e54b24a8fec5f6./usr/bin/python3.8./usr/bin/python3.8.-m#ipykernel_launcher
Info 12:56:35: PreferredConnection: .jvsc74a57bd0df0893f56f349688326838aaeea0de204df53a132722cbd565e54b24a8fec5f6./usr/bin/python3.8./usr/bin/python3.8.-m#ipykernel_launcher found for NotebookDocument: /path/to/my/jupyter_notebook_file.ipynb
Info 12:56:35: Early registration of controller for Kernel connection .jvsc74a57bd0df0893f56f349688326838aaeea0de204df53a132722cbd565e54b24a8fec5f6./usr/bin/python3.8./usr/bin/python3.8.-m#ipykernel_launcher
Info 12:56:35: TargetController found ID: .jvsc74a57bd0df0893f56f349688326838aaeea0de204df53a132722cbd565e54b24a8fec5f6./usr/bin/python3.8./usr/bin/python3.8.-m#ipykernel_launcher for document /path/to/my/jupyter_notebook_file.ipynb
Info 12:56:35: Setting controller affinity for /path/to/my/jupyter_notebook_file.ipynb .jvsc74a57bd0df0893f56f349688326838aaeea0de204df53a132722cbd565e54b24a8fec5f6./usr/bin/python3.8./usr/bin/python3.8.-m#ipykernel_launcher
Info 12:56:35: Getting activation commands for /usr/bin/python3.8 are not cached. May take a while.
Info 12:56:35: Experiment status for python is {"enabled":true,"optInto":[],"optOutFrom":[]}
Info 12:56:35: Creating controller for jupyter-notebook with interpreter /usr/bin/python3.8
Info 12:56:35: Disposing session manager
Info 12:56:35: SessionManager - dispose contents manager
Info 12:56:35: ShutdownSessionAndConnection - dispose session manager
Info 12:56:35: Finished disposing jupyter session manager
Error 12:56:35: Failed to get remote kernel connections [FetchError: request to https://0.0.0.0:8888/api/kernels?1649249795574 failed, reason: self signed certificate
    at ClientRequest.<anonymous> (/home/USER_NAME/.vscode-server/extensions/ms-toolsai.jupyter-2022.3.1000901801/out/extension.js:2:3868613)
    at ClientRequest.emit (node:events:390:28)
    at TLSSocket.socketErrorListener (node:_http_client:447:9)
    at TLSSocket.emit (node:events:390:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)]
Info 12:56:35: Creating server with settings : {"baseUrl":"https://0.0.0.0:8888/","appUrl":"","wsUrl":"wss://0.0.0.0:8888/","token":"my_notebook_server_token_0123456789","appendToken":true,"init":{"cache":"no-store","credentials":"same-origin"}}
Info 12:56:35: Disposing session manager
Info 12:56:35: SessionManager - dispose contents manager
Info 12:56:35: ShutdownSessionAndConnection - dispose session manager
Error 12:56:35: SessionManager cannot enumerate kernelspecs. Returning default {}.
Info 12:56:35: Finished disposing jupyter session manager
Error 12:56:35: Failed to get remote kernel connections [FetchError: request to https://0.0.0.0:8888/api/kernels?1649249795658 failed, reason: self signed certificate
    at ClientRequest.<anonymous> (/home/USER_NAME/.vscode-server/extensions/ms-toolsai.jupyter-2022.3.1000901801/out/extension.js:2:3868613)
    at ClientRequest.emit (node:events:390:28)
    at TLSSocket.socketErrorListener (node:_http_client:447:9)
    at TLSSocket.emit (node:events:390:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)]
Error 12:56:35: SessionManager cannot enumerate kernelspecs. Returning default {}.
Info 12:56:35: Setting setActiveController for /path/to/my/jupyter_notebook_file.ipynb
Info 12:56:35: KernelProvider switched kernel to id = .jvsc74a57bd0df0893f56f349688326838aaeea0de204df53a132722cbd565e54b24a8fec5f6./usr/bin/python3.8./usr/bin/python3.8.-m#ipykernel_launcher
Info 12:56:35: Starting Notebook in kernel.ts id = .jvsc74a57bd0df0893f56f349688326838aaeea0de204df53a132722cbd565e54b24a8fec5f6./usr/bin/python3.8./usr/bin/python3.8.-m#ipykernel_launcher for /path/to/my/jupyter_notebook_file.ipynb
Info 12:56:35: Creating raw notebook for /path/to/my/jupyter_notebook_file.ipynb
Info 12:56:35: Getting preferred kernel for /path/to/my/jupyter_notebook_file.ipynb
Info 12:56:35: Computing working directory /path/to/my/jupyter_notebook_file.ipynb
Info 12:56:35: Starting raw kernel Python 3.8.0 64-bit for interpreter /usr/bin/python3.8
Info 12:56:35: Kernel launching with ports 9000,9001,9002,9003,9004. Start port is 9000
Info 12:56:36: Registering dummy command feature
Info 12:56:36: Process Execution: > /usr/bin/python3.8 -c "import ipykernel; print(ipykernel.__version__); print("5dc3a68c-e34e-4080-9c3e-2a532b2ccb4d"); print(ipykernel.__file__)"
> /usr/bin/python3.8 -c "import ipykernel; print(ipykernel.__version__); print("5dc3a68c-e34e-4080-9c3e-2a532b2ccb4d"); print(ipykernel.__file__)"
Info 12:56:36: Process Execution: > /usr/bin/python3.8 -m pip list
> /usr/bin/python3.8 -m pip list
Info 12:56:36: Process Execution: > /usr/bin/python3.8 -m ipykernel_launcher --ip=127.0.0.1 --stdin=9003 --control=9001 --hb=9000 --Session.signature_scheme="hmac-sha256" --Session.key=b"4a5e0f9c-619c-4f3a-93bc-34b47687f29b" --shell=9002 --transport="tcp" --iopub=9004 --f=/tmp/tmp-95651J3x4guubfFs.json
> /usr/bin/python3.8 -m ipykernel_launcher --ip=127.0.0.1 --stdin=9003 --control=9001 --hb=9000 --Session.signature_scheme="hmac-sha256" --Session.key=b"4a5e0f9c-619c-4f3a-93bc-34b47687f29b" --shell=9002 --transport="tcp" --iopub=9004 --f=/tmp/tmp-95651J3x4guubfFs.json
Info 12:56:36: Process Execution: cwd: /path/to/my
cwd: /path/to/my
Info 12:56:36: ipykernel version 6.9.1 for /usr/bin/python3.8
Info 12:56:36: ipykernel location /usr/local/lib/python3.8/dist-packages/ipykernel/__init__.py for /usr/bin/python3.8
Warn 12:56:36: StdErr from Kernel Process /usr/local/lib/python3.8/dist-packages/traitlets/traitlets.py:2202: FutureWarning: Supporting extra quotes around strings is deprecated in traitlets 5.0. You can use 'hmac-sha256' instead of '"hmac-sha256"' if you require traitlets >=5.
  warn(
/usr/local/lib/python3.8/dist-packages/traitlets/traitlets.py:2157: FutureWarning: Supporting extra quotes around Bytes is deprecated in traitlets 5.0. Use '4a5e0f9c-619c-4f3a-93bc-34b47687f29b' instead of 'b"4a5e0f9c-619c-4f3a-93bc-34b47687f29b"'.
  warn(

Info 12:56:36: Kernel Output: NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.

To exit, you will have to explicitly quit this process, by either sending
"quit" from a client, or using Ctrl-\ in UNIX-like environments.

To read more about this, see https://github.com/ipython/ipython/issues/2049


To connect another client to this kernel, use:
    --existing /tmp/tmp-95651J3x4guubfFs.json

Info 12:56:36: Raw session started and connected
Started kernel Python 3.8.0 64-bit
Info 12:56:36: Finished connecting 2a4e3b0a-7236-4be4-8eaa-d7ad834b6235
Info 12:56:37: UpdateWorkingDirectoryAndPath in Kernel
Info 12:56:37: Executing silently Code (idle) = import site\nsite.addsitedir(site.getusersitepackages())\nimport os\nimport sys\n%cd "/jupyter/projects/
Info 12:56:37: Executing silently Code (completed) = import site\nsite.addsitedir(site.getusersitepackages())\nimport os\nimport sys\n%cd "/jupyter/projects/
Info 12:56:37: Waiting for idle on (kernel): a883be72-0883-4d09-8d1c-b6ffd8e896aa -> idle
Info 12:56:37: Finished waiting for idle on (kernel): a883be72-0883-4d09-8d1c-b6ffd8e896aa -> idle
Info 12:56:37: Creating server with settings : {"baseUrl":"https://0.0.0.0:8888/","appUrl":"","wsUrl":"wss://0.0.0.0:8888/","token":"my_notebook_server_token_0123456789","appendToken":true,"init":{"cache":"no-store","credentials":"same-origin"}}
Info 12:56:37: Disposing session manager
Info 12:56:37: SessionManager - dispose contents manager
Info 12:56:37: ShutdownSessionAndConnection - dispose session manager
Info 12:56:37: Finished disposing jupyter session manager
Error 12:56:37: Failed to get remote kernel connections [FetchError: request to https://0.0.0.0:8888/api/kernels?1649249797155 failed, reason: self signed certificate
    at ClientRequest.<anonymous> (/home/USER_NAME/.vscode-server/extensions/ms-toolsai.jupyter-2022.3.1000901801/out/extension.js:2:3868613)
    at ClientRequest.emit (node:events:390:28)
    at TLSSocket.socketErrorListener (node:_http_client:447:9)
    at TLSSocket.emit (node:events:390:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)]
Error 12:56:37: SessionManager cannot enumerate kernelspecs. Returning default {}.

The critical message here seems to be this one:

Error 12:56:37: Failed to get remote kernel connections [FetchError: request to https://0.0.0.0:8888/api/kernels?1649249797155 failed, reason: self signed certificate

VSC does not seem to accept the certificate, which I created.

When I connect to the Jupyter server using Firefox, I simply get the expected warning that this certificate is unknown and I proceed at my own risk.

How can I get VSC to also accept my self-signed certificate? Is there a different approach to making my Jupyter notebooks more secure with SSL that would allow me to still use VSC?

It appears to me that I have to stop using VSC for now because it is not secure enough, which is a pity.

Another question I have is which Jupyter server VSC uses if I am connected to a container but do not specify any remote Jupyter server and use "None" instead? I can run my notebooks as well using this approach (I just need to manually select the appropriate Python kernel from inside the container) but I do not know how secure this is: Is this "local" approach using a token? Is this using any encryption?

Your help would be greatly appreciated!

Cheers, Michael

  • I have followed [these instructions](https://medium.com/analytics-vidhya/get-rid-of-ssl-errors-with-jupyter-notebooks-1a80dd509988) on how to permanently add an SSL certificate to the trusted certificates recognized by Firefox & Safari. I could not get the Chrome browser to accept this certificate. This is relevant because VSCode is built on the Chromium architecture according to the [VSC docs](https://code.visualstudio.com/docs/setup/network). Setting `"http.proxyStrictSSL": false` doesn't help either. My alternatives are to use JupyterLab in Safari (i.e., no VSC) or to disable encryption. – Telefonlawine Apr 13 '22 at 07:28

1 Answers1

0

WARNING: I do not believe anymore that this is a solution. Setting NODE_TLS_REJECT_UNAUTHORIZED=0 basically allows any connection even if it does not pass the SSL check. This defeats the purpose of the certificate. If you have a solution for my problem, please let me know. Please see below for my previous answer, which I will leave here for completeness:

After some time of trying several things, I believe that my efforts have converged to a working solution. I'm happy to hear your comments.

I followed these instructions on how to create a certificate that would be accepted by Chrome. I could now access the Jupyter server using this browser as well.

I then went on to try if this already caused VSC to also accept my self-signed certificate. This time I received a different error when opening a notebook after specifying a Jupyter server within the container using the Command Palette: unable to verify the first certificate.

Following this post, I then set the environment variable NODE_TLS_REJECT_UNAUTHORIZED=0 in the .env file of my docker container.

This did the trick! I can now connect to the Jupyter server on the container using both a token and SSL encryption.

Note that in my settings.json, I left "http.proxyStrictSSL": true and "http.systemCertificates": true on both my local computer, the remote server, as well as the container. So, changing these values, as some answers on stackoverflow suggested, did not solve my problem.

To answer my second question: I can tell that my notebook in VSC is indeed running on this server because, on the right of the blue bar at the bottom where it reads "Jupyter Server: Remote", the correct URI of my server is displayed when I hover over it with the cursor.

Thanks!