amazon-web-servicesamazon-ec2aws-lambdaaws-cdkaws-cdk-typescript

Lambda functions SSM environment variables are not updated


I created a new cognito stack. I can see in the parameter store that the variables are updated to have the new ids of the new Cognito stack. However, in my lambdas the env variables are still pointing to the old cognito stack ids which is now deleted. It looks like a cache issue.. I tried deploy with --no-previous-paremeters but it didn't work, any idea on what should I do ?

export class SSMParameterReader extends AwsCustomResource {
    constructor(scope: Construct, name: string, props: SSMParameterReaderProps) {
        const { parameterName, region } = props;

        const ssmAwsSdkCall: AwsSdkCall = {
            service: 'SSM',
            action: 'getParameter',
            parameters: {
                Name: parameterName,
            },
            region,
            physicalResourceId: { id: name }, // Update physical id to always fetch the latest version
        };

        super(scope, name, {
            onUpdate: ssmAwsSdkCall,
            policy: {
                statements: [
                    new iam.PolicyStatement({
                        resources: ['*'],
                        actions: ['ssm:GetParameter'],
                        effect: iam.Effect.ALLOW,
                    }),
                ],
            },
        });
    }

    public getParameterValue(): string {
        return this.getResponseField('Parameter.Value').toString();
    }
}

And then I call this function to get my parameter

export function getFromSSM(scope: Construct, paramName: string, env?: any): string {
    return new SSMParameterReader(scope, scope.node.id + paramName + 'Reader', {
        parameterName: paramName,
        region: env?.region || 'eu-central-1',
    }).getParameterValue();
}


Solution

  • You need to randomize the physicalResourceId so the custom resource will recieve the Update event and always invoke the SDK call, i.e.

    physicalResourceId: cr.PhysicalResourceId.of(Date.now().toString())
    

    Consider the following code:

    export interface SSMParameterReaderProps {
      readonly parameterName: string;
      readonly region: string;
    };
    
    export class SSMParameterReader extends cr.AwsCustomResource {
      constructor(scope: Construct, name: string, props: SSMParameterReaderProps) {
          const { parameterName, region } = props;
    
          const ssmAwsSdkCall: cr.AwsSdkCall = {
              service: 'SSM',
              action: 'getParameter',
              parameters: {
                  Name: parameterName,
              },
              region,
              physicalResourceId: cr.PhysicalResourceId.of(Date.now().toString()), // Update physical id to always fetch the latest version
          };
    
          super(scope, name, {
              onUpdate: ssmAwsSdkCall,
              policy: {
                  statements: [
                      new iam.PolicyStatement({
                          resources: ['*'],
                          actions: ['ssm:GetParameter'],
                          effect: iam.Effect.ALLOW,
                      }),
                  ],
              },
          });
      }
    
      public getParameterValue(): string {
          return this.getResponseField('Parameter.Value').toString();
      }
    }

    And app.ts

    const app = new cdk.App();
    
    const env =  { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION };
    
    const stack = new cdk.Stack(app, 'SSMCreator', { env })
    new ssm.StringParameter(stack, 'Foo', { parameterName: 'foo', stringValue: 'bar' });
    
    const reader = new SSMParameterReader(stack, 'SSMReader', {
      parameterName: 'foo',
      region: process.env.CDK_DEFAULT_REGION || 'us-east-1',
    });
    new cdk.CfnOutput(stack, 'Value', { value: reader.getParameterValue()});

    On initial deployment, you get bar as the initial value:

    Outputs:
    SSMCreator.Value = bar
    

    Now, let's update it with AWS CLI:

    aws ssm put-parameter --name foo --value $(date +%s) --overwrite
    

    deploy again and you get the new value:

    Outputs:
    SSMCreator.Value = 1680733424
    

    Let me know if it works for you.