Skip to content

Commit

Permalink
update deployment scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisandoryan committed Nov 7, 2023
1 parent c475212 commit 5d31a95
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 37 deletions.
47 changes: 16 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,4 @@
# Gateflag for CTF A&D
**Gateflag** (practically read as *getflag*) is an IaC-enabled project that allows easy deployment of Attack & Defense CTF instances with **user/root flag** obtained from IAM-controlled API endpoints.

This allows for a subtle tick implementation: easily rotates user/root flag between ticks.

![Getflag Diagram](./documentation/gateflag_overview.png "Overview of Getflag Project")

## Cloud Environments
Currently built for AWS environment with CloudFormation stack.
The so-called stack consists of:
- AWS API Gateway (REST)
- AWS EC2
- AWS IAM & Managed Policies
- VPC, Subnet & Routing, and other networking configurations.

## How It Works
Instead of directly update the value of the user/root flag inside the CTF instance on every ticks, **Gateflag** sets up two specific API endpoints (with AWS API Gateway) that the players can call to get their user/root flag. These endpoints are protected with IAM and ACL policies, so the endpoint that emits **root flag** can only be called by the **root user**, and endpoint that emits **user flag** can only be called by the **normal user**.

![Takeflag Binary](./documentation/takeflag_binary.png "How to Get Flag in Gateflag")

### POV: CTF Administrator
As the CTF Administrator, TBA.

Then, after deploying the cloud infrastructure, you may want to adjust the Flag Server to receive and process the incoming requests relayed by the AWS API Gateway.
Certainly! Here's the completed markdown with the "TBA" sections filled in:

markdown
Copy code
# Gateflag for CTF A&D
**Gateflag** (practically read as *getflag*) is an IaC-enabled project that allows easy deployment of Attack & Defense CTF instances with **user/root flag** obtained from IAM-controlled API endpoints. This allows for a subtle tick implementation: easily rotates user/root flag between ticks.

![Getflag Diagram](./documentation/gateflag_overview.png "Overview of Getflag Project")
Expand All @@ -41,13 +13,26 @@ Currently built for AWS environment with CloudFormation stack. The so-called sta
## How It Works
Instead of directly updating the value of the user/root flag inside the CTF instance on every tick, **Gateflag** sets up two specific API endpoints (with AWS API Gateway) that the players can call to get their user/root flag. These endpoints are protected with IAM and ACL policies, so the endpoint that emits **root flag** can only be called by the **root user**, and the endpoint that emits **user flag** can only be called by the **normal user**.

![Takeflag Binary](./documentation/takeflag_binary.png "How to Get Flag in Gateflag")
![Takeflag Binary](./documentation/takeflag_binary.png "When You Get Flag in Gateflag")

### POV: CTF Administrator
After deploying the cloud infrastructure, the CTF Administrator should configure the Flag Server to handle incoming requests relayed by the AWS API Gateway and issue the correct flag for the user.
After deploying the cloud infrastructure, the CTF Administrator should configure their Flag Server to handle incoming requests relayed by the AWS API Gateway and issue the correct flag for the user.

The server will receive a request with information such as the IP address of the machine and the IAM User’s ARN of the invoker.
```
POST /user_flag HTTP/1.1
Host: flaggy.free.beeceptor.com
User-Agent: AmazonAPIGateway_mxkb7e6wih
content-length: 0
Accept: application/json
X-Amzn-Apigateway-Api-Id: mxkb7e6wih
x-Amzn-Trace-Id: Root=1-653555f7-27c812bc79b53d99d0c16925
X-Forwarded-For: 18.138.134.203
X-Forwarded-Proto: https
X-User-Arn: 725126486995
X-Source-Ip: 10.0.1.101
Accept-Encoding: gzip
```

Expand Down Expand Up @@ -76,4 +61,4 @@ Before you can use AWS CLI to deploy this project using CloudFormation, you need
#### Provisioned Deployment
TBA.

## Future Improvements
## Future Improvements
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
boto3
2 changes: 2 additions & 0 deletions scripts/aws_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY', '')
AWS_REGION_NAME = 'ap-southeast-1'


ENVIRONMENT_NAME = 'Gateflag'
GATEFLAG_SECRET = os.getenv('GATEFLAG_SECRET', '_something_should_be_kept_secret_1337')
GLOBAL_TEMPLATE_FILE = 'global.yaml'
TEAM_TEMPLATE_FILE = 'team.yaml'

Expand Down
6 changes: 3 additions & 3 deletions scripts/global.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Resources:
IntegrationResponses:
- StatusCode: 200
RequestParameters:
integration.request.header.x-adce-secret: __GATEFLAG_SECRET__
integration.request.header.x-adce-secret: '__GATEFLAG_SECRET__'
integration.request.header.x-source-ip: context.identity.sourceIp
integration.request.header.x-user-arn: context.identity.userArn
MethodResponses:
Expand All @@ -98,9 +98,9 @@ Resources:
IntegrationResponses:
- StatusCode: 200
RequestParameters:
integration.request.header.x-adce-secret: __GATEFLAG_SECRET__
integration.request.header.x-adce-secret: '__GATEFLAG_SECRET__'
integration.request.header.x-source-ip: context.identity.sourceIp
integration.request.header.x-userarn: context.identity.userArn
integration.request.header.x-user-arn: context.identity.userArn
MethodResponses:
- StatusCode: "200"
ResponseModels:
Expand Down
25 changes: 22 additions & 3 deletions scripts/provision.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
TEAM: 'team',
}

COMMA = ','
GOOD_STATES = ('CREATE_COMPLETE,UPDATE_COMPLETE,UPDATE_ROLLBACK_COMPLETE').split(COMMA)
BUSY_STATES = ('CREATE_IN_PROGRESS,ROLLBACK_IN_PROGRESS,DELETE_IN_PROGRESS,UPDATE_IN_PROGRESS,UPDATE_COMPLETE_CLEANUP_IN_PROGRESS,UPDATE_ROLLBACK_IN_PROGRESS,UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS,REVIEW_IN_PROGRESS').split(COMMA)
BAD_STATES = ('CREATE_FAILED,ROLLBACK_FAILED,DELETE_FAILED,UPDATE_ROLLBACK_FAILED,DELETE_COMPLETE,ROLLBACK_COMPLETE').split(COMMA)

def get_stack_name(stack_type, suffix=''):
if suffix != '':
return '%s-%s-%s' % (aws_config.ENVIRONMENT_NAME, stack_suffixes[stack_type], suffix)
Expand All @@ -29,8 +34,20 @@ def deploy(stack_name, template_body, params):

stack_exists = False
try:
cf_client.describe_stacks(StackName=stack_name)
stack_exists = True
stack = cf_client.describe_stacks(StackName=stack_name)
print(stack['Stacks'][0]['StackStatus'])
if stack['Stacks'][0]['StackStatus'] in GOOD_STATES:
stack_exists = True
elif stack['Stacks'][0]['StackStatus'] in BUSY_STATES:
print('Stack is already building... Cannot continue.')
exit()
else:
print('Stack is in a bad state... Will perform stack deletion.')
cf_client.delete_stack(StackName=stack_name)
print('Waiting until stack %s is deleted...' % stack_name)
cf_client.get_waiter('stack_delete_complete').wait(StackName=stack_name)


except cf_client.exceptions.ClientError as e:
stack_exists = False

Expand All @@ -44,7 +61,7 @@ def deploy(stack_name, template_body, params):
Parameters=parameters,
)

print('Waiting until stack %s deployed...' % stack_name)
print('Waiting until stack %s is deployed...' % stack_name)
cf_client.get_waiter('stack_update_complete').wait(StackName=stack_name)

stack_info = cf_client.describe_stacks(StackName=stack_name)
Expand Down Expand Up @@ -110,6 +127,7 @@ def delete_stack(stack_name):
f.close()

template = template.replace('__GATEFLAG__', aws_config.ENVIRONMENT_NAME)
template = template.replace('__GATEFLAG_SECRET__', aws_config.GATEFLAG_SECRET)

outputs = deploy(get_stack_name(GLOBAL), template, aws_config.GLOBAL_TEMPLATE_PARAMETERS)
print(outputs)
Expand All @@ -133,4 +151,5 @@ def delete_stack(stack_name):
else:
for team in aws_config.TEAMS:
delete_stack(get_stack_name(TEAM, team['name']))

delete_stack(get_stack_name(GLOBAL))

0 comments on commit 5d31a95

Please sign in to comment.