ScribblerCoder / CTFd-Helm

A Helm chart to deploy CTFd HA/Autoscaling + Redis + MariaDB + SeaweedFS S3-Compatible Storage
MIT License
16 stars 3 forks source link

Support installing plugins and themes #10

Open ScribblerCoder opened 2 months ago

ScribblerCoder commented 2 months ago

Would be nice to support install custom themes and CTFd plugins without having to build a custom image each time. This could be done using initContainers that download the theme's source code and copies it to a emptyDir volume mounted by the ctfd main container. Themes are easy but plugins might be hard because we would have to install missing pip packages.

0xPb1 commented 2 months ago

We can also do this way, right?

  1. Download all the required themes for your CTFd platform.
  2. Mount them as a directory to CTFd/themes.

This method should work effectively and provide a simple resolution. Let me know if you’d like to proceed with this approach it has any issues during/after the implementation.

ScribblerCoder commented 2 months ago

We can also do this way, right?

1. Download all the required themes for your CTFd platform.

2. Mount them as a directory to CTFd/themes.

This method should work effectively and provide a simple resolution. Let me know if you’d like to proceed with this approach it has any issues during/after the implementation.

an initContainer would automate all of this in one go and shouldn't require any extra attention from users except specifying the exact themes they would like to have. I'm planning on automating this using helm. The user would specify a list of themes in values.yaml and the templates can take care of the rest

0xPb1 commented 1 month ago

@ScribblerCoder, I gave this a try, but it seems the ghcr.io/ctfd/ctfd image used by this CTFd-Helm chart is not the latest version. As a result, I ran into some internal server errors related to recent code changes in CTFd and theme loading issues. Could you update the image to the latest CTFd version?

Error:

ERROR [CTFd] Exception on /setup [GET]
Traceback (most recent call last):
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask_restx/api.py", line 674, in error_router
    return original_handler(e)
           ^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 1516, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/CTFd/CTFd/views.py", line 301, in setup
    return render_template("setup.html", state=serialize(generate_nonce()))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/templating.py", line 147, in render_template
    return _render(
           ^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/templating.py", line 128, in _render
    rv = template.render(context)
         ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/opt/venv/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "/opt/CTFd/CTFd/themes/core-beta/templates/setup.html", line 1, in top-level template code
    {% extends "base.html" %}
  File "/opt/CTFd/CTFd/themes/core-beta/templates/base.html", line 17, in top-level template code
    {{ Assets.js("assets/js/color_mode_switcher.js", type=None) }}
    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/jinja2/sandbox.py", line 393, in call
    return __context.call(__obj, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: _AssetsWrapper.js() got an unexpected keyword argument 'type'

I have faced this error when I try to load the themes I freshly download from the ctfd themes. Later confirmed by loading the themes that I already use from my old CTFd setup which resulted in no error.

Ref -> https://github.com/CTFd/CTFd/releases/tag/3.7.4

0xPb1 commented 1 month ago

@ScribblerCoder,

~I don't believe the error I encountered was due to the image version. It might be related to the unsupported themes, although I'm not entirely sure.~

I confirm that the error I have faced was due to the usage of older ghcr.io/ctfd/ctfd image. You need to update the image with the latest CTFd code to resolve this issue.

Added more details in here -> Dividing this into two parts

I've consolidated all the themes in one place: My CTFd Themes.

The specific themes causing the error are:

Here’s the error log I received:

[2024-10-08 12:00:38 +0000] [20] [ERROR] Error handling request /favicon.ico
Traceback (most recent call last):
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 1516, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/CTFd/CTFd/views.py", line 398, in static_html
    abort(404)
  File "/opt/venv/lib/python3.11/site-packages/werkzeug/exceptions.py", line 941, in abort
    _aborter(status, *args, **kwargs)
  File "/opt/venv/lib/python3.11/site-packages/werkzeug/exceptions.py", line 924, in __call__
    raise self.mapping[code](*args, **kwargs)
werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask_restx/api.py", line 674, in error_router
    return original_handler(e)
           ^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 1386, in handle_user_exception
    return self.handle_http_exception(e)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/app.py", line 1326, in handle_http_exception
    return self.ensure_sync(handler)(e)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/CTFd/CTFd/errors.py", line 14, in render_error
    render_template(
  File "/opt/venv/lib/python3.11/site-packages/flask/templating.py", line 147, in render_template
    return _render(
           ^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/flask/templating.py", line 128, in _render
    rv = template.render(context)
         ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/opt/venv/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "/opt/CTFd/CTFd/themes/r2-terminal/templates/errors/404.html", line 1, in top-level template code
    {% extends "base.html" %}
  File "/opt/CTFd/CTFd/themes/r2-terminal/templates/base.html", line 7, in top-level template code
    <meta name="start_in" content="{{ ctf_starts_in() }}">
    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/jinja2/sandbox.py", line 391, in call
    if not __self.is_safe_callable(__obj):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/venv/lib/python3.11/site-packages/jinja2/sandbox.py", line 275, in is_safe_callable
    getattr(obj, "unsafe_callable", False) or getattr(obj, "alters_data", False)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jinja2.exceptions.UndefinedError: 'ctf_starts_in' is undefined

Setup Details:

I'm using an init container to clone and mount these themes as follows:

initContainers:
  - name: clone-themes
    image: alpine/git:latest
    command: ["/bin/sh", "-c"]
    args:
      - |
        git clone https://github.com/0xPb1/my-ctfd-themes.git /temp-themes &&
        cp -r /temp-themes/* /mnt/themes/;
    volumeMounts:
      - name: themes
        mountPath: /mnt/themes

volumes:
  - name: themes
    emptyDir: {}

volumeMounts:
  - name: themes
    mountPath: /opt/CTFd/CTFd/themes

Here’s a snapshot of my setup:

image

Edit:

Dividing this into two parts

Part 1: The Issue

  1. I'm attempting to mount CTF themes into the /opt/CTFd/CTFd/themes/ directory within the CTFd pod in Kubernetes using initContainers. However, when I mount the themes to this directory, they replace the existing default themes. As a result, I'm facing an internal server error since the application cannot load the default theme, which is core-beta.

  2. To resolve this, I downloaded the themes from the CTFd repository and added additional custom themes for my CTFd instance. However, when I mounted all these themes using an initContainer, the CTFd instance encountered a 500 Internal Server Error. The error seems to be due to recent changes in the CTFd default theme code, which prevents it from loading properly.

Part 2: The Resolution

  1. After investigation, I confirmed that the issue stemmed from using older CTFd code (referring to code changes within CTFd, not the application version).

  2. As noted in Part 1, there have been updates to the themes and related code affecting how the default theme is loaded (see ref-t1). This caused issues because I was using older CTFd code with newer themes.

  3. I dockerized the CTFd application, integrating the latest code changes. I repeated the deployment with the latest CTFd code and updated default themes (primarily core-beta, as it is the default theme called during the /setup endpoint).

  4. This resolved the primary issue. However, there are still some themes—specifically from the ctfd-r2con-themes—that remain incompatible.

ref-t1 (Last Commit Date)->

image
ScribblerCoder commented 1 month ago

@0xPb1 check that you're image is not being cached, the default imagePullPolicy is IfNotPresent . I just pulled and ran ghcr.io/ctfd/ctfd. It is indeed the latest version 3.7.4.

image

you can always check /opt/CTFd/CTFd/__init__.py to confirm

root@369d68399161:/opt/CTFd# cat ./CTFd/__init__.py | grep __version__
__version__ = "3.7.4"
    utils.set_config("ctf_version", __version__)
        app.VERSION = __version__
        if version and (StrictVersion(version) < StrictVersion(__version__)):
            utils.set_config("ctf_version", __version__)
ScribblerCoder commented 1 month ago

@0xPb1 you also see in https://github.com/CTFd/CTFd/pkgs/container/ctfd

image

This proves that ghcr.io/ctfd/ctfd is in fact NOT old at all. It is an official image published by CTFd

ScribblerCoder commented 1 month ago

I'm going to mention this for anyone who would happen to pass by in this issue and want to install certain CTFd themes. Themes compatibility is the responsibility of the theme maintainer. It's also the user's responsibility to change the image tag of CTFd if the theme happened to be not compatible with the latest CTFd if they happen to do breaking changes in UI. The helm chart's responsibility is to be customizable enough to allow the users to use any CTFd version they like.

ScribblerCoder commented 1 month ago

@0xPb1 I think its the chart's appVersion fault. Should be bumped. I think the better practice to just always set image tag in values.yaml

0xPb1 commented 1 month ago

@0xPb1 you also see in https://github.com/CTFd/CTFd/pkgs/container/ctfd

image

This proves that ghcr.io/ctfd/ctfd is in fact NOT old at all. It is an official image published by CTFd

Thank you for looking into this! I believe the update was released very recently. I started testing this on Tuesday, October 8th, and it looks like the image was released just 11 hours ago. That timing might explain the issue I encountered. I’ll check again and confirm.

image