“The only way to make sense out of change is to plunge into it, move with it, and join the dance.” -- Alan Watts
If you’ve spent any length of time in application development, you’re familiar with change. It’s the only constant.
And along with how we build applications come changes in the techniques used to keep them secure.
Securing modern applications requires more diligence than ever before. A review of how application development has changed over the past decade will explain why more diligence is necessary.
The traditional web application operates like ordering food from a menu at a restaurant. You have a list of dishes available, and you ask for one. The chef decides which ingredients are necessary and how the plate looks when it arrives.
In a traditional web app, the client fetches a URL. Let’s say you want to see a dashboard of marketing metrics, and thus your browser retrieves example.com/dashboard.jsp. The client doesn’t control what’s on the dashboard; it just knows to ask for it.
The web server processes the request in three steps:
The web server decides what data goes into the dashboard and where the data goes. The client simply asks for a resource and displays what the server returns.
In this model, the client typically has very little code. It requests a URL from the server and displays what comes back. All rendering and data processing happens on the server.
Modern web applications put the client in control. It’s more like a buffet than a sit-down restaurant.
The client is often a Single-Page Application (SPA), or an application that dynamically updates the same page instead of always requesting a new one from the server.
In a buffet, you take your plate and pick and choose the foods you want. Each dish can have multiple configurations based on your needs at the time.
SPAs work like those plates. Instead of a single server creating an entire page and returning it to the client, the client knows how to make the page and asks only for the data required to do it.
Typically, Application Programming Interfaces or APIs provide this data to the client. Business logic is exposed to clients using APIs that return only what the client needs. Maybe the client only wants the last 20 notifications for an account or the ten most recent emails.
The use of APIs for business logic and data retrieval opens up the world of application development. You no longer need to build a web application. You can use a mobile application instead. You can use any technology or form factor to access the data, from mobile to Internet of Things (IoT) or other developers building applications of their own.
JSON, a lightweight data format, is one of the most useful enabling technologies for modern applications. It allows all of the APIs, the client, and the database to store and transmit data using the same format. There are no data transformations necessary, which helps keep the application responsive.
Going back to the above dashboard example, an SPA wouldn’t ask the server for the entire dashboard at once. Instead, it would ask the appropriate APIs for the specific data it needs to build the dashboard itself.
The desire for APIs and ultimate flexibility and speed of development gave way to the development of microservices. These services are kept small on purpose to be updated independently of each other and more frequently.
SPAs emphasize the client, leading to more complex code in the clients and the risk of security vulnerabilities in the clients (more on that later). But this change has opened up transformational technologies like IoT devices.
A common theme in the evolution of application development has been toward breaking functionality and features into smaller and more granular components. Just as with the SPA example above, the functionality of the web page is in isolated components, the same trend is true when you look at overall application architecture in general.
Where a legacy application might have been designed with separate modules and functions, each internally making calls to each other, modern design now breaks out separate functions into discrete services. Now rather than each development team maintaining similar code/functionality inside their application, many business functions are separated into clearly defined services. Consider an ‘address verification’ service which can be used by many other applications. The functionality of validating an address is decoupled from the ‘customers’ that use the service, which introduces value into the delivery lifecycle. This approach enables development teams to focus on smaller, more granular changes and therefore shorten their cycle time and accelerate delivery.
Digital transformation and the rapid acceleration of the pace of change within the industry dictates a new way of thinking. This thinking is encapsulated in the following quote by Bronwyn Clere, Executive Director for Capital Planning & Delivery, at Telstra Corporation in PMI’s Pulse of the Profession 2017 report:
We are implementing features and products and using technology that were not invented 18 months ago. No longer can we afford these large monolithic programs that go on for two to three years. We know that what we set out to do at the beginning of that time is not what we will finish out doing. So, we are focusing on very rapid delivery cycles, asking ourselves: How do we mobilize a project very quickly? How do we use the right delivery techniques to work through it quickly? How do we get product into market or to customers or into the business?”
Business leaders everywhere are demanding technology teams deliver faster. As a result, teams have adopted new ways of working and new ways of architecting their solutions. We’ve seen widespread adoption of Agile, CI/CD, and DevOps tools. Similarly, application development and architectures have evolved to further enable velocity.
The increasing pace of change would put significant stress on any IT infrastructure. But cloud-native architecture has fundamentally changed how applications can be built and scaled.
Cloud-native technologies, such as containers, service meshes, microservices, immutable infrastructure, and declarative APIs, empower developers to build and run scalable applications on public, private, and hybrid clouds.
Cloud-native architecture focuses on creating loosely coupled services with high resiliency. Developers can make changes frequently without negatively impacting the entire system.
Let’s take a quick tour of cloud-native applications so you can see how they differ from traditional web applications.
The bulk of cloud-native applications include many microservices deployed in containers. Each service is isolated from the others and can be destroyed and recreated easily without affecting other services.
Often an orchestration tool like Kubernetes is used to monitor all of the microservices used in an application. Orchestration is necessary when hundreds of services serve a single application. Kubernetes can detect malfunctioning containers or services, destroy them, and recreate new ones to keep the application running smoothly.
Each service can be created and updated independently from all the others. Each service can use a different programming language altogether. As long as each service exposes a documented API, the language used behind the scenes doesn’t matter.
Below is a diagram of Microsoft’s eShop on Containers open source application. It demonstrates what a real-world application looks like using cloud-native technologies.
In this example, the development team building the Marketing microservice can make changes as often as they want without affecting the ordering or cart functionality. Different technologies can be used within each service and each service has a separate datastore. Flexibility and speed are the hallmarks of modern development.
In the next post, we’ll dive deeper into specific challenges and considerations you need to take when adopting cloud-native applications.
The pace of change affects more than technology. Processes, management styles, and even ways of thinking have to adjust to make modern application development successful within your company.
Because of the intensive need to shorten delivery cycles and to automate delivery, cloud-native architectures embrace delivery practices that support short and responsive turn around. Developers can deploy new code in seconds, with some companies pushing new code to production hundreds of times a day.
As a result, your project management processes have to change. Agile practices (Scrum, Sprint, Lean, etc.) along with strong DevOps capabilities (i.e. trunk based development, CI,CD,etc) best support wide scale microservice development. It’s critical to get delivery, cultural, and organizational changes completed before trying to do cloud-native development at scale. The DevOps Handbook is an excellent resource for those new to DevOps development.
The days of ‘throw it over the wall’ and let Operations manage the application are over. Given the complexity of modern applications with multiple microservices and associated APIs, development/product teams need to ‘own’ the application in production as much as they do in development. In order to successfully scale your adoption of cloud-native applications, you need to explore and embrace “Product Management” over “Project Management” as a practice to manage the full lifecycle of your application.
Think of your application as a long-term product that will change over time. Market insights and customer feedback will continue to improve it. It’s not a one-and-done exercise.
Security is a major concern in this new environment. The traditional approach of building a fortress of defensive walls and moats around the application and then you ‘trust’ the activity inside the fortress is insufficient in a world where the individual elements of the application are expected to communicate with other components. On many levels, the new paradigm for security is one where each microservice, each component must have security built in, they need to embrace “zero trust” as a policy for how they operate.
Zero trust is a security architecture that lives by the motto: “Never trust, always verify.” It means verifying every request before returning data or performing an action.
In a traditional network architecture, we protect the perimeters. Firewalls and DMZs only allow certain types of traffic into the network. We use VPNs to enable secure communication between company servers and remote workers.
However, the biggest flaw with this security method is that traffic within the network is implicitly trusted. It’s similar to a bouncer protecting a nightclub from a long line of wannabe party-goers. It’s tough to get into the club, but once the bouncer lets you in, you can pretty much do whatever you want.
In a zero-trust network, all traffic is considered suspect. Just because a request comes from within your environment doesn’t mean you can trust it. Check every request first before the service returns data.
Microservice architecture requires a zero-trust architecture to be secure. It’ll ensure no requests fall through the cracks.
In addition to zero trust as an approach to enabling microservices to operate securely, organizations must rethink how they monitor and manage their security posture. We’ve covered several significant changes in web applications, especially in the last ten years.
New levels of diligence are required to secure this new breed of application. Cloud-native applications and microservices create new security vulnerabilities companies must account for to keep up with attacks.
In the next post, we’ll cover what security measures need to be in place to protect cloud-native applications.
How do you know your apps are protected?
How do you know your apps are protected?
Part I: What are Modern Applications
Part I: What are Modern Applications