


{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"ec2:CreateKeyPair",
"ec2:DescribeKeyPairs",
"ssm:PutParameter"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:DeleteKeyPair",
"ssm:DeleteParameter"
],
"Resource": "*"
}
]
}

ssh-key-gen-role





ssh-key-gen

"""
This lambda implements the custom resource handler for creating an SSH key
and storing it in SSM parameter store.
e.g.
SSHKeyCR:
Type: Custom::CreateSSHKey
Version: "1.0"
Properties:
ServiceToken: !Ref FunctionArn
KeyName: MyKey
An SSH key called MyKey will be created.
"""
import json
import urllib.request
import urllib.error
import traceback
import boto3
def log_exception():
"""Log a stack trace"""
traceback.print_exc()
def send_response(event, context, response_status):
"""Send a response to CloudFormation to handle the custom resource lifecycle"""
response_body = {
'Status': response_status,
'Reason': f'See details in CloudWatch Log Stream: {context.log_stream_name}',
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
}
print('RESPONSE BODY: \n' + json.dumps(response_body))
data = json.dumps(response_body).encode('utf-8')
req = urllib.request.Request(
event['ResponseURL'],
data=data,
headers={'Content-Length': str(len(data)), 'Content-Type': ''},
method='PUT'
)
try:
with urllib.request.urlopen(req) as response:
print(f'response.status: {response.status}, response.reason: {response.reason}')
print('response from cfn: ' + response.read().decode('utf-8'))
except urllib.error.URLError as e:
print(f"Failed to send response to CloudFormation: {e}")
log_exception()
raise Exception('Received non-200 response while sending response to AWS CloudFormation')
return True
def custom_resource_handler(event, context):
'''
This function creates a PEM key, commits it as a key pair in EC2,
and stores it, encrypted, in SSM.
'''
print("Event JSON: \n" + json.dumps(event))
pem_key_name = event['ResourceProperties']['KeyName']
response_status = 'FAILED'
ec2 = boto3.client('ec2')
ssm_client = boto3.client('ssm')
if event['RequestType'] == 'Create':
try:
print(f"Creating key name {pem_key_name}")
key = ec2.create_key_pair(KeyName=pem_key_name)
key_material = key['KeyMaterial']
param = ssm_client.put_parameter(
Name=pem_key_name,
Value=key_material,
Type='SecureString'
)
print(param)
print(f'The parameter {pem_key_name} has been created.')
response_status = 'SUCCESS'
except Exception as e:
print(f'There was an error {e} creating and committing key {pem_key_name} to the parameter store')
log_exception()
response_status = 'FAILED'
send_response(event, context, response_status)
return
if event['RequestType'] == 'Update':
# Do nothing and send a success immediately
send_response(event, context, 'SUCCESS')
return
if event['RequestType'] == 'Delete':
# Delete the entry in SSM Parameter store and EC2
try:
print(f"Deleting key name {pem_key_name}")
rm_param = ssm_client.delete_parameter(Name=pem_key_name)
print(rm_param)
ec2.delete_key_pair(KeyName=pem_key_name)
response_status = 'SUCCESS'
except Exception as e:
print(f"There was an error {e} deleting the key {pem_key_name} from SSM Parameter store or EC2")
log_exception()
response_status = 'FAILED'
send_response(event, context, response_status)
def lambda_handler(event, context):
"""Lambda handler for the custom resource"""
try:
return custom_resource_handler(event, context)
except Exception:
log_exception()
# Ensure CloudFormation receives a FAILED signal if an unexpected error occurs
send_response(event, context, 'FAILED')
raise
Hãy cùng nhau phân tích đoạn mã lệnh này có những nội dung gì nhé
Thứ nhất: Hàm Handler - mọi lambda function đều có một hàm handler và chúng được gọi khi có bất kỳ một sự kiện nào xảy ra. Nội dung của hàm Handler chỉ đơn giản gọi tới một hàm khác chứa nội dung xử lý cụ thể với sự kiện vừa xảy ra.
def lambda_handler(event, context):
"""Lambda handler for the custom resource"""
try:
return custom_resource_handler(event, context)
except Exception:
log_exception()
# Ensure CloudFormation receives a FAILED signal if an unexpected error occurs
send_response(event, context, 'FAILED')
raise
if event['RequestType'] == 'Create':
try:
print(f"Creating key name {pem_key_name}")
key = ec2.create_key_pair(KeyName=pem_key_name)
key_material = key['KeyMaterial']
param = ssm_client.put_parameter(
Name=pem_key_name,
Value=key_material,
Type='SecureString'
)
print(param)
print(f'The parameter {pem_key_name} has been created.')
response_status = 'SUCCESS'
except Exception as e:
print(f'There was an error {e} creating and committing key {pem_key_name} to the parameter store')
log_exception()
response_status = 'FAILED'
send_response(event, context, response_status)
return
method='PUT' thay cho kiểu cũ, giúp code ngắn gọn và tương thích tốt hơn với Python 3).def send_response(event, context, response_status):
"""Send a response to CloudFormation to handle the custom resource lifecycle"""
response_body = {
'Status': response_status,
'Reason': f'See details in CloudWatch Log Stream: {context.log_stream_name}',
'PhysicalResourceId': context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
}
print('RESPONSE BODY: \n' + json.dumps(response_body))
data = json.dumps(response_body).encode('utf-8')
req = urllib.request.Request(
event['ResponseURL'],
data=data,
headers={'Content-Length': str(len(data)), 'Content-Type': ''},
method='PUT'
)
try:
with urllib.request.urlopen(req) as response:
print(f'response.status: {response.status}, response.reason: {response.reason}')
print('response from cfn: ' + response.read().decode('utf-8'))
except urllib.error.URLError as e:
print(f"Failed to send response to CloudFormation: {e}")
log_exception()
raise Exception('Received non-200 response while sending response to AWS CloudFormation')
return True


