AWSで作成した環境をFormer2を使ってリバースでIaCしてみたので公開 #エラー解消編

## 初めに
こちらは
[AWSで作成した環境をFormer2を使ってリバースでIaCしてみたので公開 #環境構築編](https://qiita.com/toma__/items/6a24e5a67a0405256b41)
にてFormer2で出力したファイルを使ってCloudFormationで環境を作るときのトライアンドエラーをつらつら書いた記事になります。

なぜ掲題のことやりたいと思ったかというと、ツールの検証環境作ったのはよかったのですが
同系統の別ツール触ってみたいときにきれいな環境でやりたいなと思ったときに今までの環境流用したいなと思ったからです。
ちょっと設定変えた別環境とか、どの環境がどう違うのかがファイルベールでDiffとればわかるくらいならどの環境がどう違うかはわかりやすいかなと思ったりもしたからです。

IaCを1からやるのが面倒くさいだけ、とかでは決してないです！！

それではつらつら書いていきます。
出てたらまずそうな値とか利用用途知らない値は***でマスクしてます。
※任意に着けている名前はなるべく残しておきます（環境構築編で修正後のファイルなら公開しているので並べて見れるように）

#### エラー１：「Resource handler returned message: "Invalid parameter at 'lifecyclePolicyText' failed to satisfy constraint: 'Member must not be null' (Service: Ecr, Status Code: 400, Request ID: ***)" (RequestToken: ***, HandlerErrorCode: GeneralServiceException)」
これは、ライフサイクルが設定されていないかららしい？
下記を参考に追加する。

https://dev.classmethod.jp/articles/cfn-for-ecr-lifecyclepolicy/

#### エラー２：Circular dependency between resources: [IAMRole2, CodeBuildProject, CodePipelinePipeline, IAMManagedPolicy4]
循環エラーということらしい
つまるところ参照しあっているとどれから作っていいかわからなくなるからエラーになるらしい
そのためエラー内容に書いてある設定を見て、今回はCodePipelinePipelineがわざわざ参照する必要のないところで参照していたので書き換えて修正

#### エラー３：「Resource handler returned message: "The role with name ***-codebuild-service-role cannot be found. (Service: Iam, Status Code: 404, Request ID: ***)" (RequestToken: ***, HandlerErrorCode: NotFound)」
ロールがないよと言われた、順番どうなっているとみてみると
```
    Roles: 
      - !Sub "${CodeBuildProject}-service-role
```
となっていて多分!Subだとロールとの優先度が決められないのだろうということで!Refに変えて作成順番を自動で決定してもらえるように
``` 
    Roles: 
      - !Ref IAMRole2
```
とする。

#### エラー４：「Resource handler returned message: "Invalid request provided: IamCertificateId or AcmCertificateArn can be specified only if SslSupportMethod must also be specified and vice-versa." (RequestToken: ***, HandlerErrorCode: InvalidRequest)」
SslSupportMethodは知らないので検索したら
```
  CloudFrontDistribution:
        ・・・
        ViewerCertificate: 
          CloudFrontDefaultCertificate: true
          MinimumProtocolVersion: "TLSv1"
          SslSupportMethod: "vip"
```
となっていた。
SslSupportMethodはこれ単体で設定はできないらしいので

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/quickref-cloudfront.html

を参考に
```
  CloudFrontDistribution:
        ・・・
        ViewerCertificate: 
          CloudFrontDefaultCertificate: true
```
に修正したら解消

#### エラー５：「Resource handler returned message: "Invalid request provided: CreateService error: Unable to describe task definition. (Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException; Request ID: ***; Proxy: null)" (RequestToken: ***, HandlerErrorCode: InvalidRequest)」
いろいろ試しながらやってしまったのでこのエラーに対しての修正であるかは怪しいが
ECSのtaskを作成する際にまだコンテナイメージが無いが指定必須になっている。
そのため暫定回避として、stack用のファイルを2つ作り初回用と、コンテナイメージ作成完了後のECS設定更新用を作成して回避した。（もっと別の方法がある気はする）

#### エラー６：「You have specified two resources that belong to different networks. (Service: AmazonEC2; Status Code: 400; Error Code: InvalidGroup.NotFound; Request ID: ***; Proxy: null)」
デフォルトのセキュリティグループに名前つけてなくて、Former2で出力されてなかったためAWSで設定されているセキュリティグループのIDがそのまま指定されていて、別のVPCのセキュリティグループ使おうとしていたので怒られてました。（というかこれ系のエラーがすごく多かった。。。これからはちゃんと名前つけよ。。。）
また、自己参照型のセキュリティグループを頭使わずに作成しようとすると循環エラーになるので下記を参考にデフォルトのセキュリティグループを作りました。

https://yomon.hatenablog.com/entry/2019/10/securitygroupselfref

#### エラー７-１「Resource handler returned message: "VPC vpc-*** has no internet gateway (Service: ElasticLoadBalancingV2, Status Code: 400, Request ID: ***)" (RequestToken: ***, HandlerErrorCode: InvalidRequest)」
VPCにインターネットゲートウェイが設定されていないからロードバランサー設定できませんと言われてる
コンソール上で確認してみると確かにない、でもインターネットゲートウェイ自体は設定できている。
つまるところはアタッチできていなかった。
Former2からはアタッチする設定は出力されないのだろうか、出力されるようにするやり方はあるのだろうか？
下記を追加
```
 EC2InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties: 
      InternetGatewayId: !Ref EC2InternetGateway
      VpcId: !Ref EC2VPC
```

#### エラー７-２アタッチがロードバランサ作成より先に実行されない
下記を参考に対象のロードバランサ（ElasticLoadBalancingV2LoadBalancer）に
```
  DependsOn: EC2InternetGatewayAttachment
```
を追加、明示的に順番を指定するのが必要な時もあるんですね。

https://dev.classmethod.jp/articles/cf_dependson/

#### エラー８「aws: prefixed tag key names are not allowed for external use.」
エラーの内容通りだが、tagなどに「aws:」から始まるものを入れているとエラーになる
確認したところ今回はECSでデプロイした時に自動で作成されていた```Type: "AWS::EC2::NetworkInterface"```が設定されているものをいれており、これはECSにデプロイするときにCodepipelineにて自動で作ってくれるため削除

#### エラー９「Resource handler returned message: "Invalid request provided: Create TaskDefinition: Task definition doesn't have any essential container. (Service: AmazonECS; Status Code: 400; Error Code: ClientException; Request ID: ***; Proxy: null)" (RequestToken: ***, HandlerErrorCode: InvalidRequest)」
いろいろ試してたらTaskDefinitionでコンテナの設定が消えてたり
資材側の設定をミスしていてコンテナイメージを古い方というかコピー元のECRリポジトリにプッシュしていて
新しく作ったECRリポジトリにプッシュされておらずコンテナイメージが無かったので（資材側のPushするコンテナURL）

#### エラー１０「Resource handler returned message: "Invalid request provided: CreateService error: You cannot specify an IAM role for services that require a service linked role. (Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException; Request ID: ***; Proxy: null)" (RequestToken: ***, HandlerErrorCode: InvalidRequest)」
サービスで使用するロールは決まっているとのことでロール指定している部分を削除

https://www.yokoyan.net/entry/2021/10/15/180000

#### エラー１１「Resource handler returned message: "Invalid request provided: CreateService error: The target group with targetGroupArn arn:aws:elasticloadbalancing:ap-northeast-1:***:targetgroup/***-targetgp-simpleapi/*** does not have an associated load balancer. (Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException; Request ID: ***; Proxy: null)" (RequestToken: ***, HandlerErrorCode: InvalidRequest)」
これも作成順番のエラー
```
  DependsOn: ElasticLoadBalancingV2Listener
```
をECSServiceに追加

https://houdoukyokucho.com/2022/07/14/post-4158/

#### エラー１２「Resource handler returned message: "Only one primary private IP address can be specified. (Service: Ec2, Status Code: 400, Request ID: ***)" (RequestToken: ***, HandlerErrorCode: InvalidRequest)」
エラー８同様
ECSでデプロイした時に作成されていたものをいれてしまっていたため削除

#### エラー１３ECSサービス作成が終わらない
ECSの状態を確認してみると「ResourceInitializationError: unable to pull secrets or registry auth: execution resource retrieval failed: unable to retrieve ecr registry auth: service call has been retried 3 time(s): RequestError: send request failed caused by: Post "https://api.ecr.ap-northeast-1.amazonaws.com/": dial tcp ***: i/o timeout. Please check your task network configuration.」
とあり、内容としてはECRからのPullの失敗
下記を参考に諸々を追加して解消

https://note.com/shift_tech/n/nf456dd5900df

#### エラー13「Resource handler returned message: "private-dns-enabled cannot be set because there is already a conflicting DNS domain for api.ecr.ap-northeast-1.amazonaws.com in the VPC vpc-*** (Service: Ec2, Status Code: 400, Request ID: ***)" (RequestToken: ***, HandlerErrorCode: GeneralServiceException)」
これはエラー１３修正後にいろいろ作り直ししている際に発生
VPCエンドポイントは削除を行うとDNSが消えるまで時間がかかるかららしい
下記を参考に発生してから30分ほどおいて再度やったら出なかった。

https://infraya.work/posts/vpcendpoint_create_dns_error/

#### エラー１４「ResourceInitializationError: failed to validate logger args: create stream has been retried 1 times: failed to create Cloudwatch log group: AccessDeniedException: User: arn:aws:sts::***:assumed-role/ecsTaskExecutionRole/*** is not authorized to perform: logs:CreateLogGroup on resource: arn:aws:logs:ap-northeast-1:***:log-group:/ecs/***-ecs-task:log-stream: because no identity-based policy allows the logs:CreateLogGroup action status code: 400, request id: *** : exit status 1」
ロググループ無くね？って言ってエラーになっている
```
    awslogs-create-group: "true"
```
ぱっとみこれでなければ自動作成してくれそうだと思い込んでた。
下記を参考にロググループを作成

https://www.yokoyan.net/entry/2021/10/19/180000

#### エラー１５ ECSでdocker pullできない
##### やったこと１　プライベートECRなのでアクセス許可の設定を追加

      RepositoryPolicyText : !Sub |
        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "AllowPushPull",
              "Effect": "Allow",
              "Principal": {
                "AWS": "arn:aws:iam::${AWS::AccountId}:user/${IamUser}"
              },
              "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:CompleteLayerUpload",
                "ecr:GetDownloadUrlForLayer",
                "ecr:InitiateLayerUpload",
                "ecr:PutImage",
                "ecr:UploadLayerPart"
              ]
            }
          ]
        }

##### やったこと２　ルートテーブルにて明示的なサブネットの関連付けされていなかったため関連付けを実施
Former2からアタッチするコードが出力されていなかった、やっぱりアタッチ系は出してくれないのかな？

```
  EC2RouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref EC2RouteTable
      SubnetId: !Ref EC2Subnet2

  EC2RouteTableAssociation2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref EC2RouteTable3
      SubnetId: !Ref EC2Subnet3

  EC2RouteTableAssociation3:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref EC2RouteTable2
      SubnetId: !Ref EC2Subnet

  EC2RouteTableAssociation4:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref EC2RouteTable2
      SubnetId: !Ref EC2Subnet4
```

##### やったこと３　ルートテーブルにインターネットゲートウェイが設定されていない
パブリックサブネット用のルートテーブルに
```
  EC2Route:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref EC2RouteTable2
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref EC2InternetGateway
```
を追加


### 終わりに
ここに出していないシンタックスエラー系とか、合わせて出力されてないといけなかった設定が出力されてないエラー系が
とにかく多く、エラー自体はここに出してる4倍くらいは出てた気がする。
あと、サービスによっては作成までに時間が結構かかったり、ロールバックで止まってしまったりで待ち時間が長かった。

かかった時間的にはそうでもないのかもしれない、見たことないエラーばっかりだから気疲れしただけな気がする
一旦Former2で出力した同一のAWSアカウント上で動作する構築できることを目標で10時間くらいで
別AWSアカウント上で動作する構築できることを目標でもうプラス10時間くらい
公開できるように固定値だったりアカウントIDの環境変数化とかで、もうプラス5時間くらい
大体25時間くらいかかった気がする

根気がいる作業だったけど何とか（自分の環境では）動くようになってくれたのでよかった。。。