Configure to check security group for RDS
Check the security group to be applied to RDS.
When accessing RDS from EC2, the key point is the security group; just like EC2 instances, you can apply security groups to RDS as well.
Security groups control the access that traffic has in and out of a DB instance…
By default, network access is disabled for a DB instance. You can specify rules in a security group that allow access from an IP address range, port, or security group.
Controlling access with security groups
As mentioned above, an EC2 instance will not be able to access RDS unless the security group is properly configured. In this article, we will prepare three patterns regarding the security group to be set for RDS, and check their operation.
Environment
In one of the private subnets, place an EC2 instance. The instance will act as a client that accesses the RDS as described below. The instance will be based on an AMI of the latest version of Amazon Linux2.
Create an RDS instance of type MySQL. 3 patterns are provided to clarify the relationship between RDS and security groups. All settings except for the security group should be the same.
- No security group setting
- Apply a security group that does not have a single inbound communication to allow.
- Apply a security group that allows MySQL communication (3306/tpc)
Create a VPC endpoint for S3, to install a client to connect to the MySQL instance.
In order to see how the RDS connection behavior changes depending on the security group, we will follow the steps below.
- enable VPC flow logging on the private subnet where the EC2 instance and RDS instance are placed.
- remotely access the EC2 instance and attempt to access the three RDS instances..
- Check the access results and the flow log at the time of access.
CloudFormation template files
We will build the above configuration using CloudFormation.
The CloudFormation template is placed at the following URL
https://github.com/awstut-an-r/awstut-soa/tree/main/05/001
Template points
We will cover the key points of each template file to configure this architecture.
Create security group for RDS
Identify the security group to be applied to the RDS instance.
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)
There are three types of security groups that can be applied to RDS instances.
A VPC security group controls access to DB instances and EC2 instances inside a VPC.
A DB security group controls access to EC2-Classic DB instances that are not in a VPC.
An EC2-Classic security group controls access to an EC2 instance.
Controlling access with security groups
In this case, we will create and apply a VPC security group to the RDS instances that are installed in a regular VPC.
The first security group that we will define (InstanceSecurityGroup) is the one that will be applied to the EC2 instance; we will not set the SecurityGroupIngress property. Do not set the SecurityGroupIngress property, because in this configuration, no inbound communication to the Ec2 instance will occur.
The second one (RDSDenySecurityGroup) is a security group for RDS instances. The SecurityGroupIngress property is not set here either.
The third one (RDSAllowSecurityGroup) is also for RDS instances. For this one, set the SecurityGroupIngress property to allow MySQL communication (3306/tcp). Also, by specifying the aforementioned security group for EC2 instances as the sender, only access from EC2 instances will be allowed.
Define MySQL client installation process in UserData
Check the EC2 instance. The point is the initialization process of the instance with user data.
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)
The role of the EC2 instance in this case is to act as a client to access a MySQL-type RDS instance, so we need to install a MySQL client.
For Amazon Linux 2, the MySQL client can be installed from the mariadb package. The package can be obtained from Amazon Linux repositories built on S3 buckets. In this case, the repository is accessed via the VPC endpoint for S3.
For more information on client tools and connection methods for RDS instances, please refer to the following page.
User data is set in the UserData property. In this article, we will describe the process of installing the same client after installing the repository containing the MySQL client.
There are several EC2 instance initialization processes, but this time we will use user data.
User data is set with the UserData property. Describes the process of installing the mariadb package.
For more details on the initialization process of the instance containing the user data, please refer to the following page as well.
Define three patterns of RDS instances
Check the RDS instance.
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)
We will prepare three RDS instances that are identical in all respects except for the security group settings.
The first instance (DBInstance1) will not have any security group settings.
For the second instance (DBInstance2), in the VPCSecurityGroups property, apply a security group that does not have any inbound communication to allow.
For the third instance (DBInstance3), apply a security group that only allows MySQL communication (3306/tcp).
Store VPC flow logs in CloudWatch Logs
Define the resources related to VPC flow log in soa-05-001-flowlog.yaml.
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 Flow Log is a service that can collect network logs within a VPC.
VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. Flow log data can be published to Amazon CloudWatch Logs or Amazon S3.
VPC Flow Logs
This time, we will distribute VPC flow logs to CloudWatch Logs. As for the scope of collection, we will assume that it is all logs for the entire VPC.
For more information on VPC flow logs, please refer to the following page.
Architecting
We will use CloudFormation to build this environment and check its actual behavior.
Create CloudFormation stacks and check resources in stacks
Create a CloudFormation stack.
For more information on how to create stacks and check each stack, please refer to the following page.
After checking the resources for each stack, the information for the main resource created this time is as follows
- Instance ID: i-0fe6d50e5958523a4
- Endpoint for DBInstance1: dbinstance1.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
- DBInstance2 endpoint: dbinstance2.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
- Endpoint for DBInstance3: dbinstance3.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
- ENI attached to DBInstance1: eni-085da82d3ccb0f0ad
- ENI attached to DBInstance2: eni-0acae018ffc56ba56
- ENI attached to DBInstance3: eni-0e71f2697f24bffbf
- CloudWatch Logs log group name: soa-05-001-FlowLogGroup
The security groups attached to each DB instance are as follows.
You can also check the ENIs attached to the DB instance from the instance page.
Prep 1 – Accessing with instance via SSM Session Manager
Now that we are ready, we will access the EC2 instance.
Access is done through the SSM Session Manager.
$ aws ssm start-session \
--target i-0fe6d50e5958523a4
Starting session with SessionId: root-0539c6fe4b063eeb4
sh-4.2$
Code language: Bash (bash)
I was able to access it successfully.
For more information about SSM Session Manager, please refer to the following
After accessing, check the installation status of the MySQL client, as defined in the user data.
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: Bash (bash)
During instance initialization, you can see that it has been successfully installed.
Prep 2 – Check VPC flow logs delivered to CloudWatch Logs
Check the VPC flow logs that are being delivered at this time.
You can see that a log stream is generated for each ENI that exists on the VPC.
From the top of the red box, the streams are DBInstance3, DBInstance2, and DBInstance1.
RDS Connection Test 1 – No Security Group
We will start the test with DB instance 1.
This instance does not have any security group defined.
Before starting the test, use the nslookup command to check the IP address set for the endpoint. This is because when we check the VPC flow logs later, we will use the IP address configured in RDS to search the logs.
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)
The address was 10.0.3.213.
Now let’s start the test. Try to access with the installed mysql command.
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)
It failed. Wait for a while and you will get an error message back.
The VPC flow log for this timing is as follows.
You can read more about how to look at the VPC flow log in VPC Flow Logs, but you can see that the packets sent to 10.0.3.213:3306 are REJECTed as a result.
From the above, we can see that since the security group is not applied to DB instance 1, all inbound communications are rejected, resulting in an access failure.
RDS Connection Test 2 – No inbound communication to allow
Next, we will perform the test on DB instance 2. The procedure is the same as before.
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.amazonaws.com:3306' (110)
Code language: Bash (bash)
This one also failed. The flow log also shows that MySQL communication to 10.0.3.205 is denied.
From the above, we can see that not allowing any inbound communication in the security group is equivalent to denying all inbound communication, and the behavior is the same as if we had not set up the security group.
RDS Connection Test 3 – Allow MySQL Communication
Finally, we will run the test against DB instance 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)
The access was successful. Checking the flow log, we can see that the packets sent from the EC2 instance to DB instance 3 and the return packets are ACCEPTED.
From the above, we can see that we can access the RDS by applying the appropriate security group according to the database system.
Summary
We created three patterns of RDS instances and checked the differences in behavior depending on the security group.
We found that in order to access the RDS, the appropriate security group must be set according to the database system.
We confirmed that if no security group is applied to RDS, or if a security group is applied that does not allow proper inbound communication, it will not be able to communicate properly.