About two years ago, I joined Flytoget as an architect and launched a project that was named Flint, short for Flytoget Integrations. Our goal was to replace CloudWheel, an external integration platform, by building and operating an in-house alternative through inner-source rather than relying on external vendors.
This blog post is based on an ongoing Microsoft customer story about Flytoget’s Azure migration led by Flint. I will link to the customer story when it is published.
Disclaimer
Even though I am the one writing this, it does NOT mean I have done all of this. The very talented Flint team has brought this to fruition, not only implementing it but also bringing in new ideas and techniques.
Furthermore, this blog post/customer story is solely my words and interpretation and does not represent Microsoft or Flytoget. However, it is the result of an ongoing collaboration.
Abstract
This case study examines Flytoget’s migration from a third-party integration platform to a cloud-native, in-house solution built on Azure. Following the discontinuation of Flytoget’s current SaaS integration platform in 2024, Flytoget embarked on the Flint project—an initiative to develop an integration platform that handles critical business operations, including ticket sales, payment processing, and customer management.
The implementation leverages Azure’s managed services, implements security best practices, and combines Kafka-based event-driven architecture with domain-driven design techniques.
Flytoget
Flytoget AS operates Norway’s airport express train service and provides high-speed rail connections to Oslo Airport Gardermoen. Since its launch in 1998, Flytoget has become an integral part of Norway’s transportation infrastructure, carrying millions of passengers annually and offering a journey time of just 19 minutes from the airport to Oslo Central Station.
For multiple years, Flytoget has been recognized as the second most-liked brand in Norway and is considered an innovative company that provides public services, often invited to conferences to present its innovations. Flytoget transports 5.5 million passengers to and from Oslo Airport. This represents a 30% market share, contributing to a public transport share of 70% at the airport. Flytoget is a subsidiary of the Vy Group and is one of Norway’s strongest brands, with a customer satisfaction rate of 97%.
Integration platform
Flytoget used a custom-built, third-party integration platform consisting of:
- APIs that, for the most part, act as proxies towards Flytoget’s systems
- Scheduled jobs for various financial tasks
- A module called Fare Calculation Collection (FCC)
Flytoget’s strategy is to route almost all functionality through the integration platform, making it vital to its core business, e.g., selling tickets and products, updating customer information, issuing receipts, and managing concessions through special tickets.
The jobs underpin financial reports and are vital to the financial department and to follow-ups with payment acquirers.
FCC enables customers to travel ticketless by only tapping their card during onboarding and offboarding at Oslo Gardermoen.
Due to an acquisition, the CloudWheel vendor informed Flytoget in 2024 that it would discontinue the integration platform. As a consequence, Flytoget evaluated 3 options:
- Host the SaaS integration platform ourselves
- Buy off-the-shelf software to replace it
- Kick off an inner-source culture and build it ourselves
Flytoget chose to build it themselves and named the project Flint.
Scope
Initially, Flint’s scope was to rebuild the integration platform in-house while creating an inner-source culture. Along the way, it grew into something larger to meet Flytoget’s high requirements for safe, stable operations with continuous cost optimization.
We developed architecture decision records (ADRs) and principles that our CTO approved:
- Cloud-first principles
- Event-driven architecture
- Azure Kubernetes Service (AKS)
- Everything as code
- Extensive automation
- Clear ownership within Flytoget through subdomains
Cloud migration
The original plan was to use our CSP for our infrastructure. Although it quickly became clear they could not deliver what we needed, which expanded our scope significantly.
Our Flint infrastructure instead runs on Azure, which provides the features, reliability, and flexibility we need. We track all infrastructure changes with code. Infrastructure follows an everything-as-code principle, with Terraform and official Azure Terraform providers running in GitLab, authenticated via federated credentials to a managed identity. We keep our Terraform states in Azure Blob Storage.
Over time, Flint also grew into an enabling team, helping other teams deliver POCs and applications faster by using Terraform, reusable modules, and the Azure cloud.
Flytoget aims at continuous cost optimizations. With Azure subscriptions, the management team can use Azure Cost Management and reduce the time spent following up on each team’s infrastructure spending by 80%. Furthermore, Flytoget can use Azure Cost Management to tune our infrastructure costs and continuously optimize them.
We use Microsoft Entra ID for AKS access control, in addition to assigning specific access at the subscription level. Azure access control enables fine-grained Privileged Access Control to reduce accidental production access and mitigate errors.
The applications would delegate as much infrastructure responsibility as possible to Azure-managed services, but we quickly realized we also needed a new runtime platform.
Flytoget’s new platform
One of Flint’s first inner-source initiatives was to establish a Kubernetes-based platform on Azure Kubernetes Service (AKS). We selected AKS after evaluating several options for supporting Flytoget’s workloads in a cloud-native environment.
Prioritizing secure, stable operations alongside innovation, the architecture leverages Azure’s security features, such as managed identities for AKS workloads, enabling passwordless access to Azure SQL databases and Storage Accounts without service users or passwords.
Flytoget’s Azure migration is now extending to more applications besides the Flint project, and the CTO has decided that the de facto standard will be to use the platform for all services, utilizing services like Azure SQL, Blob Storage, Key Vault, App Configuration, and AKS; reusable Terraform modules accelerate subdomain application development.
All of our Kubernetes tools are provisioned using GitOps and Argo CD.
High availability
Flytoget has strict demands for availability of its ticket sales, payments, and product catalogs. Flint leverages dual AKS clusters (test/prod in dedicated subscriptions), autoscaling, dedicated scalable node pools alongside system node pools, and Kubernetes techniques such as pod disruption budgets to meet uptime requirements.
Flint used automation to eliminate many of the planning and coordination issues we previously experienced.
Our disaster-recovery approach, using GitOps, is designed to restore services as quickly as Azure can provision the required infrastructure.
Observability
The Flint runtime platform provides an observability stack based on Grafana. We use the OpenTelemetry standard with the OpenTelemetry Collector and let Kubernetes manage our Grafana tools for metrics, logs, and traces, including Grafana Mimir, Grafana Loki, and Grafana Tempo. Our alerts are routed through Alertmanager.
Continuous Integration and Deployment
A key part of Flytoget’s innovative culture is quickly iterating on new solutions and offerings. Flint was designed to support continuous integration with GitOps tools such as Argo CD and Kargo. A key Azure component is our Azure Container Registry, which separates Continuous Integration from Continuous Deployment.
With the new Continuous Deployment setup, Flytoget significantly increased the number of production deployments, without sacrificing security or agility. GitOps enhances security by treating Git as the single source of truth for declarative infrastructure, enabling comprehensive audit trails and granular access controls via pull requests and branch protections, thereby minimizing manual errors and unauthorized modifications. Flytoget has moved its routines away from to-do list documents and instead leverages its platform capabilities and Git as its log.
Faster innovation cycles
Based on internal estimates, Flytoget previously relied on email requests for infrastructure provisioning—complete with manual replication checks across environments—and has slashed planning, QA, and deployment times by 80% through automation. Certificate management and renewals, once labor-intensive, now see nearly 90% reductions in time and cost. While we previously struggled with full disks and missing alarms, those issues are now substantially reduced, and we focus solely on Azure managed offerings.
With all workloads migrating to the Flint AKS runtime platform, team onboarding across systems is estimated to be around 70% faster.
Kubernetes upgrades are now automated, reducing planning effort and removing much of the manual coordination we used to need. We use AKS availability zones and diverse node pools to reduce cluster upgrade management issues further.
All the teams onboarded to the new platform leverage Managed Identities and federated credentials, and as a consequence, Flytoget substantially reduced its secret management time in Flint.
IBM Maximo
Flytoget needed to run and upgrade IBM Maximo, an enterprise asset management (EAM) software platform. Due to its licensing model, it required Red Hat OpenShift. Flytoget decided to minimize maintenance costs by running it on Azure using its Azure Red Hat OpenShift offering, significantly reducing management costs and complexity.
Flint migration strategy
The previous integration platform was implemented in multiple JVM languages (Java and Kotlin) using various frameworks. They employed an event-driven approach with the Apache Camel framework, which made it difficult to visualize the overall business flows. We reviewed each application individually and challenged whether the existing approach was still appropriate.
The CloudWheel deprecation had a fixed hard deadline. To minimize risk, we grouped the functionality into two categories: Flint v1 and future Flint versions. Version 1 was a lift-and-shift with obvious improvements, with larger structural changes planned for later versions.
.NET rewrite
The previous integration platform was written in various programming languages and frameworks running on the JVM. After some consideration, we standardized on using .NET and C# as the programming language. We would rewrite the application, use Kafka as our event broker, document the relevant subdomains, extend our business flows with the new information, and use our cloud-native observability tools.
Additionally, we would create alarms and dashboards to ensure continuous operations.
Because we run everything in containers, we emphasize fast startup times and small image sizes.
Domain Driven Design (DDD)
Flint utilizes DDD principles. Subdomains are placed in separate Azure subscriptions with their own infrastructure while sharing the Flint Kubernetes runtime. Secrets are synced from Azure Key Vault using an external-secrets-operator (using federated credentials), and applications get their configuration from Azure App Configuration.
We spent a substantial amount of time identifying, documenting, and clarifying the responsibilities for each of Flytoget’s IT subdomains.
Event Driven Architecture
When rewriting the SaaS integration platform applications, we had several architectural options. The integration platform needed to handle traffic surges. Additionally, Flytoget seeks a unified set of metrics and an overview of all traffic that passes through the integration platform. Flytoget adopted an event-driven architecture. Kafka is our broker, fully managed by Aiven and running on Azure.
Event-driven architecture has many benefits. However, due to its decoupled nature, it can be difficult to get an overview of business flows. We have identified the current ones using sequence diagrams and use distributed tracing to more quickly identify issues and opportunities for improvement. We use Azure Blob Storage to retain observability data for longer-term analysis and recovery.
Flytoget’s ticketless tap solution is the largest and most complicated module developed by Flint, and extensively leverages Kafka and event-driven design. The event-driven design enabled tight collaboration with domain experts and helped explicitly capture domain knowledge both in code and documentation. Additionally, it made the subsystem robust and able to handle its most important architecture characteristics: reliability, resilience, and recoverability.
Path forward
The Flint project has given Flytoget both a platform and a technological framework for faster experimentation while ensuring security and effective infrastructure management. Moving forward, Flytoget can experiment more quickly with new products while maintaining its high security standard.