AWS CloudFormation Stack Refactoring Guide for Efficient Resource Management

CloudFormation Benefits for Resource Management

Introduction

As cloud infrastructure grows, managing AWS resources efficiently becomes a challenge. CloudFormation simplifies infrastructure as code, making resource management and stack organization more effective. A key feature of CloudFormation is stack refactoring, which enables you to move resources between stacks without disruption. This post explores CloudFormation stack refactoring, its benefits, and how it helps maintain a structured and scalable cloud environment.

Understanding CloudFormation Stack Refactoring

Stack refactoring involves restructuring CloudFormation stacks by moving resources between them or renaming resources within the same stack. This feature is particularly useful when you need to:

– Break down large stacks into smaller, more manageable units.

– Reorganize resources to align with application architecture and business needs.

– Enhance readability by renaming logical resource IDs.

By leveraging CloudFormation stack refactoring, teams can improve infrastructure organization while maintaining stability.

Example Scenario: Moving Resources Between Stacks

To understand stack refactoring, consider a scenario where an SNS topic and a Lambda function exist within a single CloudFormation stack. As usage increases, separating the Lambda function into a new stack enhances modularity and maintainability.

1. Create a new template called before.yaml with your starting template:

“`yaml
AWSTemplateFormatVersion: “2010-09-09”

Resources:
Topic:
Type: AWS::SNS::Topic

MyFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: my-function
Handler: index.handler
Runtime: python3.12
Code:
ZipFile: |
import json
def handler(event, context):
print(json.dumps(event))
return event
Role: !GetAtt FunctionRole.Arn
Timeout: 30

Subscription:
Type: AWS::SNS::Subscription
Properties:
Endpoint: !GetAtt MyFunction.Arn
Protocol: lambda
TopicArn: !Ref Topic

FunctionInvokePermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
Principal: sns.amazonaws.com
FunctionName: !GetAtt MyFunction.Arn
SourceArn: !Ref Topic

FunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: “2012-10-17”
Statement:
– Action:
– sts:AssumeRole
Effect: Allow
Principal:
Service:
– lambda.amazonaws.com
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
ArnLike:
aws:SourceArn: !Sub “arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:my-function”
Policies:
– PolicyName: LambdaPolicy
PolicyDocument:
Version: “2012-10-17”
Statement:
– Action:
– logs:CreateLogGroup
– logs:CreateLogStream
– logs:PutLogEvents
Resource:
– arn:aws:logs:*:*:*
Effect: Allow
“`

2. Create a new stack using the before.yaml template.

“`bash
aws cloudformation create-stack –stack-name MySns –template-body file://before.yaml –capabilities CAPABILITY_IAM
“`

3. Create a new template called afterSns.yaml with the content below. This template has your SNS topic in it and has a new export in it that will export the SNS topic ARN. This export will be used by your other templates to get the required SNS topic ARN.

“`yaml
AWSTemplateFormatVersion: “2010-09-09”
Resources:
Topic:
Type: AWS::SNS::Topic
Outputs:
TopicArn:
Value: !Ref Topic
Export:
Name: TopicArn
“`

4. Create a new template called after Lambda.yaml with the content below. This template includes all the resources to create a Lambda subscription to your SNS topic. This template switched the !Ref Topic to use the exported value by using !ImportValue TopicArn.

“`yaml
AWSTemplateFormatVersion: “2010-09-09”
Resources:
Function:
Type: AWS::Lambda::Function
Properties:
FunctionName: my-function
Handler: index.handler
Runtime: python3.12
Code:
ZipFile: |
import json
def handler(event, context):
print(json.dumps(event))
return event
Role: !GetAtt FunctionRole.Arn
Timeout: 30
Subscription:
Type: AWS::SNS::Subscription
Properties:
Endpoint: !GetAtt Function.Arn
Protocol: lambda
TopicArn: !ImportValue TopicArn
FunctionInvokePermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
Principal: sns.amazonaws.com
FunctionName: !GetAtt Function.Arn
SourceArn: !ImportValue TopicArn
FunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: “2012-10-17”
Statement:
– Action:
– sts:AssumeRole
Effect: Allow
Principal:
Service:
– lambda.amazonaws.com
Condition:
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
ArnLike:
aws:SourceArn: !Sub “arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:my-function”
Policies:
– PolicyName: LambdaPolicy
PolicyDocument:
Version: “2012-10-17”
Statement:
– Action:
– logs:CreateLogGroup
– logs:CreateLogStream
– logs:PutLogEvents
Resource:
– arn:aws:logs:*:*:*
Effect: Allow
“`

5. Create a resource mappings file called refactor.json to rename the logical ID of a resource. This file defines the source and destination stack names and logical IDs for resources being refactored. If the logical IDs don’t change, this file doesn’t need to be specified.

“`json
[
{
“Source”: {
“StackName”: “MySns”,
“LogicalResourceId”: “MyFunction”
},
“Destination”: {
“StackName”: “MyLambdaSubscription”,
“LogicalResourceId”: “Function”
}
}
]
“`

6. Create a stack refactor task. You are using enable-stack-creation to tell the refactoring capability to create the destination stack for you. If the destination stack already exists, you don’t have to provide this option.

“`bash
aws cloudformation create-stack-refactor –stack-definitions StackName=MySns,TemplateBody@=file://afterSns.yaml StackName=MyLambdaSubscription,TemplateBody@=file://afterLambda.yaml –enable-stack-creation –resource-mappings file://refactor.json
“`

Results:

“`json
{
“StackRefactorId”: “56b06a9a-72ff-4f87-8205-32111bff83f9”
}
“`

Capture the stack refactor ID for the following steps.

7. Evaluate the stack refactor task.

“`bash
aws cloudformation describe-stack-refactor –stack-refactor-id 56b06a9a-72ff-4f87-8205-32111bff83f9
“`

Results:

“`json
{
“StackRefactorId”: “56b06a9a-72ff-4f87-8205-32111-bff83f9”,
“StackIds”: [
“arn:aws:cloudformation:<>:<>:stack/MySns/a10bfd30-cc67-11ef-877a-023cc5780193”,
“arn:aws:cloudformation:<>:<>:stack/MyLambdaSubscription/6d117360-cc68-11ef-ba33-06338dcc9d39”
],
“ExecutionStatus”: “AVAILABLE”,
“Status”: “CREATE_COMPLETE”
}
“`

If you forgot to capture the stack refactor ID you can run:

“`bash
aws cloudformation list-stack-refactors
“`

You can list stack the actions that the refactor did by running:

“`bash
aws cloudformation list-stack-refactor-actions –stack-refactor-id 56b06a9a-72ff-4f87-8205-32111bff83f9
“`

You will see that the refactor will create a new stack and what resources are being moved.

“`json
{
“StackRefactorActions”: [
{
“Action”: “Move”,
“Entity”: “Resource”,
“PhysicalResourceId”: “MySns-FunctionRole-BMO7ohLu4S6a”,
“Description”: “No configuration changes detected.”,
“Detection”: “Auto”,
“TagResources”: [],
“UntagResources”: [],
“ResourceMapping”: {
“Source”: {
“StackName”: “arn:aws:cloudformation:<>:<>:stack/MySns/a10bfd30-cc67-11ef-877a-023cc5780193”,
“LogicalResourceId”: “FunctionRole”
},
“Destination”: {
“StackName”: “arn:aws:cloudformation:<>:<>:stack/MyLambdaSubscription/6d117360-cc68-11ef-ba33-06338dcc9d39”,
“LogicalResourceId”: “FunctionRole”
}
}
},
{
“Action”: “Create”,
“Entity”: “Stack”,
“Description”: “Stack arn:aws:cloudformation:<>:<>:stack/MyLambdaSubscription/6d117360-cc68-11ef-ba33-06338dcc9d39 created.”,
“Detection”: “Manual”,
“TagResources”: [],
“UntagResources”: [],
“ResourceMapping”: {
“Source”: {},
“Destination”: {}
}
}
]
}
“`

8. Execute the stack refactor.

“`bash
aws cloudformation execute-stack-refactor –stack-refactor-id 56b06a9a-72ff-4f87-8205-32111bff83f9
“`

9. Wait for the stack refactor to complete. Evaluate the stack refactor status by executing:

“`bash
aws cloudformation describe-stack-refactor –stack-refactor-id 56b06a9a-72ff-4f87-8205-32111bff83f9
“`

Results:

“`json
{
“StackRefactorId”: “56b06a9a-72ff-4f87-8205-32111bff83f9”,
“StackIds”: [
“arn:aws:cloudformation:<>:<>:stack/MySns/a10bfd30-cc67-11ef-877a-023cc5780193”,
“arn:aws:cloudformation:<>:<>:stack/MyLambdaSubscription/6d117360-cc68-11ef-ba33-06338dcc9d39”
],
“ExecutionStatus”: “EXECUTE_COMPLETE”,
“Status”: “CREATE_COMPLETE”
}
“`

By using CloudFormation stack refactoring, organizations can reorganize resources dynamically, maintaining dependencies while improving modularity.

Conclusion

CloudFormation stack refactoring is a game-changer for infrastructure management, allowing teams to restructure their cloud environment without downtime. By automating resource movement, AWS eliminates the need for manual deletion and re-importing of resources. The ability to split monolithic stacks into smaller, independent units enhances maintainability and security while ensuring infrastructure efficiency.

For teams seeking to automate AWS deployments with CloudFormation, refactoring provides flexibility, ensuring that evolving business needs are met while preserving cloud stability. By integrating this feature, organizations can streamline their cloud architecture, making it easier to scale, manage, and secure resources effectively.

Cloudastra helps businesses optimize cloud resource management by implementing CloudFormation best practices, ensuring efficiency, automation, and security in an ever-evolving cloud ecosystem.

Do you like to read more educational content? Read our blogs at Cloudastra Technologies or contact us for business enquiry at Cloudastra Contact Us.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top