Experimenting with Amazon Q Developer CLI to investigate and operate my AWS account
I'm Ogura from the Osaka office.
This time, I tried investigating and operating my regular AWS account using Amazon Q Developer CLI.
What I tried were the following two tasks:
- Creating AWS architecture diagrams from CloudFormation stacks
- Creating WAF rules from CloudFront access logs
Preparation
You can use any environment as long as Amazon Q Developer CLI is installed,
but this time I tried running it in the Visual Studio Code Server environment from the following blog.
I usually access AWS accounts from my Mac using temporary credentials,
and the credentials expire after a certain period of time, but with the Code Server environment, I don't have to worry about that.
Installing Amazon Q Developer CLI
Since the AMI used in the created Code Server environment was ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-20250627
,
I followed the instructions on the page below to install it.
In the Code Server terminal, just execute the following commands in order.
# Download
wget https://desktop-release.q.us-east-1.amazonaws.com/latest/amazon-q.deb
# Install
sudo apt-get install -f
sudo dpkg -i amazon-q.deb
The version installed this time was 1.12.4
.
If you run q
and get You are not logged in
, the installation was successful.
ubuntu@dev:~/environment$ q
error: You are not logged in, please log in with q login
Creating an AWS Builders ID
Amazon Q Developer CLI can be used for free if you have created an AWS Builders ID,
so if you haven't created one yet, register your email address at https://profile.aws.amazon.com/ to create one.
Login
When you enter q login
in the Code Server terminal, you will be asked to Select method
.
If you select Use for Free with Builder ID
, an authentication URL will be displayed.
ubuntu@dev:~/environment$ q login
✔ Select login method · Use for Free with Builder ID
Confirm the following code in the browser
Code: XXXX-XXXX
Open this URL: https://view.awsapps.com/start/#/device?user_code=XXXX-XXXX
▰▱▱▱▱▱▱ Logging in...
Access the URL in a browser on your local machine, log in with your created Builders ID, and follow the on-screen instructions.
When the display on the Code Server terminal changes, the process is complete.
Open this URL: https://view.awsapps.com/start/#/device?user_code=XXXX-XXXX
Device authorized
Logged in successfully
```## Creating AWS Architecture Diagram
First, let's examine the running Code Server environment.
I entered `q chat` to start the interactive mode and input the following instruction:
Please investigate the CodeServer stack in the Tokyo region and create an AWS architecture diagram in drawio format
While Q CLI is creating the response, you may be prompted for execution permission in the format:
```bash
Allow this action? Use 't' to trust (always allow) this tool for the session. [y/n/t]:
In this case, we'll proceed by entering y(yes) for all prompts.
Here's the final response I received. Output values are masked with X
.
> I've investigated the VSCodeServer stack in the Tokyo region and created an AWS architecture diagram in draw.io format.
## Configuration Overview
The VSCodeServer stack consists of the following key components:
### Network Configuration
• **VPC**: vpc-XXXXXXXXXXXXXXXXX (10.0.0.0/16)
• **Internet Gateway**: igw-XXXXXXXXXXXXXXXXX
• **Public Subnets**:
• AZ 1a: subnet-XXXXXXXXXXXXXXXXX (10.0.1.0/24)
• AZ 1c: subnet-XXXXXXXXXXXXXXXXX (10.0.2.0/24)
• **Private Subnets**:
• AZ 1a: subnet-XXXXXXXXXXXXXXXXX (10.0.3.0/24)
• AZ 1c: subnet-XXXXXXXXXXXXXXXXX (10.0.4.0/24)
### Computing
• **EC2 Instance**: i-XXXXXXXXXXXXXXXXX (c7i.large)
• Running VSCode Server (code-server)
• Private IP: 10.0.1.175
• Public IP: XX.XXX.XX.XXX (Elastic IP)
### Security
• **Security Group**: Only allows HTTP access from CloudFront
• **IAM Role**: Profile for the EC2 instance
• **Key Pair**: ws-default-keypair
### Other Services
• **CloudFront**: Global distribution and security enhancement
• **Secrets Manager**: Password management for VSCode Server
• **S3 Bucket**: Storage for SSM session logs
• **SSM Document**: Instance bootstrap
• **Lambda Function**: Custom resource for S3 bucket cleanup
### Access Flow
1. Users access through CloudFront distribution
2. CloudFront forwards HTTP requests to the public IP of the EC2 instance
3. VSCode Server on the EC2 instance processes the requests
This configuration provides a secure and highly available VSCode Server environment. You can open the created draw.io file (vscode-server-architecture.drawio) in draw.io to view the detailed architecture diagram.
When I opened the created drawio file, it showed the following architecture diagram:
While some parts may be a bit difficult to see due to the icon placement, these minor details can be manually corrected. It's quite convenient that it can create all this with just one instruction.
Creating WAF Rules from CloudFront Access Logs
I tried having it analyze CloudFront access logs and create WAF rules to block malicious requests.### Preparation
The CloudFront environment was created using the following template.
- CloudFront + S3 + OAC
- CloudFront access logs output to an S3 bucket
- Custom error responses configured for HTTP status codes 403, 404
Preparation CloudFormation Template
AWSTemplateFormatVersion: '2010-09-09'
Description: 'S3 + CloudFront Static Website Hosting with S3 Access Logs'
Parameters:
BucketNamePrefix:
Type: String
Description: 'S3 bucket name prefix for hosting website'
Default: 'static-website'
Resources:
# S3 Bucket for static website content
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}'
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
# S3 Bucket for CloudFront access logs
LogBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${BucketNamePrefix}-logs-${AWS::AccountId}-${AWS::Region}'
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerPreferred
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: true
IgnorePublicAcls: false
RestrictPublicBuckets: true
LifecycleConfiguration:
Rules:
- Id: DeleteOldLogs
Status: Enabled
ExpirationInDays: 90
# S3 Bucket Policy for CloudFront
S3BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3Bucket
PolicyDocument:
Statement:
- Sid: AllowCloudFrontServicePrincipalReadOnly
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: 's3:GetObject'
Resource: !Sub '${S3Bucket.Arn}/*'
Condition:
StringEquals:
'AWS:SourceArn': !Sub 'arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}'
# CloudFront Origin Access Control
CloudFrontOriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: !Sub '${BucketNamePrefix}-${AWS::AccountId}-OAC'
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
# CloudFront Distribution
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: S3Origin
DomainName: !GetAtt S3Bucket.RegionalDomainName
S3OriginConfig:
OriginAccessIdentity: ''
OriginAccessControlId: !GetAtt CloudFrontOriginAccessControl.Id
Enabled: true
DefaultRootObject: index.html
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
QueryString: false
Cookies:
Forward: none
CustomErrorResponses:
- ErrorCode: 403
ResponseCode: 403
ResponsePagePath: /403.html
ErrorCachingMinTTL: 300
- ErrorCode: 404
ResponseCode: 404
ResponsePagePath: /404.html
ErrorCachingMinTTL: 300
PriceClass: PriceClass_100
HttpVersion: http2
Logging:
Bucket: !GetAtt LogBucket.DomainName
Prefix: cloudfront-logs/
IncludeCookies: false
Outputs:
CloudFrontDomainName:
Description: 'CloudFront Distribution Domain Name'
Value: !GetAtt CloudFrontDistribution.DomainName
CloudFrontDistributionId:
Description: 'CloudFront Distribution ID'
Value: !Ref CloudFrontDistribution
S3BucketName:
Description: 'S3 Bucket Name for website content'
Value: !Ref S3Bucket
LogBucketName:
Description: 'S3 Bucket Name for access logs'
Value: !Ref LogBucket
```Save this as a file named `s3-cloudfront-static-website.yaml` and upload it to your Code Server environment, then
deploy it to the Tokyo region yourself using the following command.
※ To ensure the S3 bucket name is unique, please replace the `BucketNamePrefix` value with one of your choice.
```bash
aws cloudformation deploy \
--template-file s3-cloudfront-static-website.yaml \
--stack-name my-static-website-stack \
--parameter-overrides BucketNamePrefix=cm-ogura \
--capabilities CAPABILITY_IAM \
--region ap-northeast-1
Since CloudFront will be created, the deployment will take about 10 minutes.### Content Creation and Display Confirmation
I'll create HTML files to be published with CloudFront.
First, to help the Q CLI understand the deployed stack, I entered the following instruction in q chat
:
Please check the my-static-website stack in the Tokyo region. This stack was created from s3-cloudfront-static-website.yaml located locally.
The end of the Q CLI response was as follows:
> ## Stack Verification Results
The status of the my-static-website-stack in the Tokyo region (ap-northeast-1) is as follows:
### Stack Basic Information
• **Status**: CREATE_COMPLETE (successfully created)
• **Creation Date**: 2025-07-11 01:21:02 UTC
• **Last Update**: 2025-07-11 01:21:08 UTC
• **Parameters**: BucketNamePrefix = "cm-ogura"
### Created Resources
1. S3 Bucket (Main Content)
• Bucket Name: cm-ogura-XXXXXXXXXXXX-ap-northeast-1
• Stores static website content
2. S3 Bucket (For Logs)
• Bucket Name: cm-ogura-logs-XXXXXXXXXXXX-ap-northeast-1
• Stores CloudFront access logs
3. CloudFront Distribution
• Distribution ID: XXXXXXXXXXXXXX
• Domain Name: XXXXXXXXXXXXX.cloudfront.net
4. CloudFront Origin Access Control
• ID: XXXXXXXXXXXXXX
• Controls secure access to S3 bucket
5. S3 Bucket Policy
• Allows access only from CloudFront
### Key Output Values
• **CloudFront Domain**: XXXXXXXXXXXXX.cloudfront.net
• **Main S3 Bucket**: cm-ogura-XXXXXXXXXXXX-ap-northeast-1
• **Log S3 Bucket**: cm-ogura-logs-XXXXXXXXXXXX-ap-northeast-1
All resources have been created successfully, and static website hosting is ready. You can access the website using the CloudFront domain name.
It seems to be reading the stack content correctly.
Next, I'll have it create HTML files.
If Q CLI understands the CloudFormation template content, I expect it to automatically create index.html
and 403.html
as described in the template.
Please create the sample HTML files needed for this template. I'll upload them later.
(omitted)
> ## Creation Complete!
Sample HTML files corresponding to the CloudFormation template have been created:
### 📁 List of Created Files
1. index.html - Main Page
• Website homepage
• Introduction to technologies and architecture
• Responsive design
2. 403.html - Access Denied Error Page
• Displayed when permission errors occur
• User-friendly error explanation
• Link guiding back to home
3. 404.html - Page Not Found Error Page
• Displayed when accessing non-existent pages
• Includes search box
• Site navigation suggestions
4. about.html - Site Overview Page
• Detailed explanation of architecture
• Technical specifications and security features
• Performance statistics
5. contact.html - Contact Page
• Multiple contact methods
• Contact form (for demo)
• FAQ section
### 🎨 Design Features
• **Unified Design**: Consistent color theme and layout across all pages
• **Responsive**: Properly displayed on mobile devices
• **Accessibility**: Readable fonts and contrast
• **Modern UI**: Gradient backgrounds and card layouts
### 📤 Next Steps
Upload these files to the S3 bucket (cm-ogura-XXXXXXXXXXXX-ap-northeast-1), and the website will be displayed at the CloudFront domain (XXXXXXXXXXXXX.cloudfront.net).
For uploading, you can use the following command:
bash
aws s3 sync . s3://cm-ogura-XXXXXXXXXXXX-ap-northeast-1 --exclude "*.yaml" --exclude "*.deb"
````index.html` and `403.html` weren't the only HTML files it created for us.
It will also upload them for us.
Please upload the created HTML files
✅ Upload Complete!
The HTML files have been successfully uploaded.
📤 Uploaded Files
• index.html (4,523 bytes) - Main page
• 403.html (3,952 bytes) - Access denied error page
• 404.html (5,666 bytes) - Page not found error page
• about.html (8,353 bytes) - Site information page
• contact.html (10,855 bytes) - Contact page
🌐 Website Access
The website can be accessed at the following URLs:
• Main site: https://XXXXXXXXXXXXX.cloudfront.net
• About site: https://XXXXXXXXXXXXX.cloudfront.net/about.html
• Contact: https://XXXXXXXXXXXXX.cloudfront.net/contact.html
🔄 Cache Invalidation
CloudFront cache invalidation has also been executed:
• Invalidation ID: XXXXXXXXXXXXXXXXXXXXXXXXXX
• Status: InProgress
• Target: All files (/*)
Cache invalidation typically completes in a few minutes, after which the new content will be available at edge locations worldwide.
🎉 Next Steps
- Check the website: Access the URL above to confirm the site displays correctly
- Test error pages: Access a non-existent page to confirm the 404 page displays
- Update content: Edit HTML files as needed and upload again
Static website construction and deployment is complete!
It seems it also handled the CloudFront cache. After the upload is complete, open the CloudFront URL in your browser. If `index.html` displays correctly, then it's working properly.

*The actual displayed index.html*### Creating WAF from Attack Requests
Using your PC's browser, access the following URLs several times.
These contain strings that are considered malicious access attempts. We will have them recorded in the access logs for later analysis with the Q CLI.
:::message alert
As these requests are considered malicious, please do not send them to any environment other than the one created for this exercise!
# Appending search=test' OR 1=1--
https://<your-cloudfront-domain>/?search=test'%20OR%201%3D1--
# Appending name=<script>alert('xss')</script>
https://<your-cloudfront-domain>/?name=%3Cscript%3Ealert('xss')%3C%2Fscript%3E
# Appending id=1 UNION SELECT username,password FROM users
https://<your-cloudfront-domain>/?id=1%20UNION%20SELECT%20username%2Cpassword%20FROM%20users
After waiting a while, log files will be output to the access log S3 bucket.
(In this case, it took about 5 minutes, but it may take longer in some cases)
Once you confirm that the log files have been generated, ask the Q CLI to analyze them.
I am considering creating an AWS WAF. Please check the CloudFront access logs and tell me if there are any malicious requests and their types.
(omitted)
> ## 🚨 CloudFront Access Log Analysis Results
After analyzing the CloudFront access logs, **multiple malicious requests** were detected. Strongly recommend implementing AWS WAF.
### 🔍 Types of Attacks Detected
#### 1. SQL Injection Attacks (2 instances)
• **Pattern 1**: search=test' OR 1=1--
• Typical SQL injection attack
• Attempting authentication bypass
• **Pattern 2**: id=1 UNION SELECT username,password FROM users
• UNION-based SQL injection
• Attempting to extract user information from the database
#### 2. Cross-Site Scripting (XSS) Attack (1 instance)
• **Pattern**: name=<script>alert('xss')</script>
• Stored/Reflected XSS attack
• Attempting to execute JavaScript code
### 📊 Attack Details
• **Source IP**: XXX.XX.X.XX
• **Attack Time**: 2025-07-11 02:25:24 - 02:25:57 UTC (approx. 33 seconds)
• **User-Agent**: Chrome 138.0.0.0 (Mac OS X)
• **Attack Frequency**: Total of 3 attack patterns, executed multiple times
• **Response**: 200/304 (attacks were not successful, but requests were processed)
### 🛡️ Recommended AWS WAF Rules
Implementation of the following AWS WAF rules is recommended:
#### 1. SQL Injection Protection
• **AWS Managed Rule**: AWSManagedRulesSQLiRuleSet
• **Custom Rule**: Detection of keywords such as UNION, SELECT, OR, --
#### 2. XSS Attack Protection
• **AWS Managed Rule**: AWSManagedRulesCommonRuleSet
• **Custom Rule**: Detection of <script>, javascript:, onerror, etc.
#### 3. Rate Limiting
• **IP-based Rate Limiting**: Limit large numbers of requests from the same IP in a short period
• **Recommended Setting**: Block more than 100 requests within 5 minutes
#### 4. Geographic Restrictions
• Restrict access from specific countries/regions as needed
### 🚀 Next Steps
1. Recommend immediate implementation of AWS WAF
2. Set up CloudWatch Alarms for early detection of attacks
3. Consider AWS Shield Advanced (for DDoS protection)
4. Automate periodic log analysis
These attack patterns are typical examples of common web application attacks, and AWS WAF protection would be effective.
```I was asked to create an AWS WAF CloudFormation template.
Let me create a CloudFormation template for AWS WAF managed rules. This will be a minimal configuration that blocks detected attacks.
AWS WAF managed rules CloudFormation template please create a new one.
Please create a minimal configuration template that sets managed rules to block detected attacks.
- Log output not required
- IP restrictions and rate limiting not required
- Association with CloudFront will be done later, so no need to consider it
I specified that log output isn't needed as I just want to check the WAF rules.
Also, while it might kindly include IP restrictions, I've indicated they're not needed for now.
The end of the output was as follows:
(omitted)
✅ AWS WAF Managed Rules CloudFormation Template Creation Complete
I've created a CloudFormation template for AWS WAF managed rules that blocks detected attacks (SQL injection, XSS).
📁 Created Files
- aws-waf-managed-rules.yaml - Main CloudFormation template
- WAF-README.md - Detailed explanation and deployment instructions
🛡️ Implemented Security Measures
Priority 1: AWSManagedRulesSQLiRuleSet
• Detected attacks: Blocks "test' OR 1=1--" and UNION SELECT attacks
• Defends against SQL injection in general
Priority 2: AWSManagedRulesCommonRuleSet
• Detected attacks: Blocks "<script>alert('xss')</script>" attacks
• Defends against XSS attacks in general
• Excludes some rules for static sites to prevent false positives
Priority 3: AWSManagedRulesKnownBadInputsRuleSet
• Defends against known malicious input patterns
• Provides an additional security layer
🚀 Deployment Instructions
Important: WAF for CloudFront must be created in the us-east-1 region.
bash
1. Create WAF stack
aws cloudformation create-stack
--stack-name my-waf-stack
--template-body file://aws-waf-managed-rules.yaml
--region us-east-1
2. Confirm creation completed
aws cloudformation describe-stacks
--stack-name my-waf-stack
--region us-east-1
📊 Expected Effects
• SQL Injection Attacks: 100% blocked
• XSS Attacks: 100% blocked
• Known Malicious Attacks: Significantly mitigated
• False Positives: Minimized (optimized for static sites)
💰 Cost Estimate
• Approximately $2.80/month + request fees
• WebACL: $1.00/month
• Three rules: $1.80/month
• Requests: $0.60/million requests
This template effectively blocks detected attack patterns and significantly improves website security.
The CloudFormation template for creating WAF was generated for me.:::
Let me check the contents of the template, which includes managed rules such as `AWSManagedRulesCommonRuleSet` and `AWSManagedRulesSQLiRuleSet`.
I'll proceed with deployment. I instructed that the CloudFront and WAF integration should be done using the AWS CLI.
Please deploy the WAF template you created. After deployment, implement the association with CloudFront using AWS CLI.
(omitted)
✅ AWS WAF Deployment Complete!
AWS WAF managed rules deployment and CloudFront association have been successfully completed.
🛡️ Deployment Result Summary
1. WAF WebACL Creation Completed
• WebACL name: static-website-waf
• WebACL ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
• ARN: arn:aws:wafv2:us-east-1:XXXXXXXXXXXX:global/webacl/static-website-waf/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
• Capacity: 1,100 WCU (Web ACL Capacity Units)
2. Implemented Managed Rules
✅ Priority 1: AWSManagedRulesSQLiRuleSet
• Blocks SQL injection attacks
• Addresses detected attacks like test' OR 1=1-- and UNION SELECT
✅ Priority 2: AWSManagedRulesCommonRuleSet
• Blocks XSS attacks
• Addresses detected attacks like <script>alert('xss')</script>
• Excludes four rules for static sites to prevent false positives
✅ Priority 3: AWSManagedRulesKnownBadInputsRuleSet
• Blocks known malicious input patterns
3. CloudFront Association Completed
• Distribution ID: XXXXXXXXXXXXXX
• Status: InProgress (expected to complete in minutes)
• WebACL ID: Successfully associated
📊 Security Enhancement Effects
Attacks to be Blocked
- SQL Injection: search=test' OR 1=1--
- SQL Injection: id=1 UNION SELECT username,password FROM users
- XSS Attack: name=<script>alert('xss')</script>
- Other known attack patterns
🔍 Monitoring and Metrics
CloudWatch Metrics
• AWSManagedRulesSQLiRuleSetMetric
• AWSManagedRulesCommonRuleSetMetric
• AWSManagedRulesKnownBadInputsRuleSetMetric
• static-website-wafMetric
💰 Cost Estimate
• WebACL: $1.00/month
• Three Rules: $1.80/month
• Requests: $0.60/million requests
• Monthly Total: About $2.80 + request charges
🚀 Next Steps
- Confirm CloudFront distribution completion (in about 5-15 minutes)
- Perform attack testing (confirm blocking with the same attack patterns)
- Configure CloudWatch metrics monitoring
- Automate periodic log analysis
With WAF enabled, all previously detected attack patterns will be blocked, significantly enhancing website security.
The WAF CloudFormation template deployment and CloudFront association were successfully implemented.
While I omitted the details, the process involved first saving the CloudFront information to a JSON file, then performing the association operation using CLI.
When attempting to access the previously identified URLs that were considered malicious access from my PC's browser,
this time the `403.html` page was displayed. This is exactly what we expected.
*Actually displayed 403.html*
## Cleanup
After you've completed your verification, don't forget to delete the CloudFront stack you created and the WAF stack that Q CLI created for you.
## Summary
I used Amazon Q Developer CLI to investigate and manipulate the AWS environment.
After trying several times, I noticed that when giving instructions to generative AI, conveying the background behind those instructions seems to bring responses closer to what humans expect.
In this case, by having the AI read the CloudFormation template in advance when generating HTML, it was able to generate the HTML files (`index.html`, `403.html`) used in the template.
When generative AI doesn't return the expected response, it might be worth rechecking whether you've properly articulated the context you have in your mind and effectively communicated it to the AI.
## References
- [Installing Amazon Q for command line](https://docs.aws.amazon.com/ja_jp/amazonq/latest/qdeveloper-ug/command-line-installing.html#command-line-installing-ubuntu)
- [AWS Managed Rules rule group list](https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-list.html)