AWS CloudFormationのテンプレートをLayer別に作成してクロススタック参照を作ってみた。その2  [ Security-Layer編 ]

## 前回のまでのおさらい
前回のNetwork編ではベースとなるVPC、Subnet,IGW、RouteTなどを作成した。今回は次のステップとして重要なセキュリティ構成をテンプレートで構築していく。
- [その1 [ Network-Layer編 ]](https://qiita.com/ezakiglico0215/items/262c93ef781ac98ca5b9)


## 概要
テンプレートと言われる構築環境をコード化させたファイルに記載し、スタックと呼ばれる作業を行うことでGUI上で作成した状況と同じ環境が自動的に作成される。1つのテンプレートに全ての環境を記載することも可能だが、AWSからは各レイヤー別に分けることがベストプラクティスと言われている。

:::note 
今回は以下3つのLayerに分けて作成する。
- Network Layer　　
- **Security Layer    　　今回はここ！**
- Application Layer
:::

## クロススタック参照
各レイヤー別にテンプレートを作成し1つの環境構築を行うためには、テンプレート間の互換性が必要になる。そのためには`クロススタック参照`を使用して他レイヤーの値を参照できるようにコードに'組込関数'と呼ばれる関数を活用していく作業がポイント。

## 構成図
このセクションではセキュリティグループをポート別に作成し構成図のここまで進める。
![security..drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601549/79bea835-349e-9a6b-8edc-63557b950651.png)


   

### Security Layer
:::note 
今回はEC2,RDS,ALB用として合計3つのセキュリティグループを作成する。VPC、Subnetなどの値は前回作成したNetwork-Layerから引用するため、組込関数の!Importvalueを使用する(Network-Layerのスタック名を今回は自分のスタック名としている）
※Ref、Subなどの関数は同じテンプレート内でなければ引用することができない。
:::


```yaml:Security-Layer.yaml
AWSTemplateFormatVersion: 2010-09-09
Description:
  Creation of SecurityRayer Related


Resources:
  #EC2用のセキュリティグループの作成
  EC2SeculityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: EC2SeculityGroup
      GroupDescription: Connection to Public ports
      VpcId: !ImportValue (スタック名)-VPCID
　　　　　　　　　　 Tags:
        - Key: Name
          Value: CfnSecurityGroupForWEB
# Rule
      SecurityGroupIngress:
        - IpProtocol: tcp  # for ssh
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp  # for ELB(Nginx)
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0

  #RDS用のセキュリティグループの作成
  RDSSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: !ImportValue (スタック名)-VPCID
      GroupName: RDS Security Group
      GroupDescription: "-"
      Tags:
        - Key: Name
          Value: RDS Security Group
# Rule
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          CidrIp: "0.0.0.0/0"


  #ALB用のセキュリティグループの作成
  ALBSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      GroupDescription: for load balancer
      VpcId: !ImportValue (スタック名)-VPCID
      GroupName: ALBSecurityGroup
      Tags:
        - Key: Name
          Value: ALBSecurityGroup
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: "0.0.0.0/0"
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: "0.0.0.0/0"

```
### OUTPuts
Application-Layerで使用するため、OutputsのExportで引用する値を設定

```yaml:Security-Layer.yaml
Outputs:
  StackSgWEB:
    Description: SG's for WEB ID
    Value: !Ref EC2SeculityGroup
    Export:
      Name: !Sub "${AWS::StackName}-Sg-WEB"

  StackSgRDS:
    Description: SG's for RDS ID
    Value: !Ref RDSSecurityGroup
    Export:
      Name: !Sub "${AWS::StackName}-Sg-RDS"
  
  StackSgALB:
    Value: !Ref ALBSecurityGroup
    Export:
      Name: !Sub "${AWS::StackName}-Sg-ALB"
```

## Application-Layerに続く
続きはこちらから。
[AWS CloudFormationのテンプレートをLayer別に作成してクロススタック参照を作ってみた。
その3 [ Application-Layer編 ]](https://qiita.com/ezakiglico0215/items/09719bfbcf6c7f164369)



## エラー事例
テンプレートを構築していく中で、多くのエラーに遭遇。
備忘録を兼ねて事象と解決方法をメモとして残しておく。

:::note alert
テンプレート作成を行う段階で遭遇したエラーと解決方法[主にcfn-lintで事前に検知]

[事象1] **cfn-lint  E1001: Top level template section VPCEndpoint is not valid**
[解決法] 作成したコードの深さの設定ミス：論理IDなどを設定するTOPの位置の深さに設定ミスがあり。

[事象2] **cfn-lint  E0000: Duplicate resource found "ParameterLabels"**
[解決法] コード内容が重複していると検出されるエラー。1つ削除して解消させる。

[事象3] **cfn-lint  E2015: Default should be allowed by AllowedPattern**
[解決法] インプットパラメーターで設定している値の表記ミス、正しく表記できていない。

[事象4] **cfn-lint  E1012: Ref CfnEC2 not found as a resource or parameter**
[解決法] インプットパラメーターで設定している値の表記ミス、正しく表記できていない。

[事象5] **Unresolved resource dependencies [ALBSecurityGroup] in the Outputs block of the template**
[解決法] !Ref関数で指定している引用元の論ID名に相違がある。

[事象6] **No export named sstack-PrivateSubnet1a found. Rollback requested by user**
[解決法] クロススタックで参照している値のtypoミス

[事象7] **Bucket name should not contain uppercase characters**
[解決法] Paraetersに記載しているS3のバケット名に大文字を使用していたため（大文字禁止）


:::