rCTF Docs
Overview

Upload providers

Configure file storage with local filesystem, Amazon S3, or Google Cloud Storage.

Upload providers handle storage for both challenge file attachments and team avatars. Both share the same provider, so anything you configure here applies to both.

Warning (v2 needs delete permissions)

Unlike rCTF v1, the v2 upload provider needs permission to delete objects, not just upload them. Avatar replacement and the admin-side file deletion flows both depend on it. If you reuse a v1 IAM policy that only grants s3:GetObject / s3:PutObject, add s3:DeleteObject to it (or the GCS equivalent storage.objects.delete).

Configuration#

uploadProvider:
name: uploads/s3
options:
bucketName: my-ctf-uploads
awsKeyId: AKIAIOSFODNN7EXAMPLE
awsKeySecret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
awsRegion: us-east-1

File handling#

  • Files are stored by their SHA256 hash, so uploading the same file content twice doesn’t create a duplicate.
  • All uploaded files are served with immutable cache headers (max-age=31536000).
  • Team avatars are resized to 256x256 pixels and converted to WebP format before upload. The maximum avatar size comes from the maxAvatarSize config option (default 1 MB).

Providers#

Stores files on the local filesystem. This is the default provider.

uploadProvider:
name: uploads/local
options:
uploadDirectory: /path/to/uploads # Optional
OptionDefaultDescription
uploadDirectory{cwd}/uploads/Directory for file storage

Files are served by the API server at /uploads/*. Path traversal protection is built in.

Tip

The local provider is fine for development and small CTFs. For production deployments with many participants, S3 or GCS is the better choice since it takes load off the platform server.

Stores files in an Amazon S3 bucket.

uploadProvider:
name: uploads/s3
options:
bucketName: my-ctf-uploads
awsKeyId: AKIAIOSFODNN7EXAMPLE
awsKeySecret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
awsRegion: us-east-1
OptionEnvironment VariableDescription
bucketNameRCTF_S3_BUCKETS3 bucket name
awsKeyIdRCTF_S3_KEY_IDAWS access key ID
awsKeySecretRCTF_S3_KEY_SECRETAWS secret access key
awsRegionRCTF_S3_REGIONAWS region

Files are stored with public-read ACL and attachment content disposition. The bucket has to allow public reads.

Stores files in a Google Cloud Storage bucket.

uploadProvider:
name: uploads/gcs
options:
projectId: my-gcp-project
bucketName: my-ctf-uploads
credentials:
type: service_account
project_id: my-gcp-project
private_key_id: ...
private_key: ...
client_email: ...
OptionEnvironment VariableDescription
projectIdRCTF_GCS_PROJECT_IDGCP project ID
bucketNameRCTF_GCS_BUCKETGCS bucket name
credentialsRCTF_GCS_CREDENTIALSGCP credentials object (env var accepts JSON string)

Files are stored with public visibility. The bucket has to be configured to allow public access.

Terraform templates#

The repo ships Terraform modules under deploy/terraform/storage/ that provision an S3 or GCS bucket with the right CORS rules, an IAM user/service account, and a policy scoped to exactly what rCTF needs. Each module writes the generated credentials to a local file so you can paste them straight into your rctf.d/ config.

Terminal window
cd deploy/terraform/storage/main
terraform init
terraform apply -var="region=eu-west-3" -var="bucket_name=my-ctf-uploads"

Outputs are written next to the module:

  • aws-rctf-access-key.json holds { access_key_id, secret_access_key } for the dedicated rctf-bucket IAM user.
  • rctf_iam_user_arn and bucket are Terraform outputs printed to stdout.

Drop the credentials into your config:

rctf.d/03-uploads.yaml
uploadProvider:
name: uploads/s3
options:
bucketName: my-ctf-uploads
awsKeyId: <access_key_id from aws-rctf-access-key.json>
awsKeySecret: <secret_access_key from aws-rctf-access-key.json>
awsRegion: eu-west-3

The module sets up CORS (GET, HEAD from any origin by default, which you can override with -var="cors_allowed_origins=[\"https://ctf.example.com\"]") and grants the IAM user s3:GetObject, s3:PutObject, s3:DeleteObject, plus the matching ACL actions and s3:ListBucket.

Terminal window
cd deploy/terraform/storage/gcs
terraform init
terraform apply -var="project_id=my-gcp-project" -var="region=europe-west1" -var="bucket_name=my-ctf-uploads"

Outputs are written next to the module:

  • gcs-sa-key.json holds the service-account key for the dedicated rctf-bucket service account.
  • rctf_sa_email and bucket are Terraform outputs printed to stdout.

Drop the credentials into your config (paste the contents of gcs-sa-key.json under credentials):

rctf.d/03-uploads.yaml
uploadProvider:
name: uploads/gcs
options:
projectId: my-gcp-project
bucketName: my-ctf-uploads
credentials:
type: service_account
project_id: my-gcp-project
# ...rest of gcs-sa-key.json

The module sets up CORS (GET, HEAD from any origin by default, which you can override with -var="cors_allowed_origins=[\"https://ctf.example.com\"]") and grants the service account a custom role with storage.objects.create, storage.objects.get, storage.objects.list, and storage.objects.delete.

Esc

Start typing to search the docs.