-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added use cert and key from secret manager (#39)
- Loading branch information
Showing
5 changed files
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Introduction | ||
This directory is still **WIP** | ||
|
||
It will contain POC of obtaining secrets from AWS Systems Manager Parameter Store. | ||
|
||
This POC is meant to showcase how you can put your authentication secrets in AWS Systems Manager Parameter Store and retrieve them to use when calling our APIs | ||
|
||
There are also samples in the `secrets-manager-samples` folder if you wish to use AWS Secrets Manager instead. | ||
|
||
# Description of files | ||
|
||
`lambda_function.py` contains the lambda function POC | ||
|
||
- Permissions given to the lambda function: | ||
- AWSLambdaBasicExecutionRole (AWS managed) | ||
- KmsDecrypt | ||
``` | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Sid": "VisualEditor0", | ||
"Effect": "Allow", | ||
"Action": "kms:Decrypt", | ||
"Resource": "*" | ||
} | ||
] | ||
} | ||
``` | ||
- SecretsPolicy | ||
``` | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Sid": "VisualEditor0", | ||
"Effect": "Allow", | ||
"Action": [ | ||
"secretsmanager:GetSecretValue" | ||
], | ||
"Resource": "*" | ||
} | ||
] | ||
} | ||
``` | ||
To import dependencies into AWS Lambda, you can add them via custom layers. The steps to do so are described [here](https://stackoverflow.com/questions/65975883/aws-lambda-python-error-runtime-importmoduleerror) | ||
The minimum dependancy required to run the lambda function provided is: | ||
- requests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# Use this code snippet in your app. | ||
# If you need more information about configurations | ||
# or implementing the sample code, visit the AWS docs: | ||
# https://aws.amazon.com/developer/language/python/ | ||
|
||
import certifi | ||
import requests | ||
import json | ||
from tempfile import NamedTemporaryFile # noqa: E402 | ||
|
||
import boto3 | ||
from botocore.exceptions import ClientError | ||
|
||
course_run_id = "35423" | ||
endpoint = f"https://uat-api.ssg-wsg.sg/courses/courseRuns/id/{course_run_id}" | ||
params = {"includeExpiredCourses": "true"} | ||
header = { | ||
"accept": "application/json", | ||
"Content-Type": "application/json"} | ||
|
||
|
||
def lambda_handler(event, context): | ||
secrets = json.loads(get_secret()) | ||
cert_pem = create_temp_file(secrets["cert"]) | ||
key_pem = create_temp_file(secrets["key"]) | ||
response = view_course_run(cert_pem, key_pem) | ||
print(response) | ||
|
||
|
||
def get_secret(): | ||
|
||
secret_name = "SampleApp/testing" | ||
region_name = "ap-southeast-1" | ||
|
||
# Create a Secrets Manager client | ||
retrieve_secrets_session = assume_role() | ||
session = boto3.session.Session() | ||
client = retrieve_secrets_session.client( | ||
service_name='secretsmanager', | ||
region_name=region_name | ||
) | ||
|
||
try: | ||
get_secret_value_response = client.get_secret_value( | ||
SecretId=secret_name | ||
) | ||
except ClientError as e: | ||
# For a list of exceptions thrown, see | ||
# https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html | ||
raise e | ||
|
||
secret = get_secret_value_response['SecretString'] | ||
|
||
# Your code goes here. | ||
return secret | ||
|
||
|
||
def assume_role(): | ||
sts_client = boto3.client('sts') | ||
response = sts_client.assume_role( | ||
RoleArn="arn:aws:iam::767397936445:role/SampleAppRetrieveSecret", | ||
RoleSessionName="retrieve-secret-session" | ||
) | ||
|
||
new_session = boto3.Session(aws_access_key_id=response['Credentials']['AccessKeyId'], | ||
aws_secret_access_key=response['Credentials']['SecretAccessKey'], | ||
aws_session_token=response['Credentials']['SessionToken']) | ||
|
||
return new_session | ||
|
||
|
||
def create_temp_file(inputStuff): | ||
''' save input into temporary file and return file name ''' | ||
temp_file = NamedTemporaryFile( | ||
delete=False, delete_on_close=False, suffix=".pem") | ||
with open(temp_file.name, 'w') as f: | ||
f.write(inputStuff) | ||
return temp_file.name | ||
|
||
|
||
def view_course_run(cert_pem, key_pem): | ||
return requests.get(endpoint, | ||
params=params, | ||
headers=header, | ||
verify=certifi.where(), | ||
cert=(cert_pem, key_pem)) |
57 changes: 57 additions & 0 deletions
57
SSG-API-Testing-Application-v2/lambda/secrets-manager-samples/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
This directory contains files specific to using AWS Secrets Manager instead of parameter store. | ||
|
||
`deploy-secrets.yml` is the workflow file for github actions to deploy the secret to AWS Secret Manager | ||
|
||
The lambda function is given the role `SampleAppLambda` with the policies below: | ||
- AWSLambdaBasicExecutionRole (AWS managed) | ||
- StsAssumeRole (Customer inline) | ||
|
||
``` | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Sid": "VisualEditor0", | ||
"Effect": "Allow", | ||
"Action": "sts:AssumeRole", | ||
"Resource": "arn:aws:iam::YourAccountNumber:role/SampleAppRetrieveSecret" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
The role that the lambda function will assume when retrieving the secret from AWS Secrets Manager `SampleAppRetrieveSecret` with the policies below: | ||
- AWSLambdaBasicExecutionRole (AWS managed) | ||
- KmsDecrypt | ||
``` | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Sid": "VisualEditor0", | ||
"Effect": "Allow", | ||
"Action": "kms:Decrypt", | ||
"Resource": "*" | ||
} | ||
] | ||
} | ||
``` | ||
- SecretsPolicy | ||
``` | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Sid": "VisualEditor0", | ||
"Effect": "Allow", | ||
"Action": [ | ||
"secretsmanager:GetSecretValue" | ||
], | ||
"Resource": "*" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
> [!NOTE] | ||
> You can choose to remove the `AWSLambdaBasicExecutionRole` policy from the `SampleAppRetrieveSecret` role if logging to CloudWatch is not required. This ensures the role adheres to the principle of least privilege by only granting the permissions necessary for its task. |
58 changes: 58 additions & 0 deletions
58
SSG-API-Testing-Application-v2/lambda/secrets-manager-samples/deploy-secrets.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
name: "Deploy Secrets to AWS Secrets Manager" | ||
|
||
on: workflow_dispatch | ||
|
||
jobs: | ||
deploy-secrets: | ||
name: "Deploy to AWS Secrets Manager" | ||
runs-on: ubuntu-latest | ||
environment: dev | ||
|
||
steps: | ||
- name: Checkout Repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Set up Terraform | ||
uses: hashicorp/setup-terraform@v3 | ||
|
||
- name: Verify Terraform Script | ||
id: create-backend-verify | ||
working-directory: ./SSG-API-Testing-Application-v2/lambda/deploy/ | ||
run: | | ||
terraform fmt | ||
terraform fmt -check | ||
- name: Initialise Backend | ||
id: init-backend | ||
working-directory: ./SSG-API-Testing-Application-v2/lambda/deploy/ | ||
run: terraform init | ||
|
||
- name: Validate Terraform Script | ||
id: create-backend-validate | ||
working-directory: ./SSG-API-Testing-Application-v2/lambda/deploy/ | ||
run: terraform validate | ||
|
||
# Generates an execution plan for Terraform | ||
- name: Terraform Plan | ||
id: plan | ||
working-directory: ./SSG-API-Testing-Application-v2/lambda/deploy/ | ||
env: | ||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | ||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | ||
AWS_REGION: ${{ env.AWS_REGION }} | ||
# this is the secret value that will be placed in aws secret manager | ||
TF_VAR_secret_value: ${{ secrets.AWS_SECRET }} | ||
run: terraform plan | ||
|
||
# On push to "main", build or change infrastructure according to Terraform configuration files | ||
- name: Terraform Apply | ||
working-directory: ./SSG-API-Testing-Application-v2/lambda/deploy/ | ||
id: apply | ||
env: | ||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | ||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | ||
AWS_REGION: ${{ env.AWS_REGION }} | ||
# this is the secret value that will be placed in aws secret manager | ||
TF_VAR_secret_value: ${{ secrets.AWS_SECRET }} | ||
run: terraform apply -auto-approve | ||
continue-on-error: true |
22 changes: 22 additions & 0 deletions
22
SSG-API-Testing-Application-v2/lambda/secrets-manager-samples/deploy/secretsmanager.tf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Define input variable for the secret value | ||
variable "secret_value" { | ||
description = "The value of the secret to be stored" | ||
type = string | ||
sensitive = true | ||
} | ||
|
||
provider "aws" { | ||
region = "ap-southeast-1" | ||
} | ||
|
||
resource "aws_secretsmanager_secret" "example_secret" { | ||
name = "SampleApp/test" # Name of the secret | ||
} | ||
|
||
resource "aws_secretsmanager_secret_version" "example_secret_version" { | ||
secret_id = aws_secretsmanager_secret.example_secret.id | ||
secret_string = jsonencode({ | ||
test_secret = var.secret_value | ||
}) | ||
} | ||
|