Enhancing Security using AWS Secret Manager
Published: 2024-02-09 07:59:33

Managing secrets such as database credentials, API keys, and other sensitive information is a critical aspect of cloud security. Exposing these secrets can lead to unauthorized access and potentially compromise your cloud environment.

**Secrets Manager**

This service is designed specifically for handling secrets, it enables you to easily rotate, manage, and retrieve database credentials, API keys, and other secrets throughout their lifecycle. Secrets Manager integrates with AWS services such as such as Amazon Redshift, Amazon DocumentDB (MongoDb), and Amazon Relational Database Service (Amazon RDS) and supports the automatic rotation of secrets.

**Lab**
In this hands-on task, we will illustrate the process of safeguarding an application through the secure storage of a Google MapsApi key and a DockerHubPassword where we will employ secret rotation techniques. We will utilize an AWS Lambda function to access the stored secrets.

**_Step 1: Setting Up AWS Secrets Manager_**

• Navigate to the AWS Secrets Manager console and create a new secret
![Image1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02ydg4zszdgnhgna10q5.PNG)
• Choose "Other type of secrets" if your application uses a custom type of secret Input your Google mapsAPI credentials or secret information and move on to the next step.
![image2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44hp0ebage5hfdj859hu.PNG)
• Configure a secret name eg. test-key and a description, and move on to the next step. In this part, we will create a secret that does not require automatic rotation.
![Image3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93brpebouedlopsigzox.PNG)

**_Step 2: Accessing Secrets from Your AWS Lambda Function_**

• Create a lambda function eg.SecretsMangerKeyRetrival. Adapt the AWS Lambda function to fetch the secret eg. test-key.
![Image4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tmp8fygqsdb8xivl1ubt.PNG)

• Utilize the AWS SDK (e.g., Boto3 for Python) in Lambda to invoke the get_secret_value API.
```
import json
import boto3
import base64

# Your secret's name and region
secret_name = "test-key"
region_name = "us-east-1"

#Set up our Session and Client
session = boto3.session.Session()
client = session.client(
    service_name='secretsmanager',
    region_name=region_name
)

def lambda_handler(event, context):

    # Calling SecretsManager
    get_secret_value_response = client.get_secret_value(
        SecretId=secret_name
    )
    
    #Raw Response
    print(get_secret_value_response)
   
    #Extracting the key/value from the secret
    secret = get_secret_value_response['SecretString']
    print(secret)
```


• Click on the role on the configuration which will direct you to the IAM console. Add the custom policy that will enable the Lambda function Assign with the necessary permissions for accessing secrets in Secrets Manager.

```
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "VisualEditor0",
			"Effect": "Allow",
			"Action": "secretsmanager:GetSecretValue",
			"Resource": "arn:aws:secretsmanager:us-east-1:799151699415:secret:DockerHubSecret-3Y8fsD"
		}
	]
}
```

• When one tests the function the credentials that were stored in the AWS Secrets Manager will be displayed. In this case, the secret name test-key displays the Google Maps API credentials.

![Image5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2p0gnujcixbh2cu06z23.PNG)

**Using Secret Rotation configuration**

**_Step 1: Setting Up AWS Secrets Manager_**

• Navigate to the AWS Secrets Manager console and create a new secret e.g DockerHubPaasword
![Image6](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8owzmz6eot3u8lvqyaty.PNG)

• Configure the Rotation Schedule minimum time unit is 4 hours. One can specify the secret to change after hours, days, weeks, or months.
![Image7](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hq296hahhvui446g6fa1.PNG)

**_Step 2: Accessing Secrets from Your AWS Lambda Function_**

• Create a lambda function eg. SecretsRotationalFunction. Adapt the AWS Lambda function to fetch the secret eg.DockerHubSecret.

![Image8](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5cvlq1rql2sin27llbyp.PNG)

• Utilize the AWS SDK (e.g., Boto3 for Python) in Lambda to invoke the get_secret_value API.

```
import json
import boto3
import base64

def lambda_handler(event, context):
    arn = event['SecretId']
    token = event['ClientRequestToken']
    step = event['Step']

    # Setup the client
    service_client = boto3.client('secretsmanager')

    # Make sure the version is staged correctly
    metadata = service_client.describe_secret(SecretId=arn)
    if not metadata['RotationEnabled']:
        raise ValueError("Secret %s is not enabled for rotation" % arn)
    
    if step == "createSecret":
        create_secret(service_client, arn, token)

    elif step == "setSecret":
        set_secret(service_client, arn, token)

    elif step == "testSecret":
        test_secret(service_client, arn, token)

    elif step == "finishSecret":
        finish_secret(service_client, arn, token)

    else:
        raise ValueError("Invalid step parameter")


def create_secret(service_client, arn, token):

    service_client.get_secret_value(SecretId=arn, VersionStage="AWSCURRENT")

    # Now try to get the secret version, if that fails, put a new secret
    try:
        service_client.get_secret_value(SecretId=arn, VersionId=token, VersionStage="AWSPENDING")
    except service_client.exceptions.ResourceNotFoundException:
        # Generate a random password
        passwd = service_client.get_random_password(ExcludeCharacters='/@"\'\\')
        # Put the secret
        service_client.put_secret_value(SecretId=arn, ClientRequestToken=token, SecretString=passwd['RandomPassword'], VersionStages=['AWSPENDING'])


def set_secret(service_client, arn, token):
    print("No database user credentials to update...")


def test_secret(service_client, arn, token):
    print("No need to testing against any service...")


def finish_secret(service_client, arn, token):
   
    # First describe the secret to get the current version
    metadata = service_client.describe_secret(SecretId=arn)

    for version in metadata["VersionIdsToStages"]:
        if "AWSCURRENT" in metadata["VersionIdsToStages"][version]:
            if version == token:
                # The correct version is already marked as current, return
                return

            # Finalize by staging the secret version current
            service_client.update_secret_version_stage(SecretId=arn, VersionStage="AWSCURRENT", MoveToVersionId=token, RemoveFromVersionId=version)
            break

```
• Click on the role on the configuration which will direct you to the IAM console. Add the custom policy that will enable the Lambda function Assign with the necessary permissions for accessing and rotating secrets in Secrets Manager.

```
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "VisualEditor0",
			"Effect": "Allow",
			"Action": [
				"secretsmanager:GetRandomPassword",
				"secretsmanager:GetSecretValue",
				"secretsmanager:DescribeSecret",
				"secretsmanager:PutSecretValue",
				"secretsmanager:UpdateSecretVersionStage"
			],
			"Resource": "*"
		}
	]
}
```

• On the configuration tab under the Resource-based policy statements edit the policy statement to enable the Secret Manager to invoke the lambda function.

![Image9](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wqlkenp38d1n3objb0bg.PNG)

• After this, when one goes back to the Secrets manager, then to the secret name under the rotation tab select the function to enable it.
![Image10](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ftlu6i9uy11nazld2ji6.PNG)
 
• When one views the secret, one identifies that the previous password has been automatically changed therefore proving the lambda function is being invoked and there is rotation of secrets.

![Image11](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b07l618kfp1nqei70h93.PNG)

![Image12](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kotoo8y6ltaimh3g1ifm.PNG)

After 4 hours.

![Image13](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gny8ar71pj0qy5azb1wp.PNG)

AWS Secrets Manager pricing is generally structured around two main cost factors: The storage of secrets AWS Secrets Manager charges a monthly fee for each secret stored. The usage of API calls typically a certain number of free API calls per month, after which you are charged a rate for additional calls.

Access to AWS Secrets Manager is managed through AWS Identity and Access Management (IAM), and activity can be monitored using AWS CloudTrail and Amazon CloudWatch. 

_**References **_
What is AWS Secrets Manager [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html)

Endre Synnes AWS Secrets Manager - Rotate Secrets

Be A Better Dev - AWS Lambda and Secrets Manager Tutorial in Python