Technical Articles
Automating Rotation of AWS User “Access and Secret Keys” through Serverless Technologies (SNS, LAMBDA and CloudWatch Event)
Introduction:
During SCP and AWS SQS integration many adapters in SAP Cloud Platform like “Advantaco” needs access to AWS SQS service so that it extracts the required detail from SQS and update the Backed SAP systems accordingly. For such scenario where there is a need for access to very specific service in AWS and there is a strict security compliance needs to be followed then this blog will provide right guidance on how to achieve this using serverless technologies.
The Architecture and configuration detail where there is a need to provide credentials is shown below:
Advantaco Detail
Credential Window Screen Shot
Pre-Requisite:
- Access to AWS Console with IAM, Lambda, SNS and CloudWatch access
- Basic Knowledge of how to create Roles and assigning Policies
- Basic Knowledge of Lambda
- Basic Knowledge on how to monitor the logs in CloudWatch and CloudWatch Event
Procedure/Steps:
- Create one users which will have the access to SQS queue and whose credentials are getting utilized in SCP Advantaco adapter and needs rotation of it’s credentials (Access Key and Secret Key).
- Create SNS topic which will get utilize to send mail after execution of Lambda Function.
- Do E-Mail subscription of the above SNS topic to get the mail containing the credential through mail.
- Create Lambda function to rotate the Credential and assign proper access to this function to utilize SNS and IAM (ListAccessKey, DeleteAccessKey and CreateAccessKey).
- Create CloudWatch Event to call the above function at scheduled day or time (Most probably 90 days).
- Analyze the Logs in CloudWatch whenever needed.
The pictorial view of the above steps are as follows:
Access Key Generation Process
Create user and assignation of Inline Policies:
Create user for Advantaco Adapter which has the required access to AWS SQS servivce. In my case this user needs to have the following policy in JSON format:
{
“Version”: “2012-10-17”,
“Statement”: [
{
“Sid”: “VisualEditor0”,
“Effect”: “Allow”,
“Action”: [
“sqs:DeleteMessage”,
“sqs:ListQueues”,
“sqs:ListDeadLetterSourceQueues”,
“sqs:ChangeMessageVisibility”,
“sqs:DeleteMessageBatch”,
“sqs:SendMessageBatch”,
“sqs:PurgeQueue”,
“sqs:ReceiveMessage”,
“sqs:SendMessage”,
“sqs:GetQueueAttributes”,
“sqs:CreateQueue”,
“sqs:ChangeMessageVisibilityBatch”
],
“Resource”: “*”
}
]
}
Advantaco User Policy Detail
No AWS Console Access
While creation of User it has to be make sure that AWS console access has not been given and least policy needs to be assigned as above, so that this user is not getting utilized for any other purpose.
Create SNS Topic and Subscribe the topic through E-Mail:
Go to SNS ->Create Topic->Standard
SNS Topic Creation
Now Subscribe the topic by using the Protocol “Email-JSON”
SNS Topic Creation and Subscription through Mail
Create Lambda Function and Assign Necessary Required Inline Policies:
Go to LAMBDA->Create Function->Name of the Function->Python
Please look into the following screen shot on how to create the function for more detail:
Lambda Function Creation
The Lambda Code is as follows:
import boto3
from botocore.exceptions import ClientError
import datetime
import json
iam_client = boto3.client(‘iam’)
def list_access_key(user, status_filter):
keydetails=iam_client.list_access_keys(UserName=user)
key_details={}
user_iam_details=[]
# Some user may have 2 access keys.
for keys in keydetails[‘AccessKeyMetadata’]:
key_details[‘UserName’]=keys[‘UserName’]
key_details[‘AccessKeyId’]=keys[‘AccessKeyId’]
key_details[‘status’]=keys[‘Status’]
user_iam_details.append(key_details)
key_details={}
return user_iam_details
def create_key(username):
access_key_metadata = iam_client.create_access_key(UserName=username)
access_key = access_key_metadata[‘AccessKey’][‘AccessKeyId’]
secret_key = access_key_metadata[‘AccessKey’][‘SecretAccessKey’]
#secmanagerv=secretmanager.put_secret_value(SecretId=username,SecretString=json_data)
emailmsg=”New Access Key# “+access_key+” and the Secret Key#”+secret_key+” has been generated.”
ops_sns_topic =’arn:aws:sns:eu-central-1:*:KeyRotationIn90Days‘
sns_send_report = boto3.client(‘sns’,region_name= ‘eu-central-1’)
sns_send_report.publish(TopicArn=ops_sns_topic, Message=emailmsg, Subject=”New Key create for user”+ username)
def disable_key(access_key, username):
try:
iam_client.update_access_key(UserName=username, AccessKeyId=access_key, Status=”Inactive”)
print(access_key + ” has been disabled.”)
except ClientError as e:
print(“The access key with id %s cannot be found” % access_key)
def delete_key(access_key, username):
try:
iam_client.delete_access_key(UserName=username, AccessKeyId=access_key)
print (access_key + ” has been deleted.”)
except ClientError as e:
print(“The access key with id %s cannot be found” % access_key)
def lambda_handler(event, context):
# details = iam_client.list_users(MaxItems=300)
# print(details)
user=event[“username”]
user_iam_details=list_access_key(user=user,status_filter=’Active’)
for _ in user_iam_details:
disable_key(access_key=_[‘AccessKeyId’], username=_[‘UserName’])
delete_key(access_key=_[‘AccessKeyId’], username=_[‘UserName’])
create_key(username=_[‘UserName’])
return {
‘statusCode’: 200,
‘body’: list_access_key(user=user,status_filter=’Active’)
}
Note: Please make sure that proper format (spacing) is followed while copy and pasting the above code in the given function area, otherwise it might result in some syntax error with spacing problem.
If one can see above in Lambda code (highlighted in Green) then you can see that SNS Topic has been utilized above to send a topic so that as soon as any message available SNS will send the mail to the subscriber on it’s registered e-mail ID.
The Lambda function when created it automatically creates required role for it’s execution and logging data to CloudWatch. For the current functionality to work there is a need to provide access to some specific policies through addition of Inline Policy, whose detail is given below:
Now assign the required Inline Policy to this function, process detail is as follows:
Required Inline Policy Assignation to Lambda Function
Inline Policy JSON format is given below:
{
“Version”: “2012-10-17”,
“Statement”: [
{
“Sid”: “VisualEditor0”,
“Effect”: “Allow”,
“Action”: [
“sqs:DeleteMessage”,
“sqs:ListQueues”,
“sqs:ListDeadLetterSourceQueues”,
“sqs:ChangeMessageVisibility”,
“sqs:DeleteMessageBatch”,
“sqs:SendMessageBatch”,
“sqs:PurgeQueue”,
“sqs:ReceiveMessage”,
“sqs:SendMessage”,
“sqs:GetQueueAttributes”,
“sqs:CreateQueue”,
“sqs:ChangeMessageVisibilityBatch”
],
“Resource”: “*”
}
]
}
Create a CloudWatch Event to Schedule Lambda Function:
Go to CloudWatch->Events->Rule->Create Rule
Schedule Cloud event to Execute Lambda Function every XX number of Days
Constant Used is as follows:
{“action”:”create”,”username”:”test”}
Note: In Place of “test” one can use the user name whose Access Key needs to be rotated.
Once the CloudWatch Event trigger it will delete the previous Access Key and generate a new Access Key and send the detail through mail by using SNS service automatically. The Mail content would by like the following:
Email Access Key and Secret Key
One can Take the Access key and Secret Key from Mail and update in the respective field:
Access Key Update in Adapter
Auditing Through CloudWatch Logs:
Also one can check and audit the log of execution through CloudWatch Log as well.
CloudWatch Log Analysis and Auditing
Pricing detail:
Since the entire process is based on Serverless the cost is very less. Cost would be defined by the LAMBDA Function execution time and memory used which is minimum. One can see the detail of Billed duration in CloudWatch Log as well.
Billing Detail
I get an error at line 31 of the lambda function where the email msg is declared. Did you face any such issue??