{"id":537,"date":"2021-02-04T19:04:08","date_gmt":"2021-02-04T19:04:08","guid":{"rendered":"http:\/\/kevinmichaelcoy.com\/blog\/?p=537"},"modified":"2021-02-08T21:44:49","modified_gmt":"2021-02-08T21:44:49","slug":"aws-dlm-lifecycle-policy-for-creating-snapshots-for-ebs-volumes-on-an-ec2-instance","status":"publish","type":"post","link":"http:\/\/kevinmichaelcoy.com\/blog\/2021\/02\/04\/aws-dlm-lifecycle-policy-for-creating-snapshots-for-ebs-volumes-on-an-ec2-instance\/","title":{"rendered":"AWS DLM LifeCycle Policy for Creating Snapshots for EBS Volumes on an EC2 Instance"},"content":{"rendered":"<p>It seems AWS CloudFormation does not readily support creating EBS Volume Snapshots via\u00a0<a href=\"https:\/\/docs.aws.amazon.com\/AWSCloudFormation\/latest\/UserGuide\/aws-properties-ec2-blockdev-mapping.html\">BlockDeviceMappings<\/a>&#8216;s\u00a0<a href=\"https:\/\/docs.aws.amazon.com\/AWSCloudFormation\/latest\/UserGuide\/aws-properties-ec2-blockdev-template.html\">EBS<\/a> property. Luckily there is an alternative approach that allows you to setup a DLM LifeCycle Policy which scans for EC2 Instance Tags (apparently there is also no support to really tag the Volumes directly via CloudFormation that I am aware of).<\/p>\n<p>As a result, here is how you can use the <a href=\"https:\/\/docs.aws.amazon.com\/AWSCloudFormation\/latest\/UserGuide\/aws-resource-dlm-lifecyclepolicy.html\">LifeCyclePolicy<\/a> to achieve EBS Volume Snapshots. I recommended not using <a href=\"https:\/\/docs.aws.amazon.com\/AWSCloudFormation\/latest\/UserGuide\/aws-properties-dlm-lifecyclepolicy-createrule.html\"><code>CronExpression<\/code><\/a>\u00a0when defining the Schedule, since it seems to not work. Also, be mindful, it seems some configurations here can not be easily changed via Stack updates. I had to physically delete the LifeCyclePolicy from the template &#8211;&gt; Update &#8211;&gt; add the policy back &#8211;&gt; then update once more with my changes at a couple of points. One such example:<br \/>\n<code><br \/>\nThe following parameter(s) cannot be updated: ResourceTypes (Service: AmazonDLM; Status Code: 400; Error Code: InvalidRequestException; Request ID: 4ba58c20-329a-4abf-b44b-6d2ab5db201b; Proxy: null)<br \/>\n<\/code><\/p>\n<p>Without further ado, here are the important parts of the CloudFormation template which includes both daily and hourly backups.<\/p>\n<pre class=\"line-numbers\" data-start=\"1\"><code class=\"language-json\">{\n\"DlmServiceRole\": {\n      \"Properties\": {\n        \"AssumeRolePolicyDocument\": {\n          \"Statement\": [\n            {\n              \"Action\": [\n                \"sts:AssumeRole\"\n              ],\n              \"Effect\": \"Allow\",\n              \"Principal\": {\n                \"Service\": [\n                  \"dlm.amazonaws.com\"\n                ]\n              }\n            }\n          ]\n        },\n        \"ManagedPolicyArns\": [\n          \"arn:aws:iam::aws:policy\/service-role\/AWSDataLifecycleManagerServiceRole\"\n        ],\n        \"Path\": \"\/service-role\/\"\n      },\n      \"Type\": \"AWS::IAM::Role\"\n    },\n    \"DlmLifecyclePolicy\": {\n        \"Type\": \"AWS::DLM::LifecyclePolicy\",\n        \"Properties\": {\n          \"Description\": {\n                  \"Fn::Join\": [\n                    \"\",\n                    [\n                      \"DLM Lifecycle Policy for \",\n                      {\n                        \"Ref\": \"Neo4JServerName\"\n                      },\n                      \" - \",\n                      {\n                        \"Ref\": \"AWS::StackName\"\n                      }\n                    ]\n                  ]\n                },\n          \"State\": \"ENABLED\",\n          \"ExecutionRoleArn\": {\n              \"Fn::GetAtt\": [\n                \"DlmServiceRole\",\n                \"Arn\"\n              ]\n            },\n          \"PolicyDetails\": {\n            \"ResourceTypes\": [\"INSTANCE\"],\n            \"TargetTags\": [\n              {\n                \"Key\": \"Name\",\n                \"Value\": {\n                  \"Fn::Join\": [\n                    \"\",\n                    [\n                      {\n                        \"Ref\": \"Neo4JServerName\"\n                      },\n                      \" (\",\n                      {\n                        \"Ref\": \"AWS::StackName\"\n                      },\n                      \")\"\n                    ]\n                  ]\n                }\n              }\n            ],\n            \"Schedules\": [\n                {\n                  \"Name\": {\n                      \"Fn::Join\": [\n                        \"\",\n                        [\n                          \"Hourly Database Backup Snapshots - \",\n                          {\n                            \"Ref\": \"Neo4JServerName\"\n                          },\n                          \" - \",\n                          {\n                            \"Ref\": \"AWS::StackName\"\n                          }\n                        ]\n                      ]\n                    },\n                  \"TagsToAdd\": [\n                      {\n                        \"Key\": \"type\",\n                        \"Value\": \"HourlySnapshot\"\n                      }\n                  ],\n                  \"CreateRule\": {\n                      \"Interval\": \"1\",\n                      \"IntervalUnit\": \"HOURS\",\n                      \"Times\": [\"16:00\"]\n                  },\n                  \"RetainRule\": {\n                      \"Count\": \"72\"\n                  },\n                  \"CopyTags\": \"true\",\n                  \"VariableTags\": [{\"Key\":\"instance-id\", \"Value\":\"$(instance-id)\"}, {\"Key\":\"timestamp\", \"Value\":\"$(timestamp)\"}]\n               },\n                {\n                  \"Name\": {\n                      \"Fn::Join\": [\n                        \"\",\n                        [\n                          \"Daily Database Backup Snapshots - \",\n                          {\n                            \"Ref\": \"Neo4JServerName\"\n                          },\n                          \" - \",\n                          {\n                            \"Ref\": \"AWS::StackName\"\n                          }\n                        ]\n                      ]\n                    },\n                    \"TagsToAdd\": [\n                      {\n                        \"Key\": \"type\",\n                        \"Value\": \"HourlySnapshot\"\n                      }\n                  ],\n                  \"CreateRule\": {\n                      \"Interval\": \"24\",\n                      \"IntervalUnit\": \"HOURS\",\n                      \"Times\": [\"16:00\"]\n                  },\n                  \"RetainRule\": {\n                      \"Count\": \"7\"\n                  },\n                  \"CopyTags\": \"true\",\n                  \"VariableTags\": [{\"Key\":\"instance-id\", \"Value\":\"$(instance-id)\"}, {\"Key\":\"timestamp\", \"Value\":\"$(timestamp)\"}]\n               }\n            ]\n          }\n      }\n    }\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>It seems AWS CloudFormation does not readily support creating EBS Volume Snapshots via\u00a0BlockDeviceMappings&#8216;s\u00a0EBS property. Luckily there is an alternative approach that allows you to setup a DLM LifeCycle Policy which scans for EC2 Instance Tags (apparently there is also no support to really tag the Volumes directly via CloudFormation that&#8230;<\/p>\n<p class=\"continue-reading-button\"> <a class=\"continue-reading-link\" href=\"http:\/\/kevinmichaelcoy.com\/blog\/2021\/02\/04\/aws-dlm-lifecycle-policy-for-creating-snapshots-for-ebs-volumes-on-an-ec2-instance\/\">Continue reading<i class=\"crycon-right-dir\"><\/i><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5,3],"tags":[369,377,379,381,380,382],"_links":{"self":[{"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/posts\/537"}],"collection":[{"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/comments?post=537"}],"version-history":[{"count":5,"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/posts\/537\/revisions"}],"predecessor-version":[{"id":548,"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/posts\/537\/revisions\/548"}],"wp:attachment":[{"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/media?parent=537"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/categories?post=537"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/kevinmichaelcoy.com\/blog\/wp-json\/wp\/v2\/tags?post=537"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}