AWS CloudFormation & Service Catalog - Can I require tags with user values?

939 Views Asked by At

Our problem seems very basic and I would expect common.

We have tags that must always be applied (for billing). However, the tag values are only known at the time the stack is deployed... We don't know what the tag values will be when developing the stack, or when creating the product in the Service Catalog...

We don't want to wait until AFTER the resource is deployed to discover the tag is missing, so as cool as AWS config may be, we don't want to rely on its rules if we don't have to.

So things like Tag Options don't work, because it appears that they expect we know the tag value months prior to some deployment (which isn't the case.)

Is there any way to mandate tags be used for a cloudformation template when it is deployed? Better yet, can we have service catalog query for a tag value when deploying? Tags like "system" or "project", for instance, come and go over time and are not known up-front for many types of cloudformation templates we develop.

Isn't this a common scenario?

I am worried that I am missing something very, very simple and basic which mandates tags be used up-front, but I can't seem to figure out what. Thank you in advance. I really did Google a lot before asking, without finding a satisfying answer.

1

There are 1 best solutions below

3
On

I don't know anything about service catalog but you can create Conditions and then use it to conditionally create (or even fail) your resource creation. Conditional Resource Creation e.g.

Parameters:
  ResourceTag:
    Type: String
    Default: ''
Conditions:
  isTagEmpty:
    !Equals [!Ref ResourceTag, '']
Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Condition: isTagEmpty
    Properties:
      DBInstanceClass: <DB Instance Type>

Here RDS DB instance will only be created if tag is non-empty. But cloudformation will still return success.

Alternatively, you can try & fail the resource creation.

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass: !If [isTagEmpty, !Ref "AWS::NoValue", <DB instance type>]

I haven't tried this but it should fail as DB instance type will be invalid if tag is null.

Edit: You can also create your stack using the createStack CFN API. Write some code to read & validate the input (e.g. read from service catalog) & call the createStack API. I am doing the same from Lambda (nodejs) reading some input from Parameter Store. Sample code -

module.exports.create = async (event, context, callback) => {

 let request = JSON.parse(event.body);

 let subnetids = await ssm.getParameter({
     Name: '/vpc/public-subnets'
 }).promise();

 let securitygroups = await ssm.getParameter({
     Name: '/vpc/lambda-security-group'
 }).promise();

 let params = {
    StackName: request.customerName, /* required */
    Capabilities: [
        'CAPABILITY_IAM',
        'CAPABILITY_NAMED_IAM',
        'CAPABILITY_AUTO_EXPAND',
        /* more items */
    ],
    ClientRequestToken: 'qwdfghjk3912',
    EnableTerminationProtection: false,
    OnFailure: request.onfailure,
    Parameters: [
        {
            ParameterKey: "SubnetIds",
            ParameterValue: subnetids.Parameter.Value,
        },
        {
            ParameterKey: 'SecurityGroupIds',
            ParameterValue: securitygroups.Parameter.Value,
        },
        {
            ParameterKey: 'OpsPoolArnList',
            ParameterValue: request.userPoolList,
        },
        /* more items */
    ],
    TemplateURL: request.templateUrl,
 };

 cfn.config.region = request.region;

 let result = await cfn.createStack(params).promise();

 console.log(result);
}

Another option: add a AWS Custom Resource backed by Lambda. Check for tags in this section & return failure if it doesn't satisfy the constraints. Make all other resource creation depend on this resource (so that they all create if your checks pass). Link also contains example. You will also have to add handling for stack update & deletion (like a default success). I think this is your best bet as of now.