Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use of CloudFormation intrinsic functions in AutoPublishAlias #220

Closed
dslagle opened this issue Dec 1, 2017 · 11 comments
Closed

Use of CloudFormation intrinsic functions in AutoPublishAlias #220

dslagle opened this issue Dec 1, 2017 · 11 comments

Comments

@dslagle
Copy link

dslagle commented Dec 1, 2017

I'm relatively new to CloudFormation and AWS SAM, so forgive me for any misunderstandings. I'm attempting to assign an alias to a function version using a CF function such as !Sub or !Join, but this does not seem to be allowed. I've successfully used the functions with the Lambda's FunctionName attribute, but it will not work with AutoPublishAlias. For example the following works:

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Parameters:
  ENVIRONMENT:
    Type: String

Resources:
  Ec2DescribeInstances:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub '${ENVIRONMENT}MyFunction'
      Handler: index.handler
      Runtime: nodejs6.10
      AutoPublishAlias: MyFunction1

But when I switch the !Sub function to AutoPublishAlias it fails:

      ...
      FunctionName: MyFunction
      ...
      AutoPublishAlias: !Sub '${ENVIRONMENT}MyFunction'

The error message is: 'AutoPublishAlias' must be a string or a Ref to a template parameter. Is this intentional or a bug, and is it something that could be supported in the future?

Thanks in advance for any help/information!

@jfuss
Copy link
Contributor

jfuss commented Dec 1, 2017

Hey @dslagle,

At the moment, we don't support Sub for AutoPublishAlias. Can you explain your use-case to wanting this a little more? It would good for us to understand why you want to make this AutoPublishAlias 'dynamic' like this.

You can do something like this though:

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Parameters:
  FunctionAlias:
    Type: String
  ENVIRONMENT:
    Type: String

Resources:
  Ec2DescribeInstances:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub '${ENVIRONMENT}MyFunction'
      Handler: index.handler
      Runtime: nodejs6.10
      AutoPublishAlias: 
        Ref:
          FunctionAlias

@jfuss jfuss added the question label Dec 2, 2017
@dslagle
Copy link
Author

dslagle commented Dec 3, 2017

My thought was to use aliases for various environments like dev, test, prod, etc. and be able to control them through environment variables for the purposes of CI/CD. This way I can maintain a single template and a single function (instead of naming the function dev-, test-, etc.). To do that I was trying to make use of the --parameter-overrides option on the CLI aws stack deploy. Not ideal, but I'm just exploring my options. I could use a single variable for the function alias itself as you pointed out, but my preference would be to maintain a single variable that indicates the environment. Thanks!

@dslagle
Copy link
Author

dslagle commented Dec 4, 2017

I'm going to work around it by altering the template as part of the CI process before deployment. But on a side note, is it possible to tell where the intrinsic functions in CF are supported and where they are not based on documentation? Both the Function Name and the Alias name are String types, but, as noted, the Alias doesn't support the intrinsic functions. Is there an easy way to know? Thanks.

@jfuss
Copy link
Contributor

jfuss commented Dec 4, 2017

@dslagle I am going to answer both your questions here.

For your first comment:
I don't completely understand your current setup. Are you trying to have only one Lambda Function that you can use for dev, test, and prod? That would mean all of these are controlled through the same CloudFormation stack?
If that is the case, I do not recommend you (or anyone) to use aliases for various environments. The biggest concern I have with this is that you are running the risk of impacting prod with a change to test or dev. You are creating a bigger blast radius in the event something goes wrong with a deploy. My other concern would be around security of your functions. You may have to add credentials or policies specific to dev or test which will or could be replicated in prod. My suggestion is to split out dev, test, and prod into separate CloudFormation stacks so that each environments in isolated for each other. You then only have to manage the one CloudFormation template and can deploy it through you CI/CD system at an environment level. You will still only be managing one Lambda function (through SAM) but this setup will reduce blast radius for deployments and isolate your different environment's functions and resources.

If that is not what you are attempting to do, can you explain your setup further or what you are trying to achieve?

For your second comment:
Alias does support intrinsics but we limited it only to Ref currently.

The team knows that documentation and intrinsic support is an area for improvement. We are working towards this improvement but will take some time to get out. Right now, I do not have a good way to surface this information to you or the community. I would like us to do this the right way and get better documentation up. We may do a quick update to surface this information but will depend on how far out the documentation update is. I know this isn't a great answer but hopefully this pain will go away soon enough.

@dslagle
Copy link
Author

dslagle commented Dec 4, 2017

I see what you are saying. I'm new to CloudFormation and wasn't thinking about it from that perspective, but what you are saying makes sense. I will adjust to take this approach. I really appreciate the answers/feedback.

@gallamine
Copy link

@jfuss can you clarify this statement:

My suggestion is to split out dev, test, and prod into separate CloudFormation stacks so that each environments in isolated for each other. You then only have to manage the one CloudFormation template and can deploy it through you CI/CD system at an environment level. You will still only be managing one Lambda function (through SAM) but this setup will reduce blast radius for deployments and isolate your different environment's functions and resources.

Does this mean "3 stacks, 1 template, 1 lambda function" or "3 stacks, 1 template, 3 lambda functions"?

@jfuss
Copy link
Contributor

jfuss commented Dec 4, 2017

@gallamine Sure.

This would mean "3 stacks, 1 template, 3 lambda". Let me attempt to describe this a little further.

My recommendation is to have a CloudFormation stack per environment or stage (depending on your terminology). So taking the example above, lets say we have 3 stages (dev, test, and prod). Each of those stages would have their own CloudFormation stack, lets name them as follows: dev-stack, test-stack, prod-stack. Your CI/CD system will need to deploy to dev-stack, test-stack, and then prod-stack but will be pushing one template through all of these stacks.

Let's look go a little deeper into what is going on from a dev flow.
So Dev1, makes a change to the CloudFormation template. He or she wants to be able to add this rad traffic shifting to feature. They will edit the template, go through code review or whatever process your company follows and then push their code. Assuming everything is automated, this kicks off a deployment of the new template in the dev-stack. Dev1 validates the changes, integ tests are run, etc and then the template is deployed to the next stage. Since each stage is a CloudFormation Stack, all resources in that template will be created in each stack. This is a very common pattern. You can take this further and have each stack in a different account. This isn't necessarily needed but I think it is a good practice to follow if it makes sense to your company or team.

Advantages of this kind of structure:

  • It limits the blast radius for any given deployment. Since everything is scoped in a CloudFormation Stack and each stack is one stage, you will never be editing production resources on accident.
  • Easy replication. If you need to support multiple regions, you can replicate this easily by creating a new stack (prod-Ohio-stack and prod-Ireland-stack) in your CI/CD system and you still only manage one CloudFormation template.
  • If you choose to have developers stacks, it becomes easy to replicate production by deploying the template in a new stack. (goes along with easy replication)

Caveats:

  • You may need to manage different stages differently. Maybe the dev or test stack doesn't need a prod provisioned Dynamo Table. This can be done through a combination of Stack Parameters, Conditions, and Fn::If statements. As templates grow this does become a little harder to manage (in my personally opinion).

There are probably more caveats to this but can't think of them currently.

Would be happy to discuss further. I have become very passionate about these kinds of topics (safe deployments/"Infrastructure as Code"/reduce blast radius/etc).

@brettswift
Copy link

brettswift commented Mar 29, 2018

I ran into this as well. My use case is similar but I'm basing my deploys off a pipeline.

Pseudo:

pipeline:
     stages:
        - name: deploy_lambda_dev:
          Type: Codebuild project "DeployLambdaStack"
                --> aws cfn package & deploy
           ParameterOverrides:
                - EnvironmentName: Dev
        - name: deploy_lambda_SCARY_PRODUCTION:
           Type: Codebuild project "DeployLambdaStack"
                --> aws cfn package & deploy
           ParameterOverrides:
                - EnvironmentName: Prod

I have one template, that is run at each stage in my pipeline:

AWSTemplateFormatVersion: 2010-09-09
Transform: 'AWS::Serverless-2016-10-31'
Parameters:
  EnvironmentName:
    Description: Used to name the lambda alias instance
    Type: String
  AlexaSkillFunction:
    Type: AWS::Serverless::Function
    Properties:
      AutoPublishAlias: !Sub "AliasAlexaSkill${EnvironmentName}"
      Handler: index.handler
      Runtime: nodejs6.10
    ~ ~
    

My Pipeline owns naming the lambda alias. Dev will always be dev, prod will always be prod. Different lambda's underneath.

In Dev, and in Prod, I could manually downgrade the version number if I need to. (This is really the only reason I'm using the alias).

Do you see a risk in doing it this way?

FYI: my workaround is to not pass in Dev but the full AlexaLambdaAliasDev, and just use !Ref

However, options are nicer.

@nirajvbhatt
Copy link

Hi,
Please bear with me as I have just stared working on serverless and I have many gaps in my understanding.

I want to create 3 different environment, DEV, QA and PROD.

1st Tech Stack: Xamarin based mobile APP(.NET) which uses COGNITO, LAMBDA, DYNAMODB, SNS etc.

I want to create DEV, QA and PROD stacks and will keep updating that stacks for eventual CI/CD pipeline(which I have no idea where to start from). I am playing with .NET SDK for AWS and created AWS lambda project templates (AWS Lambda Project and AWS Serverless Applicatin with Tests). I am also able to deploy it using Publish to AWS Lambda wizard.

Actualy I want to know how I can achieve following:

Create CloudFormation stacks for each DEV, QA and PROD environment. I want to create seperate stacks rather than one single stack. This should create all COGNITO pools, roles, DynamoDB tables, Lambda functions in that environment. However I don’t have any need to use API Gateway for these Lambda functions. I am planning to pass environment variables as input parameter like “DEV”, “STAGING” so that related resource names are created using that input.
I don’t understand how exactly I can automate this process. We are using Git and I want to trigger DEV stack create/update when we do check-in. How can I create zip package from .NET Lambda project that contains all lambda functions and put it in S3? Also should I create different S3 buckets for each DEV, QA and PROD?
If only I can get steps and a sample yaml, I think i will be good. I also fail to understand how I can automate this process? I am not aware of CodePipeLine or any other tool like that.

2nd Tech Stack: I also have a small web application (Node.js) based which uses LAMBDA API Gateway which contains

how can I maintain similar DEV, QA and PROD environment for this tech stack?
I am not able to find any examples that match my criteria. Any guidance/samples would be highly appreciated.

@milancermak
Copy link

@jfuss Thanks a lot for your detailed comment above. It helped me to realize how to build my pipelines better, some concepts finally clicked for me. 🍻

@c2tarun
Copy link
Contributor

c2tarun commented Aug 12, 2020

Closing this issue as there has been no activity in over year, with the assumption that answers by Jacob answered the overall question. Please re-open if you have more questions.

@c2tarun c2tarun closed this as completed Aug 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants