Skip to content

serverless frameworkアップデート時に発生したエラー調査

Published: at 23:13

2021/04/14 追記

3行で頼む

発生した事象

serverless frameworkを 1.78.1 → 2.33.1 にアップデートして、デプロイ実行したらModifying service token is not allowedエラーとなり失敗した。

$ npx sls deploy
Serverless: Deprecation warning: CLI options definitions were upgraded with "type" property (which could be one of "string", "boolean", "multiple"). Below listed plugins do not predefine type for introduced options:
             - Prune for "number", "stage", "region", "function", "layer", "includeLayers", "dryRun"
            Please report this issue in plugin issue tracker.
            Starting with next major release, this will be communicated with a thrown error.
            More Info: https://www.serverless.com/framework/docs/deprecations/#CLI_OPTIONS_SCHEMA
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Installing dependencies for custom CloudFormation resources...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service xxx.zip file to S3 (13.53 MB)...
Serverless: Uploading custom CloudFormation resources...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.............
Serverless: Operation failed!
Serverless: View the full error output: https://ap-northeast-1.console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#/stack/detail?stackId=arn%3Aaws%3Acloudformation%3Aap-northeast-1%3Axxxxxxxxxxxx%3Astack%xxx-dev%2F2ecb8c70-9d8e-11ea-87ef-0af0ae9d5064

 Serverless Error ----------------------------------------

  An error occurred: XXXCustomS31 - Modifying service token is not allowed..

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com

  Your Environment Information ---------------------------
     Operating System:          darwin
     Node Version:              14.16.1
     Framework Version:         2.33.1 (local)
     Plugin Version:            4.5.3
     SDK Version:               4.2.2
     Components Version:        3.8.1

上記エラーは XXXCustomS31 というCustom Resourceの更新で発生している。 このCustom Resourceはevents.s3existing: trueを設定すると作成されるもので、1.78.1 の時に作成している。

# serverless.yml

func:
  handler: bin/func
    events:
      - s3:
        bucket: xxxx
        event: s3:ObjectCreated:*
        rules:
          - suffix: .txt
        existing: true

Modifying service token is not allowed はどんなエラーか?

Custom ResourceのServiceTokenを変更しようとして失敗している。

何故ServiceTokenは変わったのか?

Custom Resourceの定義は以下の通り。ServiceTokenには、existing: trueを指定した時にframework側で作成するLambda関数のARNを指定している。

Custom ResourceのCloudFormation定義

// .serverless/cloudformation-template-update-stack.json

"XXXCustomS31": {
  "Type": "Custom::S3",
  ...
  "Properties": {
    "ServiceToken": {
      "Fn::GetAtt": [
        "CustomDashresourceDashexistingDashs3LambdaFunction",
        "Arn"
      ]
    },
    ...

(1.78.1の) 該当関数のCloudFormation定義

// .serverless/cloudformation-template-update-stack.json

"CustomDashresourceDashexistingDashs3LambdaFunction": {
  "Type": "AWS::Lambda::Function",
  "Properties": {
    "Code": {
      "S3Bucket": {
        "Ref": "ServerlessDeploymentBucket"
      },
      "S3Key": "serverless/xxx/dev/1617775748688-2021-04-07T06:09:08.688Z/custom-resources.zip"
    },
    "FunctionName": "xxx-dev-custom-resource-existing-s3",
    "Handler": "s3/handler.handler",
    "MemorySize": 1024,
    "Runtime": "nodejs12.x",
    "Timeout": 180,
    "Role": {
      "Fn::GetAtt": [
        "IamRoleCustomResourcesLambdaExecution",
        "Arn"
      ]
    }
  },
  "DependsOn": [
    "IamRoleCustomResourcesLambdaExecution"
  ]
},

(2.33.1の) 該当関数のCloudFormation定義

// .serverless/cloudformation-template-update-stack.json

"CustomDashresourceDashexistingDashs3LambdaFunction": {
  "Type": "AWS::Lambda::Function",
  "Properties": {
    "Code": {
      "S3Bucket": {
        "Ref": "ServerlessDeploymentBucket"
      },
      "S3Key": "serverless/xxx/dev/1617775041490-2021-04-07T05:57:21.490Z/custom-resources.zip"
    },
    "FunctionName": "xxx-undefined-custom-resource-existing-s3",
    "Handler": "s3/handler.handler",
    "MemorySize": 1024,
    "Runtime": "nodejs12.x",
    "Timeout": 180,
    "Role": {
      "Fn::GetAtt": [
        "IamRoleCustomResourcesLambdaExecution",
        "Arn"
      ]
    }
  },
  "DependsOn": [
    "IamRoleCustomResourcesLambdaExecution"
  ]
},

1.78.1 のFunctionNameには、stageである dev が含まれていたが、2.33.1 ではその部分が undefined になっている。

2.33.1 のスタックでデプロイすると、

  1. FunctionNameがかわる = 新しい関数を作成しようとする
  2. 新しい関数のARNをCustom ResourceのServiceTokenに反映(更新)しようとして失敗した

ということらしい。

対応策

https://forum.serverless.com/t/modifying-service-token-is-not-allowed/12404 に書いてある通り、sls deployにstageオプションを明示することで回避できた。

発生条件を調べる

以下の方法で調べたところ、2.32.0からこの事象が発生する。

# <version>を落として、正しいFunctionNameを取得できるまで繰り返す

$ npm i -D serverless@<version>
$ npx sls package
$ cat .serverless/cloudformation-template-update-stack.json | jq .Resources.CustomDashresourceDashexistingDashs3LambdaFunction.Properties.FunctionName
“xxxx-undefined-custom-resource-existing-s3”

関連PRは https://github.com/serverless/serverless/pull/9171

2.31.0 以前の挙動

lib/plugins/aws/lib/validate.jsoptionspluginManager.cliOptionsを参照しているので、このタイミングでcliOptions.stageを設定していた。 そして、lib/plugins/aws/customResources/index.jscliOptions.stageを取得して関数名に dev を設定していた。

2.32.0 以降の挙動

プラグインのoptionspluginManager.cliOptionsを設定するための serverless.init()の実行より後に scripts/serverless.jspluginManager.cliOptionsを別のオブジェクトに更新しているので、プラグインのoptionscliOptionsを参照しない。 validate.js の処理を通過しても、参照していないcliOptions.stageundefined のままで、それが関数名に設定される。

上記コードを実行するのは、serverless.ymlで外部プラグインを追加している場合だけで、設定していたプラグインを全て外してパッケージを作ってみたら正しい関数名になっていた。

おわり

ちょっとserverless frameworkに詳しくなった。 もしまだ無かったらIssueかPRを投げたい。