Skip to content
Merged
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
43 changes: 39 additions & 4 deletions backend/resources/dynamodb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ Resources:
LocalSecondaryIndexes:
- IndexName: QuestionLSI
KeySchema:
- AttributeName: hashKey
KeyType: HASH
- AttributeName: question
KeyType: RANGE
- AttributeName: hashKey
KeyType: HASH
- AttributeName: question
KeyType: RANGE
Projection:
ProjectionType: ALL

Expand Down Expand Up @@ -140,3 +140,38 @@ Resources:
KeyType: RANGE
Projection:
ProjectionType: ALL

EntitiesParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /${self:custom.stage}-sparcs-events-entities
Type: String
Value: ${self:custom.entities}

RegistrationsParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /${self:custom.stage}-sparcs-events-registrations
Type: String
Value: ${self:custom.registrations}

PreRegistrationsParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /${self:custom.stage}-sparcs-events-preregistrations
Type: String
Value: ${self:custom.preregistrations}

EvaluationsParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /${self:custom.stage}-sparcs-events-evaluations
Type: String
Value: ${self:custom.evaluations}

EventsParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /${self:custom.stage}-sparcs-events-events
Type: String
Value: ${self:custom.events}
43 changes: 43 additions & 0 deletions backend/resources/frontend_role.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Resources:
FrontendSSMReadOnlyRole:
Type: AWS::IAM::Role
Properties:
RoleName: frontend-ssm-role-${sls:stage}
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: SSMReadOnlyAccess
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ssm:GetParameter
- ssm:GetParameters
- ssm:GetParametersByPath
Resource:
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/techtix/auth-api-url-${sls:stage}"
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/techtix/events-api-url-${sls:stage}"
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/techtix/payment-api-url-${sls:stage}"

- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/techtix/cognito-user-pool-id-${sls:stage}"
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/techtix/cognito-user-pool-client-id-${sls:stage}"
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/techtix/cognito-domain-url-${sls:stage}"
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/techtix/cognito-signin-redirect-${sls:stage}"
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/techtix/cognito-signin-redirect-local"

- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${sls:stage}-sparcs-events*"

- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sparcs-events-email-queue-url-${sls:stage}"
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sparcs-events-certificate-queue-url-${sls:stage}"

Outputs:
FrontendRoleArn:
Value: !GetAtt FrontendSSMReadOnlyRole.Arn
10 changes: 10 additions & 0 deletions backend/resources/s3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,23 @@ Resources:
Status: Enabled
CorsConfiguration:
CorsRules:
- AllowedHeaders: ["*"]
- AllowedHeaders: ["*"]
AllowedMethods: [GET, PUT, HEAD]
AllowedOrigins: ["*"]
AllowedOrigins: ["*"]
Id: ${self:custom.bucket}-name
MaxAge: "3600"
MaxAge: "3600"
PublicAccessBlockConfiguration:
BlockPublicAcls: false
IgnorePublicAcls: false
BlockPublicPolicy: false
RestrictPublicBuckets: false

BucketNameParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /${self:custom.stage}-sparcs-events-file-bucket
Type: String
Value: ${self:custom.bucket}
150 changes: 150 additions & 0 deletions backend/scripts/generate-env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import argparse
import json
import os
from enum import Enum

import boto3
from botocore.exceptions import ClientError


class Environments(str, Enum):
DEV = 'dev'
PROD = 'prod'
LOCAL = 'local'
TEST = 'test'


class ConfigAssembler:
"""
Assembles the TechTix (Backend) config file
"""

def __init__(self, aws_region='ap-southeast-1', environment=Environments.DEV.value):
self.__input_environment = environment
self.__project_name = 'sparcs-events'

# Determine the deployment stage, defaulting to 'dev' for None or 'local' environments
if not self.__input_environment or self.__input_environment == Environments.LOCAL.value:
self.__stage = Environments.DEV.value
else:
self.__stage = self.__input_environment

self.__region = 'ap-southeast-1' if aws_region is None else aws_region
self.__ssm_client = boto3.client('ssm', region_name=self.__region)
self.__secrets_client = boto3.client('secretsmanager', region_name=self.__region)
self.__base_dir = os.getcwd()

def __get_parameter(self, key, decrypt=False) -> str:
"""
Retrieves parameter values from SSM

:param key: key of parameter value to be retrieved
:param decrypt: flag if value is decrypted
:return: parameter value string
"""
kwargs = {'Name': key, 'WithDecryption': decrypt}
value = ''
try:
resp = self.__ssm_client.get_parameter(**kwargs)
except ClientError as e:
print(f'Error: {e.response["Error"]["Code"]} - {key}')
else:
value = resp['Parameter']['Value']
return value

def __get_secret(self, secret_arn) -> str:
"""
Retrieves secret value from AWS Secrets Manager

:param secret_arn: ARN of the secret to retrieve
:return: secret value string
"""
try:
resp = self.__secrets_client.get_secret_value(SecretId=secret_arn)
return resp['SecretString']
except ClientError as e:
print(f'Error retrieving secret: {e.response["Error"]["Code"]} - {secret_arn}')
return ''

@staticmethod
def escape_env_value(value: str) -> str:
return value.replace('$', '$$')

@staticmethod
def write_config(file_handle, key, value) -> None:
"""
Writes specified config key-value in the config file

:param file_handle: File pointer
:param key: key of config
:param value: value of config
:return: None
"""
entry = f'{key}={ConfigAssembler.escape_env_value(str(value))}\n'
file_handle.write(entry)

def construct_config_file(self) -> None:
"""
Constructs the config file for Helix

:return: None
"""

region = 'ap-southeast-1'
stage = self.__stage
entities_table = self.__get_parameter(f"/{stage}-sparcs-events-entities")
registrations_table = self.__get_parameter(f"/{stage}-sparcs-events-registrations")
preregistrations_table = self.__get_parameter(f"/{stage}-sparcs-events-preregistrations")
evaluations_table = self.__get_parameter(f"/{stage}-sparcs-events-evaluations")
events_table = self.__get_parameter(f"/{stage}-sparcs-events")
email_queue = self.__get_parameter(f"/sparcs-events-email-queue-url-{stage}")
certificate_queue = self.__get_parameter(f"/sparcs-events-certificate-queue-url-{stage}")
s3_bucket = self.__get_parameter(f"/{stage}-sparcs-events-file-bucket")

userpool_id = f"techtix/cognito-user-pool-id-{stage}"
userpool_client_id = f"techtix/cognito-user-pool-client-id-{stage}"

if self.__input_environment == Environments.LOCAL.value or stage == Environments.LOCAL.value:
frontend_url = 'http://localhost:3000'
else:
frontend_url = self.__get_parameter(f"techtix/frontend-url-{stage}")

# Determine if this is a local environment
is_local = (
self.__input_environment == Environments.LOCAL.value
or self.__input_environment == Environments.TEST.value
)

config_file = f'{self.__base_dir}/.env'

with open(config_file, 'w', encoding='utf-8') as file_handle:
self.write_config(file_handle, 'REGION', region)
self.write_config(file_handle, 'FRONTEND_URL', frontend_url)
self.write_config(file_handle, 'ENTITIES_TABLE', entities_table)
self.write_config(file_handle, 'REGISTRATIONS_TABLE', registrations_table)
self.write_config(file_handle, 'PREREGISTRATIONS_TABLE', preregistrations_table)
self.write_config(file_handle, 'EVALUATIONS_TABLE', evaluations_table)
self.write_config(file_handle, 'EVENTS_TABLE', events_table)
self.write_config(file_handle, 'EMAIL_QUEUE', email_queue)
self.write_config(file_handle, 'CERTIFICATE_QUEUE', certificate_queue)
self.write_config(file_handle, 'S3_BUCKET', s3_bucket)
self.write_config(file_handle, 'USERPOOL_ID', userpool_id)
self.write_config(file_handle, 'USERPOOL_CLIENT_ID', userpool_client_id)
self.write_config(file_handle, 'STAGE', stage)

print(f'Configuration file created successfully at: {config_file}')


if __name__ == '__main__':
print(Environments)
parser = argparse.ArgumentParser(description='TechTix (Backend) Configuration Assembler')
parser.add_argument('-r', '--region', help='AWS Region (default: ap-southeast-1)')
parser.add_argument('-s', '--stage', help='Environment Name (default: dev)')
args = parser.parse_args()

print('Arguments:', args)
region = args.region
input_stage = args.stage

config_assembler = ConfigAssembler(region, input_stage)
config_assembler.construct_config_file()
1 change: 1 addition & 0 deletions backend/serverless.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ resources:
- ${file(resources/api_gateway.yml)}
- ${file(resources/s3.yml)}
- ${file(resources/sqs.yml)}
- ${file(resources/frontend_role.yml)}
- Resources:
ApiGatewayCloudWatchRole:
Type: AWS::IAM::Role
Expand Down