14 KiB
Task 47
The Nautilus DevOps team needs to implement priority queuing using Amazon SQS and SNS. The goal is to create a system where messages with different priorities are handled accordingly. You are required to use AWS CloudFormation to deploy the necessary resources in your AWS account. The CloudFormation template should be created on the AWS client host at /root/datacenter-priority-stack.yml, the stack name must be datacenter-priority-stack and it should create the following resources:
Two SQS queues named datacenter-High-Priority-Queue and datacenter-Low-Priority-Queue. An SNS topic named datacenter-Priority-Queues-Topic. A Lambda function named datacenter-priorities-queue-function that will consume messages from the SQS queues. The Lambda function code is provided in /root/index.py on the AWS client host. An IAM role named lambda_execution_role that provides the necessary permissions for the Lambda function to interact with SQS and SNS. Once the stack is deployed, to test the same you can publish messages to the SNS topic, invoke the Lambda function and observe the order in which they are processed by the Lambda function. The high-priority message must be processed first.
topicarn=$(aws sns list-topics --query "Topics[?contains(TopicArn, 'datacenter-Priority-Queues-Topic')].TopicArn" --output text)
aws sns publish --topic-arn $topicarn --message 'High Priority message 1' --message-attributes '{"priority" : { "DataType":"String", "StringValue":"high"}}'
aws sns publish --topic-arn $topicarn --message 'High Priority message 2' --message-attributes '{"priority" : { "DataType":"String", "StringValue":"high"}}'
aws sns publish --topic-arn $topicarn --message 'Low Priority message 1' --message-attributes '{"priority" : { "DataType":"String", "StringValue":"low"}}'
aws sns publish --topic-arn $topicarn --message 'Low Priority message 2' --message-attributes '{"priority" : { "DataType":"String", "StringValue":"low"}}'
Solution
SQS/SNS Priority Queue via CloudFormation Task (datacenter) — KodeKloud-Constrained
A CloudFormation task — deploy SNS → (filtered fan-out) → two SQS queues, plus a Lambda that drains high-priority first. The priority logic is: SNS message-attribute filter policies route priority=high messages to the high queue and priority=low to the low queue; the Lambda (provided index.py) reads the high queue before the low queue on invocation.
⚠️ KodeKloud + CloudFormation caveat (HIGHLIGHT): KodeKloud's general FAQ warns that arbitrary CloudFormation/Terraform "will almost certainly not work due to IAM restrictions." This task explicitly requires CloudFormation, which means the lab has curated the IAM permissions for this specific scenario. So it works here — but it's why the IAM role below uses managed policies, not inline (inline
PutRolePolicyis the restricted path). Don't add custom/inline policies to the role.
Where KodeKloud limits are specifically applied
| Limit | Where it lands in this task | Highlighted below |
|---|---|---|
| Lambda timeout ≤ 10s | Timeout: 10 on the function |
⚠️ HIGHLIGHT |
| Lambda memory ≤ 256 MB | MemorySize: 256 on the function |
⚠️ HIGHLIGHT |
| IAM: managed policies only, no inline/custom | Role uses ManagedPolicyArns |
⚠️ HIGHLIGHT |
| IAM: can't exceed login user's scope | AWS-managed policies (SQS/SNS/Logs Full) are within scope | ⚠️ HIGHLIGHT |
| Lambda config set at create, not updated later | All props set in the template | ⚠️ HIGHLIGHT |
| SQS/SNS "basic operations only" | Standard queues, standard topic — nothing advanced | (implicit) |
Step 1 — Write the template (everything except the embedded code)
The Lambda code from /root/index.py gets injected into the template (inline ZipFile) in Step 2, so here we write the template up to the ZipFile: | line, with the Lambda as the last resource and Code its last property.
cat > /root/datacenter-priority-stack.yml << 'YAML'
AWSTemplateFormatVersion: '2010-09-09'
Description: Priority queuing with SNS filter-policy fan-out to SQS + Lambda consumer
Resources:
HighPriorityQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: datacenter-High-Priority-Queue
LowPriorityQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: datacenter-Low-Priority-Queue
PriorityTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: datacenter-Priority-Queues-Topic
HighSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref PriorityTopic
Protocol: sqs
Endpoint: !GetAtt HighPriorityQueue.Arn
RawMessageDelivery: true
FilterPolicy:
priority:
- high
LowSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref PriorityTopic
Protocol: sqs
Endpoint: !GetAtt LowPriorityQueue.Arn
RawMessageDelivery: true
FilterPolicy:
priority:
- low
# SPLIT: one QueuePolicy per queue — SQS requires exactly one resource per statement
HighQueuePolicy:
Type: AWS::SQS::QueuePolicy
Properties:
Queues:
- !Ref HighPriorityQueue
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: "*"
Action: sqs:SendMessage
Resource: !GetAtt HighPriorityQueue.Arn
Condition:
ArnEquals:
aws:SourceArn: !Ref PriorityTopic
LowQueuePolicy:
Type: AWS::SQS::QueuePolicy
Properties:
Queues:
- !Ref LowPriorityQueue
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: "*"
Action: sqs:SendMessage
Resource: !GetAtt LowPriorityQueue.Arn
Condition:
ArnEquals:
aws:SourceArn: !Ref PriorityTopic
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: lambda_execution_role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSQSFullAccess
- arn:aws:iam::aws:policy/AmazonSNSFullAccess
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
PriorityLambda:
Type: AWS::Lambda::Function
Properties:
FunctionName: datacenter-priorities-queue-function
Handler: index.lambda_handler
Runtime: python3.13
Role: !GetAtt LambdaExecutionRole.Arn
Timeout: 10
MemorySize: 256
Environment:
Variables:
high_priority_queue: !Ref HighPriorityQueue
low_priority_queue: !Ref LowPriorityQueue
Code:
ZipFile: |
YAML
⚠️ HIGHLIGHTED limit applications in that template:
Timeout: 10— KodeKloud auto-resets Lambda timeouts > 10s to 3s and suspends the session for > 30s. 10 is the ceiling. This is a hard limit you must set here.MemorySize: 256— the lab cap; > 256 gets reset to 128. Set it explicitly.ManagedPolicyArnsinstead of inlinePolicies— the lab restricts custom/inline policy creation (yourPutRolePolicydenial earlier). Attaching AWS-managed policies is permitted because they don't exceed your login user's scope.AmazonSQSFullAccess+AmazonSNSFullAccess+AWSLambdaBasicExecutionRolecover "interact with SQS and SNS" + logging.- All function config is set at create time in the template — KodeKloud blocks post-hoc
update-function-configuration, so getting it right in the stack matters.
Step 2 — Inject /root/index.py into the template (indented under ZipFile: |)
The inline ZipFile block scalar needs each code line indented to 10 spaces (deeper than the ZipFile: | at 8). sed handles it; appending is all that's needed since the Lambda is the last resource.
sed 's/^/ /' /root/index.py >> /root/datacenter-priority-stack.yml
# Sanity-check the tail of the template shows your indented code
tail -20 /root/datacenter-priority-stack.yml
Two things to verify:
- Handler match: the template uses
Handler: index.lambda_handler. If the function inside/root/index.pyis named something other thanlambda_handler, change the handler toindex.<actual_function_name>. Check withgrep '^def ' /root/index.py. - Inline code size limit: CloudFormation inline
ZipFilecaps at ~4096 bytes.wc -c /root/index.py— if it's over 4 KB, you can't inline it; you'd zip it to S3 and useCode: {S3Bucket, S3Key}instead. A simple priority processor is almost always well under 4 KB.
Step 3 — Deploy the stack
REGION=us-east-1
aws cloudformation deploy \
--template-file /root/datacenter-priority-stack.yml \
--stack-name datacenter-priority-stack \
--capabilities CAPABILITY_NAMED_IAM \
--region $REGION
⚠️ --capabilities CAPABILITY_NAMED_IAM is mandatory — the stack creates an IAM role with an explicit name (lambda_execution_role). CloudFormation refuses to create named IAM resources without this acknowledgment (CAPABILITY_IAM alone isn't enough for named ones). Omit it and the deploy fails with an InsufficientCapabilities error.
Step 4 — Test (publish to SNS, invoke Lambda)
topicarn=$(aws sns list-topics \
--query "Topics[?contains(TopicArn, 'datacenter-Priority-Queues-Topic')].TopicArn" \
--output text)
aws sns publish --topic-arn $topicarn --message 'High Priority message 1' \
--message-attributes '{"priority":{"DataType":"String","StringValue":"high"}}'
aws sns publish --topic-arn $topicarn --message 'High Priority message 2' \
--message-attributes '{"priority":{"DataType":"String","StringValue":"high"}}'
aws sns publish --topic-arn $topicarn --message 'Low Priority message 1' \
--message-attributes '{"priority":{"DataType":"String","StringValue":"low"}}'
aws sns publish --topic-arn $topicarn --message 'Low Priority message 2' \
--message-attributes '{"priority":{"DataType":"String","StringValue":"low"}}'
# Give SNS a couple seconds to fan out to the queues, then invoke the Lambda
sleep 5
aws lambda invoke --function-name datacenter-priorities-queue-function \
--region $REGION /tmp/out.json
cat /tmp/out.json
⚠️ Don't loop the invoke — KodeKloud deletes any Lambda invoked > 300 times in an hour. A handful of test invokes is fine; don't script a hammer loop.
The priority message attribute is what the SNS filter policy keys on: high messages match HighSubscription's filter and land in the high queue; low in the low queue. The Lambda reads high first, so high-priority messages process ahead of low — the task's success condition.
Verify
# Stack created cleanly
aws cloudformation describe-stacks --stack-name datacenter-priority-stack \
--region $REGION --query 'Stacks[0].StackStatus'
# All resources present
aws cloudformation describe-stack-resources --stack-name datacenter-priority-stack \
--region $REGION --query 'StackResources[].{Type:ResourceType,Status:ResourceStatus,Id:PhysicalResourceId}' \
--output table
# Messages fanned out to the queues (before Lambda drains them)
for Q in datacenter-High-Priority-Queue datacenter-Low-Priority-Queue; do
URL=$(aws sqs get-queue-url --queue-name $Q --region $REGION --query QueueUrl --output text)
echo "$Q:"; aws sqs get-queue-attributes --queue-url $URL \
--attribute-names ApproximateNumberOfMessages --region $REGION \
--query 'Attributes.ApproximateNumberOfMessages' --output text
done
# Lambda processing order — check its logs
aws logs tail /aws/lambda/datacenter-priorities-queue-function --region $REGION --since 5m
Want: stack CREATE_COMPLETE, all resources CREATE_COMPLETE, messages present in both queues after publish, and the Lambda logs showing high-priority messages processed before low. That ordering in the logs is the task's proof.
Debug order
- Deploy fails
InsufficientCapabilities→ missing--capabilities CAPABILITY_NAMED_IAM. - Deploy fails on the IAM role (
AccessDenied/not authorized) → the lab didn't grant role creation for this scenario, or you left inlinePoliciesin the template. Confirm you're usingManagedPolicyArnsonly. If it still fails, the role may be pre-created — remove the role resource and reference the existinglambda_execution_roleARN in the function'sRole. - Messages don't reach the queues → SNS filter policy attribute mismatch (must be
priority), or theQueuePolicydidn't allow SNSSendMessage. AlsoRawMessageDelivery: truematters so the SQS message body is the raw message, not SNS-wrapped JSON — check whatindex.pyexpects. - Lambda errors on invoke →
ImportModuleError(handler/filename mismatch — must beindex.lambda_handlerforindex.py), orAccessDenied(role missing SQS/SNS perms — the managed policies cover it). - Inline code rejected at deploy →
index.py> 4096 bytes; switch to S3-packagedCode.
Full KodeKloud compliance checklist
| Constraint | Applied |
|---|---|
| Region us-east-1 | ✅ |
| Lambda timeout ≤ 10s | ⚠️✅ Timeout: 10 |
| Lambda memory ≤ 256 MB | ⚠️✅ MemorySize: 256 |
| IAM managed policies (no inline/custom) | ⚠️✅ ManagedPolicyArns |
| IAM within login-user scope | ⚠️✅ AWS-managed policies |
| Config at create, not updated later | ⚠️✅ all in template |
| SQS/SNS basic ops only (standard) | ✅ standard queue/topic |
| ≤ 300 Lambda invocations/hr | ⚠️✅ single test invoke |
| CFN named-IAM capability | ✅ CAPABILITY_NAMED_IAM |