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

Split ctfd_challenge in two separate resources #134

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
services:
ctfd:
image: ctfd/ctfd:3.7.1@sha256:6ab10e197c954f6bff3dea03bf87b8b7c8ef1072bf434030d0e5f3c61ebbd7ef
image: ctfd/ctfd:3.7.5@sha256:7f456b23727286c9df2b58e0b7398cc0196e2b74e4c1c5b3cda7a5b71034637d
ports:
- 8000:8000
env:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ provider "ctfd" {

We recommend setting the environment variable `CTFD_API_KEY` to enable the provider to communicate with your CTFd instance.

Then, you could use a `ctfd_challenge` resource to setup your CTFd challenge, with for instance the following configuration.
Then, you could use a `ctfd_challenge_standard` resource to setup your CTFd challenges, with for instance the following configuration.
```hcl
resource "ctfd_challenge" "my_challenge" {
name = "My Challenge"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "ctfd_challenges Data Source - terraform-provider-ctfd"
page_title: "ctfd_challenges_dynamic Data Source - terraform-provider-ctfd"
subcategory: ""
description: |-

---

# ctfd_challenges (Data Source)
# ctfd_challenges_dynamic (Data Source)



Expand All @@ -25,21 +25,18 @@ description: |-

Read-Only:

- `attribution` (String) Attribution to the creator(s) of the challenge.
- `category` (String) Category of the challenge that CTFd groups by on the web UI.
- `connection_info` (String) Connection Information to connect to the challenge instance, useful for pwn or web pentest.
- `decay` (Number)
- `description` (String) Description of the challenge, consider using multiline descriptions for better style.
- `function` (String) Decay function to define how the challenge value evolve through solves, either linear or logarithmic.
- `id` (String) Identifier of the challenge.
- `max_attempts` (Number) Maximum amount of attempts before being unable to flag the challenge.
- `minimum` (Number)
- `name` (String) Name of the challenge, displayed as it.
- `next` (Number) Suggestion for the end-user as next challenge to work on.
- `requirements` (Attributes) List of required challenges that needs to get flagged before this one being accessible. Useful for skill-trees-like strategy CTF. (see [below for nested schema](#nestedatt--challenges--requirements))
- `state` (String) State of the challenge, either hidden or visible.
- `tags` (List of String) List of challenge tags that will be displayed to the end-user. You could use them to give some quick insights of what a challenge involves.
- `topics` (List of String) List of challenge topics that are displayed to the administrators for maintenance and planification.
- `type` (String) Type of the challenge defining its layout, either standard or dynamic.
- `value` (Number)

<a id="nestedatt--challenges--requirements"></a>
Expand Down
48 changes: 48 additions & 0 deletions docs/data-sources/challenges_standard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "ctfd_challenges_standard Data Source - terraform-provider-ctfd"
subcategory: ""
description: |-

---

# ctfd_challenges_standard (Data Source)





<!-- schema generated by tfplugindocs -->
## Schema

### Read-Only

- `challenges` (Attributes List) (see [below for nested schema](#nestedatt--challenges))
- `id` (String) The ID of this resource.

<a id="nestedatt--challenges"></a>
### Nested Schema for `challenges`

Read-Only:

- `attribution` (String) Attribution to the creator(s) of the challenge.
- `category` (String) Category of the challenge that CTFd groups by on the web UI.
- `connection_info` (String) Connection Information to connect to the challenge instance, useful for pwn or web pentest.
- `description` (String) Description of the challenge, consider using multiline descriptions for better style.
- `id` (String) Identifier of the challenge.
- `max_attempts` (Number) Maximum amount of attempts before being unable to flag the challenge.
- `name` (String) Name of the challenge, displayed as it.
- `next` (Number) Suggestion for the end-user as next challenge to work on.
- `requirements` (Attributes) List of required challenges that needs to get flagged before this one being accessible. Useful for skill-trees-like strategy CTF. (see [below for nested schema](#nestedatt--challenges--requirements))
- `state` (String) State of the challenge, either hidden or visible.
- `tags` (List of String) List of challenge tags that will be displayed to the end-user. You could use them to give some quick insights of what a challenge involves.
- `topics` (List of String) List of challenge topics that are displayed to the administrators for maintenance and planification.
- `value` (Number)

<a id="nestedatt--challenges--requirements"></a>
### Nested Schema for `challenges.requirements`

Read-Only:

- `behavior` (String) Behavior if not unlocked, either hidden or anonymized.
- `prerequisites` (List of String) List of the challenges ID.
26 changes: 13 additions & 13 deletions docs/resources/challenge.md → docs/resources/challenge_dynamic.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "ctfd_challenge Resource - terraform-provider-ctfd"
page_title: "ctfd_challenge_dynamic Resource - terraform-provider-ctfd"
subcategory: ""
description: |-
CTFd is built around the Challenge resource, which contains all the attributes to define a part of the Capture The Flag event.
This provider builds a cleaner API on top of CTFd's one to improve its adoption and lifecycle management.
This implementation has support of a more dynamic behavior for its scoring through time/solves thus is different from a standard challenge.
---

# ctfd_challenge (Resource)
# ctfd_challenge_dynamic (Resource)

CTFd is built around the Challenge resource, which contains all the attributes to define a part of the Capture The Flag event.

This provider builds a cleaner API on top of CTFd's one to improve its adoption and lifecycle management.
This implementation has support of a more dynamic behavior for its scoring through time/solves thus is different from a standard challenge.

## Example Usage

```terraform
resource "ctfd_challenge" "http" {
resource "ctfd_challenge_dynamic" "http" {
name = "My Challenge"
category = "misc"
description = "..."
Expand All @@ -36,25 +36,25 @@ resource "ctfd_challenge" "http" {
}

resource "ctfd_flag" "http_flag" {
challenge_id = ctfd_challenge.http.id
challenge_id = ctfd_challenge_dynamic.http.id
content = "CTF{some_flag}"
}

resource "ctfd_hint" "http_hint_1" {
challenge_id = ctfd_challenge.http.id
challenge_id = ctfd_challenge_dynamic.http.id
content = "Some super-helpful hint"
cost = 50
}

resource "ctfd_hint" "http_hint_2" {
challenge_id = ctfd_challenge.http.id
challenge_id = ctfd_challenge_dynamic.http.id
content = "Even more helpful hint !"
cost = 50
requirements = [ctfd_hint.http_hint_1.id]
}

resource "ctfd_file" "http_file" {
challenge_id = ctfd_challenge.http.id
challenge_id = ctfd_challenge_dynamic.http.id
name = "image.png"
contentb64 = filebase64(".../image.png")
}
Expand All @@ -66,23 +66,23 @@ resource "ctfd_file" "http_file" {
### Required

- `category` (String) Category of the challenge that CTFd groups by on the web UI.
- `decay` (Number) The decay defines from each number of solves does the decay function triggers until reaching minimum. This function is defined by CTFd and could be configured through `.function`.
- `description` (String) Description of the challenge, consider using multiline descriptions for better style.
- `minimum` (Number) The minimum points for a dynamic-score challenge to reach with the decay function. Once there, no solve could have more value.
- `name` (String) Name of the challenge, displayed as it.
- `value` (Number) The value (points) of the challenge once solved. Internally, the provider will handle what target is legitimate depending on the `.type` value, i.e. either `value` for "standard" or `initial` for "dynamic".
- `value` (Number) The value (points) of the challenge once solved. It is mapped to `initial` under the hood, but displayed as `value` for consistency with the standard challenge.

### Optional

- `attribution` (String) Attribution to the creator(s) of the challenge.
- `connection_info` (String) Connection Information to connect to the challenge instance, useful for pwn, web and infrastructure pentests.
- `decay` (Number) The decay defines from each number of solves does the decay function triggers until reaching minimum. This function is defined by CTFd and could be configured through `.function`.
- `function` (String) Decay function to define how the challenge value evolve through solves, either linear or logarithmic.
- `max_attempts` (Number) Maximum amount of attempts before being unable to flag the challenge.
- `minimum` (Number) The minimum points for a dynamic-score challenge to reach with the decay function. Once there, no solve could have more value.
- `next` (Number) Suggestion for the end-user as next challenge to work on.
- `requirements` (Attributes) List of required challenges that needs to get flagged before this one being accessible. Useful for skill-trees-like strategy CTF. (see [below for nested schema](#nestedatt--requirements))
- `state` (String) State of the challenge, either hidden or visible.
- `tags` (List of String) List of challenge tags that will be displayed to the end-user. You could use them to give some quick insights of what a challenge involves.
- `topics` (List of String) List of challenge topics that are displayed to the administrators for maintenance and planification.
- `type` (String) Type of the challenge defining its layout/behavior, either standard or dynamic (default).

### Read-Only

Expand Down
90 changes: 90 additions & 0 deletions docs/resources/challenge_standard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "ctfd_challenge_standard Resource - terraform-provider-ctfd"
subcategory: ""
description: |-
CTFd is built around the Challenge resource, which contains all the attributes to define a part of the Capture The Flag event.
It is the first historic implementation of its kind, with basic functionalities.
---

# ctfd_challenge_standard (Resource)

CTFd is built around the Challenge resource, which contains all the attributes to define a part of the Capture The Flag event.

It is the first historic implementation of its kind, with basic functionalities.

## Example Usage

```terraform
resource "ctfd_challenge_standard" "http" {
name = "My Challenge"
category = "misc"
description = "..."
value = 500

topics = [
"Misc"
]
tags = [
"misc",
"basic"
]
}

resource "ctfd_flag" "http_flag" {
challenge_id = ctfd_challenge_standard.http.id
content = "CTF{some_flag}"
}

resource "ctfd_hint" "http_hint_1" {
challenge_id = ctfd_challenge_standard.http.id
content = "Some super-helpful hint"
cost = 50
}

resource "ctfd_hint" "http_hint_2" {
challenge_id = ctfd_challenge_standard.http.id
content = "Even more helpful hint !"
cost = 50
requirements = [ctfd_hint.http_hint_1.id]
}

resource "ctfd_file" "http_file" {
challenge_id = ctfd_challenge_standard.http.id
name = "image.png"
contentb64 = filebase64(".../image.png")
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `category` (String) Category of the challenge that CTFd groups by on the web UI.
- `description` (String) Description of the challenge, consider using multiline descriptions for better style.
- `name` (String) Name of the challenge, displayed as it.
- `value` (Number) The value (points) of the challenge once solved.

### Optional

- `attribution` (String) Attribution to the creator(s) of the challenge.
- `connection_info` (String) Connection Information to connect to the challenge instance, useful for pwn, web and infrastructure pentests.
- `max_attempts` (Number) Maximum amount of attempts before being unable to flag the challenge.
- `next` (Number) Suggestion for the end-user as next challenge to work on.
- `requirements` (Attributes) List of required challenges that needs to get flagged before this one being accessible. Useful for skill-trees-like strategy CTF. (see [below for nested schema](#nestedatt--requirements))
- `state` (String) State of the challenge, either hidden or visible.
- `tags` (List of String) List of challenge tags that will be displayed to the end-user. You could use them to give some quick insights of what a challenge involves.
- `topics` (List of String) List of challenge topics that are displayed to the administrators for maintenance and planification.

### Read-Only

- `id` (String) Identifier of the challenge.

<a id="nestedatt--requirements"></a>
### Nested Schema for `requirements`

Optional:

- `behavior` (String) Behavior if not unlocked, either hidden or anonymized.
- `prerequisites` (List of String) List of the challenges ID.
30 changes: 13 additions & 17 deletions examples/provider-install-verification/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@ provider "ctfd" {



resource "ctfd_challenge" "http" {
resource "ctfd_challenge_dynamic" "http" {
name = "HTTP Authentication"
category = "network"
description = <<-EOT
Oh non ! Je n'avais pas vu que ma connexion n'était pas chiffrée !
J'espère que personne ne m'espionnait...

Authors:
- NicolasFgrx
EOT
attribution = "NicolasFgrx"
value = 500
initial = 500
decay = 17
Expand All @@ -39,50 +37,48 @@ resource "ctfd_challenge" "http" {
}

resource "ctfd_flag" "http_flag" {
challenge_id = ctfd_challenge.http.id
challenge_id = ctfd_challenge_dynamic.http.id
content = "24HIUT{Http_1s_n0t_s3cuR3}"
}

resource "ctfd_hint" "http_hint_1" {
challenge_id = ctfd_challenge.http.id
challenge_id = ctfd_challenge_dynamic.http.id
content = "Les flux http ne sont pas chiffrés"
cost = 50
}

resource "ctfd_hint" "http_hint_2" {
challenge_id = ctfd_challenge.http.id
challenge_id = ctfd_challenge_dynamic.http.id
content = "Les informations sont POSTées en HTTP :)"
cost = 50
requirements = [ctfd_hint.http_hint_1.id]
}

resource "ctfd_file" "http_file" {
challenge_id = ctfd_challenge.http.id
challenge_id = ctfd_challenge_dynamic.http.id
name = "capture.pcapng"
contentb64 = filebase64("${path.module}/capture.pcapng")
}



resource "ctfd_challenge" "icmp" {
resource "ctfd_challenge_dynamic" "icmp" {
name = "Stealing data"
category = "network"
description = <<-EOT
L'administrateur réseau vient de nous signaler que des flux étranges étaient à destination d'un serveur.
Visiblement, il s'agit d'un serveur interne. Vous pouvez nous dire de quoi il s'agit ?

(La capture a été réalisée en dehors de l'infrastructure du CTF)

Authors:
- NicolasFgrx
EOT
attribution = "NicolasFgrx"
value = 500
decay = 17
minimum = 50
state = "visible"
requirements = {
behavior = "anonymized"
prerequisites = [ctfd_challenge.http.id]
prerequisites = [ctfd_challenge_dynamic.http.id]
}

flags = [{
Expand All @@ -99,25 +95,25 @@ resource "ctfd_challenge" "icmp" {
}

resource "ctfd_flag" "icmp_flag" {
challenge_id = ctfd_challenge.icmp.id
challenge_id = ctfd_challenge_dynamic.icmp.id
content = "24HIUT{IcmpExfiltrationIsEasy}"
}

resource "ctfd_hint" "icmp_hint_1" {
challenge_id = ctfd_challenge.icmp.id
challenge_id = ctfd_challenge_dynamic.icmp.id
content = "Vous ne trouvez pas qu'il ya beaucoup de requêtes ICMP ?"
cost = 50
}

resource "ctfd_hint" "icmp_hint_2" {
challenge_id = ctfd_challenge.icmp.id
challenge_id = ctfd_challenge_dynamic.icmp.id
content = "Pour l'exo, le ttl a été modifié, tente un `ip.ttl<=20`"
cost = 50
requirements = [ctfd_hint.icmp_hint_2.id]
}

resource "ctfd_file" "icmp_file" {
challenge_id = ctfd_challenge.icmp.id
challenge_id = ctfd_challenge_dynamic.icmp.id
name = "icmp.pcap"
contentb64 = filebase64("${path.module}/icmp.pcap")
}
Loading
Loading