AWS’ Elastic Compute Cloud, more popularly known as EC2, is a service that allows organizations to spin up virtual machines that can be used to host and run applications, databases, and much more. EC2 instances come with a wide variety of options - from selecting the number of CPU cores to disk space, memory, operating system, to name a few. The EC2 service also comes packed with different configuration options and settings for an instance to work with. Uncle Ben said, “With great power comes great responsibility” and in this case with a lot of settings to choose from, comes a lot of misconfigurations. Thus, in this article we will look at how we can securely configure our EC2 instances.
Although this is not an exhaustive list of actions to take to secure your instances, these configurations are a good starting point as they are easy to understand as well as implement. As one gets familiar with AWS and its various other services, additional (advanced) measures can be taken to further strengthen the security of EC2 instances. For now, we will stick to the list of security settings that are directly applicable to EC2 instances.
Instance metadata service (IMDS) provides information about the instance and various parameters associated with it such as user data that is specified at launch. IMDSv1 stored credentials in the endpoint which could be retrieved and then used to perform actions with say AWS CLI with those credentials. This could prove devastating in the case of the credentials being exfiltrated and thus IMDSv2 was introduced to stop various attacks against the abuse of metadata endpoints. IMDSv2 uses a session but does not store the session token as information in the endpoint itself, making it impossible to retrieve the token after it is generated in subsequent calls.
When launching an instance, under “Configure Instance Details” page, navigate to the “Advanced Details” section and:
Select “Enabled” for “Metadata accessible” option
Select “V2 (token required)” for “Metadata version” option
To enable IMDSv2 while launching an instance with AWS CLI, use the following flag in the command:
aws ec2 run-instances --image-id <IMAGE_ID> \
<other required options for your instance> \
--metadata-options "HttpEndpoint=enabled,HttpTokens=required"
Run the following AWS CLI command to modify the instance and enable IMDSv2:
aws ec2 modify-instance-metadata-options \
--instance-id <INSTANCE_ID> \
--http-tokens required \
--http-endpoint enabled
Security groups are firewalls that define permitted inbound and outbound reachability to and from the instance to various other resources, on public internet as well as within the VPCs. It is important to ensure that we expose only those services running on the instance that are required and limit the access to only those users / groups who require it. For that we need to add security group rules that are as explicit as possible. For example, instead of using 0.0.0.0/0 as the allowed source for SSH protocol, we can specify a common VPN that the team that needs access to the instance uses as the source explicitly.
AWS has extensive documentation for creating and managing Security groups and rules which can be found here.
Patching refers to the activity of applying software updates to the operating system for a performance upgrade, bug fixes, and security fixes released by the vendor that maintains the operating system.
The steps for patching differ from OS to OS but the idea essentially remains the same, use the operating system’s mechanism to check if there is a patch/update available and apply it. Some patches also require reboots for the system although this is not always the case.
For example, the following steps can be performed to patch an EC2 instance running Ubuntu 18.04 as the operating system:
sudo apt update
sudo apt upgrade
sudo reboot
Applying a patch manually is fine if the number of instances we are dealing with is small, say 10. But in most real-life cases, the number is usually bigger than that, and thus patching manually becomes a fairly daunting task. Thankfully, AWS has a service called Systems Manager, or SSM for short. SSM can execute commands on multiple machines simultaneously and take away the hassle of manually accessing one machine at a time, making it an amazingly useful tool to utilize.
The following article from Kloudle Academy can be used to understand how to patch multiple EC2 servers using AWS SSM under the section “Patching multiple machines on AWS and GCP > AWS with SSM”
Data stored on EC2 instances should be regularly backed up to avoid issues of data loss due to disk failures, data corruption, etc. AWS; Data Lifecycle Manager is a service that can be utilized to create a backup schedule to take automated backups of our EBS volumes.
To enable regular backup with Amazon Data Lifecycle Manager from the console, follow the below mentioned steps:
Navigate to the EC2 details page and then select the “Lifecycle Manager” link under the “Elastic Block Storage” sub-menu
Select the “EBS snapshot policy” and click on the “Next step” button
Select the target resource type - Volume or Instance and specify the tag to identify the selected resource type and click on the “Add” button
Add a description for the backup policy
Add necessary tags for the policy
Ensure “Enabled” option is selected in the “Policy status” section and click on the “Next” button
Add details for the backup schedule as per requirement, ideally, a daily backup is recommended
Scroll down and click on the “Review policy” button
Lastly, click on the “Create policy” button to create the backup policy and schedule
To enable regular backup with Amazon Data Lifecycle Manager with AWS CLI, follow the below-mentioned steps:
Create a file called policy.json and add the following contents in the file replacing the configuration as required
{
"ResourceTypes": [
"VOLUME"
],
"TargetTags": [
{
"Key": "createdBy",
"Value": "ayush"
}
],
"Schedules":[
{
"Name": "DailySnapshots",
"CopyTags": true,
"TagsToAdd": [
{
"Key": "type",
"Value": "myDailySnapshot"
}
],
"CreateRule": {
"Interval": 24,
"IntervalUnit": "HOURS",
"Times": [
"03:00"
]
},
"RetainRule": {
"Count":5
}
}
]
}
Obtain the ARN of the IAM role that would be used to create the backup for EBS volumes
Lastly, run the following AWS CLI command
aws dlm create-lifecycle-policy
—description “My first policy”
—state ENABLED
—execution-role-arn <ARN_OF_IAM_ROLE>
—policy-details file:///path/to/policy.json
EBS volumes should be encrypted to ensure that the data they hold cannot be read or misused by unauthorized entities who may have gained access to the volume. We can enable a configuration to enforce encryption on all EBS volumes by default when they are created.
To enable encryption by default for the AWS account with AWS CLI, the following steps can be used:
Navigate to the EC2 dashboard page and click on the “EBS encryption” link
Click on the “Manage” button
Select the checkbox “Enable” for “Always encrypt new EBS volumes” setting and click on “Update EBS encryption” button
To enable encryption by default for the AWS account with AWS CLI, the following command can be used:
aws ec2 enable-ebs-encryption-by-default
The above configuration encrypts new EBS volumes that are created in the account. To encrypt existing volumes this documentation by AWS can be used as a reference.
EBS snapshots are used as backups for EBS volumes which can be used to recover instance states, launch new instances from the backup, etc. Since EBS snapshots are essentially equivalent to the EBS volumes themselves, ensuring that the snapshots are encrypted as well as their counterpart EBS volumes is necessary.
A good feature in EC2 snapshots is that when a snapshot is created for a volume that is encrypted, the snapshot too is encrypted by default thus eliminating the need for ever having to encrypt snapshots that were created after enabling EBS encryption setting we configured in the previous section on encrypting EBS volumes. That being said, there might be old snapshots that are unencrypted that we need to encrypt which can be done by creating a copy of the unencrypted snapshot, and for the new, copied snapshot we will enable encryption.
To enable encryption for an existing unencrypted snapshot via Console, the following steps can be performed:
Navigate to the EC2 dashboard
Click on the “Snapshots” link under the “Elastic Block Storage” sub-menu
Select the snapshot to make an encrypted copy for, click on the Actions drop-down, and click on the “Copy snapshot” option
In the “Copy snapshot” page, ensure that the “Encrypt this snapshot” checkbox is selected under the “Encryption” section and click on the “Copy snapshot” button
Optionally, a different KMS key can be chosen instead of the default one
To enable encryption for an existing snapshot with AWS CLI, the following command can be run:
aws ec2 copy-snapshot \
--source-region <SOURCE_SNAPSHOT_REGION> \
--source-snapshot-id <SOURCE_SNAPSHOT_ID> \
--encrypted \
--kms-key-id <KMS_KEY_ALIAS>
Amazon Machine Images or AMIs are launch configuration packages for EC2 instances that need to be specified when launching an instance. These AMIs can be created by anyone and shared with specific AWS accounts or with everyone by making them public. This may lead to a possibility where a malicious AMI may be shared. Thus as a security measure, we should either create and use AMIs ourselves for our instances or use public AMIs that are published by trusted vendors only. One such trusted AMI is the Amazon Linux Image that is created and maintained by Amazon itself. Other images can also be trusted although based on the vendor, not the name, as one can create an image and call it Ubuntu, for example, but the publisher may not actually be associated with the Canonical Group that maintains and releases Ubuntu Operating Systems.
AMIs selected at the time of launching an image are not exactly a configuration associated with the instance, so there are no specific steps to take in the case of this security measure. The AMI being used needs to be vetted for trust before usage, and at the time of launching an instance:
IAM roles are used to delegate permissions to perform actions on AWS resources and perform their required roles. When an IAM role is attached to an EC2 instance, it is called an instance role, and this instance role can be used by the server to perform permitted actions, for example, uploading a local backup to an S3 bucket.
Least-privilege access is a security best practice where we add the exact permission(s) that a role (or in other cases, an IAM user) requires to perform its job. Applying this principle to IAM roles that are attached to instances, only the permissions that are required by the instance to perform its job should be added to the instance role and nothing else. This ensures that in the case of the credentials getting leaked, the damage is minimized.
Configuring the least-privilege permission for an IAM role is very contextual i.e. it cannot be generalized thus, it goes beyond the scope of this article to provide an exhaustive list of combinations of different possible permissions that can be utilized by an instance and the various use-cases.
Virtual Private Cloud or VPC is an AWS service that allows users to create virtual networks that are isolated logically from one another. Talking specifically about EC2 instances, as an example, we can think of a case where some EC2 instances need to access only internal resources and do not require access to the internet. For such instances, we can create a VPC that does not allow inbound and outbound connections from the internet so the communication can only happen between resources in the same VPC. The following documentation from AWS can be used to understand how to create new VPCs.
Perform the following steps to create a new VPC:
Navigate to the VPC management page
Click on the “Launch VPC Wizard” button
Choose the “VPC with a Single Public Subnet” option and click on the “Select” button, we can add more subnets later if we want to
Provide the IPv4 CIDR block for the VPC and click on the “Create VPC” button
Run the following command to create a new VPC with the specified CIDR being 192.168.0.0/16:
aws ec2 create-vpc --cidr-block 192.168.0.0/16
Subnets are sub-components within a VPC that can further segregate resources within smaller virtual networks. For example, a VPC created with CIDR block 192.168.0.0/16,can have subnets 192.168.1.0/24 and 192.168.2.0/24 , where both subnets are within the same VPC but isolated from each other.
Perform the following steps to create a new VPC:
Navigate to the VPC management page
Click on the “Subnets” link for the “Virtual Private Cloud” menu
Click on the “Create subnet” button
Select the VPC to create the Subnet inside
Add the CIDR block for the subnet and optionally a name and tags
Lastly, click on the “Create subnet” button
Run the following command to create a new Subnet within CIDR block 192.168.1.0/24:
aws ec2 create-subnet --vpc-id <VPC_ID> --cidr-block 192.168.1.0/24
EC2 instances have basic monitoring in place by default from the time of launch. The basic monitoring is good-to-have, but more often than not, it falls inadequate, and here comes detailed monitoring for EC2 instances such as CPU credit metrics, instance metrics, and so forth.
Perform the following steps to enable detailed monitoring for EC2 instances via console:
Navigate to the EC2 Dashboard
Select the instance that detailed monitoring needs to be enabled for, click on the “Actions” drop-down menu, choose the “Manage detailed monitoring option” under the “Monitor and troubleshoot” sub-menu
Ensure that the “Enable” checkbox is selected and click on the “Save” button
Run the following AWS CLI command to enable detailed monitoring for existing instances:
aws ec2 monitor-instances --instance-ids <INSTANCE_IDS>
Run the following AWS CLI command to enable detailed monitoring when launching a new instance:
aws ec2 run-instances --image-id <AMI_ID> --monitoring Enabled=true #Amongst other options/flags
EC2 is an extensively utilized service offered by AWS, to run our applications and so much more. With its list of extensive usability, comes a longer list of options to apply to these instances which can lead to misconfigurations or use of insecure default configurations.
In this article we took a look at the various security measures we can take to secure our EC2 instances, some by applying settings directly on the EC2 instances like using trusted AMIs or enabling IMDSv2, and some that align with the instance tangentially such as using VPCs to isolate various instances from each other or encrypting the EBS volumes and snapshots. In all these cases we saw why these configurations are highly recommended to use if not outright mandatory to apply.
This article is brought to you by Kloudle Academy, a free e-resource compilation, created and curated by Kloudle. Kloudle is a cloud security management platform that uses the power of automation and simplifies human requirements in cloud security. If you wish to give your feedback on this article, you can write to us here.