<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>François Dexemple — Blog</title><description>François Dexemple&apos;s tech blog — Lead SRE, HashiCorp Ambassador, AWS Community Builder. Articles on Terraform, AWS, AI, SRE.</description><link>https://bydexemple.tech/</link><language>en-us</language><item><title>Welcome to my blog</title><link>https://bydexemple.tech/en/blog/hello-world/</link><guid isPermaLink="true">https://bydexemple.tech/en/blog/hello-world/</guid><description>First post: why this blog, what you&apos;ll find here, and what I&apos;m cooking up behind the scenes (Udemy courses on Terraform &amp; AI).</description><pubDate>Mon, 27 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why this blog?&lt;/h2&gt;
&lt;p&gt;After years sharing my learnings on LinkedIn, running user groups, and teaching
DevOps &amp;amp; Cloud to engineering students at EFREI, it was time to have a &lt;strong&gt;place
of my own&lt;/strong&gt; to post the longer-form articles — the ones that don&apos;t fit in 3,000
LinkedIn characters.&lt;/p&gt;
&lt;p&gt;You&apos;ll find three kinds of content here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Real-world lessons learned&lt;/strong&gt; — consulting gigs at Veolia, TotalEnergies,
Edenred, SNCF/Hove, Engie. Patterns that work, pitfalls to dodge, architecture
trade-offs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Technical deep-dives&lt;/strong&gt; — Terraform (I&apos;ve been a HashiCorp Ambassador for
three years), AWS (7 certs, Community Builder), observability, FinOps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The AI workbench&lt;/strong&gt; — how I use AI agents to augment my day-to-day as an
SRE (not just to generate poems).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;What&apos;s coming&lt;/h2&gt;
&lt;p&gt;I&apos;m preparing &lt;strong&gt;Udemy courses&lt;/strong&gt; on Terraform (zero to production, with the
actual enterprise patterns) and on &lt;strong&gt;AI applied to engineering work&lt;/strong&gt;. Subscribe
to the &lt;a href=&quot;/en/rss.xml&quot;&gt;RSS feed&lt;/a&gt; to be the first to know when they drop.&lt;/p&gt;
&lt;h2&gt;About the blog itself&lt;/h2&gt;
&lt;p&gt;This site is open-source:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Astro v6 (hybrid static + SSR)&lt;/li&gt;
&lt;li&gt;Tailwind v4 for the royal-blue design&lt;/li&gt;
&lt;li&gt;Bilingual content collections (FR/EN)&lt;/li&gt;
&lt;li&gt;Serverless AWS deployment (Lambda + CloudFront + S3) driven by Terraform —
because, you know, dogfooding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A future post will walk through the full architecture. Enjoy the read!&lt;/p&gt;
</content:encoded><category>meta</category><category>terraform</category><category>aws</category><category>ai</category></item><item><title>Watch AWS Transform Custom migrate a PHP app to Python + Angular</title><link>https://bydexemple.tech/en/blog/grab-the-popcorn/</link><guid isPermaLink="true">https://bydexemple.tech/en/blog/grab-the-popcorn/</guid><description>Strava put their Year in Sport behind a paywall this year.</description><pubDate>Sat, 20 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Grab the popcorn! Watch AWS Transform Custom migrate a PHP app to Python + Angular from the comfort of my couch. Did it actually exceed expectations?&lt;/h2&gt;
&lt;p&gt;Strava put their Year in Sport behind a paywall this year. Frustrating, right? It’s my data! 😤&lt;/p&gt;
&lt;p&gt;I wasn’t about to pay to see my own stats, so I went looking for alternatives. I found an awesome open-source tool on GitHub that generates a report… but it was written in PHP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: I don’t really know PHP, and I wanted to hack the code to add my own custom metrics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: AWS Transform Custom.&lt;/p&gt;
&lt;p&gt;I decided to run an experiment: Could I use AWS’s new AI migration agent to rewrite this PHP app into a stack I love (Python + Angular) so I could customize it?&lt;/p&gt;
&lt;p&gt;As you might have heard, AWS announced &lt;strong&gt;AWS Transform&lt;/strong&gt; earlier this year for mainframe migrations — basically moving legacy stuff to something a bit more “AWS compatible.” Honestly, I saw the service and thought, &lt;em&gt;“Okay, definitely not for me.”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But then came re:Invent (I was there 🙌).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/grab-the-popcorn/01.jpeg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;They dropped new features: Python 2 to 3 upgrades… and &lt;strong&gt;AWS Transform Custom&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;On paper? You train AWS Transform Custom, and it modernizes your stack exactly how you want. Perfect! I thought, &lt;em&gt;“This is exactly what I need.”&lt;/em&gt; I inherited a PHP project and wanted to switch it to a more modern, different stack. Let’s see how it works and if it actually lives up to the promises AWS sold us!&lt;/p&gt;
&lt;p&gt;To get started, you &lt;em&gt;could&lt;/em&gt; check the AWS console, but it’s pretty useless for our specific case. I didn’t even need to open it. Everything happens in the CLI with a program built for the occasion.&lt;/p&gt;
&lt;p&gt;Let’s install atx:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -fsSL https://desktop-release.transform.us-east-1.api.aws/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And let’s verify everything worked with atx --version. When I ran my tests, I was on v1.0.0.&lt;/p&gt;
&lt;p&gt;Full docs are here if needed: &lt;a href=&quot;https://docs.aws.amazon.com/transform/latest/userguide/custom-get-started.html&quot;&gt;https://docs.aws.amazon.com/transform/latest/userguide/custom-get-started.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you haven’t already, you’ll need to use your AWS credentials. Yep, they need to bill you somehow 😀. Nothing new here, just like the standard AWS CLI, it uses either your profile or environment variables.&lt;/p&gt;
&lt;p&gt;By default, AWS offers “models” (I’m assuming they’re models, but without knowing the backend architecture, I can’t say for sure. If anyone knows more, drop a comment!). Right now, we have these transformation models trained and tested by AWS:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Language Version Upgrades:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWS/java-version-upgrade&lt;/strong&gt; — Upgrade Java applications using any build system from any source JDK version to any target JDK version with comprehensive dependency modernization including Jakarta EE migration, database drivers, ORM frameworks, and Spring ecosystem updates. You can specify your desired target JDK version either through interactive chat with the agent, or by passing an additionalPlanContext configuration parameter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS/python-version-upgrade&lt;/strong&gt; — Migrate Python projects from Python 3.8/3.9 to Python 3.11/3.12/3.13, ensuring compatibility with the latest Python features, security updates, and runtime while maintaining functionality and performance. You can specify your desired target Python version either through interactive chat with the agent, or by passing an additionalPlanContext configuration parameter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS/nodejs-version-upgrade&lt;/strong&gt; — Upgrade NodeJS applications from any source NodeJS version to any target NodeJS version. You can specify your desired target NodeJS version either through interactive chat with the agent, or by passing an additionalPlanContext configuration parameter.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;AWS SDK Migrations:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWS/java-aws-sdk-v1-to-v2&lt;/strong&gt; — Upgrade the AWS SDK from V1 to V2 for Java projects using Maven or Gradle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS/python-boto2-to-boto3&lt;/strong&gt; — Migrate Python applications from boto2 to boto3, based on the official AWS migration documentation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AWS/nodejs-aws-sdk-v2-to-v3&lt;/strong&gt; — Upgrade Node.js applications from AWS SDK for JavaScript v2 to v3 to leverage modular architecture, first-class TypeScript support, middleware stack, and improved performance while ensuring all AWS service interactions continue to function correctly, without modifying the underlying Node.js version.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Source : &lt;a href=&quot;https://docs.aws.amazon.com/transform/latest/userguide/transform-aws-customs.html&quot;&gt;https://docs.aws.amazon.com/transform/latest/userguide/transform-aws-customs.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I suggest keeping an eye on the source regularly; other models are bound to pop up very quickly. This is just the start of the service launch!&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Okay! But back to our use case! PHP to Python+Angular.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;It’s not on AWS’s list… &lt;em&gt;Arf&lt;/em&gt;. Problematic. Does my hype train stop here? Do I have to wait for AWS to ship this specific transformation?&lt;/p&gt;
&lt;p&gt;Not at all! And this is where it gets interesting! AWS gives us the ability to build our &lt;em&gt;own&lt;/em&gt; transformations.&lt;/p&gt;
&lt;p&gt;I’m thinking for companies doing mass migrations, this could be huge! You train the model on work you’ve already done, and you let it handle the rest. No magic involved: the more input data you give it, the better the agent performs.&lt;/p&gt;
&lt;p&gt;In my case? I have zero examples of this transformation to give it. Let’s be reckless and provide &lt;strong&gt;no extra input data&lt;/strong&gt;. The result won’t be perfect, but maybe it’ll chew up the work for me.&lt;/p&gt;
&lt;p&gt;To kick off the process, just run atx and start chatting with the agent:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fdexemple@MacBook-Pro-de-revadmin-6:~/Downloads|
⇒  atx                                                                                                                     tfv1.16.0-rc2 
 █████╗ ██╗    ██╗███████╗                                                     
██╔══██╗██║    ██║██╔════╝                                                     
███████║██║ █╗ ██║███████╗                                                     
██╔══██║██║███╗██║╚════██║                                                     
██║  ██║╚███╔███╔╝███████║                                                     
╚═╝  ╚═╝ ╚══╝╚══╝ ╚══════╝                                                     
                                                                               
████████╗██████╗  █████╗ ███╗   ██╗███████╗███████╗ ██████╗ ██████╗ ███╗   ███╗
╚══██╔══╝██╔══██╗██╔══██╗████╗  ██║██╔════╝██╔════╝██╔═══██╗██╔══██╗████╗ ████║
   ██║   ██████╔╝███████║██╔██╗ ██║███████╗█████╗  ██║   ██║██████╔╝██╔████╔██║
   ██║   ██╔══██╗██╔══██║██║╚██╗██║╚════██║██╔══╝  ██║   ██║██╔══██╗██║╚██╔╝██║
   ██║   ██║  ██║██║  ██║██║ ╚████║███████║██║     ╚██████╔╝██║  ██║██║ ╚═╝ ██║
   ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝╚══════╝╚═╝      ╚═════╝ ╚═╝  ╚═╝╚═╝     ╚═╝
┌──────────────────────────────────────────────────────────────────────────────┐
│                                Trusted Tools                                 │
│                                                                              │
│ Built-in Trusted Tools                                                       │
│   Configuration: Built-in read-only tools                                    │
│   • file_read                                                                │
│   • get_transformation_from_registry                                         │
│   • list_available_transformations_from_registry                             │
│   • document_manager (add operations only)                                   │
└──────────────────────────────────────────────────────────────────────────────┘
Welcome to AWS Transform. You can discover, create, and execute transformations (AWS-managed or custom ones published to your registry). How can I help?
&amp;gt; I want to create a new transformation.
📝 Conversation log: /Users/fdexemple/.aws/atx/custom/20251214_122843_441e8cbd/logs/2025-12-14T12-28-45-conversation.log
📊 Monitor progress: tail -f /Users/fdexemple/.aws/atx/custom/20251214_122843_441e8cbd/logs/2025-12-14T12-28-45-conversation.log
If interrupted, you can resume this conversation by running: atx --conversation-id 20251214_122843_441e8cbd
&amp;gt; What kind of transformation would you like to create?
&amp;gt; I want to migrate a php application to a python api + angular frontend
&amp;gt; I&apos;ll help you create a transformation for migrating a PHP application to a Python API with an Angular frontend.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ll spare you the part where it scans for known transformations. We eventually get to the moment where we switch to custom mode:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; I checked the available transformations in the registry, and there isn&apos;t an existing transformation for migrating a PHP application to a Python API with an Angular frontend. This is a complex cross-language and architectural migration that would be a good fit for a custom transformation.
Let me help you create this new transformation. I&apos;ll help you create a transformation definition for migrating your PHP application to a Python API with an Angular frontend. This modernization will give you improved scalability, better separation of concerns with a clear API layer, and access to modern frontend tooling.
To create an effective transformation definition, it is useful to know such things as:
- What type of PHP application is this (monolithic MVC, Laravel, Symfony, custom framework)?
- Which Python framework are you targeting for the API (Flask, Django, FastAPI)?
- What Angular version are you planning to use for the frontend?
- How is your current PHP application structured (architecture, database interactions, authentication)?
You can also provide file paths to migration guides, documentation, or example code if you have them available. If you don&apos;t have these paths right now, you can always add them later.
&amp;gt; The php use Symphony. I want to use fastapi for the python app. You should use angular v 21. For angular use tailwindcss, apexcharts for the chart
s, ngrx for the store &amp;amp; cache. 
&amp;gt; Thanks for the information! I&apos;ll create a transformation definition for migrating your Symfony PHP application to a FastAPI Python backend with an Angular v21 frontend, including Tailwind CSS for styling, ApexCharts for data visualization, and NgRx for state management and caching.
Let me create this transformation definition for you now.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And very quickly, we get a result:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;● Completed in 1ms
&amp;gt; I&apos;ve created a comprehensive transformation definition for migrating your Symfony PHP application to a FastAPI Python backend with an Angular v21 frontend. The definition includes 24 detailed implementation steps covering the full migration process including NgRx state management with caching, Tailwind CSS styling, and ApexCharts integration for data visualization. The transformation definition for migrating a PHP application to a Python API with Angular frontend has been successfully created and is now available in your session. The transformation definition file is located at:
~/.aws/atx/custom/20251214_122843_441e8cbd/artifacts/tp-staging/transformation_definition.md
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;You can review and update the transformation definition directly at that location if needed.
Would you like to:
1. Apply this transformation to your PHP codebase
2. Review or modify the transformation definition further
3. Publish this transformation to the registry for future use
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I assume the more rules and examples you provide, the longer the creation process takes. But I noted two interesting things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$1&lt;/li&gt;
&lt;li&gt;$1&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; I&apos;ll help you apply this transformation to your PHP codebase.
What is the file system path to the code repository where you want to apply this transformation?
/Users/fdexemple/Downloads/statistics-for-strava-master
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And boom, we launch the machine! And here comes the big mistake: I didn’t read the atx docs... I &lt;strong&gt;strongly&lt;/strong&gt; recommend enabling the --trust-all-tools (-t) option (proceed carefully, you give all rights to AI with this option, I love danger zone)&lt;/p&gt;
&lt;p&gt;In my case, it crunched numbers for 15 minutes, tried to use a new tool, and then blocked, waiting for my approval. I wanted it to run autonomously — fail. There aren’t many CLI options yet, so take a look before you start: &lt;a href=&quot;https://docs.aws.amazon.com/transform/latest/userguide/custom.html&quot;&gt;https://docs.aws.amazon.com/transform/latest/userguide/custom.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Another thing: AWS Transform commits regularly, at every step! Awesome, but I sign my commits and my token expires every 5 minutes, so I had to babysit the commit steps. It did start its own branch though, which is practical and aligns with enterprise rules.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/grab-the-popcorn/02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I let it run, approving tools occasionally. I can’t give you an exact time; for me, it took a day, but pure calculation time was probably more like a few hours. It felt like the tool crashed a few times (it’s pretty verbose), and after hours of silence, I killed the process. Luckily, atx gives you a conversation ID at the start, so I picked up exactly where I left off using: atx --conversation-id 20251214_122843_441e8cbd (it tells you this right at the beginning—super handy!).&lt;/p&gt;
&lt;p&gt;In the end, I got a nice summary:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; Perfect! Now let me provide a summary to the user:)
## Validation Summary
I&apos;ve successfully addressed several critical exit criteria and implemented key improvements to the migration. Here&apos;s the summary:
### Overall Status: **PARTIAL - 11/16 criteria passing (69%)**
---
### ✅ **Successfully Fixed (5 Critical Items)**
1. **ApexCharts Integration** - PASS
   - Installed apexcharts 5.3.6 and ng-apexcharts 1.8.0
   - Created ActivitiesChartComponent with line chart visualization
   - Production build successful with charts integrated
2. **NgRx Effects &amp;amp; Entity Adapters** - PASS
   - Implemented AuthEffects and ActivitiesEffects
   - Created EntityAdapter for activities with normalized state
   - All effects registered and working with proper async handling
3. **HTTP Interceptors** - PASS
   - authInterceptor: Automatic Bearer token injection
   - errorInterceptor: Centralized error handling for all HTTP status codes
   - Both registered in app.config.ts
4. **Route Guards** - PASS
   - Created authGuard using NgRx authentication state
   - Protected routes (/dashboard, /activities) with guard
   - Redirects to /login when not authenticated
5. **Webhook Endpoints** - PASS
   - Added GET/POST /api/strava/webhook endpoints
   - Migrated from Symfony StravaWebhookRequestHandler
---
### ❌ **Critical Gaps Remaining**
1. **Template Migration** - FAIL (3/88 templates, 3.4% complete)
   - 85 Twig templates still need Angular component conversion
   - This is the largest remaining gap
2. **Angular Reactive Forms** - FAIL
   - No client-side form validation implemented
   - Only server-side Pydantic validation exists
---
### 📊 **Progress Breakdown**
- **✅ PASS**: 11 criteria (69%) - up from 8 previously
- **⚠️ PARTIAL**: 2 criteria (13%)
- **❌ FAIL**: 2 criteria (13%) - down from 4 previously
---
### 📝 **Files Created/Modified**
**24 new files created**, including:
- NgRx effects for auth and activities
- HTTP interceptors (auth, error)
- Route guards (authGuard)
- Chart components with ApexCharts
- Activities list component
- Enhanced services with CRUD operations
**8 files modified** to integrate new features
---
Complete validation summary has been written to `~/.aws/atx/custom/20251214_122843_441e8cbd/artifacts/validation_summary.md`
**Do you have any feedback or questions about the transformation execution?**
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Wait a minute!&lt;/strong&gt; My goal is a working app, and you’re telling me you only converted 3.4% of the HTML templates? &lt;em&gt;Whoa.&lt;/em&gt; That leaves me with a ton of work. We aren’t talking about a few misaligned pixels; we’re talking about almost all the pages.&lt;/p&gt;
&lt;p&gt;As you can guess, I pressed on. I want this agent to chew up the work for me, so here’s my feedback, and off we go for another round!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;implement the missings part
&amp;gt; I&apos;ll implement the missing critical parts. Let me start by creating Angular reactive forms and then work on migrating more Twig templates to Angular components.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Great. But, by the way, how much did all this time-saving cost me?&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/grab-the-popcorn/03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;$20.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cheap for the hours worked, expensive for the result I got. But as I said, I went in blind without giving it data or examples so it would know &lt;em&gt;how&lt;/em&gt; to do it, so the result is fair enough.&lt;/p&gt;
&lt;p&gt;In a corporate context — spending a few days providing good examples and reviewing steps — $20 to migrate an app is unbeatable. Agreed, the migration won’t be 100% complete, there will always be adjustments, but logically you’re only supposed to do them once because Transform learns! It has a &lt;strong&gt;Continual Learning&lt;/strong&gt; system.&lt;/p&gt;
&lt;p&gt;Note: this is specific to &lt;em&gt;you&lt;/em&gt;. Meaning, if you stay in draft mode and don’t publish your transform, everything you teach it stays local and won’t be shared with your colleagues. If you publish it to an AWS account, it stays on that AWS account. For mass migrations, you’ll need to think about running transforms from the same account to get a single super-trained model, even if you want to re-bill the costs elsewhere.&lt;/p&gt;
&lt;h2&gt;But wait, does it compile?&lt;/h2&gt;
&lt;p&gt;Great question! Let’s check the damage.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/grab-the-popcorn/04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Whoa&lt;/em&gt;, it looks like a teenager’s bedroom in here! My folder is a total mess, it mixed everything up. My PHP code is sitting right next to my Angular code. I didn’t specify separation, so I didn’t get it. At least it made a subfolder for the frontend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Good&lt;/strong&gt; news: my frontend compiles! And without errors!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/grab-the-popcorn/05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Bad news: I have a white screen in the browser… I’ll need to dig into that. I think using Kiro to help with the full migration chain and getting into the details would be a good move here.&lt;/p&gt;
&lt;p&gt;However, looking at the code, I really like the structure. It’s simple to read and doesn’t scream “AI-generated” immediately — no massive blocks of comments, just what’s necessary. I’d totally see myself taking over this codebase without issues.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/grab-the-popcorn/06.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On the Python side&lt;/strong&gt;, same deal. It compiles, but what bothers me more is that the app is almost empty and things are missing in a lot of places. It mocked the routes and seems to have never come back to them. The structure is good, but the substance is missing.&lt;/p&gt;
&lt;p&gt;Another thing: it really &lt;em&gt;only&lt;/em&gt; generated the frontend &amp;amp; backend. In the existing project I gave it, there was a Dockerfile and a Github CI/CD. It didn’t touch them at all. It focused solely on the requested tasks. Some will see this as a plus because it doesn’t go off the rails; others will be disappointed it didn’t handle that automatically.&lt;/p&gt;
&lt;p&gt;Just know that if you want it to adapt everything, you have to ask it and not forget anything. Once again, you have to spend time reading the specs it generates at the start and challenge them!&lt;/p&gt;
&lt;p&gt;I’ll allow myself to paraphrase &lt;a href=&quot;https://thekernel.news/articles/dawn-of-the-renaissance-developer/&quot;&gt;Dr. Werner Vogels from his re:Invent 2025 Keynote: the developer’s job is changing&lt;/a&gt;, we need to spend more time on reviews. I noticed it again today — I skipped that step, and someone who seriously reviews the specs would get a much better result than I did and would be much more in demand on the market.&lt;/p&gt;
&lt;h2&gt;What about the collaborative aspect?&lt;/h2&gt;
&lt;p&gt;I have a base (to rework), but how do I share it with my colleagues? As I mentioned, right now we are only local, so we need to publish our transform to the AWS account. To do that, you just ask it in natural language (there’s a CLI command too, but asking is way easier).&lt;/p&gt;
&lt;h2&gt;What if we helped AWS Transform with MCPs?&lt;/h2&gt;
&lt;p&gt;I didn’t do this, and I probably should have. AWS Transform lets you configure MCP servers in the ~/.aws/atx/mcp.json file. I like to check if it works with atx mcp tools.&lt;/p&gt;
&lt;p&gt;I wish AWS shipped 2–3 default MCPs. Here are my “must-haves” that I copy into all my Agentic tools (and I complete them based on needs):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;fetch&quot;: {
      &quot;command&quot;: &quot;uvx&quot;,
      &quot;args&quot;: [
        &quot;mcp-server-fetch&quot;
      ],
      &quot;env&quot;: {},
      &quot;disabled&quot;: false,
      &quot;autoApprove&quot;: [
        &quot;fetch&quot;
      ]
    },
    &quot;aws-docs&quot;: {
      &quot;command&quot;: &quot;uvx&quot;,
      &quot;args&quot;: [
        &quot;awslabs.aws-documentation-mcp-server@latest&quot;
      ],
      &quot;env&quot;: {
        &quot;FASTMCP_LOG_LEVEL&quot;: &quot;ERROR&quot;
      },
      &quot;disabled&quot;: false,
      &quot;autoApprove&quot;: []
    },
    &quot;git&quot;: {
      &quot;command&quot;: &quot;uvx&quot;,
      &quot;args&quot;: [
        &quot;mcp-server-git&quot;
      ],
      &quot;disabled&quot;: false,
      &quot;autoApprove&quot;: []
    },
    &quot;filesystem&quot;: {
      &quot;command&quot;: &quot;npx&quot;,
      &quot;args&quot;: [
        &quot;-y&quot;,
        &quot;@modelcontextprotocol/server-filesystem&quot;,
        &quot;/path/to/allowed/directory&quot;
      ],
      &quot;disabled&quot;: true,
      &quot;autoApprove&quot;: []
    },
    &quot;aws-knowledge-mcp&quot;: {
      &quot;url&quot;: &quot;[https://knowledge-mcp.global.api.aws](https://knowledge-mcp.global.api.aws)&quot;,
      &quot;disabled&quot;: false
    },
    &quot;awslabs.terraform-mcp-server&quot;: {
      &quot;command&quot;: &quot;uvx&quot;,
      &quot;args&quot;: [
        &quot;awslabs.terraform-mcp-server@latest&quot;
      ],
      &quot;env&quot;: {
        &quot;FASTMCP_LOG_LEVEL&quot;: &quot;ERROR&quot;
      },
      &quot;disabled&quot;: false
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;And AWS Transform VS Kiro ?&lt;/h2&gt;
&lt;p&gt;I also gave Kiro a shot just out of curiosity, using the specs feature. The results are way behind AWS Transform. The main issue I noticed is that Kiro didn’t actually read all the project files; it looked like it was trying to cut corners to save on context window. Then it tried to rebuild everything from its own generated spec, and the output is totally off. It feels a bit like a game of &lt;strong&gt;Telephone&lt;/strong&gt; — there’s a massive gap between the start and the finish. Transform, on the other hand, keeps the source in the loop the whole time.&lt;/p&gt;
&lt;h2&gt;Verdict?&lt;/h2&gt;
&lt;p&gt;So, is AWS Transform Custom the magic wand we’ve been waiting for? Am I really going to sell migration services for €1,000 a day from the comfort of my couch? Let’s get crazy! Can one person handle multiple migrations at once? Yes and no (heheh). It’s not going to take your legacy PHP spaghetti and turn it into a pristine (not yet), enterprise-grade Python/Angular architecture while you sleep, at least, not without some serious guidance.&lt;/p&gt;
&lt;p&gt;But for $20? It did the heavy lifting. It set up the structure, handled the boilerplate, and gave me a solid foundation to build on. It’s like hiring a junior dev who works incredibly fast but &lt;strong&gt;needs code review&lt;/strong&gt;. If you’re willing to put in the time to train it and review the specs, it’s a massive productivity booster. Just don’t forget to read the docs, turn on --trust-all-tools if you value your sanity, and maybe keep an eye on those commit logs.&lt;/p&gt;
&lt;p&gt;I’m definitely keeping atx in my toolbox. Now, back to debugging that white screen...I want my Strava report !&lt;/p&gt;
</content:encoded><category>agentic-ai</category><category>software-development</category><category>aws</category><category>ai</category><category>migration</category></item><item><title>Brilliant, Broken, and Frustrating: My Deep Dive into Amazon’s Kiro AI IDE, the Flawed Junior…</title><link>https://bydexemple.tech/en/blog/brilliant-broken-and-frustrating-my-deep-dive-into-amazons-kiro-ai-ide-the-flawed-junior/</link><guid isPermaLink="true">https://bydexemple.tech/en/blog/brilliant-broken-and-frustrating-my-deep-dive-into-amazons-kiro-ai-ide-the-flawed-junior/</guid><description>We’ve all been there.</description><pubDate>Fri, 24 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Brilliant, Broken, and Frustrating: My Deep Dive into Amazon’s Kiro AI IDE, the Flawed Junior Developer&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/brilliant-broken-and-frustrating-my-deep-dive-into-amazons-kiro-ai-ide-the-flawed-junior/01.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We’ve all been there. You throw a few prompts at an AI coding tool, and like magic, a functional app appears. It’s the peak of “vibe coding” — fast, exciting, and instantly gratifying. But then comes the hangover, and, oh boy, I have &lt;strong&gt;personally&lt;/strong&gt; hit this wall hard. The requirements were fuzzy. The design decisions were undocumented. &lt;strong&gt;Does the output even solve the problem?&lt;/strong&gt; What was once a fun prototype quickly &lt;strong&gt;becomes&lt;/strong&gt; a maintenance nightmare; without clear design documentation, future changes are just guesswork. This is why so many AI-built prototypes hit a wall.&lt;/p&gt;
&lt;p&gt;Enter Kiro, a new agentic IDE from AWS that takes a completely different path. It promises to tame the chaos by injecting a dose of engineering discipline into AI-assisted development. Instead of unstructured chats, it champions a structured, spec-driven workflow. After a deep dive into how Kiro works in its current preview state, a few realities stood out — some powerful, some frustrating, and all of them surprising. Here are the five surprising and often contradictory realities of using the tool that wants to wage war on vibe coding.&lt;/p&gt;
&lt;h2&gt;1. Its core mission is the opposite of “Vibe Coding”&lt;/h2&gt;
&lt;p&gt;Kiro’s entire philosophy is built on spec-driven development. This is a deliberate, structured, three-phase workflow that moves from a high-level prompt to a series of formal engineering artifacts: requirements.md, design.md, and tasks.md. The AI doesn’t just generate code; it first generates a detailed plan, user stories, architectural diagrams using Mermaid.js, and a sequenced task list.&lt;/p&gt;
&lt;p&gt;This is the polar opposite of the unstructured “prompt-and-pray” chaos of vibe coding. The process forces you to plan and clarify your intent upfront, ensuring that what gets built aligns with actual requirements. It’s a trade-off: you get the rigor of traditional software engineering, but it can feel like a slower, more rigid “waterfall approach” compared to the quick dopamine hits of seeing code appear instantly. While this structure provides discipline, early user feedback highlights a critical flaw: its rigidity can kill momentum. One user described it as a “waterfall approach” where “requirements and design artifacts don’t auto-update,” causing the implementation and specs to drift apart and breaking the iterative flow developers rely on.&lt;/p&gt;
&lt;h2&gt;2. It’s an AWS product that tries hard not to be one&lt;/h2&gt;
&lt;p&gt;Here’s one of the biggest strategic surprises: Kiro is developed by Amazon Web Services, but it’s not branded as an “AWS” or “Amazon” product. This is AWS’s most significant strategic gamble in the developer tool space in years, a deliberate attempt to shed its “walled garden” reputation to win a war for developer mindshare that it has, until now, been losing.&lt;/p&gt;
&lt;p&gt;It lives on its own website (kiro.dev), and you don’t even need an AWS account to use it, supporting logins via common providers like Google and GitHub, side-stepping the usual requirement for an AWS account (though AWS Builder ID and IAM roles are also supported for deeper integration). By shedding the AWS branding, Kiro aims to be a tool for all developers, not just those building on Amazon’s cloud.&lt;/p&gt;
&lt;h2&gt;3. The hype collided with a wall of errors and limits&lt;/h2&gt;
&lt;p&gt;The launch of Kiro was met with what the company called “unprecedented demand,” and the preview experience reflects a system struggling under the load. The ambitious vision of a seamless, AI-driven workflow has, for many users, been replaced by a reality of constant friction and failure.&lt;/p&gt;
&lt;p&gt;The user-reported issues have been widespread and consistent:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Initial Waitlists:&lt;/strong&gt; At first, new users were often waitlisted before they could even download the IDE. Thankfully, the waitlist is now removed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Daily Usage Limits:&lt;/strong&gt; Early users were hitting daily limits that halted their projects, with no option to pay for more capacity. This also seems to be resolved.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Frequent Errors:&lt;/strong&gt; Messages like “The model you’ve selected is experiencing a high volume of traffic. Try changing the model and re-running your prompt” and “An unexpected error occurred, please retry” are common. &lt;strong&gt;Personally, I still get these&lt;/strong&gt; 1–2 times a week, though it’s much better than the daily errors at the start.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stuck Tasks:&lt;/strong&gt; Tasks frequently get stuck, fail, and require numerous manual retries. I ran into a lot of problems with my terminal that was configured with many plugins; the issue and solution are on GitHub: &lt;a href=&quot;https://github.com/kirodotdev/Kiro/issues/53&quot;&gt;https://github.com/kirodotdev/Kiro/issues/53&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The frustration is compounded by the fact that a failed task often loses all context, forcing developers to restart the entire process from scratch and burning through their daily usage limits on unsuccessful attempts. This gap between the product’s promise and its current usability has been a major source of frustration, perfectly captured by my own user’s experience:&lt;/p&gt;
&lt;p&gt;I’ve been retrying 50+ times over the last 10+ hours and still get: “The model you’ve selected is experiencing a high volume of traffic. Try changing the model and re-running your prompt.” But with the paid plan, that’s over. I do not get this anymore.&lt;/p&gt;
&lt;h2&gt;4. Its real power isn’t just generating code, it’s automating the entire project&lt;/h2&gt;
&lt;p&gt;Beyond generating code from specs, Kiro’s true potential lies in two powerful automation features that represent its core argument for how AI development should work: not as a chatty assistant, but as an embedded, reactive system that automates the tedious rituals of software engineering.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent Steering: Solving the AI Memory Problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Agent Steering is Kiro’s solution to the notorious short-term memory of AI assistants. It gives the AI persistent knowledge about your project’s conventions — tech stack, file structure, coding patterns — through a series of markdown files in a .kiro/steering/ directory. Kiro consults these files to ensure it generates code that consistently follows your team&apos;s established standards, without you having to repeat the rules in every prompt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent Hooks: Automating the Engineering Rituals&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Agent Hooks are event-driven automations that trigger AI agents to perform tasks in the background. For example, a hook can automatically update test files whenever a component is saved, refresh documentation when an API endpoint changes, or scan for security leaks before a commit. However, the feature is limited in its preview state; only one hook can execute per file save, and there is no way to orchestrate a sequence of hooks.&lt;/p&gt;
&lt;p&gt;It’s like having a very attentive pair programmer who takes care of the tedious stuff without interrupting your flow.&lt;/p&gt;
&lt;h2&gt;5. The AI is still a flawed (and overeager) Junior Dev&lt;/h2&gt;
&lt;p&gt;Despite its sophisticated planning and structured approach, Kiro’s AI is far from infallible. In practice, it often behaves like an overeager junior developer who, while well-intentioned, can make fundamental mistakes and overcomplicate simple problems.&lt;/p&gt;
&lt;p&gt;Here are a few documented examples of its flaws:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Code Bloat&lt;/strong&gt;: I asked Kiro to create a simple app that will display my Strava data. The result was an “absolute mess” of approximately 20 files and over 1,500 lines of convoluted code riddled with “console.log gibberish” for a task that a human could solve in under 200 lines. It seems Kiro defaults to an “industrial, military-grade” product, so you have to review the tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debugging Loops:&lt;/strong&gt; The AI has been observed falling into a circular debugging loop, where it identifies a problem and applies the same incorrect fix over and over again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Infinite Optimizations:&lt;/strong&gt; A user discovered they could repeatedly trigger a “code smell” hook on the same file. Each time, Kiro would find new “optimizations,” continuing until the code was “arguably worse than when we started.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Losing Context:&lt;/strong&gt; In one project, Kiro correctly implemented DynamoDB caching logic but then unexpectedly mixed it with secrets management code from a completely different, earlier task, demonstrating a breakdown in context retention.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This reveals the central paradox of Kiro today: it builds an elaborate scaffolding of engineering discipline to constrain the AI, yet the AI inside still behaves like an unpredictable junior developer, requiring constant senior-level oversight to prevent it from over-engineering itself into a corner.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Kiro’s vision is undeniably the future for any team that cares about building durable, enterprise-grade software with AI. It is a brilliant and necessary correction to the chaotic, short-term thinking of “vibe coding.” The constant errors, limits, and AI quirks make it clear that while the destination is exciting, the journey there is still incredibly bumpy. This leaves us with a critical question:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Is the engineering discipline Kiro enforces worth the current struggle, or will the instant gratification of “vibe coding” win out?&lt;/em&gt;&lt;/p&gt;
</content:encoded><category>ai</category><category>software-development</category><category>aws</category><category>agentic-ai</category><category>cloud-computing</category></item><item><title>Centralised Logging with CloudWatch OAM and HCP Terraform</title><link>https://bydexemple.tech/en/blog/centralised-logging-with-cloudwatch-oam-and-hcp-terraform/</link><guid isPermaLink="true">https://bydexemple.tech/en/blog/centralised-logging-with-cloudwatch-oam-and-hcp-terraform/</guid><description>*© Devoteam Revolve* **This blog post is based on my talk at the Community Day Dach in Munich.</description><pubDate>Thu, 31 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../../assets/medium/centralised-logging-with-cloudwatch-oam-and-hcp-terraform/01.jpeg&quot; alt=&quot;© Devoteam Revolve&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;© Devoteam Revolve&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This blog post is based on my talk at the Community Day Dach in Munich. In my daily work, I often run into a frustrating problem. When I need to debug or understand how an application works, I naturally go to CloudWatch. However, the different parts of a project are often segregated into different AWS accounts. So, I go back to the SSO portal and access this new account.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But very frequently I need to go back to the first account, which is still open in a tab of my browser, but, oh no, I have been disconnected from the account… Annoying, isn’t it?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now that we’ve discussed the problem, let’s see how we can access all our log data without being disconnected.&lt;/p&gt;
&lt;h2&gt;The Solution: CloudWatch OAM&lt;/h2&gt;
&lt;p&gt;While third-party solutions like Datadog and Dynatrace exist, they come with costs and require leaving the AWS environment. I will introduce you to a relatively unknown and underutilized AWS feature: CloudWatch Observability Access Manager (OAM).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/centralised-logging-with-cloudwatch-oam-and-hcp-terraform/02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/centralize-monitoring-by-using-amazon-cloudwatch-observability-access-manager.html&quot;&gt;https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/centralize-monitoring-by-using-amazon-cloudwatch-observability-access-manager.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Before we begin, I’d like to review **the basics of **&lt;a href=&quot;https://rebirth.devoteam.com/2022/06/30/5-questions-observabilite/&quot;&gt;&lt;strong&gt;observability&lt;/strong&gt;&lt;/a&gt;, the three pillars of which are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Metrics:&lt;/strong&gt; These numerical data points tell you how your systems and applications perform. Examples include CPU utilisation, memory usage, and request latency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logs:&lt;/strong&gt; These are records of events in your systems and applications. They provide detailed information about what happened, when it happened, and where it happened.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traces:&lt;/strong&gt; These track the flow of requests through your applications, helping you understand how different components interact and identify performance bottlenecks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These three pillars are valid for all applications and infrastructures, not just on AWS. However, in addition to these three pillars, we find two other types of data that CloudWatch OAM can manage:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application Insights:&lt;/strong&gt; This provides in-depth monitoring for your applications, collecting data like request rates, error rates, and response times.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internet Monitor:&lt;/strong&gt; This monitors the availability and performance of your applications from the perspective of your end users, giving you insights into how they experience your services.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Seeing this article as an excellent opportunity to introduce you to another deployment method simultaneously, I will introduce you to HCP Terraform, the version of Terraform managed by HashiCorp with lots of little extras that don’t exist in the community version. You could compare it to what AWS is to on-premises infrastructure.&lt;/p&gt;
&lt;h2&gt;Why HCP Terraform?&lt;/h2&gt;
&lt;p&gt;HCP Terraform is a managed Terraform offering by HashiCorp. Think of it as the AWS of the Terraform world. It provides several advantages over the community version, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Managed infrastructure:&lt;/strong&gt; No need to manage your own Terraform infrastructure. HCP takes care of that for you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced collaboration:&lt;/strong&gt; Improved collaboration features make it easier for teams to work together.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration with other HashiCorp tools:&lt;/strong&gt; Seamless integration with Vault, Consul, and Nomad, expanding your infrastructure management capabilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Understanding the Implementation&lt;/h2&gt;
&lt;p&gt;Before we start the implementation, I’ll explain the complete setup to help you understand why we’re doing it this way.&lt;/p&gt;
&lt;p&gt;We’re going to create a Terraform stack that will be used to deploy our AWS organisation. We could do this with AWS Account Factory for Terraform (AFT) or Control Tower, but these methods each have their own advantages and disadvantages. So, we will manually create our first project for our master account, which will be connected to a stack hosted on a GitHub repo. This Terraform stack will deploy (meaning create) our HCP Terraform projects on HCP and create our AWS accounts, each of which will be linked to its own HCP project. We could create a single HCP project, but with an actual enterprise organisation that can contain 100 or even 1000 AWS accounts, the Terraform stack would quickly become unmanageable. However, if we have one HCP project per account, we’ll only have a single Terraform codebase that will be hosted on a repo. Here’s a diagram:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/centralised-logging-with-cloudwatch-oam-and-hcp-terraform/03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, the organisation stack will also create the observability account, but it won’t have its own HCP project. The account will be managed directly by the organisation stack.&lt;/p&gt;
&lt;p&gt;Before we continue, let’s look at how….&lt;/p&gt;
&lt;p&gt;_Find the next part of this article on my company’s blog (free): _&lt;a href=&quot;https://rebirth.devoteam.com/2024/10/10/centralised-logging-cloudwatch-oam/&quot;&gt;&lt;em&gt;https://rebirth.devoteam.com/2024/10/10/centralised-logging-cloudwatch-oam/&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>aws</category><category>observability</category><category>cloudwatch</category></item><item><title>AWS Lambda Strategies: Clever Ways to Rotate IPs and Avoid Blockades</title><link>https://bydexemple.tech/en/blog/aws-lambda-strategies-clever-ways-to-rotate-ips-and-avoid-blockades/</link><guid isPermaLink="true">https://bydexemple.tech/en/blog/aws-lambda-strategies-clever-ways-to-rotate-ips-and-avoid-blockades/</guid><description>In the next chapter of my journey, which you can explore in detail through the links below: - Article 1 : [How to reverse engineering an Android App and Its API — Example with an a</description><pubDate>Mon, 06 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the next chapter of my journey, which you can explore in detail through the links below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Article 1 : &lt;a href=&quot;https://medium.com/@francoisdexemple/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government-5172c3bea2af&quot;&gt;How to reverse engineering an Android App and Its API — Example with an app from the US government&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Article 2 : &lt;a href=&quot;https://medium.com/@francoisdexemple/aws-secrets-the-guide-to-bypassing-cors-for-developers-bd544fd5077f&quot;&gt;AWS Secrets: The Guide to Bypassing CORS for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Article 3 : &lt;a href=&quot;https://medium.com/@francoisdexemple/aws-blacklisted-stealth-tactics-for-lambda-functions-outside-a-vpc-857e37835fe8&quot;&gt;AWS Blacklisted? Stealth Tactics for Lambda Functions Outside a VPC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In a recent side project, I encountered a challenge: I have an AWS Lambda function that calls an API I don’t own, and after a certain number of requests, I get blocked by their anti-bot system, resulting in the dreaded 403 error.&lt;/p&gt;
&lt;p&gt;In this article, I will discuss a Lambda function** outside of a VPC**. Managing the IP address of a Lambda function within a VPC would be much easier.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-lambda-strategies-clever-ways-to-rotate-ips-and-avoid-blockades/01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Before I delve into my solution, let’s revisit how AWS Lambda functions operate.&lt;/p&gt;
&lt;h2&gt;AWS Lambda and Firecracker MicroVM&lt;/h2&gt;
&lt;p&gt;AWS Lambda is powered by Firecracker, a virtualization technology crafted by Amazon using Rust. This technology serves as the core engine for running Lambda functions, delivering a platform that is both lightweight and sturdy for code execution. Firecracker’s innovative architecture provides the security and isolation typical of virtual machines, yet it achieves the rapid performance and resource efficiency usually associated with containers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-lambda-strategies-clever-ways-to-rotate-ips-and-avoid-blockades/02.png&quot; alt=&quot;https://firecracker-microvm.github.io/&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;https://firecracker-microvm.github.io/&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;See more on Firecracker here : &lt;a href=&quot;https://firecracker-microvm.github.io/&quot;&gt;https://firecracker-microvm.github.io/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;AWS Lambda and containers&lt;/h2&gt;
&lt;p&gt;A Lambda function is executed within a container. For a deeper understanding of the lifecycle of this container, you can visit the AWS documentation: &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/operatorguide/execution-environments.html&quot;&gt;AWS Lambda Execution Environments&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-lambda-strategies-clever-ways-to-rotate-ips-and-avoid-blockades/03.png&quot; alt=&quot;https://docs.aws.amazon.com/lambda/latest/operatorguide/execution-environments.html&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;https://docs.aws.amazon.com/lambda/latest/operatorguide/execution-environments.html&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When multiple invocations occur in parallel, AWS simply launches multiple containers :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-lambda-strategies-clever-ways-to-rotate-ips-and-avoid-blockades/04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-lambda-strategies-clever-ways-to-rotate-ips-and-avoid-blockades/05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;When updating a Lambda function, here’s what happens:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-lambda-strategies-clever-ways-to-rotate-ips-and-avoid-blockades/06.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The entire solution to the problem I faced lies in updating the AWS Lambda function to trigger the launch of a new container, thereby acquiring a new IP address. However, updating the code every time this is needed is not practical as it would become cumbersome to maintain. Instead, my approach is more focused on utilizing environment variables. Here’s a simple Python example to illustrate this method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os
import string
import random

import boto3
from aws_lambda_powertools import Logger

client = boto3.client(&quot;lambda&quot;)
logger = Logger()

def change_ip_address():
    try:
        lambda_name = os.environ[&quot;AWS_LAMBDA_FUNCTION_NAME&quot;]
        response = client.get_function_configuration(FunctionName=lambda_name)
        env_var = response[&quot;Environment&quot;][&quot;Variables&quot;]
        letters = string.ascii_lowercase
        env_var[&quot;RANDOM&quot;] = &quot;&quot;.join(random.choice(letters) for i in range(5))
        response = client.update_function_configuration(FunctionName=lambda_name, Environment={&quot;Variables&quot;: env_var})
        logger.info(response)
        logger.info(&quot;Lambda config changed, we should have a new ip at the next launch&quot;)
    except Exception as e:
        logger.warning(&quot;Not possible to change ip address due to &quot;,e)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And if you want to test your actual IP you can use :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;current_ip = requests.get(&quot;http://checkip.amazonaws.com&quot;).text.rstrip()
logger.info(f&quot;Current ip : {current_ip}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The downside is that we experience a cold start with each execution, which can significantly slow down our execution times.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://awstip.com/aws-lambda-strategies-clever-ways-to-rotate-ips-and-avoid-blockades-42f2b4e49e6e&quot;&gt;AWS Lambda Strategies: Clever Ways to Rotate IPs and Avoid Blockades&lt;/a&gt; was originally published in &lt;a href=&quot;https://awstip.com&quot;&gt;AWS Tip&lt;/a&gt; on Medium, where people are continuing the conversation by highlighting and responding to this story.&lt;/p&gt;
</content:encoded><category>aws</category><category>aws-lambda</category></item><item><title>AWS Blacklisted? Stealth Tactics for Lambda Functions Outside a VPC</title><link>https://bydexemple.tech/en/blog/aws-blacklisted-stealth-tactics-for-lambda-functions-outside-a-vpc/</link><guid isPermaLink="true">https://bydexemple.tech/en/blog/aws-blacklisted-stealth-tactics-for-lambda-functions-outside-a-vpc/</guid><description>In the next chapter of my journey, which you can explore in detail through the links below: - Article 1 : [How to reverse engineering an Android App and Its API — Example with an a</description><pubDate>Mon, 29 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-blacklisted-stealth-tactics-for-lambda-functions-outside-a-vpc/01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In the next chapter of my journey, which you can explore in detail through the links below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Article 1 : &lt;a href=&quot;https://medium.com/@francoisdexemple/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government-5172c3bea2af&quot;&gt;How to reverse engineering an Android App and Its API — Example with an app from the US government&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Article 2 : &lt;a href=&quot;https://medium.com/@francoisdexemple/aws-secrets-the-guide-to-bypassing-cors-for-developers-bd544fd5077f&quot;&gt;AWS Secrets: The Guide to Bypassing CORS for Developers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today, we’ll explore how to effectively utilize AWS even when its network is blacklisted. I conducted all of my development locally. Here’s an overview of the actual architecture I used:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-blacklisted-stealth-tactics-for-lambda-functions-outside-a-vpc/02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I developed my AWS Lambda functions in Python and conducted all the necessary tests, which all passed flawlessly. However, upon deployment, I encountered an unexpected issue — all my requests to the third-party API were met with 403 errors. After verifying my code and re-testing it locally (where everything functioned perfectly) and from another network (which also worked), I deduced that the AWS network might be blacklisted by the API.&lt;/p&gt;
&lt;p&gt;From a security perspective, if the API is designed primarily for end-users, blocking AWS IPs is a sensible and straightforward approach, especially since AWS publishes its IP ranges &lt;a href=&quot;https://docs.aws.amazon.com/vpc/latest/userguide/aws-ip-ranges.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For those not on AWS looking to minimize unwanted traffic, using such IP filters can be an effective starting point.&lt;/p&gt;
&lt;p&gt;So, what could I do next, given that not being able to use my Lambda functions was quite disheartening? The issue was the IP address AWS assigned to my Lambda, which led me to consider using a proxy. Fortunately, I own a Synology NAS at home, which I decided to use as a proxy server. It’s always on and can relay my calls to the final server. Since my NAS is connected to my home network, it uses an IP that isn’t blacklisted, allowing me to perform local tests successfully.&lt;/p&gt;
&lt;p&gt;I explored the Synology Package Center and, luckily, found an official application that fits the bill:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-blacklisted-stealth-tactics-for-lambda-functions-outside-a-vpc/03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once installed, setting up the proxy is quick and straightforward, taking only about 5 minutes.&lt;/p&gt;
&lt;p&gt;To integrate this new proxy with my Python Lambda functions, I needed to make a few adjustments. Here is the code snippet to help illustrate the modifications:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-blacklisted-stealth-tactics-for-lambda-functions-outside-a-vpc/04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To provide a clearer understanding of the changes we’re implementing, here’s a visual representation of our setup:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-blacklisted-stealth-tactics-for-lambda-functions-outside-a-vpc/05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I deployed my changes, and like magic, it worked: I started receiving the correct responses from the API! My suspicions were confirmed — the only issue was the AWS-assigned IP. This example illustrates how you can leverage AWS’s power while masking its use from external APIs. However, the infamous 403 error soon reappeared, but for a completely different reason. Stay tuned for the continuation of this saga in my next article!&lt;/p&gt;
</content:encoded><category>aws</category><category>aws-lambda</category><category>python</category><category>cloud</category></item><item><title>AWS Secrets: The Guide to Bypassing CORS for Developers</title><link>https://bydexemple.tech/en/blog/aws-secrets-the-guide-to-bypassing-cors-for-developers/</link><guid isPermaLink="true">https://bydexemple.tech/en/blog/aws-secrets-the-guide-to-bypassing-cors-for-developers/</guid><description>In my previous article, I showed you how I managed to reverse-engineer an application to find its API.</description><pubDate>Thu, 18 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-secrets-the-guide-to-bypassing-cors-for-developers/01.jpeg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In my previous article, I showed you how I managed to reverse-engineer an application to find its API. Now, I want to use this API through a script and a small frontend app. And I encountered a problem that every frontend developer has faced in their career: the infamous CORS issue.&lt;/p&gt;
&lt;p&gt;Proud of having succeeded in finding the schema of my API and understanding how it works, I started coding my serverless stack to create my little script. Then I thought a graphical interface would be cool indeed. I made my first pages, and occasionally, I needed the raw data from the API without processing it, so I called the API directly, but then I received this error:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-secrets-the-guide-to-bypassing-cors-for-developers/02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;CORS Mechanics&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;$1&lt;/li&gt;
&lt;li&gt;$1&lt;/li&gt;
&lt;li&gt;$1&lt;/li&gt;
&lt;li&gt;$1&lt;/li&gt;
&lt;li&gt;$1&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;CORS is essential for web security. It protects users from malicious attacks such as CSRF (Cross-Site Request Forgery) and ensures that sensitive data cannot be shared across domains without explicit permission. At the same time, it allows developers to build rich and interactive web applications that integrate resources from multiple origins&lt;/p&gt;
&lt;p&gt;— —&lt;/p&gt;
&lt;h2&gt;So ?&lt;/h2&gt;
&lt;p&gt;As you’ve gathered, CORS issues arise from the browser, which is why I don’t face this problem with my script running on a server. In my case, since I don’t own the API, I can’t add the missing headers myself. To bypass this issue, I will use a well-known AWS service: API Gateway. API Gateway will act as a proxy, which is very quick to set up (1–2 minutes) and will be free in my case.&lt;/p&gt;
&lt;p&gt;Here’s the idea:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-secrets-the-guide-to-bypassing-cors-for-developers/03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As we can see in this setup, where the API acts as a proxy, when our browser responds to the HTTP OPTIONS call, it’s our API Gateway that will respond. In the configuration, I will allow all origins. However, if my browser makes a call to the real API, the API Gateway will simply forward the call to the real API, which will then respond. And there are no CORS issues in this case; remember, it’s only browsers that initiate OPTIONS calls. Once my API Gateway has received the response, it transfers the response back to the browser.&lt;/p&gt;
&lt;p&gt;I will describe how to easily create this API through the console, and I will include the Terraform code at the end.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$1&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-secrets-the-guide-to-bypassing-cors-for-developers/04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We create our HTTP integration&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-secrets-the-guide-to-bypassing-cors-for-developers/05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We establish a catch-all Proxy+ route, configured to intercept and forward all incoming requests.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-secrets-the-guide-to-bypassing-cors-for-developers/06.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;We can click on create API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then we activate the CORS (do not forget to click on add and then save). Check by returning to the page.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/aws-secrets-the-guide-to-bypassing-cors-for-developers/07.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And there you have it, we just have to call our API Gateway endpoint with our routes from our frontend application!&lt;/p&gt;
&lt;p&gt;And there is the terraform code :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;provider &quot;aws&quot; {
  region = &quot;us-east-1&quot;
}

resource &quot;aws_apigatewayv2_api&quot; &quot;my_http_api&quot; {
  name          = &quot;my-http-api&quot;
  protocol_type = &quot;HTTP&quot;

  cors_configuration {
    allow_origins = [&quot;*&quot;]
    allow_methods = [&quot;*&quot;]
    allow_headers = [&quot;*&quot;]
    allow_credentials = false
  }
}

resource &quot;aws_apigatewayv2_integration&quot; &quot;my_integration&quot; {
  api_id           = aws_apigatewayv2_api.my_http_api.id
  integration_type = &quot;HTTP_PROXY&quot;
  integration_uri  = &quot;https://myapi.com&quot; # Replace with your API URL
  integration_method = &quot;ANY&quot;
}

resource &quot;aws_apigatewayv2_route&quot; &quot;my_route&quot; {
  api_id    = aws_apigatewayv2_api.my_http_api.id
  route_key = &quot;ANY /{proxy+}&quot; # This sets up a catch-all route
  target    = aws_apigatewayv2_integration.my_integration.id
}

resource &quot;aws_apigatewayv2_stage&quot; &quot;my_stage&quot; {
  api_id      = aws_apigatewayv2_api.my_http_api.id
  name        = &quot;default&quot;
  auto_deploy = true
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>aws</category><category>api-gateway</category></item><item><title>How to reverse engineering an Android App and Its API— Example with an app from the US government</title><link>https://bydexemple.tech/en/blog/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/</link><guid isPermaLink="true">https://bydexemple.tech/en/blog/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/</guid><description>In the past, I’ve developed several native and cross-platform Android applications (using Ionic) and thus, I’m quite familiar with how they work.</description><pubDate>Fri, 05 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/01.jpeg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In the past, I’ve developed several native and cross-platform Android applications (using Ionic) and thus, I’m quite familiar with how they work. Today, on an application, whose name I will intentionally omit, I must perform a repetitive task several times a week and ensure I’m among the first to do so. Another problem is that there’s a specific known time for this, but slots may open up throughout the day.&lt;/p&gt;
&lt;p&gt;Throughout this article, I will use an application as an example; I’ve chosen the app provided by the U.S. government that offers information on national parks. I highly recommend it if you’re visiting the U.S.: &lt;a href=&quot;https://play.google.com/store/apps/details?id=gov.nps.mobileapp&amp;amp;hl=fr&amp;amp;gl=US&quot;&gt;https://play.google.com/store/apps/details?id=gov.nps.mobileapp&amp;amp;hl=fr&amp;amp;gl=US&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To start, let’s revisit the operation and architecture of an Android application. There are 3 types of applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Native apps: A native Android app is developed in Java or Kotlin via Android Studio, optimized for Android, offering high performance and full access to the phone’s features.&lt;/li&gt;
&lt;li&gt;Hybrid apps: A hybrid application is developed with web technologies to function on multiple platforms, offering wide portability at the potential expense of performance and system integration.&lt;/li&gt;
&lt;li&gt;Web apps: A web application operates in an internet browser and does not require installation on the user’s device, offering universal accessibility but with limitations in terms of performance and access to system features.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/03.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To determine the type of an application, you need to retrieve its APK, the installation package. Generally, if the APK file is a few MBs or tens of MBs in size, it’s likely a native app. To be certain, there’s no choice but to open this installation package and do some digging.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/04.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I mention APKs, but it’s important to know that Google has implemented a new packaging system called AAB (Android App Bundle). It replaces the traditional APK (Android Package Kit) as the publication format on the Google Play Store. The AAB allows for the creation of a more optimized and lighter version of the application by downloading only the resources and code specific to the user’s device configurations (CPU architecture, screen density, languages, etc.), instead of downloading a single package containing all possible resources.&lt;/p&gt;
&lt;p&gt;Using AAB helps developers reduce the download size of their application, thereby improving user experience by speeding up the download process and reducing the required storage space on the device. Additionally, it simplifies the application version management process for developers, as Google Play automatically generates the optimized APKs for different devices from the application bundle.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/05.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here is how an APK file is constructed:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/06.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Thus, we find a tree structure of this type:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/07.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To retrieve the APK file, there are two methods. The easiest way is to find the file on the internet; many websites act as mirrors for the Play Store and offer an easy way to download APK files. Or, build it from the application installed on your phone using another application.&lt;/p&gt;
&lt;p&gt;To read our APK file, there are several solutions. The most widespread and reliable is to use JADX, but in my case, I will use APK Editor Studio, which will make the task easier for me afterward. If you prefer to use JADX, here is a very good article on the subject: &lt;a href=&quot;https://korben.info/decompiler-application-android-apk-recompiler.html&quot;&gt;https://korben.info/decompiler-application-android-apk-recompiler.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After opening our APK, we can start to sift through the code files to understand how our application works and what it uses. In my case, this proves to be challenging, and I’m leaning towards another method. I could deduce from the code that the application uses standard protocols to communicate with an API:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/08.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I decided to install a proxy, in my case Charles (though you’re likely familiar with Wireshark), to observe all these requests. Before doing this, I set up an emulator in Android Studio to have a controlled environment.&lt;/p&gt;
&lt;p&gt;Selecting a phone, the choice matters little here; in my case, I know I need Google services, so it’s important to ensure there’s a small icon in the Play Store column.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/09.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I choose a fairly recent SDK without necessarily picking the latest one, to have resources available on the web in case of bugs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A subtle detail in Android Studio: to access the settings, including those for the proxy, you need to go into the settings and uncheck the “Launch in the Running Devices tool window” option.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We start Charles to launch our proxy. We enter our local IP and the default port for Charles, which is 8888. We copy this information into the settings section of the emulator.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We can start to intercept our requests by launching our application :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It’s normal if we don’t understand much at first, as almost the entire web now uses the HTTPS protocol, which secures data in transit. To deal with this, we need to activate SSL proxying via the button shaped like a padlock.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/14.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;When I restart the request interception, I notice that I receive nothing except an error: “SSL handshake with client failed: An unknown issue occurred processing the certificate (certificate_unknown).”&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/17.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And that’s quite normal; I am clearly in this situation, where SSL indeed serves to protect the request.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/16.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ok, the problem comes from the certificate, but I have control over my emulator. What if I gave it my “fake” certificate from the proxy? Let’s try!&lt;/p&gt;
&lt;p&gt;Ok, let’s add the certificate to our system. On our emulator, go to the URL &lt;a href=&quot;http://charlesproxy.com/getssl&quot;&gt;http://charlesproxy.com/getssl&lt;/a&gt; with the proxy still activated; otherwise, it won’t work. We go to Settings-&amp;gt;Security-&amp;gt;Encryption &amp;amp; credentials-&amp;gt;Install a certificate-&amp;gt;CA certificate.&lt;/p&gt;
&lt;p&gt;Still the same result! But why?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/17.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Previously, up until Android 6 (API 23), one could add a certificate to the device, and the application would trust it by default. Now, that’s no longer the case; you have to add a piece of code to your application to tell it to accept certificates added by the user. You may not be able to see decrypted SSL traffic from the app unless the app’s developers have enabled support for user certificates. Here is the post if you want to dig deeper: &lt;a href=&quot;https://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html?source=post_page-----c480e2143743--------------------------------&quot;&gt;https://android-developers.googleblog.com/2016/07/changes-to-trusted-certificate.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/18.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Indeed, it’s relatively straightforward in our case since we have access to the code. We just need to modify the specific file in question and recompile our application. There’s a little nuance, though: we must sign our application because it’s mandatory on Android. Obviously, we won’t be able to re-sign it with the original key, but that’s not an issue.&lt;/p&gt;
&lt;p&gt;Let’s modify our app. I use APK Editor Studio, which allows me to easily modify resources and re-sign the app with one click.&lt;/p&gt;
&lt;p&gt;We just need to modify or create the file res/xml/network_security_config.xml&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
    
        
            
        
    
    
        
            
            
        
    

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To edit the “AndroidManifest.xml” file and specify that the app should use the modified “network_security_config.xml” file, you need to locate the &amp;lt;application&amp;gt; tag within the &quot;AndroidManifest.xml&quot;. Then, you look for the android:networkSecurityConfig attribute inside it. If this attribute doesn&apos;t exist, you should add it. The modification should look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells the Android operating system to refer to your custom network security configuration file (network_security_config.xml) for instructions on network security policies, including the acceptance of custom certificates for SSL. This step is crucial for allowing your application to trust the proxy&apos;s SSL certificate, enabling you to intercept HTTPS traffic without errors.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/19.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Recompile the APK using APK Editor Studio. This process combines the edited files and resources into a new APK file and signs it. Signing an APK is mandatory for its installation on our emulator. Before installing the new version, ensure to delete the old one, as the keys are different, and you won’t be able to install the new one over the old one.&lt;/p&gt;
&lt;p&gt;Let’s retest… And it works!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../../../assets/medium/how-to-reverse-engineering-an-android-app-and-its-api-example-with-an-app-from-the-us-government/20.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now, you can navigate through the application and see the API routes being called in real-time, which will allow you to reuse them in scripts or small programs. This opens up possibilities for automation, testing, or even understanding how the application communicates with its backend services.&lt;/p&gt;
&lt;p&gt;In my next article, we’ll explore how to circumvent the CORS issue using AWS.&lt;/p&gt;
</content:encoded><category>android</category><category>reverse-engineering</category></item></channel></rss>