Question regarding using the AWS Crosswalk ALB and...
# aws
b
Question regarding using the AWS Crosswalk ALB and attempting to use multiple AWS managed certificates for
443
listener. It is unclear to me the correct way to add multiple SSL CERTs for a
443
listener. I wrote some code below, however I suspect i might be misunderstanding how to use pulumi inputs/outputs correctly so If anyone can point me to the right direction that would be greatly appreciated. Example code in 🧵 .
Typescript example code
Copy code
// code above that creates vpc + security groups

const appLb = new awsx.lb.ApplicationLoadBalancer(`${stack}-my-lb`, {
  subnetIds: vpc.publicSubnetIds,
  securityGroups: [securityGroup.id],
  defaultTargetGroup: {
    port: 80,
    protocol: 'HTTP',
    ipAddressType: 'ipv4',
    healthCheck: {
      interval: 10,
      enabled: true,
      path: '/healthcheck',
    },
  },
  listeners: [
    {
      port: 80,
      protocol: 'HTTP',
    },
    {
      port: 443,
      protocol: 'HTTPS',
      // ARN of a manually created SSL cert managed by AWS for our domain
      certificateArn:
        'ARN OF CERT HERE',
    },
  ],
});


const listeners = appLb.listeners.get();
const tlsListenerArn = listeners?.find(
  (listener) => listener.port.get() === 443
)?.arn;

//I want to add an additional cert
const otherDomainCert = new aws.lb.ListenerCertificate('different-domains-cert', {
  
  // PROBLEM HERE here is that the ARN is an Output but Really want this to be an INPUT
  listenerArn: tlsListenerArn,
  certificateArn:
    'ARN OF an additional cert',
});

// more code below
m
Have you tried applying the Output?
Copy code
listenerArn: tlsListenerArn.apply(v => v),
I believe that this produces an Output:
Copy code
const tlsListenerArn = listeners?.find(
  (listener) => listener.port.get() === 443
)?.arn;
The Input for
listenerArn
takes a string.
All input properties are implicitly available as output properties.
To get the string value of an Output, you have to
.apply()
it.
b
It does produce an
Ouput<string | undefined>
, which causes a typing issue because it could be
undefined
if the listener was not defined. I guess my question here is does it make sense to assert that the that the previously defined resources exists in this case since it was created above?
m
An Output inside of an Input of another resource should resolve correctly. You may need to coerce it in some cases with opts such as
dependsOn
. In some cases, the entire resource needs to be put inside of an
apply
, but I believe that is considered bad practice because resources inside of an apply won't show up in a preview. e.g. something like:
Copy code
appLb.apply(lb => {
    const listeners = lb.listeners.get();
    const tlsListenerArn = listeners?.find(
        (listener) => listener.port.get() === 443
    )?.arn;

    //I want to add an additional cert
    const otherDomainCert = new aws.lb.ListenerCertificate('different-domains-cert', {

        // PROBLEM HERE here is that the ARN is an Output but Really want this to be an INPUT
        listenerArn: tlsListenerArn,
        certificateArn:
            'ARN OF an additional cert',
    });
});
b
I was able to get this working, thank you @millions-furniture-75402.
m
Can you share your solution?
b
I thought I had a solution to this and just ran it today however I ran into the issue that I have been unable to cocere the boolean to be able to do the
listeners?.find(
bit. As it will always be an output and doing
.get()
for the port throws an exception (which is expected).
Copy code
Error: Cannot call '.get' during update or preview.
    To manipulate the value of this Output, use '.apply' instead.
This technically works, but I was hoping there was a more robust solution to get the listener with port 443 defined instead of relying on the order matching because i would imagine it could potentially not match.
Copy code
const otherDomainCert = new aws.lb.ListenerCertificate('different-domains-cert', {
        // Feels like a bad approach because it does not handle listeners changing order 
        listenerArn: appLb.listeners.apply((listeners) => listeners![1].arn),
        certificateArn:
            'ARN OF an additional cert',
    });
m
Ahh yeah, that makes sense, and that's cleaner than nesting the resource inside an apply
b
Yea but I still think there should be a dynamic way to get the listener for that port and that would make this code alot more robust to changes in the future.
m
I think that sort of behavior goes into the higher-level abstractions provider, "crosswalk", aka, "awsx".
Then I'm not sure if that's being broken out into other resource/service specific packages now. I haven't really kept up.
b
I suspect what I would need to do around the dynamic part is instead of using “crosswalk” (
awsx
) I need to instead provision the lower level resources myself to because then I could just reference them directly from the
const resource = new aws.<resource>…..
to get ARNs.