jeznag
jeznag

Reputation: 4723

How can I attach multiple certificates to a load balancer in CDK?

I'm setting up grafana on ECS and want it to be available through two different URLs on different subdomains: grafana.subdomain.mycompany.com and grafana.mycompany.com (We need two URLs because the subdomain version is required for a grafana auth proxy whereas the non subdomain version is used for people editing dashboards).

My problem is that the ApplicationLoadBalancedFargateService only allows you to supply one certificate.

My best solution so far is to do this.

        const grafanaService = new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'Grafana', {
            cluster: this.props.ecsCluster,
            taskDefinition: taskdef,
            domainZone: this.props.hostedZone,
            domainName: this.grafanaDns,
            publicLoadBalancer: true
        })

        const sslListener = grafanaService.loadBalancer.addListener('SSL', {
            port: 443,
            certificates: [this.props.certificateHarvestSubdomain, this.props.certificateRootSubdomain],
            protocol: ApplicationProtocol.HTTPS
        })

        sslListener.addTargets('grafanaTarget', {
            targets: [grafanaService.service],
            port: 80,
            protocol: ApplicationProtocol.HTTP,
            healthCheck: {
                path: '/login',
                interval: cdk.Duration.minutes(1)
            }
        })

        new ARecord(this, 'Alias', {
            zone: this.props.hostedZone,
            target: route53.RecordTarget.fromAlias(new LoadBalancerTarget(grafanaService.loadBalancer)),
            recordName: 'grafana'
        })

This does the trick but it leaves me with one problem: I can’t do HTTP to HTTPS redirection because the ApplicationLoadBalancedFargateService already creates a listener on port 80 and I can’t find a way to access the existing listener. If I try to create another listener, it fails stating that a listener already exists.

Upvotes: 1

Views: 3551

Answers (1)

mchlfchr
mchlfchr

Reputation: 4278

The issue is, as you mentioned, a default listener on port 80 will be created. However, you can override the listenerPort to match 443. Though you need to specify a domainName, domainZone and a certificate, because HTTP as protocol is being used by default if one of them is missing. Redirections from HTTP -> HTTPS won't work with this default setting. However, you want to add multiple certificates all at once.

Therefore, you need to pass the protocol argument in the ALB-FGS constructor to override the HTTP default in order to make the HTTP -> HTTPS happen. The redirectHTTP argument of the ALB-FGS is working with the protocol then.

To provide multiple certificates, you can explicitly add on the (default) 443 listener the certificates. Getting the listener object from the service and add the multiple certificates should do the trick.

Find the adapted code in the following.

DISCLAIMER: I ran the cdk synth and didn't deploy it actually. If you find an error during deployment, please let me know.

   const grafanaService = new ecspatterns.ApplicationLoadBalancedFargateService(
      this,
      "Grafana",
      {
        cluster: this.props.ecsCluster,
        taskDefinition: taskdef,
        domainZone: this.props.hostedZone,
        domainName: this.grafanaDns,
        publicLoadBalancer: true,
        // here are the changes, mentioned in the description above for the FGS
        // if you only had one certificate, 
        // you would add it here directly and get rid of the `protocol` argument
        listenerPort: 443,
        protocol: ApplicationProtocol.HTTPS,
        redirectHTTP: true,
      }
    );

    grafanaService.listener.addCertificates("GrafanaHttpsCertificates", [
      this.props.certificateHarvestSubdomain,
      this.props.certificateRootSubdomain,
    ]);

Upvotes: 1

Related Questions