Getting Ready for AWS
(First, create an account and sign in to AWS. Remember that you initially sign in as the AWS account root user.)
IAM
Like Linux or Windows, which have a highest-privileged root/administrator account, AWS has one too. It feels a little like a domain setup. ROOT has the highest privileges in AWS and can control everything. But everyone knows what happens if you keep using root: if the account gets compromised, the attacker does not even need to escalate privileges—they already have everything. That is why IAM exists.
With IAM, you can create a user and assign access to a service. Say I want to grant someone permissions for S3. AWS asks me to set a username and password, then generates a dedicated URL that can be used to sign in to that account, also known as an IAM account. When you host services such as Tomcat or Nginx locally, they usually run as a user like www-data. This is somewhat similar. The domain analogy comes from the fact that ROOT can change a lot of things, as shown below.

You can create user groups, users, roles, policies, and so on. It feels a lot like a domain. Linux and Windows work similarly too: you can assign roles and define policies, almost like setting a security baseline. The difference is that AWS manages everything centrally and distributes the configuration instead of operating on a single machine, which is why it feels like a domain controller. For the rest of this learning process, we need to create an administrator account.
Creating an Account

Providing AWS Management Console access lets an IAM user work through the web interface (the AWS console), rather than only through the API. I enable everything here because, while learning, I want to understand both the web interface and the API.
Click Next to reach the permissions page.

Create a group directly and choose the first permission. The goal here is to create a group with administrator privileges. If I want to create more users with administrator privileges later, I can simply drop them into this group. If that does not matter to you, click Attach policies directly on the far right and attach AdministratorAccess instead. (The architecture is extremely similar to Windows/Linux account management.)
At the bottom of this page, there is also an option for setting a permissions boundary. This is easy to understand: AdministratorAccess grants all permissions, but if I want an IAM user to manage only EC2 and not S3, I can set that restriction here even if the user belongs to the administrators group.

We do not need this here, so just continue to the next step.

This only adds tags, similar to descriptions for users and user groups. Just click Create user.

Roles
Here is a quick introduction to the roles section.

Normally, two default roles are generated. The important part is the ARN.

Every role has an ARN, somewhat like /etc/passwd on Linux or a SID on Windows. My current understanding is that if you want to learn cloud penetration testing, you have to understand IAM roles because they come into play later during privilege escalation.
As I understand it, an IAM role lets AWS services such as EC2 and Lambda access AWS resources automatically without an API Key. In other words, if one service needs resources from another service, you can configure a role for it. You can retrieve its temporary credentials like this:
| |
This returns temporary credentials. If you assign the role to EC2, however, you must be logged in to that EC2 instance to access this URL. The address is a special IP, 169.254.169.254, visible only to the current EC2 instance and inaccessible externally. IMDS automatically identifies the EC2 instance and returns temporary credentials for the IAM role currently attached to it.
This is both safe and convenient. If you access a service with an APIKEY as described above, that key is long-lived. Once stolen, an attacker can keep using it for a long time. These temporary credentials usually survive for only an hour, so even if someone obtains them, they will soon be unable to sign in or maintain persistent control.
Advanced IAM Penetration Testing (Paused)
That covers the basic concepts. The penetration-testing topics below are still blank because I have not started studying them yet, but I am leaving the outline here.
1️⃣ Identifying IAM account information
- Use
aws sts get-caller-identityto retrieve information about the current IAM account - Use
aws iam list-usersandaws iam list-rolesto identify users and roles in the account - Determine AWS account ownership from an IAM ARN
2️⃣ IAM privilege escalation (Privilege Escalation)
- Use
iam:AttachUserPolicyto attach administrator privileges (AdministratorAccess) - Use
sts:AssumeRoleto switch to a more privileged role - Use
iam:CreateAccessKeyto create a new API Key for accessing AWS - Use
iam:PassRole+ec2:RunInstancesto attach a highly privileged role through EC2
3️⃣ Abusing IAM roles
- Use
aws sts assume-roleto obtain temporary permissions - Read the IAM role of an EC2 instance (
169.254.169.254/latest/meta-data/iam/security-credentials/) - Read IAM role credentials through SSRF (IMDS v1 vulnerability)
- IMDS v2 protections and bypass techniques
4️⃣ Analyzing IAM access policies
- Parse policy content returned by
aws iam list-policies - Interpret IAM policies in JSON format
- Use
aws iam get-policy-versionto view policy version history - Find overly privileged IAM roles (Overly Permissive Policies)
5️⃣ IAM role abuse
- Use
aws iam list-attached-role-policiesto inspect policies attached to an IAM role - Use
sts assume-roleto obtain cross-account access - Find misconfigured external identity providers (OIDC/SAML)
6️⃣ Accessing AWS resources with an IAM account
- Use
aws s3 lsto enumerate an IAM account’s access to S3 - Use
aws ec2 describe-instancesto check access to EC2 resources - Use
aws lambda list-functionsto view the IAM roles attached to Lambda functions
7️⃣ IAM account data exposure
- Public S3 buckets (
aws s3 ls s3://target-bucket --no-sign-request) - Exposed CloudFormation/Terraform configuration files
- Use
aws iam get-account-authorization-detailsto retrieve detailed IAM account permissions - Use
aws iam list-access-keysto check for exposed AWS API Keys
8️⃣ Defense and detection
- Monitor AWS CloudTrail logs to detect IAM account abuse
- Use AWS GuardDuty to monitor unusual IAM activity
- Restrict the scope of
sts:AssumeRoleaccess for IAM roles - Enable IAM Access Analyzer
EC2
You can think of EC2 as a “virtual machine in the cloud” provided by AWS. Its main concepts include:
- Instance: A cloud server that can be started, stopped, and restarted.
- AMI (Amazon Machine Image): An operating system image for EC2, such as Ubuntu, Amazon Linux, or Windows Server.
- Instance Type: Determines the CPU, memory, and bandwidth, such as the free
t2.micro. - EBS (Elastic Block Store): EC2 disk storage—the cloud equivalent of a hard drive.
- Security Group: EC2 firewall rules that control which IPs are allowed to connect.
- Public IP & Private IP:
- Public IP: An IP that can be accessed directly from the internet.
- Private IP: An IP that can only be accessed inside a VPC (the AWS internal network).
Create an instance by searching for EC2 and opening the instance creation page, then use the configuration shown below. On the free tier, an instance is free if total use stays under 750 hours per month. Since 750 hours is a little over 31 days, you might wonder why they do not simply call it free. EC2 lets you create multiple instances, though: if you create two, each can only run for 375 hours. I use the configuration below. (Amazon Linux is widely used outside China and integrates conveniently with AWS, so I create that here. It is also a chance to learn how Amazon Linux differs from ordinary Linux distributions.)




That is enough. Connect over SSH and try it out—the main goal is simply to understand what EC2 is.
There is also the Security Group, which is very similar to what you see with Alibaba Cloud and other Chinese cloud providers. Those providers enable this firewall automatically, so even after opening a port on the machine itself, you still have to open it in the Alibaba Cloud console. It is basically a firewall.
Next is EBS. I think of it in terms of a VMware virtual machine: when a virtual machine needs more storage, you can attach another virtual disk. The disk itself is virtualized and does not disappear. It is like plugging in another hard drive that can store data independently—essentially a convenient standalone cloud disk.
That may be the whole idea behind cloud services. EFS, meanwhile, is a disk shared over NFS. I do wonder whether communication might lag, but it still sounds pretty useful.
S3
S3 is object storage, not a traditional file system.
Alibaba Cloud OSS provides plenty of familiar real-world examples. When you upload a file, for instance, it is often uploaded to an OSS service and read back from there. No matter how you upload it, the file never reaches the local server; it goes to another cloud service instead. To me, S3 does not seem very different from OSS.
Differences Between S3 and OSS
| Feature | AWS S3 | Alibaba Cloud OSS |
|---|---|---|
| Bucket name | Globally unique | Unique within a region |
| Region restrictions | You must choose an AWS region, such as us-east-1 | You must choose an Alibaba Cloud region, such as cn-hangzhou |
| Storage classes | Standard, Infrequent Access (IA), Glacier | Standard, Infrequent Access, Archive, Cold Archive |
| API compatibility | S3 API | Partially compatible with the S3 API, with additional proprietary Alibaba Cloud APIs |
| Default access | Private by default; must be changed manually | Private by default; must be changed manually |
| Cross-region replication | Supports replication across AWS regions | Supports replication across Alibaba Cloud regions |
Buckets are private by default, so you can store backups and other material without other people seeing it. To start working with S3, we need to learn how to create a bucket and try operating it through a URL and AWSCLI.
Creating an S3 Bucket

Use the following configuration.



After creating the bucket, find it and upload any file.

Then enter the following policy under Bucket policy:
| |
By default, only the current user can access uploaded resources. For learning purposes, however, it is easier to make everything public. After allowing the bucket policy to control access, we still need to add a rule permitting external access to the bucket. At that point, the image becomes accessible.

AWS CLI
First, Check Whether AWS CLI Is Installed
Run:
| |
If it is not installed, see the official documentation:
- Linux/macOS:
| |
- Windows: Download AWS CLI
Configuring AWS CLI (Linking Your AWS Account)
You need to configure an Access Key and Secret Key, which can be created in IAM, and then run:
| |
Enter the following when prompted:
- AWS Access Key ID: Your AWS access key
- AWS Secret Access Key: Your AWS secret key
- Default region name:
ap-southeast-1(the region you selected) - Default output format:
json(JSON is the default and recommended format)

The region is shown on the home page. Both keys are under the user’s access keys.

Common S3 CLI Operations
These are common S3 commands. Together with the bucket permissions above, you can test them directly in a terminal.
Create an S3 bucket:
| |
mb = make bucket
List buckets:
| |
Upload a file to S3:
| |
cp = copy
To upload an entire folder recursively:
| |
Download a file from S3:
| |
List files in a bucket:
| |
Delete a file from an S3 bucket:
| |
Delete an entire bucket:
| |
rb = remove bucket, and --force deletes all contents before deleting the bucket.
Lambda
Lambda is a managed environment that can run code automatically. Think of it like this: you write some Python code → but do not need to run a server for it.
- Event Source: When does the Lambda code run?
- S3 event: Run Lambda automatically after a file is uploaded
- API Gateway: Triggered when a user accesses an API
- CloudWatch event: Triggered on a schedule
- SNS / SQS message: A message triggers Lambda
Runtime:
- Lambda supports several languages, including Python, Node.js, Go, Java, C#, and Ruby.
- You need to choose a runtime, such as
Python 3.9.
Execution time limit:
- Lambda has a maximum execution time of 15 minutes.
- The longer the code runs, the more it costs.
Search for Lambda to find it. When you first open it, there is a tutorial you can follow step by step, so take your time. One particularly interesting part is how it responds to events. As listed above, both S3 events and API events can trigger Lambda functions, which is pretty neat.

The defaults are fine. Add a trigger first, mainly to get familiar with the process.


Start testing by uploading a file to S3.
| |

You can see that it was triggered.
Of course, you can view the details in CloudWatch.


As for the exact event, all we can see at this point is that Lambda was triggered. We cannot tell which event triggered it or what the result was.
Go back to Lambda, enter the following code, and click Deploy to save it.
| |
Trigger it again. Uploading a file or clicking the code test button will both work.
This is the log from testing the code directly. You can see that the returned JSON is identical to the JSON in the test and was recorded in the log.

This is the log triggered by uploading a file to the S3 bucket. It includes detailed AWSCLI fields, the uploaded filename, the bucket name, the file size, and more.

event (event data)
eventis the data AWS passes in automatically when it triggers Lambda. For example:
- When S3 triggers Lambda,
eventcontains the uploaded filename and bucket name. - When API Gateway triggers Lambda,
eventcontains HTTP request information. - When CloudWatch triggers Lambda,
eventcontains scheduled-task information.
That is why printing event gave us so much information about the S3 bucket, including the uploader’s IP.
context (execution environment)
context is not event data. It contains environment information from AWS while Lambda is running, such as:
context.function_name→ Lambda function namecontext.memory_limit_in_mb→ Allocated memorycontext.aws_request_id→ ID of the current requestcontext.get_remaining_time_in_millis()→ Remaining Lambda execution time
context contains the information above. If you want to inspect it, you can also reference it in the function.
AWS CLI
First, make sure you have configured AWS CLI correctly with aws configure and have sufficient permissions.
Listing All Lambda Functions
| |
This command returns a list of your Lambda functions. You should see MyFirstFunction.
Getting Lambda Details
| |
This displays the Lambda code storage location, runtime (Python 3.9), execution role, and other information. It also returns a link to the ZIP archive containing the code, which you can download.
Invoking Lambda Manually
You can trigger Lambda directly from the CLI, which is equivalent to the console’s “Test” feature.
| |
After Lambda finishes, the result is saved to response.json.
If you use a newer version of AWS CLI v2, add –cli-binary-format raw-in-base64-out so AWS CLI sends the JSON request body directly without base64 encoding, allowing Lambda to parse it correctly.
View the result:
| |
You should see:
| |
If your Lambda code prints event, you will also see logs showing how it parsed the input data.
Updating Lambda Code
Suppose you have a new lambda_function.py. You can upload it like this:
| |
This command updates the Lambda code directly, so you do not need to upload it manually through the AWS console.
Updating Lambda Configuration
To change the Lambda runtime, memory, or timeout, use:
| |
This changes the Lambda memory to 256MB and the timeout to 30 seconds.
Deleting a Lambda Function
If you no longer need this Lambda function, delete it with:
| |
Warning: This operation is irreversible!
Writing and Uploading Lambda Code
I will skip the basics here. More advanced work involves boto3, which I still need to learn.
| |
| |
| |
CloudTrail
CloudTrail is the audit log for an AWS account.
- Records who (users, roles, or services) did what in AWS, such as creating, modifying, or deleting resources.
- Records when and from where, including the IP address and geographic location, someone accessed AWS.
- Records API calls made through the AWS console, CLI, or SDK.
Put simply, CloudTrail is like the “black box” of an AWS account. It records AWS activity to help troubleshoot problems and spot anomalies.
It is mainly used for activity auditing, much like a bastion host recording every action performed by operations staff.

Create one and you will be able to see events here. Calls to S3 interfaces, such as running ls or downloading a file, are not recorded unless data events are enabled. As shown below, data events can be enabled, but they cost money, so I am leaving them alone. It is enough for now to understand how to call these APIs. Next, let us look at AWSCLI.

AWS CLI
Querying Recent CloudTrail Events
| |
This queries the 10 most recent events. By default, it returns all management events, excluding S3 data events.
Querying by Event Name
| |
This filters for all CreateBucket events, meaning S3 bucket creation operations.
| |
This attempts to find S3 file download (GetObject) events, provided you have already enabled S3 data events.
Querying by IAM User
| |
This finds the 10 most recent operations by the MentalityXt user.
Querying by Resource Name
| |
This filters for all events involving the mentalityxttest S3 bucket.
Querying by Time Range
| |
This queries all CloudTrail events from March 3, 2025.
Listing All CloudTrail Trails
| |
This lists every CloudTrail trail in the AWS account.
Getting Details About a Trail
| |
This queries detailed information about CloudTrail trails, including their S3 log storage locations.
Stopping CloudTrail Logging
| |
This stops logging for the management-events trail. It does not delete logs that have already been stored.
Restarting CloudTrail Logging
| |
This restarts logging for the management-events trail.
Downloading CloudTrail Event Logs
| |
This lists CloudTrail logs stored in S3, if you enabled S3 storage.
| |
This downloads and extracts a CloudTrail log file so it can be analyzed locally.
I listed a whole pile of commands above, but I think the log-download command is the most useful because it lets you download all the logs and analyze them at your own pace. The individual queries are more useful when the data volume is particularly large. If there is not much data, downloading everything for analysis is probably better. So far, I have noted only a handful of AWS CLI commands. They are really meant for a scenario where a leaked Access Key and Secret Key can be used to retrieve information through the API. There is no need to memorize all of this, but you should know that these API request methods exist.
CloudWatch
CloudWatch is AWS’s monitoring and log management service. It can:
- Monitor AWS resources, including EC2, S3, Lambda, and RDS
- Collect and store logs from Lambda, EC2, CloudTrail, and more
- Configure alarms, such as an alarm triggered when CPU usage exceeds 80%
- Visualize data by creating Dashboards
It is similar to the previous service, but CloudTrail primarily audits user actions, while CloudWatch monitors resources. If you have used almost any security appliance, you have probably seen something like this in a WAF, IPS/IDS, situational-awareness platform, and so on.
Just search for it, open it, and have a look. API auditing can sometimes be broken down in more detail. We actually created something in the Lambda section and opened it once, so I will drop in a screenshot here.

You can click through the other items one by one to get a general feel for them. Also:
- CloudWatch itself does not record API requests, but CloudTrail records API calls
- To see API logs in CloudWatch, you need to send CloudTrail events to CloudWatch Logs
- Then you can use AWS CLI to query API call logs!
I will not go into more detail here. If I need to deploy services on AWS later, I can learn more then. It is not necessary right now.
While looking around, I found an interesting feature: the traffic monitor. It requires an EC2 instance, though, and I had already shut mine down because I barely use it after finishing the lesson and it might cost money. That is why there is no traffic data below.

With the default setup, it records rejected traffic but not successful flows. The method below can forward those logs.

Pay attention to the location in the upper-left corner. It is a bit of a hassle, so I will not set it up here. It is worth mentioning that this can also be configured and queried through AWSCLI. I thought of a scenario: suppose a target’s KEY is exposed, and the target also runs a popular site. Its traffic may be unencrypted, or it might use JS encryption that can be reversed. Capturing other users’ traffic could easily reveal their passwords or COOKIEs, which would be pretty serious. (That actually does not work. It can only record the source IP/target IP, source port/target port, transport protocol (TCP/UDP/ICMP), and packet/byte counts.) That makes it feel useful mostly for development, apart from cloud security cases where you also need to enable it. I have realized that everything I am studying covers both attack and defense: logging systems can support tracing, incident response, and reconstruction of an attack chain.
The crossed-out idea above can be handled another way. AWS also has a WAF where you can write custom rules. When a login request contains sensitive terms such as username/passwd, you can add a rule and capture it, but that costs money.

Never mind. It is enough to know that the feature exists.
VPC
- A VPC is a Virtual Private Cloud on AWS
- You can create resources such as EC2 instances, databases (RDS), and load balancers (ELB) inside a VPC
- A VPC lets you control the network topology, including subnets, route tables, security groups, and NACLs
- All AWS resources run inside some VPC
I first learned this concept during an internship in 2022. At the time, I wanted to buy a VPS to run some services, but I found that a VPC seemed cheaper than a VPS and felt roughly the same. What I really wanted was the public IP.
A VPC is mainly a network environment. Everything below relates to network configuration. With the right setup, you could actually build an internal AWS lateral-movement lab with dual-NIC machines, which sounds pretty interesting.

In the EC2 section, I mentioned that this seemed different from aliyun. Over there, the firewall is built in, while I could not find it here. It turns out it is here.

My understanding is still pretty basic, so it is worth looking through everything. VPC handles network traffic, while EC2 is mainly for compute, such as assigning CPU and memory to an operating system.
On the defensive side, VPC is mainly about access control and traffic management. On the offensive side, the goal is to obtain configuration information or bypass those defenses.
That is roughly how I understand it. The defensive VPC features are listed on the left in the screenshot above, while our focus is mainly offensive. Here are some important APIs for querying this configuration information, assuming you have obtained a KEY.
| Service | What the API does | Potential offensive use |
|---|---|---|
| VPC | DescribeVpcs | Retrieve the CIDR, status, default VPC, and other details for all VPCs |
| Subnet | DescribeSubnets | View the IP ranges, availability zones, and other details for all subnets |
| Route Table | DescribeRouteTables | Retrieve routing configuration for the current VPC and inspect public-access policies |
| NACL (Network ACL) | DescribeNetworkAcls | View ACL rules for the current VPC, including inbound and outbound restrictions |
| Security Groups | DescribeSecurityGroups | Retrieve EC2 security-group rules and look for open ports |
| Internet Gateway (IGW) | DescribeInternetGateways | Determine how the VPC connects to external networks and whether it is exposed publicly |
| NAT Gateway | DescribeNatGateways | Retrieve NAT proxy information that might allow public-network restrictions to be bypassed |
| VPN Connection | DescribeVpnConnections | Retrieve VPN connection information and potentially attempt to hijack the VPN |
| DNS Firewall | ListFirewallRules | Retrieve DNS firewall rules and potentially attempt to bypass filtering |
| Elastic IP | DescribeAddresses | Retrieve public IPs attached to the current account and look for targets |
These APIs can all be queried through AWS CLI or an SDK, for example:
| |
Use the results from these APIs to find vulnerabilities and work out how to bypass them.
- Create new security-group rules to loosen access restrictions
- Create a hidden IAM account to maintain a backdoor
- Modify VPC flow logs to hide access records
- Create an Elastic IP and attach it to an instance you control
RDS
RDS is mainly used to manage relational databases. Compared with deploying MySQL yourself:
- Less manual administration: AWS automatically manages backups, patches, monitoring, and scaling.
- High availability: You can deploy across multiple Availability Zones (AZs) so the database stays available during failures.
- Security: You can use private VPC deployment, encrypted storage, and automatic backups.
- Performance optimization: It supports automatic scaling, Read Replicas, and Aurora for high-performance reads and writes.
This is where things start to become a little more important. Developers often use cloud database services because they are more convenient, more secure, and cheaper.
Key RDS Concepts
| Concept | Purpose |
|---|---|
| RDS instance | The host running the database, equivalent to a database server |
| Database engine | Supports MySQL, PostgreSQL, MariaDB, Oracle, SQL Server, and Aurora |
| Subnet Group | Runs the database in specific VPC subnets |
| Security Group | Controls access to RDS, including whether external connections are permitted |
| Parameter Group | Controls database configuration parameters, such as MySQL’s max_connections |
| Snapshot | Backs up the database so it can be restored at any time |
| Read Replica | Optimizes read operations and reduces load on the primary instance |
| Multi-AZ deployment | Runs the primary database across multiple Availability Zones (AZs) so primary/standby failover does not interrupt service |
Setting Up MYSQL
As before, find the corresponding console. This time, we are looking for RDS.
Follow my configuration below, or you may be charged.



For everything else, clicking through with the defaults is fine.
Connecting to MYSQL (AWSCLI)
I will skip the first method, which is connecting from EC2. It is just a normal database connection.
| |
The second method, through AWSCLI, is the main one here.
Querying RDS Instances
| |
Example response:
| |
- You can get the RDS connection address from “Endpoint”
- “DBInstanceStatus” shows the database status
Backing Up RDS
| |
- Create a snapshot (backup)
Deleting RDS
| |
- Delete the database immediately, skipping the final snapshot
Checking Whether RDS Allows Public Access
| |
Example response (access was denied):
| |
Enabling Public Access to RDS
| |

Once the command completes, it returns the MySQL address and enables public access.
Enabling the RDS Security-Group Policy
The step above successfully enabled external access to MySQL in RDS, but the security group still blocks it. Even though public access is enabled, the security group is a firewall, and the database remains unreachable until the traffic is allowed. Here, we add an inbound rule to the security group.
| |
result:
| |
Remember the VpcSecurityGroupId.
Grant access:
| |
Success.


Changing the MYSQL Password
| |
The command above can change the password directly, after which you can connect and inspect the data. This is generally not allowed, though. Even during an authorized penetration test, doing this could get you into serious trouble. Just make a note of it.
That wraps up RDS. We added an inbound rule with AWSCLI and configured RDS for external access. Now delete everything through the web console.

The second step is to disable remote access to RDS.
| |
Steps:
- Go to the AWS console → RDS service.
- Find your
database-1database in the Database instances list. - Click Modify.
- Find the Connectivity section and clear
Publicly accessible. - Choose Apply Immediately or Wait for the maintenance window.
- Save the changes and wait for the RDS instance to restart.

I already deleted mine, so I will not include screenshots of these steps.
Fundamentals Complete
That completes the fundamentals. If you need to set up a service, define a baseline, configure access control, manage storage, or do anything similar, everything covered above can help you do it. You can even use what you learned to build a free web server with a solid architecture spanning several different services.
There are plenty of directions to go next. I could take AWS Certified Security – Specialty first, for example, or choose one of the following:
- Follow the security path: dig deeper into IAM, VPC, attack-and-defense exercises, and penetration testing
- Follow the DevOps & automation path: Terraform, CI/CD, and Serverless
- Explore specialized AWS services: AI, IoT, blockchain, and more
CI/CD appears quite a lot in Jenkins, Azure DevOps, and similar platforms. I am not sure whether AWS’s built-in DevOps tooling can be used to carry out penetration testing. My next step is penetration testing on the security track.