Skip to content

Instantly share code, notes, and snippets.

@danpaldev
Created September 22, 2022 14:54
Show Gist options
  • Save danpaldev/9ca284cebc77413cfd809d201f16c522 to your computer and use it in GitHub Desktop.
Save danpaldev/9ca284cebc77413cfd809d201f16c522 to your computer and use it in GitHub Desktop.
Terraform infra
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
provider "aws" {
region = var.default_region
}
data "aws_caller_identity" "current" {}
locals {
accountId = data.aws_caller_identity.current.account_id
}
output "accountId" {
value = local.accountId
}
# Creating the S3 Bucket for storing audios
resource "aws_s3_bucket" "tts-audios" {
bucket = "audios-from-pollychan"
# TODO -> Add Lifecycle config. to delete obj in 24 hrs.
}
resource "aws_s3_bucket_acl" "tts-audios-s3-acl" {
bucket = aws_s3_bucket.tts-audios.id
acl = "private"
}
# Creating Policy
resource "aws_iam_policy" "policy_for_lambda" {
name = "polly-tts-lambda-policy"
path = "/"
description = "Required permissions for the lambda function"
# Terraform's "jsonencode" function converts a
# Terraform expression result to valid JSON syntax.
policy = jsonencode({
Version : "2012-10-17",
Statement : [
{
Sid : "AllowReadWriteOnS3",
Action : [
"s3:DeleteObject",
"s3:GetObject",
"s3:ListBucket",
"s3:PutObject"
],
Effect : "Allow",
Resource : "*"
},
{
Sid : "AllowTTSGenerationOnPolly",
Action : [
"polly:StartSpeechSynthesisTask",
"polly:SynthesizeSpeech"
],
Effect : "Allow",
Resource : "*"
},
{
Sid : "FullCloudwatchAccess",
Action : "logs:*",
Effect : "Allow",
Resource : "*"
}
]
})
}
/*
Fixing the error:
MalformedPolicyDocument: Has prohibited field Resource
https://stackoverflow.com/a/61971229/
https://stackoverflow.com/a/44581645/
*/
# Creating the role for the lambda function
resource "aws_iam_role" "permissions-lambda-tts" {
name = "PermissionsLambdaTTS"
assume_role_policy = jsonencode({
Version : "2012-10-17",
Statement : [
{
Action : "sts:AssumeRole",
Principal : {
Service : "lambda.amazonaws.com"
},
Effect : "Allow",
}
]
})
}
# Binding the Policy to the Role
resource "aws_iam_role_policy_attachment" "resource_for_attach" {
role = aws_iam_role.permissions-lambda-tts.name
policy_arn = aws_iam_policy.policy_for_lambda.arn
}
# Creating Lambda
resource "aws_lambda_function" "tts-generator" {
# If the file is not in the current working directory you will need to include a
# path.module in the filename.
runtime = "python3.9"
filename = "lambda_code.zip"
function_name = "tts-generator"
role = aws_iam_role.permissions-lambda-tts.arn
handler = "lambda_code.lambda_handler"
depends_on = [aws_iam_role.permissions-lambda-tts]
# The filebase64sha256() function is available in Terraform 0.11.12 and later
# For Terraform 0.11.11 and earlier, use the base64sha256() function and the file() function:
# source_code_hash = "${base64sha256(file("lambda_function_payload.zip"))}"
source_code_hash = filebase64sha256("lambda_code.zip")
environment {
variables = {
DEFAULT_LANG = "japanese"
}
}
}
# Creating REST API
resource "aws_api_gateway_rest_api" "polly-chan-api" {
name = "polly-chan-api"
endpoint_configuration {
types = ["REGIONAL"]
}
}
/************
I didn't create any resource (i.e., a path for the API),
because using the root one (/) is enough for my needs.
This path (/) is inherently created whenever a new REST API
is created, so I can reference the root path in my methods
without having to create it!
https://stackoverflow.com/a/61084896/
**************/
// Creating the Option Method (Needed when API Gateway is "proxied" to lambda)
resource "aws_api_gateway_method" "OPTIONS-method" {
authorization = "NONE"
http_method = "OPTIONS"
resource_id = aws_api_gateway_rest_api.polly-chan-api.root_resource_id
rest_api_id = aws_api_gateway_rest_api.polly-chan-api.id
}
resource "aws_api_gateway_integration" "OPTIONS-Integration" {
rest_api_id = aws_api_gateway_rest_api.polly-chan-api.id
resource_id = aws_api_gateway_rest_api.polly-chan-api.root_resource_id
http_method = aws_api_gateway_method.OPTIONS-method.http_method
type = "MOCK"
}
resource "aws_api_gateway_method_response" "mocked_200" {
rest_api_id = aws_api_gateway_rest_api.polly-chan-api.id
resource_id = aws_api_gateway_rest_api.polly-chan-api.root_resource_id
http_method = aws_api_gateway_method.OPTIONS-method.http_method
status_code = "200"
// This headers are used to prevent browsers from complaining about CORS
response_parameters = {
"method.response.header.Access-Control-Allow-Headers" = true,
"method.response.header.Access-Control-Allow-Methods" = true,
"method.response.header.Access-Control-Allow-Origin" = true,
}
/*
You need to add a integration_response (the resource just below this),
in order to succesfully define an empty application/json response_model
See here:
https://github.com/hashicorp/terraform/issues/10157#issuecomment-263560025
*/
response_models = {
"application/json" = "Empty"
}
}
resource "aws_api_gateway_integration_response" "MyDemoIntegrationResponse" {
rest_api_id = aws_api_gateway_rest_api.polly-chan-api.id
resource_id = aws_api_gateway_rest_api.polly-chan-api.root_resource_id
http_method = aws_api_gateway_method.OPTIONS-method.http_method
status_code = aws_api_gateway_method_response.mocked_200.status_code
response_templates = {
"application/json" = ""
}
}
// Creating the POST Method
resource "aws_api_gateway_method" "POST-method" {
authorization = "NONE"
http_method = "POST"
resource_id = aws_api_gateway_rest_api.polly-chan-api.root_resource_id
rest_api_id = aws_api_gateway_rest_api.polly-chan-api.id
}
resource "aws_api_gateway_integration" "POST-Integration" {
rest_api_id = aws_api_gateway_rest_api.polly-chan-api.id
resource_id = aws_api_gateway_rest_api.polly-chan-api.root_resource_id
http_method = aws_api_gateway_method.POST-method.http_method
integration_http_method = "POST"
type = "AWS_PROXY"
uri = aws_lambda_function.tts-generator.invoke_arn
}
// Method Configuration resource. Only created to set up the throttling limits for the API
resource "aws_api_gateway_method_settings" "all" {
rest_api_id = aws_api_gateway_rest_api.polly-chan-api.id
stage_name = aws_api_gateway_stage.polly-chan-api.stage_name
method_path = "*/*"
settings {
throttling_rate_limit = 100
throttling_burst_limit = 50
}
}
// Invoke policy to allow lambda execution. As in https://bit.ly/3BPpskU
resource "aws_lambda_permission" "api_invoke_policy" {
statement_id = "AllowExecutionFromAPIGateway"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.tts-generator.function_name
principal = "apigateway.amazonaws.com"
# More: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-control-access-using-iam-policies-to-invoke-api.html
source_arn = "arn:aws:execute-api:${var.default_region}:${local.accountId}:${aws_api_gateway_rest_api.polly-chan-api.id}/*/*/"
}
// Creating the Deployment
resource "aws_api_gateway_deployment" "polly-chan-deployment" {
rest_api_id = aws_api_gateway_rest_api.polly-chan-api.id
depends_on = [
aws_api_gateway_integration.POST-Integration,
aws_api_gateway_integration.OPTIONS-Integration
]
description = "Deployed ${timestamp()}"
}
resource "aws_api_gateway_stage" "polly-chan-api" {
deployment_id = aws_api_gateway_deployment.polly-chan-deployment.id
rest_api_id = aws_api_gateway_rest_api.polly-chan-api.id
stage_name = "dev"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment