FSxW + EC2(Win,Linux)構築ハンズオン

## はじめに
FSxを久しぶりにハンズオンで構築しようとしたら、すっかり細かい設定を忘れていたので、こういったものこそCFnしておかなければなと思い立ったのでハンズオン。
いろいろハマりました。

------------

## 構成図
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-18-18.01.43-574x640.png)

------------

## ハンズオン
### 構築のながれ
#### 1.Amazon FSx環境作成　

-----------

### 1.Amazon FSx環境作成　

#### 1.1.主な作成リソース一覧
|サービス名|CIDR|用途|
|:-:|:-:|:-:|
|VPC|192.168.0.0/16|-|
|PublicSubnetA|192.168.10.0/24|EC2(Windows)用|
|PublicSubnetB|192.168.20.0/24|EC2(Linux)用|
|PrivateSubnetA|192.168.30.0/24|MicrosoftAD用|
|PrivateSubnetB|192.168.40.0/24|MicrosoftAD用|
|PrivateSubnetC|192.168.50.0/24|FSx用|
|PrivateSubnetD|192.168.60.0/24|FSx用|
|PublicRouteTable|-|Public ルートテーブル|
|PrivateRouteTable|-|Private ルートテーブル|
|MicrosoftAD|192.168.${30,40}.XX|FSx構築の際必須リソース|
|EC2 SecurityGroup|-|EC2用セキュリティグループ|
|EC2(Windows)|192.168.10.YY|FSxマウント用EC2|
|EC2(AmazonLinux)|192.168.20.ZZ|FSxマウント用EC2|
|FSx SecurityGroup|-|FSx用セキュリティグループ|
|FSx|192.168.${50,60}.AA|FSx|

#### 1.2.テンプレート
・全てのリソースが構築されるには30分程度かかります。
・個人的にハマった`MicrosoftAD`と`EC2(Windows)`は別途記載あり。

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: FSx Create
# ------------------------------------------------------------#
#  Metadata
# ------------------------------------------------------------#
Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "NetWork Configuration"
        Parameters:
          - VpcCidrPrefix
      - Label:
          default: "MicrosoftAD Configuration"
        Parameters:
          - MicrosoftAdDomainName
          - MicrosoftPassword
      - Label:
          default: "EC2 Configuration"
        Parameters:
          - Ec2Image-amazonlinuxId
          - EC2Image-WindowsID
          - MyIP
          - KeyName
      - Label:
          default: "Tags"
        Parameters:
          - UserName
        
# ------------------------------------------------------------#
#  InputParameters
# ------------------------------------------------------------#
Parameters:
  VpcCidrPrefix:
    Type: String
    Description: '(Example: 10.22)'
    Default: 【CIDRプレフィックス】

  MicrosoftAdDomainName:
    Type: String
    Description: '(Example: inamura.local)'
    Default: 【ドメイン名】

  MicrosoftAdPassword:
    Type: String
    NoEcho: True

  Ec2ImageAmazonlinuxId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

  EC2ImageWindowsID:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-windows-latest/Windows_Server-2016-Japanese-Full-Base

  MyIP:
    Type: String
    Description: 'MyIP'
    Default: 【利用しているIPを記入】

  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Default: 【利用しているKeyPairを記入】

  UserName:
    Type: String
    Description: 'TagsName'
    Default: 【タグを利用の場合】



# ------------------------------------------------------------#
#  Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
#  VPC
# ------------------------------------------------------------#
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Sub '${VpcCidrPrefix}.0.0/16'
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-vpc'
        - Key: UserName
          Value: !Ref UserName
# ------------------------------------------------------------#
#  IGW
# ------------------------------------------------------------#
  IGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-igw'

  VPCGW:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref IGW
# ------------------------------------------------------------#
#  Public Subnet
# ------------------------------------------------------------#
  PublicSubnetA: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: !Select
        - 0
        - Fn::GetAZs: !Ref 'AWS::Region'
      CidrBlock: !Sub '${VpcCidrPrefix}.10.0/24'
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-public-a"
        - Key: User
          Value: !Ref UserName

  PublicSubnetB: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: !Select
        - 1
        - Fn::GetAZs: !Ref 'AWS::Region'
      CidrBlock: !Sub '${VpcCidrPrefix}.20.0/24'
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-public-b"
        - Key: User
          Value: !Ref UserName

# ------------------------------------------------------------#
#  Private Subnet
# ------------------------------------------------------------#
  PrivateSubnetA: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: !Select
        - 0
        - Fn::GetAZs: !Ref 'AWS::Region'
      CidrBlock: !Sub '${VpcCidrPrefix}.30.0/24'
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-private-a"
        - Key: User
          Value: !Ref UserName

  PrivateSubnetB: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: !Select
        - 1
        - Fn::GetAZs: !Ref 'AWS::Region'
      CidrBlock: !Sub '${VpcCidrPrefix}.40.0/24'
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-private-b"
        - Key: User
          Value: !Ref UserName

  PrivateSubnetC: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: !Select
        - 0
        - Fn::GetAZs: !Ref 'AWS::Region'
      CidrBlock: !Sub '${VpcCidrPrefix}.50.0/24'
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-private-c"
        - Key: User
          Value: !Ref UserName

  PrivateSubnetD: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: !Select
        - 1
        - Fn::GetAZs: !Ref 'AWS::Region'
      CidrBlock: !Sub '${VpcCidrPrefix}.60.0/24'
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub "${AWS::StackName}-private-d"
        - Key: User
          Value: !Ref UserName
# ------------------------------------------------------------#
#  Public RouteTable
# ------------------------------------------------------------#
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-public-routetable'
        - Key: User
          Value: !Ref UserName

# ------------------------------------------------------------#
# Routing
# ------------------------------------------------------------#
  PublicRoute: 
    Type: "AWS::EC2::Route"
    Properties: 
      RouteTableId: !Ref PublicRouteTable 
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref IGW

  VpcPublicSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetA
      RouteTableId: !Ref PublicRouteTable

  VpcPublicSubnetBRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetB
      RouteTableId: !Ref PublicRouteTable
# ------------------------------------------------------------#
#  Private RouteTable
# ------------------------------------------------------------#
  PrivateRouteTable: 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC 
      Tags: 
        - Key: Name
          Value: !Sub '${AWS::StackName}-private-routetable'
        - Key: User
          Value: !Ref UserName

  PrivateSubnetARouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PrivateSubnetA
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnetBRouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PrivateSubnetB
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnetCRouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PrivateSubnetC
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnetDRouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PrivateSubnetD
      RouteTableId: !Ref PrivateRouteTable
# ------------------------------------------------------------#
#  MicrosoftAD
# ------------------------------------------------------------#        
  MicrosoftAD:
    Type: AWS::DirectoryService::MicrosoftAD
    Properties:
      Name: !Ref MicrosoftAdDomainName
      Password: !Ref MicrosoftAdPassword
      VpcSettings:
        SubnetIds:
          - !Ref PrivateSubnetA
          - !Ref PrivateSubnetB
        VpcId: !Ref VPC
      Edition: Standard

  DHCPOptions:
    Type: AWS::EC2::DHCPOptions
    Properties:
      DomainName: !Ref MicrosoftAdDomainName
      DomainNameServers: !GetAtt MicrosoftAD.DnsIpAddresses
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-dhcp-options'

  VPCDHCPOptionsAssociation:
    Type: AWS::EC2::VPCDHCPOptionsAssociation
    Properties:
      DhcpOptionsId: !Ref DHCPOptions
      VpcId: !Ref VPC

# ------------------------------------------------------------#
#  SG EC2 Windows&Linux
# ------------------------------------------------------------#
  Ec2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub '${AWS::StackName}-ec2-sg'
      GroupName: !Sub '${AWS::StackName}-ec2-sg'
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      SecurityGroupIngress:
        - CidrIp: !GetAtt VPC.CidrBlock
          Description: allow all access from vpc
          IpProtocol: "-1"
          FromPort: "-1"
          ToPort: "-1"
        - CidrIp: !Sub '${MyIP}/32'
          Description: allow all access from MyIP
          IpProtocol: "-1"
          FromPort: "-1"
          ToPort: "-1"
      VpcId: !Ref VPC
      Tags: 
        - Key: UserName
          Value: !Ref UserName
# ------------------------------------------------------------#
#  IAM EC2 Windows&Linux
# ------------------------------------------------------------#
  Ec2IamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
        - 'arn:aws:iam::aws:policy/AmazonSSMDirectoryServiceAccess'
      RoleName: !Sub '${AWS::StackName}-iamrole'

  Ec2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref Ec2IamRole
# ------------------------------------------------------------#
#  EC2 Windows
# ------------------------------------------------------------#
  EC2Windows:
    DependsOn: FSx
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: !Select
        - 0
        - Fn::GetAZs: !Ref 'AWS::Region'
      ImageId: !Ref EC2ImageWindowsID
      IamInstanceProfile: !Ref Ec2InstanceProfile
      InstanceInitiatedShutdownBehavior: stop
      InstanceType: t2.micro
      KeyName: !Ref KeyName
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnetA
          GroupSet:
            - !Ref Ec2SecurityGroup
      SsmAssociations:
        - AssociationParameters:
            - Key: directoryId
              Value:
                - !Ref MicrosoftAD
            - Key: directoryName
              Value:
                - !Ref MicrosoftAdDomainName
          DocumentName: AWS-JoinDirectoryServiceDomain
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-windows'
        - Key: UserName
          Value: !Ref UserName
# ------------------------------------------------------------#
#  EC2 Linux
# ------------------------------------------------------------#
  EC2Linux:
    DependsOn: EC2Windows
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: !Select
        - 1
        - Fn::GetAZs: !Ref 'AWS::Region'
      ImageId: !Ref Ec2ImageAmazonlinuxId
      IamInstanceProfile: !Ref Ec2InstanceProfile
      InstanceInitiatedShutdownBehavior: stop
      InstanceType: t2.micro
      KeyName: !Ref KeyName
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnetB
          GroupSet:
            - !Ref Ec2SecurityGroup
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-linux'
        - Key: UserName
          Value: !Ref UserName

# ------------------------------------------------------------#
#  SG FSx
# ------------------------------------------------------------#
  FSXSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub '${AWS::StackName}-fsx-sg'
      GroupName: !Sub '${AWS::StackName}-fsx-sg'
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          Description: Allow all outbound traffic by default
          IpProtocol: "-1"
      SecurityGroupIngress:
        - CidrIp: !GetAtt VPC.CidrBlock
          Description: allow all access from vpc
          IpProtocol: "-1"
      VpcId: !Ref VPC

# ------------------------------------------------------------#
#  FSx
# ------------------------------------------------------------#
  FSx:
    Type: AWS::FSx::FileSystem
    Properties:
      FileSystemType: WINDOWS
      SubnetIds:
        - !Ref PrivateSubnetC
        - !Ref PrivateSubnetD
      SecurityGroupIds:
        - !GetAtt FSXSecurityGroup.GroupId
      StorageCapacity: 32
      StorageType: SSD
      WindowsConfiguration:
        ActiveDirectoryId: !Ref MicrosoftAD
        AutomaticBackupRetentionDays: 0
        DeploymentType: MULTI_AZ_1
        PreferredSubnetId: !Ref PrivateSubnetC
        ThroughputCapacity: 8
      Tags:        
        - Key: UserName
          Value: !Ref UserName
```

<br />

#### 1.3.テンプレート解説
##### 1.3.1.MicrosoftAD
・DHCPオプションを作成して、ADを含むVPCにDHCPオプション設定を割り当てる。これによりVPC内のインスタンスで、指定のドメイン及びDNSサーバを参照してドメイン名を解決できるようになる。
参考：[DHCP オプションセットの作成](https://docs.aws.amazon.com/ja_jp/directoryservice/latest/admin-guide/simple_ad_dhcp_options_set.html)
```yaml
# ------------------------------------------------------------#
#  MicrosoftAD
# ------------------------------------------------------------#        
  MicrosoftAD:
    Type: AWS::DirectoryService::MicrosoftAD
    Properties:
      Name: !Ref MicrosoftAdDomainName
      Password: !Ref MicrosoftAdPassword
      VpcSettings:
        SubnetIds:
          - !Ref PrivateSubnetA
          - !Ref PrivateSubnetB
        VpcId: !Ref VPC
      Edition: Standard

  DHCPOptions:
    Type: AWS::EC2::DHCPOptions
    Properties:
      DomainName: !Ref MicrosoftAdDomainName
      DomainNameServers: !GetAtt MicrosoftAD.DnsIpAddresses
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-dhcp-options'

  VPCDHCPOptionsAssociation:
    Type: AWS::EC2::VPCDHCPOptionsAssociation
    Properties:
      DhcpOptionsId: !Ref DHCPOptions
      VpcId: !Ref VPC
```

##### 1.3.2.EC2(Windows)
・EC2のロールに`AmazonSSMManagedInstanceCore`,`AmazonSSMDirectoryServiceAccess`を付与する。こちらのロールにより、EC2Windowsの項目にある`SsmAssociations`が実行できる。
・`SsmAssociations`により、EC2インスタンス構築時にAWS Managed MicorsoftADに参加させることができる。
参考:[Windows Server 用の EC2 インスタンスとドメインとのシームレス結合をテストする](https://docs.aws.amazon.com/ja_jp/directoryservice/latest/admin-guide/step4_test_ec2_access.html)
※EC2はパブリックに配置しているので、InternetGatewayを経由してSSMへ通信を行う
・EC2の`DependsOn: FSx`は、構築直後`AWS Managed MicorsoftAD`のステータスが「Impaired」の状態のため、順番を制御してステータスが変わるのを待つために記載する。

```yaml
# ------------------------------------------------------------#
#  IAM EC2 Windows&Linux
# ------------------------------------------------------------#
  Ec2IamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
        - 'arn:aws:iam::aws:policy/AmazonSSMDirectoryServiceAccess'
      RoleName: !Sub '${AWS::StackName}-iamrole'

  Ec2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref Ec2IamRole
# ------------------------------------------------------------#
#  EC2 Windows
# ------------------------------------------------------------#
  EC2Windows:
    DependsOn: FSx
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: !Select
        - 0
        - Fn::GetAZs: !Ref 'AWS::Region'
      ImageId: !Ref EC2ImageWindowsID
      IamInstanceProfile: !Ref Ec2InstanceProfile
      InstanceInitiatedShutdownBehavior: stop
      InstanceType: t2.micro
      KeyName: !Ref KeyName
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnetA
          GroupSet:
            - !Ref Ec2SecurityGroup
      SsmAssociations:
        - AssociationParameters:
            - Key: directoryId
              Value:
                - !Ref MicrosoftAD
            - Key: directoryName
              Value:
                - !Ref MicrosoftAdDomainName
          DocumentName: AWS-JoinDirectoryServiceDomain
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-windows'
        - Key: UserName
          Value: !Ref UserName
```

------------

### 挙動の確認
#### 1.EC2(Windows,Linux)のFSxマウント方法を確認
#####　1.1.マウント方法確認
FSx > アタッチを押下
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-19-7.02.43-1-640x193.png)
<br />

#####　1.2.各種マウント方法確認
各種アタッチしたい方法選択する
今回は赤枠のWindowsの場合と、Linuxの2つを実施する
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-19-7.04.46.png)
<br />

#### 2.EC2(Windows)をFSxにマウント
##### 2.1.EC2(Windows)のマウント方法確認
1.2.のWindowsのマウント方法を確認する
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-19-7.13.54.png)
<br />
##### 2.2.EC2(Windows)のマウントコマンド実施
EC2（Windows）にRDPしてコマンドプロンプトを開く
※EC2をパブリックサブネットに配置しているので、SSMを利用してフリートマネージャから実施可能

・ユーザ名：Admin＠【ドメイン名】
・パスワード：`MicrosoftAdPassword`で入力したパスワード
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-19-7.35.33-640x71.png)
<br />

##### 2.3.EC2(Windows)のマウント成功確認
ブラウザよりマウントされていることを確認できる
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-19-7.11.31-2-640x506.png)
<br />
#### 3.EC2(Linux)をFSxにマウント
##### 3.1.EC2(Linux)のマウント方法確認
1.2.のLinuxのマウント方法を確認する
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-19-7.14.14.png)


##### 3.2.EC2(Linux)のマウントコマンド実施
EC2（Linux）にログインして、記載してあるコマンドを実施していく
※EC2をパブリックサブネットに配置しているので、SSMを利用してフリートマネージャから実施可能
・`cifs-utils`のインストール
・`mkdir /FSx` を作成して、`local_path`部分を作成
・`user@DOMAIN`部分は、Windowsと同様に Admin@【ドメイン名】
・パスワード：`MicrosoftAdPassword`で入力したパスワード

【入力したコマンド】
```yaml
sudo su -
sudo yum install cifs-utils
※インストール中に（y/n）は　y　を選択
mkdir /FSx
sudo mount -t cifs -o vers=3.0,sec=ntlmsspi,user=Adomin@【ドメイン名】 //192.168.50.155/share /FSx

```
##### 3.3.EC2(linux)のマウント成功確認
`df`コマンドで赤枠部分にマウントされていることが確認できる
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-19-9.28.45.png)
<br />

#### 4.ファイル共有の確認
##### 4.1.EC2(Linux)でファイル作成
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-19-9.31.46.png)
<br />
##### 4.2.EC2(Windows)でファイルを確認する
EC2(Linux)で作成されたファイルが共有されていることを確認する
![](https://cloud5.jp/wp-content/uploads/2023/02/スクリーンショット-2023-02-19-9.38.23-640x302.png)

------------

## さいごに
さっくりできるものかと思っていましたが、EC2インスタンス構築時の`Microsoft AD`に参加させる部分が、かなり分かっていなかったので理解が捗りました。
エラーへのアプローチも、記載しているテンプレート全てを実行して失敗を待つと検証するにも15分程度かかってしまうので、ネットワーク部分とEC2部分にテンプレートを分けたりして`何がわかっていないのか？`を炙り出すことで理解に至りました。