diff --git a/.gitignore b/.gitignore index 5da9419..5bc7495 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ development/cert # Local environment variables files, typically with secrets local.env *.local.env + +# Terraform +.terraform/ diff --git a/.whitesource b/.whitesource deleted file mode 100644 index f056952..0000000 --- a/.whitesource +++ /dev/null @@ -1,8 +0,0 @@ -{ - "generalSettings": { - "shouldScanRepo": true - }, - "checkRunSettings": { - "vulnerableCheckRunConclusionLevel": "failure" - } -} \ No newline at end of file diff --git a/LICENSE b/LICENSE index 2527dee..1b42223 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 SIL International +Copyright (c) 2017-2022 SIL International Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index b1a5f5b..2f417ba 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,26 @@ To run this locally (such as for development)... ``` 5. Bring up the `idp-in-a-box` repo. See that repo's README.md for instructions. +## Serverless + +To start a local container for development of Serverless configuration: + +``` +docker-compose run --rm dev bash +``` + +## Credential Rotation + +### AWS Serverless User + +1. Use the Terraform CLI to taint the old access key +``` +terraform taint module.serverless-user.aws_iam_access_key.serverless +``` +2. Run a new plan on Terraform Cloud +3. Review the new plan and apply if it is correct +4. Copy the new key and secret from the Terraform output into Codeship + ## Glossary - `API Key`: A hex string used to identify calls to most of the endpoints on diff --git a/codeship/deploy-dev.sh b/codeship/deploy-dev.sh deleted file mode 100755 index 9c5b811..0000000 --- a/codeship/deploy-dev.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -serverless deploy -v --stage dev diff --git a/codeship/deploy-prod.sh b/codeship/deploy-prod.sh deleted file mode 100755 index 6d650c8..0000000 --- a/codeship/deploy-prod.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -serverless deploy -v --stage prod diff --git a/codeship/deploy.sh b/codeship/deploy.sh new file mode 100755 index 0000000..cb7dfb8 --- /dev/null +++ b/codeship/deploy.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +# Exit script with error if any step fails. +set -e + +# Print the Serverless version in the logs +serverless --version + +echo "Deploying stage $1..." +serverless deploy --verbose --stage "$1" diff --git a/codeship/setup.sh b/codeship/setup.sh index 9e90a59..893df5d 100755 --- a/codeship/setup.sh +++ b/codeship/setup.sh @@ -3,5 +3,5 @@ # Exit script with error if any step fails. set -e -npm install -g serverless@1 +npm install -g serverless@3.7 npm install diff --git a/codeship/test.sh b/codeship/test.sh index fadd3b6..9e998c7 100755 --- a/codeship/test.sh +++ b/codeship/test.sh @@ -3,4 +3,13 @@ # Exit script with error if any step fails. set -e +# Echo commands to console +set -x + npm test + +# Print the Serverless version in the logs +serverless --version + +# Validate Serverless config +serverless info diff --git a/development/Dockerfile b/development/Dockerfile new file mode 100644 index 0000000..5474127 --- /dev/null +++ b/development/Dockerfile @@ -0,0 +1,3 @@ +FROM node:16 + +RUN npm i -g serverless@3 diff --git a/development/create-tables.sh b/development/create-tables.sh index 9d19292..f86df01 100755 --- a/development/create-tables.sh +++ b/development/create-tables.sh @@ -2,6 +2,8 @@ set -e +set -x + aws dynamodb create-table \ --table-name development_server_api-key \ --attribute-definitions AttributeName=value,AttributeType=S \ diff --git a/docker-compose.yml b/docker-compose.yml index 813a6d5..24106ef 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,8 @@ version: "3" + services: do-full-recovery: - build: recovery/. + build: recovery volumes: - ./:/data working_dir: /data @@ -11,3 +12,12 @@ services: image: amazon/dynamodb-local ports: - "8000:8000" + + dev: + build: development + env_file: + - ./local.env + volumes: + - ./:/data + working_dir: /data + diff --git a/local.env.example b/local.env.example new file mode 100644 index 0000000..57c51ca --- /dev/null +++ b/local.env.example @@ -0,0 +1,2 @@ +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= diff --git a/serverless.yml b/serverless.yml index 2801f78..e314e81 100644 --- a/serverless.yml +++ b/serverless.yml @@ -1,6 +1,6 @@ -service: ${opt:service, 'mfa-api'} +service: mfa-api -frameworkVersion: ">=1.21.0 <2.0.0" +frameworkVersion: ^3.7.0 provider: name: aws @@ -13,11 +13,14 @@ provider: # 256 MB = 71 ms # 128 MB = 159 ms memorySize: 512 - apiKeys: + apiGateway: + apiKeys: - ${self:custom.namespace}_global - iamRoleStatements: - - Effect: Allow - Action: + iam: + role: + statements: + - Effect: Allow + Action: - dynamodb:DescribeTable - dynamodb:Query - dynamodb:Scan @@ -25,18 +28,17 @@ provider: - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem - Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:custom.namespace}_*" + Resource: "arn:aws:dynamodb:${aws:region}:*:table/${self:custom.namespace}_*" custom: - stage: ${opt:stage, self:provider.stage} - namespace: ${self:service}_${self:custom.stage} + namespace: ${self:service}_${sls:stage} apiKeyTable: ${self:custom.namespace}_api-key totpTable: ${self:custom.namespace}_totp u2fTable: ${self:custom.namespace}_u2f package: - exclude: - - node_modules/aws-sdk/** + patterns: + - '!node_modules/aws-sdk/**' functions: apiKeyActivate: @@ -179,32 +181,42 @@ resources: BillingMode: PAY_PER_REQUEST TableName: ${self:custom.u2fTable} ApiKeyActivateLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" ApiKeyCreateLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" TotpCreateLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" TotpDeleteLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" TotpValidateLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" U2fCreateAuthenticationLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" U2fCreateRegistrationLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" U2fDeleteLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" U2fValidateAuthenticationLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" U2fValidateRegistrationLogGroup: + Type: AWS::Logs::LogGroup Properties: RetentionInDays: "30" diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl new file mode 100644 index 0000000..38fe924 --- /dev/null +++ b/terraform/.terraform.lock.hcl @@ -0,0 +1,10 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "4.2.0" + constraints = "~> 4.0" + hashes = [ + "h1:qfnMtwFbsVJWvzxUCajm4zUkjEH9GDdT3FFYffEEhYQ=", + ] +} diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..f934fbd --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,20 @@ + +/* + * Create IAM user for Serverless framework to use to deploy the lambda function + */ +module "serverless-user" { + source = "silinternational/serverless-user/aws" + version = "0.1.0" + + app_name = "mfa-api" + aws_region = var.aws_region + enable_api_gateway = true +} + +output "serverless-access-key-id" { + value = module.serverless-user.aws_access_key_id +} +output "serverless-secret-access-key" { + value = module.serverless-user.aws_secret_access_key + sensitive = true +} diff --git a/terraform/providers.tf b/terraform/providers.tf new file mode 100644 index 0000000..9b7432a --- /dev/null +++ b/terraform/providers.tf @@ -0,0 +1,5 @@ +provider "aws" { + region = var.aws_region + access_key = var.aws_access_key + secret_key = var.aws_secret_key +} diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..26f1f65 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,9 @@ +variable "aws_region" { + default = "us-east-1" +} + +variable "aws_access_key" { +} + +variable "aws_secret_key" { +} diff --git a/terraform/versions.tf b/terraform/versions.tf new file mode 100644 index 0000000..76be609 --- /dev/null +++ b/terraform/versions.tf @@ -0,0 +1,10 @@ + +terraform { + required_version = ">= 1.0" + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.0" + } + } +}