copilot-cli icon indicating copy to clipboard operation
copilot-cli copied to clipboard

Expose target group ARN as stack output

Open sugarjig opened this issue 3 years ago • 5 comments

Context

I have a short term need for my load balanced web service to support an external domain name. My understanding is that this will be added as a feature to Copilot, but it will not be available for at least two months. See #1188.

In the meantime, I would like to create a workaround, which involves adding listener rules and certificates for the external domain to the load balancer created by Copilot. The CloudFormation template for an addon would look like this:

Parameters:
  App:
    Type: String
    Description: Your application's name.
  Env:
    Type: String
    Description: The environment name your service, job, or workflow is being deployed to.
  Name:
    Type: String
    Description: The name of the service, job, or workflow being deployed.

Mappings:
  CustomDomains:
    ...

Resources:
  HTTPListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - Type: redirect
          RedirectConfig:
            Protocol: HTTPS
            Port: 443
            Host: "#{host}"
            Path: "/#{path}"
            Query: "#{query}"
            StatusCode: HTTP_301
      Conditions:
        - Field: 'host-header'
          HostHeaderConfig:
            Values: !FindInMap [CustomDomains, !Ref Env, CustomDomains]
        - Field: 'path-pattern'
          PathPatternConfig:
            Values:
              - "/*"
      ListenerArn:
        Fn::ImportValue: !Sub '${App}-${Env}-HTTPListenerArn'
      Priority: 40000

  HTTPSListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      Conditions:
        - Field: 'host-header'
          HostHeaderConfig:
            Values: !FindInMap [CustomDomains, !Ref Env, CustomDomains]
        - Field: 'path-pattern'
          PathPatternConfig:
            Values:
              - "/*"
      Fn::ImportValue: !Sub '${App}-${Env}-HTTPSListenerArn'
      Priority: 40000

  HTTPSCertificate:
    Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
    Properties:
      Certificates: !FindInMap [CustomDomains, !Ref Env, Certificates]
      ListenerArn:
        Fn::ImportValue: !Sub '${App}-${Env}-HTTPSListenerArn'

There is one missing piece to getting this working, however. The TargetGroup resource and ARN are not available to addons.

Feature Proposal

I propose adding it as an output to the service's stack. I think it would be a matter of adding the following to the templates/workloads/services/lb-web/cf.yml file:

  TargetGroupARN:
    Description: ARN of the Target Group.
    Value: !GetAtt TargetGroup.Arn
    Export:
      Name: !Sub "${AppName}-${EnvName}-${WorkloadName}-TargetGroupARN"

sugarjig avatar Jul 21 '21 18:07 sugarjig

@sugarjig Thanks for this suggestion!

huanjani avatar Jul 23 '21 17:07 huanjani

My use case: I'd like the ability to add a listener rule to block a certain path. The ability to add a listener rule with a rule condition to restrict access to a sensitive route. I suppose a workaround would be to do it with a WAF rule.

e.g. a source IP rule for one of the following:

  • /open-api
  • /admin
  • /dashboard

matthewhembree avatar May 16 '22 19:05 matthewhembree

Hello @matthewhembree. Seems like you can utilize customizing addons parameters to do the same thing since the target group is created in the service stack.

iamhopaul123 avatar May 20 '22 21:05 iamhopaul123

Hi @iamhopaul123 . I'm not following what you mean. I want to add a listener rule, but I need the ListenerArn:

Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties: 
  Actions: 
    - Action
  Conditions: 
    - RuleCondition
  ListenerArn: String  # Need this.
  Priority: Integer

matthewhembree avatar May 21 '22 02:05 matthewhembree

Hello @matthewhembree. Listener arn should be included as one of the outputs of the environment stack. Can you import it as

Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties: 
  Actions: 
    - Action
  Conditions: 
    - RuleCondition
  ListenerArn:
    Fn::ImportValue: !Sub '${App}-${Env}-HTTPSListenerArn'
  Priority: Integer

iamhopaul123 avatar May 23 '22 06:05 iamhopaul123

@efekarakus

+1 for the initial request for exposing TargetGroupARN as a stack output.

I'm deploying my own CloudFront distribution in front of copilot to work around the issue described here: https://github.com/aws/copilot-cli/issues/4394#issuecomment-1402106907. This means that I have a custom domain name, not managed through copilot, that I need to route through the copilot ALB to the correct target group. I got everything working with a custom HTTPSListenerRule, but the downside is that I have to hardcode the target group ARN in my service addon template. My template looks basically the same as @sugarjig's.

mlazar-endear avatar Feb 09 '23 14:02 mlazar-endear

@mlazar-endear hi! We're actively working on #4208 and #4209 that should unlock that use case of specifying additional outputs

efekarakus avatar Feb 09 '23 16:02 efekarakus

The new CFN patching feature solved this beautifully for me. Instead of using an addon to define a custom HTTPSListenerRule, I can simply patch the existing rule to point to my cloudfront domain!

- op: replace
  path: /Resources/HTTPSListenerRule/Properties/Conditions/0/HostHeaderConfig/Values
  value:
    - my-custom.domain

mlazar-endear avatar May 18 '23 15:05 mlazar-endear

Closing this as you can now use yaml patch to export anything from the CloudFormation stack ❤️

Lou1415926 avatar Aug 16 '23 20:08 Lou1415926