UNPKG

@bowtie/sls

Version:

Serverless helpers & utilities

405 lines (384 loc) 15.4 kB
# Welcome to Serverless! # # This file is the main config file for your service. # It's very minimal at this point and uses default values. # You can always add more config options for more control. # We've included some commented out config examples here. # Just uncomment any of them to get that config option. # # For full config options, check the docs: # docs.serverless.com # # Happy Coding! service: sls-ci-${self:custom.serviceName}-ci plugins: - serverless-offline # - serverless-webpack # You can pin your service to only deploy with a specific Serverless version # Check out our docs for more details # frameworkVersion: "=X.X.X" package: exclude: - tmp/** - .git/** - test/** - services/** include: - "./services/${self:custom.serviceName}.yml" provider: name: aws runtime: nodejs12.x stage: dev region: ${self:custom.region} profile: ${opt:aws-profile, self:custom.service.aws.profile} apiGateway: restApiId: Fn::ImportValue: '${self:custom.serviceName}-restApiId' restApiRootResourceId: Fn::ImportValue: '${self:custom.serviceName}-restApiRootResourceId' # restApiResources: # users: { 'Fn::ImportValue': '${self:custom.serviceName}-ApiGatewayResourceUsers' } # users/me: # Fn::ImportValue: '${self:custom.serviceName}-ApiGatewayResourceUsersMe' # [HIGH] TODO: Clean this up, don't default to full access to Dynamo iamRoleStatements: - Effect: "Allow" Action: - "dynamodb:*" Resource: "*" environment: SLS_BASE_URL: { "Fn::Join" : ["", [" https://", { "Fn::ImportValue" : "${self:custom.serviceName}-restApiId" }, ".execute-api.${self:custom.region}.amazonaws.com/${self:provider.stage}" ] ] } SLS_API_BASE: ${self:custom.apiBaseUrl} SLS_STAGE: ${self:provider.stage} CTX_SECURE: sec ECR_REPO_NAME: ${self:custom.ecrRepoName} SERVICE_NAME: ${self:custom.serviceName} # TODO: Add github secret, token BUILD_BUCKET_NAME: ${self:custom.buildBucketName} SITE_BUCKET_NAME: ${self:custom.siteBucketName} ASSET_BUCKET_NAME: ${self:custom.assetBucketName} SECURE_BUCKET_NAME: ${self:custom.secureBucketName} BUILDS_TABLE_NAME: ${self:custom.buildsTableName} DEPLOYS_TABLE_NAME: ${self:custom.deploysTableName} AUDITS_TABLE_NAME: ${self:custom.auditsTableName} DOCUMENTS_TABLE_NAME: ${self:custom.documentsTableName} SUBMISSIONS_TABLE_NAME: ${self:custom.submissionsTableName} BUILD_PROJECT_NAME: ${self:custom.buildProjectName} RECAPTCHA_SECRET_KEY: ${self:custom.recaptchaSecretKey} # TODO: Add slack token for app/commands/etc SLACK_WEBHOOK: ${self:custom.service.slack.webhook, ''} SLACK_CHANNEL: ${self:custom.service.slack.channel, ''} SLACK_USERNAME: ${self:custom.service.slack.username, ''} SLACK_ICON_EMOJI: ${self:custom.service.slack.icon_emoji, ''} SLACK_ICON_URL: ${self:custom.service.slack.icon_url, ''} SEND_EMAIL_FROM: ${self:custom.sendEmailFromAddress} SEND_EMAIL_CONF: ${self:custom.sendEmailConfName} PUBNUB_PUBLISH_KEY: ${self:custom.service.pubnub.publish_key, ''} PUBNUB_SUBSCRIBE_KEY: ${self:custom.service.pubnub.subscribe_key, ''} UPDATE_ROLE_ARN: { "Fn::Join" : ["", ["arn:aws:iam::", { "Ref" : "AWS::AccountId" }, ":role/${self:custom.serviceUpdateRoleName}" ] ] } NOTIFY_SNS_ARN: { "Fn::Join" : ["", ["arn:aws:sns:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":${self:custom.stackChangeTopic}" ] ] } custom: serverless-offline: port: 5000 prefix: dev stage: dev service: ${file(./services/${env:SERVICE_NAME}.yml):${env:SERVICE_NAME}} apiVersion: v1 apiBaseUrl: "api/${self:custom.apiVersion}" region: ${opt:region, self:custom.service.aws.region} namespace: "${self:service}-${self:custom.region}" serviceName: ${env:SERVICE_NAME} ecrRepoName: ${self:custom.namespace}-repo buildBucketName: ${self:custom.namespace}-build-bucket siteBucketName: ${self:custom.namespace}-site assetBucketName: ${self:custom.namespace}-assets secureBucketName: ${self:custom.namespace}-secure buildsTableName: "${self:custom.namespace}-builds" deploysTableName: "${self:custom.namespace}-deploys" auditsTableName: "${self:custom.namespace}-audits" documentsTableName: "${self:custom.namespace}-documents" submissionsTableName: "${self:custom.namespace}-submissions" buildProjectName: "${self:custom.namespace}-build-project" # buildProjectSource: ${self:custom.service.source} buildProjectSourceType: ${self:custom.service.source.type, 'GITHUB'} buildProjectSourceBase: ${self:custom.service.source.base, 'https://github.com'} sendEmailFromAddress: ${self:custom.service.email, ''} stackChangeTopic: "${self:custom.namespace}-stack-change" buildChangeTopic: "${self:custom.namespace}-build-change" buildProjectRoleName: "${self:custom.namespace}-build-project-role" startBuildRoleName: "${self:custom.namespace}-start-build-role" sendEmailRoleName: "${self:custom.namespace}-send-email-role" sendEmailConfName: "${self:custom.namespace}-send-email-conf" apiCiRoleName: "${self:custom.namespace}-api-ci-role" notifySlackRoleName: "${self:custom.namespace}-notify-slack-role" stackUpdateRoleName: "${self:custom.namespace}-update-stack-role" serviceUpdateRoleName: "${self:custom.namespace}-update-service-role" recaptchaSecretKey: "${self:custom.service.recaptcha_secret_key, ''}" functions: info: handler: handler.info role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/info method: get cors: true builds-index: handler: handler.builds_index role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/builds method: get cors: true builds-tags: handler: handler.builds_tags role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/builds/tags method: get cors: true builds-show: handler: handler.builds_show role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/builds/{id} method: get cors: true request: parameters: paths: id: true # builds-create: # handler: handler.builds_create # role: apiCiRole # events: # - http: # path: ${self:custom.apiBaseUrl}/builds # method: post # cors: true # builds-update: # handler: handler.builds_update # role: apiCiRole # events: # - http: # path: ${self:custom.apiBaseUrl}/builds/{id} # method: put # cors: true # request: # parameters: # paths: # id: true # builds-destroy: # handler: handler.builds_destroy # role: apiCiRole # events: # - http: # path: ${self:custom.apiBaseUrl}/builds/{id} # method: delete # cors: true # request: # parameters: # paths: # id: true deploys-index: handler: handler.deploys_index role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/deploys method: get cors: true deploys-stacks: handler: handler.deploys_stacks role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/deploys/stacks method: get cors: true deploys-show: handler: handler.deploys_show role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/deploys/{id} method: get cors: true request: parameters: paths: id: true deploys-create: handler: handler.deploys_create role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/deploys method: post cors: true deploys-update: handler: handler.deploys_update role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/deploys/{id} method: put cors: true request: parameters: paths: id: true deploys-destroy: handler: handler.deploys_destroy role: apiCiRole events: - http: path: ${self:custom.apiBaseUrl}/deploys/{id} method: delete cors: true request: parameters: paths: id: true resources: Conditions: HasTargetEcs: { "Fn::Equals" : ["${self:custom.service.target}", "ecs"] } HasTargetS3: { "Fn::Equals" : ["${self:custom.service.target}", "s3"] } # HasEmailFrom: { "Fn::Not": [ "Fn::Equals": ["${self:custom.sendEmailFromAddress}", ""] ] } Resources: apiCiRole: Type: AWS::IAM::Role Properties: RoleName: ${self:custom.apiCiRoleName} AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: slsApiPolicy PolicyDocument: Version: '2012-10-17' Statement: # [HIGH] TODO: Refactor policies & access => min required perms - Effect: "Allow" Action: - "s3:*" Resource: # - 'arn:aws:s3:::${self:custom.secureBucketName}' # - 'arn:aws:s3:::${self:custom.secureBucketName}/*' - 'arn:aws:s3:::${self:custom.buildBucketName}' - 'arn:aws:s3:::${self:custom.buildBucketName}/*' - 'arn:aws:s3:::${self:custom.siteBucketName}' - 'arn:aws:s3:::${self:custom.siteBucketName}/*' # - 'arn:aws:s3:::${self:custom.assetBucketName}' # - 'arn:aws:s3:::${self:custom.assetBucketName}/*' - Effect: "Allow" Action: - "logs:CreateLogStream" Resource: - { "Fn::Join" : ["", ["arn:aws:logs:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":log-group:/aws/lambda/${self:service}-${self:provider.stage}-*:*" ] ] } - Effect: "Allow" Action: - "logs:PutLogEvents" Resource: - { "Fn::Join" : ["", ["arn:aws:logs:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":log-group:/aws/lambda/${self:service}-${self:provider.stage}-*:*:*" ] ] } - Effect: Allow Action: - dynamodb:* Resource: - { "Fn::Join" : ["", ["arn:aws:dynamodb:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":table/${self:custom.buildsTableName}"]]} - { "Fn::Join" : ["", ["arn:aws:dynamodb:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":table/${self:custom.deploysTableName}"]]} # - { "Fn::Join" : ["", ["arn:aws:dynamodb:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":table/${self:custom.documentsTableName}"]]} # - { "Fn::Join" : ["", ["arn:aws:dynamodb:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":table/${self:custom.submissionsTableName}"]]} # - { "Fn::Join" : ["", ["arn:aws:dynamodb:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":table/${self:custom.auditsTableName}"]]} # - Effect: Allow # Action: # - codebuild:BatchGetBuilds # Resource: # - { "Fn::Join" : ["", ["arn:aws:codebuild:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":project/${self:custom.buildProjectName}"]]} - Effect: Allow Action: - "logs:GetLogEvents" Resource: - { "Fn::Join" : ["", ["arn:aws:logs:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":log-group:/aws/codebuild/${self:custom.buildProjectName}:log-stream:*"]]} # - Effect: "Allow" # Action: # - "cloudformation:UpdateStack" # - "cloudformation:DescribeStacks" # Resource: # # - "*" # # [HIGH] TODO: Why was this failing perms for example-app? # - { "Fn::Join" : ["", ["arn:aws:cloudformation:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":stack/${self:custom.serviceName}-*" ] ] } # - Effect: "Allow" # Action: # - "iam:PassRole" # Resource: # - { "Fn::Join" : ["", ["arn:aws:iam::", { "Ref" : "AWS::AccountId" }, ":role/${self:custom.serviceUpdateRoleName}" ] ] } # Outputs: # buildBucket: # Description: 'buildBucket value' # Value: { "Ref": "buildBucket" } # Export: # Name: "${self:custom.serviceName}-buildBucket" # siteBucket: # Description: 'siteBucket value' # Value: { "Ref": "siteBucket" } # Export: # Name: "${self:custom.serviceName}-siteBucket" # buildProject: # Description: 'buildProject value' # Value: { "Ref": "buildProject" } # Export: # Name: "${self:custom.serviceName}-buildProject" # buildProjectRole: # Description: 'buildProjectRole value' # Value: { "Ref": "buildProjectRole" } # Export: # Name: "${self:custom.serviceName}-buildProjectRole" # buildsTable: # Description: 'buildsTable value' # Value: { "Ref": "buildsTable" } # Export: # Name: "${self:custom.serviceName}-buildsTable" # deploysTable: # Description: 'deploysTable value' # Value: { "Ref": "deploysTable" } # Export: # Name: "${self:custom.serviceName}-deploysTable" # ecrRepository: # Description: 'ecrRepository value' # Value: { "Ref": "ecrRepository" } # Export: # Name: "${self:custom.serviceName}-ecrRepository" # notifySlackRole: # Description: 'notifySlackRole value' # Value: { "Ref": "notifySlackRole" } # Export: # Name: "${self:custom.serviceName}-notifySlackRole" # startBuildRole: # Description: 'startBuildRole value' # Value: { "Ref": "startBuildRole" } # Export: # Name: "${self:custom.serviceName}-startBuildRole" # updateServiceRole: # Description: 'updateServiceRole value' # Value: { "Ref": "updateServiceRole" } # Export: # Name: "${self:custom.serviceName}-updateServiceRole" # updateStackRole: # Description: 'updateStackRole value' # Value: { "Ref": "updateStackRole" } # Export: # Name: "${self:custom.serviceName}-updateStackRole" # notifySnsTopic: # Description: 'notifySnsTopic value' # Value: { "Fn::Join" : ["", ["arn:aws:sns:${self:custom.region}:", { "Ref" : "AWS::AccountId" }, ":${self:custom.stackChangeTopic}" ] ] } # Export: # Name: "${self:custom.serviceName}-notifySnsTopic"