Cloudformation + Lambdaで環境変数にパラメータストア-SecureString-の値を設定する

LambdaProjectを新設したので、デプロイ周りを構築中。
環境変数をパラメータストアから取得しようとしたら・・・

```
SSM Secure reference is not supported in: [AWS::Lambda::Function/Properties/Environment/Variables/ENV_NAME]
```
なん....だと？

[公式ドキュメント](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#template-parameters-dynamic-patterns-resources)を見ると。

> Resources that support dynamic parameter patterns for secure strings
Resources that support the ssm-secure dynamic reference pattern currently include:
 - AWS::DirectoryService::MicrosoftAD
 - AWS::DirectoryService::SimpleAD
 - AWS::ElastiCache::ReplicationGroup
 - AWS::IAM::User
 - AWS::KinesisFirehose::DeliveryStream
 - AWS::OpsWorks::App
 - AWS::OpsWorks::Stack
 - AWS::OpsWorks::Stack
 - AWS::RDS::DBCluster
 - AWS::RDS::DBInstance
 - AWS::Redshift::Cluster

Lambdaがサポートされていない...!!!
しょうがないので強引にパラメータストアから取得するように挑戦。

## 成果物

CodePipeLine + CloudFormationの構成を想定。
その他基本設定については割愛する。

```template.yaml
AWSTemplateFormatVersion: 2010-09-09
Resources:

  Lambda:
    Type: AWS::Lambda::Function
    Properties:
      Code: app.zip
      FunctionName: LamndaFunction
      Handler: index.handler
      Runtime: nodejs12.x
      Environment:
        Variables:
          ENV01: __ENV01__
          ENV02: __ENV02__
      Role:
        Fn::GetAtt:
          - "Role"
          - "Arn"
      MemorySize: 1024
      Timeout: 3

  Role:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "edgelambda.amazonaws.com"
                - "lambda.amazonaws.com"
            Action:
              - sts:AssumeRole

```

```buildspec.yaml
version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 12
    commands:
      - yum install -y aws-cli
  pre_build:
    commands:
      - json=$(aws --region ap-northeast-1 ssm get-parameters-by-path --path "/" --with-decryption | jq -r .Parameters)
      - len=$(echo $json | jq length)
      - for i in $( seq 0 $(($len - 1)) ); do Name=$(echo $json | jq .[$i].Name);Value=$(echo $json | jq .[$i].Value);Key=__$(echo $Name | sed 's/\"//g')__;sed -i -e "s/$Key/$Value/g" ./template.yaml; done
  build:
    commands:
      - yarn install --production=true
      - zip -r app.zip index.js node_modules
  post_build:
    commands:
      - aws cloudformation package --template-file template.yaml --s3-bucket BUCKET_NAME --s3-prefix `date '+%Y%m%d%H%M%S'` --output-template-file packaged.yaml
      - aws cloudformation deploy --region ap-northeast-1 --template-file packaged.yaml --stack-name STACK_NAME --capabilities CAPABILITY_IAM
artifacts:
  files:
    - packaged.yaml
```

## 説明

簡単に説明すると、CodeBuild内でパラメータストアからキーと値を取ってきて、template.yaml内の文字列を置換しています。

```template.yaml
AWSTemplateFormatVersion: 2010-09-09
Resources:

  Lambda:
    Type: AWS::Lambda::Function
    Properties:
      〜〜〜
      Environment:
        Variables:
          ENV01: __ENV01__
          ENV02: __ENV02__
      〜〜〜

```
置換対象の文字列は`__${パラメータストアのkey名}__`としております。

```buildspec.yaml
version: 0.2

phases:
  〜〜〜
  pre_build:
    commands:
      - json=$(aws --region ap-northeast-1 ssm get-parameters-by-path --path "/" --with-decryption | jq -r .Parameters)
      - len=$(echo $json | jq length)
      - for i in $( seq 0 $(($len - 1)) ); do Name=$(echo $json | jq .[$i].Name);Value=$(echo $json | jq .[$i].Value);Key=__$(echo $Name | sed 's/\"//g')__;sed -i -e "s/$Key/$Value/g" ./template.yaml; done
  〜〜〜
```

まずは、パラメータストアの値をjson形式で取得。

```.sh
json=$(aws --region ap-northeast-1 ssm get-parameters-by-path --path "/" --with-decryption | jq -r .Parameters)
```

その後、jsonレコード分ループし、文字列を置換。

```.sh
len=$(echo $json | jq length)
for i in $( seq 0 $(($len - 1)) ); do Name=$(echo $json | jq .[$i].Name);Value=$(echo $json | jq .[$i].Value);
    Key=__$(echo $Name | sed 's/\"//g')__;sed -i -e "s/$Key/$Value/g" ./template.yaml;
done
```

以上。