CommsCentral

My Technology Adventures

Using CloudFormation with AWS Config

Posted at: 2017-02-15 @ 07:13:04

If your anything like me, you probably manage a lot of AWS accounts. Every day there will be another service that has a need for its own AWS account, be it for isolation, security or billing purposes.

To make this process easier, I have a standard set of cloud formation templates that gets deployed onto any new account, so we can ensure the new accounts meet our compliance and security needs.

One of the services we deploy is AWS Config.
I wrote and deployed a cloudformation template to setup config, it all works. Great!

A day or so later I wanted to adjust the configuration so I deleted the stack and redeployed it. The redeploy fails with an error!
Failed to put configuration recorder 'config-testing-ConfigRecorder-VMRU0MAZTLEU' because the maximum number of configuration recorders: 1 is reached.


WHAT?!?

Well, turns out that there is something interesting about ConfigRecorder object: You can only have 1 config recorder per region and you can only create it ONCE when using cloudformation!

You can however adopt a config recorder that was previously created and reuse that.
I've no idea why this is the case, it feels silly and breaks the whole idea of cloudformation, when you delete the stack you should be able to redeploy that same stack without error and hence it should remove the ConfigRecorder.

This issue probably lies with Cloudformation team vs Config team as I see that the the AWS Config API does have a DeleteConfigurationRecorder API call.

For now, to fix this issue, what I have done is have a parameter in my template for ConfigRecorderName. If that field is filled out, then I will attempt to Adopt the ConfigRecorder or that name when the stack is deployed. If that field isn't filled in, then I will create one.

The key sections of the template are shown below:

First we collect the config recorder name, in cloudformation JSON the Parameter section looks like this

"Parameters": {
"ConfigRecorderName":{
"Description": "(Optional) If we already have a config recorder - it can't be deleted - so enter its name here and we will adopt it",
"Type":"String",
"Default":""
}
}


Next we create a cloudformation Condition based on what we entered into the Parameter.
CreateWithName will be set to true if the value of the Parameter is NOT Equal to the default value of ""

"Conditions": {
"CreateWithName": {
"Fn::Not": [{
"Fn::Equals": [{
"Ref": "ConfigRecorderName"
}, ""]
}]
}
},


Now we have done the parameters and set the condition its time to tie it all together in the resource section.

At the line titled Name:, We have an Fn::If statement that checks to see if the CreateWithName condition is true.
If that condition is true the template will then use the name that has been entered into the parameter field. If the condition is false it inserts the AWS::NoValue value, which causes cloudformation to ignore the line completely.

As per the cloudformation documentation if the Name field of AWS::Config::ConfigurationRecorder is not supplied cloudformation will allocate a randomly generated name and create the config recorder.

"Resources": {
"ConfigRecorder": {
"Type": "AWS::Config::ConfigurationRecorder",
"Properties": {
"Name": {"Fn::If" : ["CreateWithName", {"Ref":"ConfigRecorderName"},{"Ref" : "AWS::NoValue"}] },
"RecordingGroup": {
"AllSupported": true,
"IncludeGlobalResourceTypes": true
},
"RoleARN": {
"Fn::GetAtt": ["AWSIAM", "Arn"]
}
}
},



And there you have it! Its not the most elegant solution but its the best one I've been able to find so far.
Hopefully this is useful to someone else in the future and do hit me up on twitter/email if you find a better way!

You can find the full template over on GitHub https://github.com/adcreare/cloudformation/blob/master/Config/Deploy-AWS-Config-And-S3Bucket.json


References:
AWS Config Cloudformation Reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-configurationrecorder.html

AWS Config API Reference: https://docs.aws.amazon.com/config/latest/APIReference/Welcome.html






© 2015 CommsCentral