From b6024e31234e24d5b46b8d7d8885e063d753be4b Mon Sep 17 00:00:00 2001 From: zer0x64 Date: Fri, 19 Sep 2025 18:55:58 -0400 Subject: [PATCH 1/2] update rust-webservice template to use build container --- .../ansible/challenge/app.py | 2 +- ctf/new.py | 15 ++- .../new/rust-webservice/build.yaml.j2 | 111 ++++++++++++++++++ .../new/rust-webservice/deploy.yaml.j2 | 93 +-------------- 4 files changed, 131 insertions(+), 90 deletions(-) create mode 100644 ctf/templates/new/rust-webservice/build.yaml.j2 diff --git a/challenges/mock-track-python-service/ansible/challenge/app.py b/challenges/mock-track-python-service/ansible/challenge/app.py index 96654bb..73c0d66 100644 --- a/challenges/mock-track-python-service/ansible/challenge/app.py +++ b/challenges/mock-track-python-service/ansible/challenge/app.py @@ -29,4 +29,4 @@ def index(): -""" \ No newline at end of file +""" diff --git a/ctf/new.py b/ctf/new.py index d308912..c9617b7 100644 --- a/ctf/new.py +++ b/ctf/new.py @@ -52,7 +52,6 @@ def new( typer.Option( "--with-build", help="If a build container is required.", - prompt="Is a build container required?", ), ] = False, ) -> None: @@ -67,6 +66,9 @@ def new( ) exit(code=1) + if template == Template.RUST_WEBSERVICE: + with_build_container = True + if os.path.exists( path=( new_challenge_directory := os.path.join( @@ -253,10 +255,19 @@ def new( LOG.debug(msg=f"Wrote {p}.") if with_build_container: - track_template = env.get_template(name=os.path.join("common", "build.yaml.j2")) + try: + track_template = env.get_template( + name=os.path.join(template, "build.yaml.j2") + ) + except jinja2.TemplateNotFound: + track_template = env.get_template( + name=os.path.join("common", "build.yaml.j2") + ) + render = track_template.render( data={"name": name, "with_build": with_build_container} ) + with open( file=(p := os.path.join(ansible_directory, "build.yaml")), mode="w", diff --git a/ctf/templates/new/rust-webservice/build.yaml.j2 b/ctf/templates/new/rust-webservice/build.yaml.j2 new file mode 100644 index 0000000..107403e --- /dev/null +++ b/ctf/templates/new/rust-webservice/build.yaml.j2 @@ -0,0 +1,111 @@ +# This Ansible script is used to compile your challenge, create an archive and extract that archive on to the local host. +# This script only shows a proof of concept of building a C program. Change it as per your needs. +- name: "Build container" + hosts: "build-container" + vars_files: + - ../track.yaml + tasks: + - name: "Load flags" + loop: "{{ '{{ flags }}' }}" + vars: + key: "{{ '{{ (item.tags).discourse }}' }}" + value: "{{ '{{ item.flag }}' }}" + ansible.builtin.set_fact: + track_flags: "{{ '{{ track_flags | default({}) | combine({key: value}) }}' }}" + + - name: Initial System Upgrade + ansible.builtin.apt: + update_cache: true + install_recommends: false + upgrade: full + + # Install the tools required to compile your code such as npm, nodejs, gcc... + - name: Install dependencies to build the track + ansible.builtin.apt: + name: + - npm + - curl + state: present + + - name: Check if cargo is installed + ansible.builtin.stat: + path: /root/.cargo/bin/cargo + register: cargo_exists + + - name: Download Cargo Installer + ansible.builtin.get_url: + url: https://sh.rustup.rs + dest: /tmp/sh.rustup.rs + mode: '0755' + force: true + when: not cargo_exists.stat.exists + tags: + - rust + + - name: Install Cargo + when: not cargo_exists.stat.exists + ansible.builtin.command: /tmp/sh.rustup.rs -y + register: my_output + changed_when: my_output.rc != 0 + tags: + - rust + + - name: Copy the challenge sources + ansible.builtin.copy: + src: challenge/ + dest: /tmp/{{ data.name }} + owner: root + group: root + mode: '0644' + + - name: NPM install + community.general.npm: + path: /tmp/{{ data.name }}/client/ + environment: + NODE_OPTIONS: "--dns-result-order=ipv4first" + + - name: Build + ansible.builtin.command: + cmd: /root/.cargo/bin/cargo build --release + chdir: /tmp/{{ data.name }}/ + register: my_output + changed_when: my_output.rc != 0 + + - name: Create dist directory + ansible.builtin.file: + path: /tmp/dist/{{ data.name }} + state: directory + mode: '0755' + + - name: Copy server binary + ansible.builtin.copy: + remote_src: true + src: /tmp/{{ data.name }}/target/release/{{ data.name }} + dest: /tmp/dist/{{ data.name }}/{{ data.name }} + owner: root + group: root + mode: '0744' + + - name: Copy client + ansible.builtin.copy: + remote_src: true + src: /tmp/{{ data.name }}/dist + dest: /tmp/dist/{{ data.name }}/ + owner: root + group: root + mode: '0644' + + # Create a TAR archive with the compiled program + - name: Create archive of build + community.general.archive: + path: /tmp/dist/{{ data.name }} + dest: /tmp/build.tar + format: tar + mode: '0644' + + # Extract the archive from the build container and save it on the local host + - name: Fetch archive + ansible.builtin.fetch: + src: /tmp/build.tar + dest: /tmp/nsec/{{ data.name }}.tar + flat: true diff --git a/ctf/templates/new/rust-webservice/deploy.yaml.j2 b/ctf/templates/new/rust-webservice/deploy.yaml.j2 index 678feb9..be5b97a 100644 --- a/ctf/templates/new/rust-webservice/deploy.yaml.j2 +++ b/ctf/templates/new/rust-webservice/deploy.yaml.j2 @@ -1,7 +1,7 @@ # This is the main ansible script to deploy the challenge. # Example on how to run stuff on all hosts of the track -- name: "Install rust and npm" +- name: "Setup web server" hosts: all{% if data.with_build %},!build{% endif %} vars_files: - ../track.yaml @@ -23,77 +23,13 @@ install_recommends: false upgrade: full - - name: Install build dependencies - ansible.builtin.apt: - name: - - npm - - curl - state: present - - - name: Check if cargo is installed - ansible.builtin.stat: - path: /root/.cargo/bin/cargo - register: cargo_exists - - - name: Download Cargo Installer - ansible.builtin.get_url: - url: https://sh.rustup.rs - dest: /tmp/sh.rustup.rs - mode: '0755' - force: true - when: not cargo_exists.stat.exists - tags: - - rust - - - name: Install Cargo - when: not cargo_exists.stat.exists - ansible.builtin.command: /tmp/sh.rustup.rs -y - register: my_output - changed_when: my_output.rc != 0 - tags: - - rust - - - name: Copy the challenge sources - ansible.builtin.copy: - src: challenge/ - dest: /tmp/{{ data.name }} - owner: root - group: root - mode: '0644' - - - name: NPM install - community.general.npm: - path: /tmp/slot-machine/client/ - environment: - NODE_OPTIONS: "--dns-result-order=ipv4first" - - - name: Build - ansible.builtin.command: - cmd: /root/.cargo/bin/cargo build --release - chdir: /tmp/{{ data.name }}/ - register: my_output - changed_when: my_output.rc != 0 - - - name: Copy server binary - ansible.builtin.copy: - src: /tmp/{{ data.name }}/target/release/{{ data.name }} - dest: /opt/{{ data.name }}/{{ data.name }} - owner: root - group: root - mode: '0744' - - - name: Copy client - ansible.builtin.copy: - src: /tmp/{{ data.name }}/dist - dest: /opt/{{ data.name }}/dist + - name: Unarchive the content of the build + ansible.builtin.unarchive: + src: /tmp/nsec/{{ data.name }}.tar + dest: /opt/ owner: root group: root - mode: '0644' - - - name: Remove Build - ansible.builtin.file: - path: /tmp/{{ data.name }}/ - state: absent + mode: '0755' - name: Create systemd service ansible.builtin.copy: @@ -116,26 +52,9 @@ [Install] WantedBy=default.target - - name: Remove curl and npm - ansible.builtin.apt: - name: - - npm - - curl - state: absent - - name: Start service ansible.builtin.service: name: {{ data.name }}.service state: restarted enabled: true daemon_reload: true -{% if data.with_build %} - # When using a build container, the unarchive module can be used to install the content on the remote. - - name: Unarchive the content of the build - ansible.builtin.unarchive: - src: /tmp/build.tar - dest: /tmp/ - owner: root - group: root - mode: '0755' -{% endif %} From c6796beccfa17c050c5432370bad0285bd7a4433 Mon Sep 17 00:00:00 2001 From: zer0x64 Date: Sun, 28 Sep 2025 14:58:33 -0400 Subject: [PATCH 2/2] address review comments --- ctf/templates/new/rust-webservice/build.yaml.j2 | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ctf/templates/new/rust-webservice/build.yaml.j2 b/ctf/templates/new/rust-webservice/build.yaml.j2 index 107403e..ac9536c 100644 --- a/ctf/templates/new/rust-webservice/build.yaml.j2 +++ b/ctf/templates/new/rust-webservice/build.yaml.j2 @@ -1,5 +1,5 @@ # This Ansible script is used to compile your challenge, create an archive and extract that archive on to the local host. -# This script only shows a proof of concept of building a C program. Change it as per your needs. +# This script builds a frontend using NPM and a Rust program. Change it as per your needs. - name: "Build container" hosts: "build-container" vars_files: @@ -13,6 +13,11 @@ ansible.builtin.set_fact: track_flags: "{{ '{{ track_flags | default({}) | combine({key: value}) }}' }}" + - name: Check if IPv4 address is set + ansible.builtin.debug: + msg: IPv4 address is set + when: ansible_all_ipv4_addresses | length > 0 + - name: Initial System Upgrade ansible.builtin.apt: update_cache: true @@ -58,11 +63,17 @@ group: root mode: '0644' - - name: NPM install + - name: NPM install (if IPv4) community.general.npm: path: /tmp/{{ data.name }}/client/ environment: NODE_OPTIONS: "--dns-result-order=ipv4first" + when: ansible_all_ipv4_addresses | length > 0 + + - name: NPM install (if IPv6) + community.general.npm: + path: /tmp/{{ data.name }}/client/ + when: ansible_all_ipv4_addresses | length == 0 - name: Build ansible.builtin.command: