|
| 1 | +service: |
| 2 | + name: issue-tracker |
| 3 | + |
| 4 | +plugins: |
| 5 | + - serverless-webpack |
| 6 | + - serverless-iam-roles-per-function |
| 7 | + - serverless-reqvalidator-plugin |
| 8 | + - serverless-aws-documentation |
| 9 | + - serverless-plugin-tracing |
| 10 | +# package: |
| 11 | +# individually: true |
| 12 | + |
| 13 | +provider: |
| 14 | + name: aws |
| 15 | + runtime: nodejs12.x |
| 16 | + |
| 17 | + stage: ${opt:stage, 'dev'} |
| 18 | + region: ${opt:region, 'us-east-1'} |
| 19 | + |
| 20 | + tracing: |
| 21 | + lambda: true |
| 22 | + apiGateway: true |
| 23 | + |
| 24 | + environment: |
| 25 | + ISSUES_TABLE: Issues-${self:provider.stage} |
| 26 | + REPORTER_ID_INDEX: ReporterIdIndex |
| 27 | + ASSIGNEE_ID_INDEX: AssigneeIdIndex |
| 28 | + ATTACHMENTS_S3_BUCKET: serverless-issues-attachments-${self:provider.stage} |
| 29 | + SIGNED_URL_EXPIRATION: 300 |
| 30 | + |
| 31 | + iamManagedPolicies: |
| 32 | + - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" |
| 33 | + iamRoleStatements: |
| 34 | + - Effect: Allow |
| 35 | + Action: |
| 36 | + - codedeploy:* |
| 37 | + Resource: |
| 38 | + - "*" |
| 39 | + - Effect: "Allow" |
| 40 | + Action: |
| 41 | + - "xray:PutTraceSegments" |
| 42 | + - "xray:PutTelemetryRecords" |
| 43 | + Resource: |
| 44 | + - "*" |
| 45 | + |
| 46 | +custom: |
| 47 | + documentation: |
| 48 | + api: |
| 49 | + info: |
| 50 | + version: v1.0.0 |
| 51 | + title: Issue Tracker Serverless API |
| 52 | + description: Issue Tracker Serverless API |
| 53 | + models: |
| 54 | + - name: CreateIssue |
| 55 | + contentType: application/json |
| 56 | + schema: ${file(models/create-issue-request.json)} |
| 57 | + - name: UpdateIssue |
| 58 | + contentType: application/json |
| 59 | + schema: ${file(models/update-issue-request.json)} |
| 60 | + - name: DeleteIssue |
| 61 | + contentType: application/json |
| 62 | + schema: ${file(models/delete-issue-request.json)} |
| 63 | + - name: GetIssues |
| 64 | + contentType: application/json |
| 65 | + schema: ${file(models/get-issues-request.json)} |
| 66 | + |
| 67 | +functions: |
| 68 | + Auth: |
| 69 | + handler: src/lambda/auth/auth0Authorizer.handler |
| 70 | + |
| 71 | + GetAllIssues: |
| 72 | + handler: src/lambda/http/getAllIssues.handler |
| 73 | + events: |
| 74 | + - http: |
| 75 | + method: get |
| 76 | + path: issues |
| 77 | + authorizer: Auth |
| 78 | + cors: true |
| 79 | + iamRoleStatements: |
| 80 | + - Effect: Allow |
| 81 | + Action: |
| 82 | + - dynamodb:Query |
| 83 | + Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.ISSUES_TABLE}/index/${self:provider.environment.REPORTER_ID_INDEX} |
| 84 | + - Effect: Allow |
| 85 | + Action: |
| 86 | + - dynamodb:Query |
| 87 | + Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.ISSUES_TABLE}/index/${self:provider.environment.ASSIGNEE_ID_INDEX} |
| 88 | + |
| 89 | + GetIssuesByFilter: |
| 90 | + handler: src/lambda/http/getIssuesByFilter.handler |
| 91 | + events: |
| 92 | + - http: |
| 93 | + method: post |
| 94 | + path: issues |
| 95 | + authorizer: Auth |
| 96 | + cors: true |
| 97 | + reqValidatorName: RequestBodyValidator |
| 98 | + documentation: |
| 99 | + summary: Get all issues |
| 100 | + description: Get all issues by requestor or assignee |
| 101 | + requestModels: |
| 102 | + "application/json": GetIssues |
| 103 | + iamRoleStatements: |
| 104 | + - Effect: Allow |
| 105 | + Action: |
| 106 | + - dynamodb:Query |
| 107 | + Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.ISSUES_TABLE}/index/${self:provider.environment.REPORTER_ID_INDEX} |
| 108 | + - Effect: Allow |
| 109 | + Action: |
| 110 | + - dynamodb:Query |
| 111 | + Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.ISSUES_TABLE}/index/${self:provider.environment.ASSIGNEE_ID_INDEX} |
| 112 | + |
| 113 | + CreateIssue: |
| 114 | + handler: src/lambda/http/createIssue.handler |
| 115 | + events: |
| 116 | + - http: |
| 117 | + method: post |
| 118 | + path: issues/new |
| 119 | + authorizer: Auth |
| 120 | + cors: true |
| 121 | + reqValidatorName: RequestBodyValidator |
| 122 | + documentation: |
| 123 | + summary: Create a new issue |
| 124 | + description: Create a new issue |
| 125 | + requestModels: |
| 126 | + "application/json": CreateIssue |
| 127 | + iamRoleStatements: |
| 128 | + - Effect: Allow |
| 129 | + Action: |
| 130 | + - dynamodb:PutItem |
| 131 | + Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.ISSUES_TABLE} |
| 132 | + |
| 133 | + UpdateIssue: |
| 134 | + handler: src/lambda/http/updateIssue.handler |
| 135 | + events: |
| 136 | + - http: |
| 137 | + method: patch |
| 138 | + path: issues/{issueId} |
| 139 | + authorizer: Auth |
| 140 | + cors: true |
| 141 | + reqValidatorName: RequestBodyValidator |
| 142 | + documentation: |
| 143 | + summary: Update an existing issue |
| 144 | + description: Update an existing issue |
| 145 | + requestModels: |
| 146 | + "application/json": UpdateIssue |
| 147 | + iamRoleStatements: |
| 148 | + - Effect: Allow |
| 149 | + Action: |
| 150 | + - dynamodb:Query |
| 151 | + - dynamodb:GetItem |
| 152 | + - dynamodb:UpdateItem |
| 153 | + - dynamodb:PutItem |
| 154 | + Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.ISSUES_TABLE} |
| 155 | + |
| 156 | + deleteIssue: |
| 157 | + handler: src/lambda/http/deleteIssue.handler |
| 158 | + events: |
| 159 | + - http: |
| 160 | + method: delete |
| 161 | + path: issues/{issueId} |
| 162 | + authorizer: Auth |
| 163 | + cors: true |
| 164 | + iamRoleStatements: |
| 165 | + - Effect: Allow |
| 166 | + Action: |
| 167 | + - dynamodb:Query |
| 168 | + - dynamodb:DeleteItem |
| 169 | + Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.ISSUES_TABLE} |
| 170 | + |
| 171 | + GenerateUploadUrl: |
| 172 | + handler: src/lambda/http/generateUploadUrl.handler |
| 173 | + events: |
| 174 | + - http: |
| 175 | + method: post |
| 176 | + path: issues/{issueId}/attachment |
| 177 | + authorizer: Auth |
| 178 | + cors: true |
| 179 | + iamRoleStatements: |
| 180 | + - Effect: Allow |
| 181 | + Action: |
| 182 | + - s3:PutObject |
| 183 | + - s3:GetObject |
| 184 | + Resource: arn:aws:s3:::${self:provider.environment.ATTACHMENTS_S3_BUCKET}/* |
| 185 | + - Effect: Allow |
| 186 | + Action: |
| 187 | + - dynamodb:Query |
| 188 | + - dynamodb:GetItem |
| 189 | + - dynamodb:UpdateItem |
| 190 | + - dynamodb:PutItem |
| 191 | + Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.ISSUES_TABLE} |
| 192 | + |
| 193 | +resources: |
| 194 | + Resources: |
| 195 | + GatewayResponseDefault4XX: |
| 196 | + Type: AWS::ApiGateway::GatewayResponse |
| 197 | + Properties: |
| 198 | + ResponseParameters: |
| 199 | + gatewayresponse.header.Access-Control-Allow-Origin: "'*'" |
| 200 | + gatewayresponse.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" |
| 201 | + gatewayresponse.header.Access-Control-Allow-Methods: "'GET,OPTIONS,POST,PATCH,DELETE'" |
| 202 | + ResponseType: DEFAULT_4XX |
| 203 | + RestApiId: |
| 204 | + Ref: ApiGatewayRestApi |
| 205 | + |
| 206 | + RequestBodyValidator: |
| 207 | + Type: AWS::ApiGateway::RequestValidator |
| 208 | + Properties: |
| 209 | + Name: "request-body-validator" |
| 210 | + RestApiId: |
| 211 | + Ref: ApiGatewayRestApi |
| 212 | + ValidateRequestBody: true |
| 213 | + ValidateRequestParameters: false |
| 214 | + |
| 215 | + # DynamoDB config |
| 216 | + IssuesDynamoDBTable: |
| 217 | + Type: AWS::DynamoDB::Table |
| 218 | + Properties: |
| 219 | + AttributeDefinitions: |
| 220 | + - AttributeName: issueId |
| 221 | + AttributeType: S |
| 222 | + - AttributeName: reporterId |
| 223 | + AttributeType: S |
| 224 | + - AttributeName: assigneeId |
| 225 | + AttributeType: S |
| 226 | + - AttributeName: createdAt |
| 227 | + AttributeType: S |
| 228 | + KeySchema: |
| 229 | + - AttributeName: issueId |
| 230 | + KeyType: HASH |
| 231 | + - AttributeName: createdAt |
| 232 | + KeyType: RANGE |
| 233 | + GlobalSecondaryIndexes: |
| 234 | + - IndexName: ${self:provider.environment.REPORTER_ID_INDEX} |
| 235 | + KeySchema: |
| 236 | + - AttributeName: reporterId |
| 237 | + KeyType: HASH |
| 238 | + - AttributeName: createdAt |
| 239 | + KeyType: RANGE |
| 240 | + Projection: |
| 241 | + ProjectionType: ALL |
| 242 | + - IndexName: ${self:provider.environment.ASSIGNEE_ID_INDEX} |
| 243 | + KeySchema: |
| 244 | + - AttributeName: assigneeId |
| 245 | + KeyType: HASH |
| 246 | + - AttributeName: createdAt |
| 247 | + KeyType: RANGE |
| 248 | + Projection: |
| 249 | + ProjectionType: ALL |
| 250 | + BillingMode: PAY_PER_REQUEST |
| 251 | + TableName: ${self:provider.environment.ISSUES_TABLE} |
| 252 | + |
| 253 | + # S3 Config |
| 254 | + AttachmentsBucket: |
| 255 | + Type: AWS::S3::Bucket |
| 256 | + Properties: |
| 257 | + BucketName: ${self:provider.environment.ATTACHMENTS_S3_BUCKET} |
| 258 | + CorsConfiguration: |
| 259 | + CorsRules: |
| 260 | + - AllowedOrigins: |
| 261 | + - "*" |
| 262 | + AllowedHeaders: |
| 263 | + - "*" |
| 264 | + AllowedMethods: |
| 265 | + - GET |
| 266 | + - PUT |
| 267 | + - POST |
| 268 | + - DELETE |
| 269 | + - HEAD |
| 270 | + MaxAge: 3000 |
| 271 | + |
| 272 | + BucketPolicy: |
| 273 | + Type: AWS::S3::BucketPolicy |
| 274 | + Properties: |
| 275 | + PolicyDocument: |
| 276 | + Id: MyPolicy |
| 277 | + Version: "2012-10-17" |
| 278 | + Statement: |
| 279 | + - Sid: PublicReadForGetBucketObjects |
| 280 | + Effect: Allow |
| 281 | + Principal: "*" |
| 282 | + Action: "s3:GetObject" |
| 283 | + Resource: "arn:aws:s3:::${self:provider.environment.ATTACHMENTS_S3_BUCKET}/*" |
| 284 | + Bucket: !Ref AttachmentsBucket |
0 commit comments