RDS接続時の挙動をセキュリティグループのパターンごとに確認

目次

RDS用のセキュリティグループを確認する構成

RDSに適用するセキュリティグループを確認します。

EC2からRDSにアクセスする場合、ポイントとなるのはセキュリティグループです。EC2インスタンスと同様に、RDSにもセキュリティグループを適用することができます。

セキュリティグループにより DB インスタンスに対する送受信トラフィックへのアクセスを制御します。 (中略) デフォルトでは、ネットワークアクセスは、DB インスタンスで無効になっています。セキュリティグループで IP アドレス範囲、ポート、またはセキュリティグループからのアクセスを許可するルールを指定できます。

セキュリティグループによるアクセスコントロール

上記の通り、セキュリティグループを適切に設定しなければ、EC2インスタンスはRDSにアクセスすることはできません。今回はRDSに設定するセキュリティグループに関して3つのパターンを用意して、動作を確認します。

構築する環境

Diagram of checking RDS connection by security gorup pattern.

プライベートサブネットの1つに、EC2インスタンスを配置します。インスタンスは、後述のRDSへアクセスするクライアントとして動作します。インスタンスは、最新版のAmazon Linux2のAMIをベースにします。

MySQLタイプのRDSインスタンスを作成します。RDSとセキュリティグループの関係を明らかにするために、3つのパターンを用意します。なおセキュリティグループ以外の設定は全て同一とします。

  • セキュリティグループ設定なし
  • 許可するインバウンド通信が1つもないセキュリティグループを適用する
  • MySQL通信(3306/tpc)を許可するセキュリティグループを適用する

S3用VPCエンドポイントを作成します。MySQLインスタンスに接続するためのクライアントをインストールするためです。

セキュリティグループによって、RDS接続時の挙動がどのように変化するかを確認するために、以下の手順で検証します。

  1. EC2インスタンス・RDSインスタンスを配置したプライベートサブネットでVPCフローログを有効化する。
  2. EC2インスタンスにリモートアクセスし、3つのRDSインスタンスにアクセスを試みる。
  3. アクセス結果およびアクセス時のフローログを確認する。

環境構築用のCloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。

以下のURLにCloudFormationテンプレートを配置してます。

https://github.com/awstut-an-r/awstut-soa/tree/main/05/001

テンプレートファイルのポイント解説

今回のアーキテクチャを構成するための、各テンプレートファイルのポイントを取り上げます。

RDS用セキュリティグループ

RDSインスタンスに適用するセキュリティグループを確認します。いくつかパターンを用意します。

Resources:
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${Prefix}-InstanceSecurityGroup"
      GroupDescription: Deny All.
      VpcId: !Ref VPC

  RDSDenySecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${Prefix}-RDSDenySecurityGroup"
      GroupDescription: Deny All.
      VpcId: !Ref VPC

  RDSAllowSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub "${Prefix}-RDSAllowSecurityGroup"
      GroupDescription: Allow MySQL.
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: !Ref MySQLPort
          ToPort: !Ref MySQLPort
          SourceSecurityGroupId: !Ref InstanceSecurityGroup
Code language: YAML (yaml)

RDSインスタンスに適用可能なセキュリティグループには3種類あります。

VPC セキュリティグループは、VPC 内の DB インスタンスと EC2 インスタンスへのアクセスを制御します。

DB セキュリティグループは、VPC 内にない EC2-Classic DB インスタンスへのアクセスを制御します。

EC2-Classic セキュリティグループは、EC2 インスタンスへのアクセスを制御します。

セキュリティグループによるアクセスコントロール

今回は通常のVPC内に設置されているRDSインスタンスが対象となりますので、VPCセキュリティグループを作成し、適用します。

定義する1つ目のセキュリティグループ(InstanceSecurityGroup)はEC2インスタンスに適用するものです。SecurityGroupIngressプロパティは設定しません。今回の構成では、Ec2インスタンスへのインバウンド通信は発生しないためです。

2つ目(RDSDenySecurityGroup)はRDSインスタンス用のセキュリティグループです。こちらもSecurityGroupIngressプロパティを設定しません。

3つ目(RDSAllowSecurityGroup)もRDSインスタンス用です。こちらはSecurityGroupIngressプロパティでMySQL通信(3306/tcp)を許可するように設定します。また送信元に先述のEC2インスタンス用セキュリティグループを指定することで、EC2インスタンスからのアクセスのみを許可します。

UserDataでMySQLクライアントのインストール処理を定義する

EC2インスタンスを確認します。ポイントはユーザーデータによるインスタンスの初期化処理です。

Resources:
  Instance:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref PrivateSubnet1
          GroupSet:
            - !Ref InstanceSecurityGroup
      UserData: !Base64 |
        #!/bin/bash -xe
        yum update -y
        yum install -y mariadb
Code language: YAML (yaml)

今回のEC2インスタンスの役目は、MySQLタイプのRDSインスタンスにアクセスするクライアントとしての働きです。ですからMySQLクライアントをインストールする必要があります。

Amazon Linux 2の場合、MySQLクライアントはmariadbパッケージからインストールできます。同パッケージはS3バケット上に構築されているAmazon Linuxリポジトリから取得可能です。今回はS3用VPCエンドポイント経由で、同リポジトリにアクセスします。
RDSインスタンスのクライアントツールおよび接続方法については、以下のページをご確認ください。

あわせて読みたい
AL2で全RDSに接続する方法まとめ 【Amazon Linux 2からRDSの全DBエンジンに接続する方法】 2022年現在、RDSは以下の7種類のDBエンジンを提供しています。 Aurora(PostgreSQL) Aurora(MySQL) PostgreSQL ...

EC2インスタンスの初期化処理はいくつかありますが、今回はユーザーデータを使用します。
ユーザーデータはUserDataプロパティで設定します。先述のmariadbパッケージのインストール処理を記載します。

ユーザーデータを含むインスタンスの初期化処理に関する詳細は、以下のページもご確認ください。

あわせて読みたい
Linuxインスタンスの初期化方法4選 【Linuxインスタンスを初期化する4つの方法】 EC2インスタンスの起動時に初期化処理を実行する方法を考えます。 EC2インスタンスを構築時に初期化する以下の4つの手法を...

3パターンのRDSインスタンスを定義する

RDSインスタンスを確認します。

Resources:
  DBInstance1:
    Type: AWS::RDS::DBInstance
    Properties:
      AllocatedStorage: !Ref DBAllocatedStorage
      AvailabilityZone: !Sub "${AWS::Region}${AvailabilityZone1}"
      DBInstanceClass: !Ref DBInstanceClass
      DBInstanceIdentifier: dbinstance1
      DBName: !Ref DBName
      DBSubnetGroupName: !Ref DBSubnetGroup
      Engine: !Ref DBEngine
      EngineVersion: !Ref DBEngineVersion
      MasterUsername: !Ref DBMasterUsername
      MasterUserPassword: !Ref DBMasterUserPassword
      #VPCSecurityGroups:

  DBInstance2:
    Type: AWS::RDS::DBInstance
    Properties:
      ...
      VPCSecurityGroups:
        - !Ref RDSDenySecurityGroup

  DBInstance3:
    Type: AWS::RDS::DBInstance
    Properties:
      ...
      VPCSecurityGroups:
        - !Ref RDSAllowSecurityGroup
Code language: YAML (yaml)

セキュリティグループに関する設定以外は全て同じRDSインスタンスを3台用意します。

1台目のインスタンス(DBInstance1)は、セキュリティグループに関する設定を行いません。

2台目のインスタンス(DBInstance2)は、VPCSecurityGroupsプロパティにて、許可するインバウンド通信が1つもないセキュリティグループを適用します。

3台目のインスタンス(DBInstance3)は、MySQL通信(3306/tcp)のみを許可するセキュリティグループを適用します。

CloudWatch LogsにVPCフローログを保存する

soa-05-001-flowlog.yamlでVPCフローログ関係のリソースを定義します。

Resources:
  FlowLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "${Prefix}-FlowLogGroup"

  FlowLogToCloudWatchLogs:
    Type: AWS::EC2::FlowLog
    DependsOn:
      - FlowLogGroup
    Properties:
      DeliverLogsPermissionArn: !GetAtt DeliverLogRole.Arn
      LogDestinationType: cloud-watch-logs
      LogGroupName: !Sub "${Prefix}-FlowLogGroup"
      ResourceId: !Ref VPC
      ResourceType: VPC
      TrafficType: ALL
Code language: YAML (yaml)

VPCフローログはVPC内のネットワークログを収集できるサービスです。

VPC フローログは、VPC のネットワークインターフェイスとの間で行き来する IP トラフィックに関する情報をキャプチャできるようにする機能です。フローログデータは Amazon CloudWatch Logs または Amazon S3 に発行できます。

VPC フローログ

今回はCloudWatch LogsにVPCフローログを配信します。収集する範囲ですが、VPC全体の全てのログとします。

VPCフローログの詳細については、以下のページをご確認ください。

あわせて読みたい
VPCフローログをS3/CloudWatch Logsに配信する 【VPCフローログを取得する構成】 VPCフローログを確認します。 VPCフローログはVPC内のトラフィック情報を取得することができるサービスです。 VPC フローログは、VPC ...

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。

スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • インスタンスのID:i-0fe6d50e5958523a4
  • DBInstance1のエンドポイント:dbinstance1.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
  • DBInstance2のエンドポイント:dbinstance2.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
  • DBInstance3のエンドポイント:dbinstance3.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
  • DBInstance1にアタッチされているENI:eni-085da82d3ccb0f0ad
  • DBInstance2にアタッチされているENI:eni-0acae018ffc56ba56
  • DBInstance3にアタッチされているENI:eni-0e71f2697f24bffbf
  • CloudWatch Logsのロググループ名:soa-05-001-FlowLogGroup

各DBインスタンスにアタッチされているセキュリティグループは以下の通りです。

Security groups attached to RDS.

またDBインスタンスにアタッチされているENIは、インスタンスのページから確認することができます。

ENIs attached to RDS.

事前準備1 – SSM Session Manager経由でインスタンスでアクセスする

準備が整いましたので、EC2インスタンスにアクセスします。

アクセスはSSM Session Managerを通じて行います。

$ aws ssm start-session \
--target i-0fe6d50e5958523a4

Starting session with SessionId: root-0539c6fe4b063eeb4
sh-4.2$
Code language: Bash (bash)

正常にアクセスすることができました。

SSM Session Managerに関しては、以下をご確認ください。

あわせて読みたい
LinuxインスタンスにSSM Session Manager経由でアクセスする 【LinuxインスタンスにSSM Session Manager経由でアクセスする】 EC2インスタンスにSSM Session Manager経由でアクセスする構成を確認します。 Session Manager は完全...

アクセス後、ユーザーデータで定義した、MySQLクライアントのインストール状況を確認します。

sh-4.2$ sudo yum list installed | grep mysql
mysql-community-client.aarch64        8.0.27-1.el7                   @mysql80-community
mysql-community-client-plugins.aarch64        8.0.27-1.el7                   @mysql80-community
mysql-community-common.aarch64        8.0.27-1.el7                   @mysql80-community
mysql-community-libs.aarch64          8.0.27-1.el7                   @mysql80-community
mysql-community-libs-compat.aarch64   8.0.27-1.el7                   @mysql80-community
mysql80-community-release.noarch      el7-1                          installed  Code language: PHP (php)

インスタンスの初期化中に、正常にインストールされていることが確認できます。

事前準備2 – CloudWatch Logsに配信されたVPCフローログを確認する

現時点で配信されているVPCフローログを確認します。

A stream of VPC flow logs is created for each ENI.

VPC上に存在するENIごとにログストリームが生成されていることがわかります。

赤枠の上から順に、DBInstance3, DBInstance2, DBInstance1のストリームです。

RDS接続試験1 – セキュリティグループなし

まずDBインスタンス1から試験を始めます。

このインスタンスにはセキュリティグループが定義されていません。

試験を始める前に、nslookupコマンドでエンドポイントに設定されているIPアドレスを確認します。これは後ほどVPCフローログを確認する際に、RDSに設定されているIPアドレスを使用してログを検索するためです。

sh-4.2$ nslookup dbinstance1.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
Server:         10.0.0.2
Address:        10.0.0.2#53

Non-authoritative answer:
Name:   dbinstance1.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
Address: 10.0.3.213
Code language: Bash (bash)

アドレスは10.0.3.213でした。

それでは試験を始めます。インストールしたmysqlコマンドでアクセスを試みます。

sh-4.2$ mysql -u testuser -p -h dbinstance1.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
Enter password:
ERROR 2003 (HY000): Can't connect to MySQL server on 'dbinstance1.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com:3306' (110)
Code language: Bash (bash)

失敗しました。しばらく待つとエラーメッセージが返ってきます。

失敗時のVPCフローログは以下の通りです。

Patterns for not setting security groups for DBInstance.

VPCフローログの見方はVPC フローログに詳しいですが、10.0.3.213:3306宛にパケットを送った結果、REJECTされていることがわかります。

以上のことから、DBインスタンス1にはセキュリティグループを適用していないため、全インバウンド通信が拒否されるという挙動となり、アクセス失敗という結果になったことがわかります。

RDS接続試験2 – 許可するインバウンド通信が1つもなし

次にDBインスタンス2に対して試験を行います。手順は先ほどと同様です。

sh-4.2$ nslookup dbinstance2.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
Server:         10.0.0.2
Address:        10.0.0.2#53

Non-authoritative answer:
Name:   dbinstance2.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
Address: 10.0.3.205
Code language: Bash (bash)
sh-4.2$ mysql -u testuser -p -h dbinstance2.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
Enter password:
ERROR 2003 (HY000): Can't connect to MySQL server on 'dbinstance2.cl50iikpthxs.ap-northeast-1.rds.a
mazonaws.com:3306' (110)
Code language: Bash (bash)
Patterns in which the security group set for DBInstance is not appropriate.

こちらも失敗しました。フローログでも、10.0.3.205へのMySQL通信が拒否されていることがわかります。

以上のことから、セキュリティグループにおいて1つもインバウンド通信を許可しないということは、全インバウンド通信を拒否するということと同義であり、セキュリティグループを設定していない場合と同様の挙動になることをわかりました。

RDS接続試験3 – MySQL通信を許可

最後にDBインスタンス3に対して試験を行います。

sh-4.2$ nslookup dbinstance3.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
Server:         10.0.0.2
Address:        10.0.0.2#53

Non-authoritative answer:
Name:   dbinstance3.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
Address: 10.0.3.82
Code language: Bash (bash)
sh-4.2$ mysql -u testuser -p -h dbinstance3.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 29
Server version: 8.0.23 Source distribution

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
Code language: Bash (bash)
Patterns with appropriate security groups set for DBInstance.

アクセスに成功しました。フローログを確認しても、EC2インスタンスからDBインスタンス3に送信したパケットと、戻りのパケットがACCEPTされていることがわかります。

以上のことから、RDSに対して、データベースシステムに応じた適切なセキュリティグループを適用することによって、アクセスできるようになることがわかりました。

まとめ

3パターンのRDSインスタンスを作成し、セキュリティグループによる挙動の違いを確認しました。

RDSにアクセスするためには、データベースシステムに応じた適切なセキュリティグループが設定されている必要があることがわかりました。

RDSに対してセキュリティグループを適用しない、あるいは適切なインバウンド通信を許可しないセキュリティグループを適用している場合は、正常に通信することができないことを確認しました。

目次