Here is some information about this architecture.
Here are the steps you can follow to build this solution on your own.
This project involves integrating AWS Lambda with the Systems Manager Parameter Store. You'll learn how to securely manage, retrieve, and use configuration data within your Lambda functions. This collaboration offers a structured way to manage and control sensitive information like database passwords or API keys.
If you're using the Skillmix Labs feature, open the lab settings (the beaker icon) on the right side of the code editor. Then, click the Start Lab button to start hte lab environment.
Wait for the credentials to load. Then run this in the terminal.
Be sure to enter in your own access key and secret key and name your profile 'smx-lab'.
$ aws configure --profile smx-lab
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]: us-west-2
Default output format [None]:
Note: If you're using your own AWS account you'll need to ensure that you've created and configured a named AWS CLI profile named smx-lab.
Next, we'll create the terraform
config. This config is used to specify the providers that are required for our Terraform configuration. In this case, we are specifying that we require the aws
provider from HashiCorp with a version constraint of ~> 4.22
.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.22"
}
}
required_version = ">= 0.14.9"
}
Next, we'll create the aws config which is used to configure the AWS provider in Terraform. This config specifies the AWS profile to use, which is 'smx-lab', and the region to operate in, which is 'us-west-2'.
provider "aws" {
profile = "smx-lab"
region = "us-west-2"
}
Next, we'll create the ssm_parameter_name
config. This config is used to define a variable named ssm_parameter_name
with a type of string
and a default value of ExampleParameterName
.
variable {
ssm_parameter_name = {
type = "${string}"
default = "ExampleParameterName"
}
}
Next, we'll create the aws_caller_identity
config. This config is used to retrieve information about the AWS caller identity, such as the AWS account ID and the ARN of the IAM user or role making the request.
data "aws_caller_identity" "current" {
# No configuration required
}
Next, we'll create the aws_region
config. This config is used to retrieve the current AWS region.
data "aws_region" "current" {
}
Next, we'll create the aws_partition
config. This config is used to retrieve information about the current AWS partition.
data "aws_partition" "current" {
}
Next, we'll create the archive_file config. This config is used to create a zip file from the source file app.js
located in the current module's directory. The resulting zip file will be named lambda.zip
and will also be stored in the current module's directory.
data "archive_file" "lambda_zip_file" {
type = "zip"
source_file = "${path.module}/src/app.js"
output_path = "${path.module}/lambda.zip"
}
Next, we'll create the aws_iam_policy
config. This config is used to define an IAM policy for the lambda_basic_execution_role_policy
with the name AWSLambdaBasicExecutionRole
.
data "aws_iam_policy" "lambda_basic_execution_role_policy" {
name = "AWSLambdaBasicExecutionRole"
}
Next, we'll create the aws_iam_policy_document
config. This config is used to define an IAM policy document for AWS Lambda.
data "aws_iam_policy_document" "lambda_policy_document" {
statement {
effect = "Allow"
actions = ["ssm:GetParameter", "ssm:PutParameter"]
resources = ["${aws_ssm_parameter.ssm_parameter.arn}"]
}
}
Next, we'll create the aws_lambda_function config. This config is used to define an AWS Lambda function.
resource "aws_lambda_function" "lambda_function" {
function_name = "SSMParameterFunction"
filename = "${data.archive_file.lambda_zip_file.output_path}"
source_code_hash = "${data.archive_file.lambda_zip_file.output_base64sha256}"
handler = "app.handler"
role = "${aws_iam_role.lambda_iam_role.arn}"
runtime = "nodejs14.x"
environment {
variables = {
SSMParameterName = "${var.ssm_parameter_name}"
}
}
}
Next, we'll create the aws_iam_role config. This config is used to create an AWS IAM role for a Lambda function. The role will have a name prefix of 'LambdaSSMParameterRole-' and will be associated with two managed policies: 'lambda_basic_execution_role_policy' and 'lambda_policy'. The role will also have an assume role policy that allows the Lambda service to assume this role.
resource "aws_iam_role" "lambda_iam_role" {
name_prefix = "LambdaSSMParameterRole-"
managed_policy_arns = [
"${data.aws_iam_policy.lambda_basic_execution_role_policy.arn}",
"${aws_iam_policy.lambda_policy.arn}"
]
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
Next, we'll create the aws_iam_policy
config. This config is used to define an IAM policy in AWS.
resource "aws_iam_policy" "lambda_policy" {
name_prefix = "lambda_policy-"
path = "/"
policy = "${data.aws_iam_policy_document.lambda_policy_document.json}"
lifecycle {
create_before_destroy = true
}
}
Next, we'll create the aws_ssm_parameter
config. This config is used to create an AWS Systems Manager Parameter Store parameter.
resource "aws_ssm_parameter" "ssm_parameter" {
name = "${var.ssm_parameter_name}"
type = "String"
value = "{\"key1\":\"value1\"}"
}
Next, we'll create the LambdaFunctionName config. This config is used to output the name of the Lambda function.
output "LambdaFunctionName" {
value = aws_lambda_function.lambda_function.arn
description = "Lambda function name."
}
Deploy the Solution
Let's deploy this thing! If you haven't done so, start the Skillmix lab session and get the account credentials. Configure your Terraform environment to use those credentials.
Then, open a terminal or command prompt, navigate to the folder with your Terraform file, and execute these commands:
# initiatlize the project
$ terraform init
# show the plan
$ terraform plan
# apply the changes
$ terraform apply
Wait for the changes to be applied before proceeding.
This pattern creates an AWS Lambda function and an AWS Systems Manager Parameter Store parameter. The parameter is added as a function environment variable named "SSMParameterName". The function execution role only allows Get and Put actions on the parameter. The function supports a JSON event in the following format:
{
"method": "{GET || PUT}",
"body": "{NewParameterValue}"
}
The method can be either GET (retrieve current parameter value) or PUT (update parameter with new value). The body of the event is used to define the new value of the parameter.
The function code can easily be modified to support an Amazon API Gateway API event by changing the format for method:
API v1 event: event.httpMethod
API v2 event: event.requestContext.http.method
Once the application is deployed, navigate to the Lambda function and configure GET and PUT test events. Invoke the function using each test event. Review the Amazon CloudWatch Logs for details on the function invocation. Navigate to the AWS Systems Manager Paramater Store to observe changes to the parameter value after a PUT event.
Example GET test event:
{
"method": "GET",
"body": ""
}
Response:
{
"statusCode": 200,
"body": "{\"Parameter\":{\"Name\":\"ExampleParameterName\",\"Type\":\"String\",\"Value\":\"{\\\"key1\\\":\\\"value1\\\"}\",\"Version\":5,\"LastModifiedDate\":\"2021-04-02T13:46:55.828Z\",\"ARN\":\"arn:aws:ssm:us-east-2:{AwsAccount}:parameter/ExampleParameterName\",\"DataType\":\"text\"}}"
}
Example PUT test event:
{
"method": "PUT",
"body": "{\"key1\":\"value1\", \"key2\":\"value2\"}"
}
Response:
{
"statusCode": 200,
"body": "{\"Version\":6,\"Tier\":\"Standard\"}"
}
Source: https://github.com/aws-samples/serverless-patterns/tree/main/lambda-ssm-parameter-terraform