All writing

Multi-cloud without lowest-common-denominator architecture

Multi-cloud design should create consistent organisational boundaries, developer journeys and operating evidence without forcing AWS, Azure and Google Cloud into an artificial service model limited to the features they happen to share.

about 19 minutes min read

A company decides to adopt multiple cloud providers.

The first architecture workshop creates a rule:

Every capability must work identically
on AWS, Azure and Google Cloud.

The intention is understandable.

The organisation wants:

  • portability
  • negotiating leverage
  • resilience
  • reduced provider dependence
  • consistent engineering practices

The rule appears to promise all five.

Then the design begins.

A managed database feature available in one provider is rejected because another provider implements it differently.

Native workload identity is replaced with permanent application credentials because static credentials are easy to reproduce everywhere.

Advanced network controls are avoided because their equivalents are not symmetrical.

Provider security and operational events are flattened into a schema containing only the fields all three clouds happen to share.

The final platform is technically portable.

It is also more manual, less secure and less capable than any of the clouds beneath it.

AWS CAPABILITY ───────┐
                      │
AZURE CAPABILITY ─────┼──► SMALLEST SHARED FEATURE SET
                      │
GCP CAPABILITY ───────┘

This is lowest-common-denominator architecture.

It does not create one excellent multi-cloud platform.

It creates a fourth, imaginary cloud whose limitations are assembled from the differences between the real three.

Multi-cloud architecture should standardise the outcomes teams need while allowing each cloud to fulfil those outcomes through its own native strengths.

CONSISTENT INTENT

does not require

IDENTICAL IMPLEMENTATION

A production workload should have:

  • bounded administrative access
  • private application networking
  • protected data
  • workload identity
  • observable deployments
  • tested recovery

Those outcomes can remain consistent.

The underlying resource hierarchies, identity systems, network models and managed services do not need to pretend they are the same.

Multi-cloud becomes useful when the abstraction sits at the level of the organisational promise rather than the provider product name.

Decide which multi-cloud promise is required

Multi-cloud is not one architecture.

It is a portfolio of operating postures, each with a different promise, cost and evidence requirement.

Portfolio multi-cloud

Different workloads use different providers.

WORKLOAD A ──► AWS

WORKLOAD B ──► AZURE

WORKLOAD C ──► GOOGLE CLOUD

No routine movement is promised.

The organisation needs common governance, visibility and ownership across a varied estate.

Portable placement

A new instance of a workload can be deployed to more than one provider.

The application and platform contract are portable enough to support alternative placement.

Existing data may not move quickly.

Migratable service

An existing service, including data, identity and operating state, can move within a demonstrated period.

This requires more than rebuilding containers.

Recoverable across clouds

A second provider can restore the service after a defined failure.

The recovery path, authority, data and dependencies have been exercised.

Active multi-cloud

Several providers serve the workload at the same time.

This introduces difficult questions about traffic, writes, consistency, capacity and incident coordination.

These claims are not interchangeable:

runs in several clouds
can be deployed to several clouds
can move between clouds
can recover in another cloud
serves traffic from several clouds

A service should declare the posture it actually needs.

Service:
    review-service

Posture:
    portable placement

Supported providers:
    AWS
    Azure

Data movement:
    rebuild from source data

Failover promise:
    none

Useful motivations may include:

  • customer or regulatory placement
  • acquisition of teams already operating elsewhere
  • access to provider-specific capabilities
  • commercial negotiation
  • gradual migration
  • selected provider-failure recovery

An architecture cannot be optimised for an unnamed goal.

Portability is multidimensional

A system is not simply portable or non-portable.

Different layers have different movement costs.

SOURCE CODE

ARTEFACT

CONFIGURATION

IDENTITY

NETWORK

DATA

OPERATIONS

KNOWLEDGE

A Go service packaged as a container may run on several Kubernetes services with modest changes.

Its surrounding system may still depend on:

  • one provider’s identity model
  • one managed database
  • provider-native messaging
  • regional DNS
  • encryption keys
  • backup formats
  • operating procedures

The application binary may be portable.

The service is not automatically portable.

A useful review asks about:

Compute portability

Can the workload execute elsewhere?

Configuration portability

Can its runtime intent be expressed for another environment?

Identity portability

Can human and workload access be reconstructed without weakening controls?

Data portability

Can state be exported, transferred, restored and verified?

Operational portability

Can the organisation deploy, observe, recover and support the service elsewhere?

Knowledge portability

Do engineers understand the target provider well enough to operate it?

PORTABLE ARTEFACT

is only one part of

PORTABLE SERVICE

This prevents the container image from receiving credit for moving an entire operating model it has never met.

Standardise versioned capability contracts

A multi-cloud platform should expose organisational capabilities rather than generic copies of provider products.

Weak abstraction:

kind: GenericCloudDatabase
spec:
  providerFields:
    settingA: value
    settingB: value
    settingC: value

This moves provider complexity behind a different resource name.

A stronger contract describes the outcome.

PLATFORM CAPABILITY CONTRACT

Capability:
    ServiceDatabase

Version:
    transactional-mysql-v3

Required properties:
    private connectivity
    workload identity
    encryption
    automated backups
    restore-tested recovery

Service objective:
    99% ready within 15 minutes

Failure semantics:
    actionable rejection
    retryable provider failure
    terminal fulfilment failure

Status:
    common platform conditions
    native reference for operators

Required evidence:
    identity decision
    provisioning result
    recovery-contract result

Provider extensions:
    explicitly documented

Each implementation publishes conformance.

AWS:
    conformant

Azure:
    conformant with extension

Google Cloud:
    unsupported

The contract should define:

  • user intent
  • required semantics
  • eligibility rules
  • success criteria
  • SLO measurement
  • failure behaviour
  • status vocabulary
  • recovery outcome
  • required evidence
  • allowed extensions
  • known limitations

A common API is useful only when every implementation can demonstrate that it fulfils the same versioned contract.

Required properties and extensions should be distinct

The platform should distinguish:

REQUIRED PROPERTY

every supported implementation
must provide


OPTIONAL PROFILE

available where implemented


PROVIDER EXTENSION

explicitly cloud specific

A provider extension should not silently change the meaning of a common field.

A shared term such as:

availability: resilient

needs one documented service property:

  • tolerated infrastructure failure
  • expected recovery behaviour
  • backup profile
  • cost class
  • maintenance expectations

The implementations may differ.

The promise should not.

Without semantic ownership, common fields become decorative adjectives.

Common SLOs need common semantics

A shared SLO such as:

99% of valid development database requests should become ready within fifteen minutes.

is useful only when every implementation agrees on:

  • what qualifies as valid
  • when measurement begins
  • what ready means
  • whether connection verification is included
  • which failures count against the target

Common percentages without common semantics create comparison theatre.

Preserve native boundaries beneath the contract

The platform should standardise principles before products.

ENVIRONMENTS ARE SEPARATED

PRODUCTION ACCESS IS TEMPORARY

WORKLOADS USE FEDERATED IDENTITY

LOGS LEAVE WORKLOAD FAILURE DOMAINS

BACKUPS ARE RESTORE TESTED

PUBLIC EXPOSURE IS DELIBERATE

Each cloud implements those principles natively.

Resource hierarchies remain visible

AWS accounts, Azure subscriptions and Google Cloud projects can all act as useful administrative boundaries.

They are not perfect synonyms.

Their surrounding hierarchies affect:

  • policy inheritance
  • billing
  • quotas
  • identity
  • lifecycle
  • isolation

A common organisational model still needs accurate local maps.

Identity should federate, not flatten

A central identity provider can govern:

  • user lifecycle
  • multi-factor authentication
  • organisational groups
  • privileged-access process

Each cloud should retain native authorisation.

A shared responsibility such as:

ProductionInvestigator

may map to different native roles in each provider.

The user experience can remain consistent:

  • temporary access
  • read-only investigation
  • recorded session
  • automatic expiry

The implementation remains provider-native.

Workload identity should remain native

The common requirement is:

This workload receives temporary,
scoped authority based on
its runtime identity.

The platform should not standardise on permanent access keys merely because every provider supports them.

PORTABLE WEAKNESS

is not better than

NATIVE STRENGTH

Networks should share intent, not topology

A common policy may require:

  • controlled public entry
  • private application workloads
  • non-public data services
  • observable egress
  • separated management paths
  • explicitly allowed service communication

The providers do not need identical subnet counts, routing structures or appliance placement.

The user expresses communication intent.

The provider implementation preserves native network correctness.

Kubernetes is one portability layer

Kubernetes provides a valuable common workload API.

It does not make provider identity, storage, networking and load balancing identical.

A shared manifest full of provider-specific annotations is not a clean abstraction.

The file is technically shared.

The implementation is an archaeological layer cake.

Common workload intent should remain separate from provider integration through overlays, modules, compositions or explicit platform profiles.

Treat state and semantics as the real portability test

Stateless compute is often the easiest part of multi-cloud.

State makes the architecture honest.

A database may contain:

  • large data volumes
  • provider-specific backups
  • replication state
  • extensions
  • encryption dependencies
  • operational history

Moving it requires decisions about:

  • export format
  • transfer duration
  • downtime
  • consistency
  • validation
  • residency
  • rollback
  • reconciliation
SOURCE DATABASE
       │
       ▼
CONSISTENT EXPORT OR REPLICATION
       │
       ▼
TRANSFER
       │
       ▼
TARGET DATABASE
       │
       ▼
APPLICATION VERIFICATION

The platform should distinguish:

DATA CAN BE EXPORTED

from:

SERVICE CAN MOVE
WITHIN ITS RECOVERY OBJECTIVES

Those claims are far apart.

Native value and portability cost should be explicit

A provider-native managed capability may offer:

  • stronger identity integration
  • lower operating burden
  • better reliability
  • useful business capability

Its exit cost may include:

  • data extraction
  • replacement APIs
  • skill coupling
  • migration duration
  • control-plane dependency

The decision should compare current value with expected exit cost and the required operating posture.

Rejecting useful managed services to preserve an untested future option may increase current risk.

Provider coupling is not automatically failure.

Invisible provider coupling is.

A coupling record can make the decision visible.

PROVIDER COUPLING

Capability:
    AWSStreamingAnalytics

Current benefit:
    managed scaling
    native identity
    lower operating burden

Exit dependencies:
    data export
    API redesign
    replacement processing engine

Tested exit level:
    documented only

Owner:
    analytics-platform

Messaging abstractions should preserve semantics

A generic publish(message) API can hide differences in:

  • ordering
  • delivery
  • retention
  • acknowledgement
  • retry
  • dead-letter handling
  • transaction support

A stronger profile defines observable properties.

messaging:
  profile: durable-domain-events
  orderingKey: order_id
  retention: operational

The contract should state what each implementation must provide.

Syntax without semantics is not portability.

Migration tests need cutover and rollback

A movement exercise should include:

  1. build the target artefact
  2. provision the target environment
  3. recreate identity
  4. transfer or restore data
  5. stop or coordinate source writes
  6. move traffic
  7. verify user journeys
  8. measure elapsed time
  9. test rollback criteria
  10. reconcile writes if rollback occurs
  11. record provider-specific changes
  12. decide when the source may be decommissioned

A migration that succeeds only when every step goes perfectly is not a complete operating capability.

Data gravity also has an economic dimension.

A technically portable service may be economically immovable because of:

  • egress charges
  • transfer bandwidth
  • repeated synchronisation
  • cross-cloud traffic
  • duplicated telemetry
  • parallel operating cost

Govern outcomes and retain native evidence

Provider selection should usually be derived from constraints rather than chosen from an unrestricted cloud dropdown.

A request might declare:

placement:
  residency: uk
  availability: regional
  capability: transactional

The platform can report:

Selected provider:
    AWS

Reason:
    UK placement
    supported database profile
    existing service dependencies

An explicit provider request can remain available when provider selection is itself a business requirement.

The requester supplies constraints.

The placement system derives or validates the provider.

Placement should also consider implementation maturity.

AWS:
    generally available

Azure:
    pilot

Google Cloud:
    unsupported

A theoretically conformant implementation should not receive production workloads before its ownership, SLOs and recovery evidence are ready.

Governance should be common in outcome and native in enforcement

The organisation may define common requirements:

production data is encrypted

resources have owners

audit logs leave workload boundaries

privileged access is temporary

approved regions are used

backups are restore tested

Native provider controls should enforce these conditions close to the action.

A shared evidence layer can then compare outcomes across clouds.

NATIVE PREVENTION

plus

CROSS-CLOUD EVIDENCE

Normalised evidence should not replace raw evidence

A common view may normalise:

  • time
  • cloud
  • account, subscription or project
  • identity
  • action
  • resource
  • decision
  • result

The raw provider event should remain available.

The weakest design discards every field that cannot be mapped universally.

It produces a tidy schema that knows almost nothing about the incident.

Design independence for the failure you named

Running in several clouds does not automatically create multi-cloud resilience.

The clouds may still share:

  • one identity provider
  • one DNS control plane
  • one Git repository
  • one CI platform
  • one registry
  • one policy engine
  • one central platform cluster
AWS ───────┐
           │
AZURE ─────┼──► SHARED DEPENDENCY
           │
GCP ───────┘

Multiple clouds do not guarantee independent operating paths.

A resilience design must name:

  • which failure is being tolerated
  • which services must continue
  • which data remains consistent
  • which control planes remain available
  • how traffic moves
  • how operators gain access
  • how recovery is tested

Central control planes can recreate common-mode failure

One Crossplane or platform cluster managing every provider may create:

ONE PLATFORM FAILURE
        │
        ├── AWS changes blocked
        ├── Azure changes blocked
        └── Google Cloud changes blocked

That may be acceptable for portfolio placement.

It may violate a cross-cloud recovery objective.

The topology should follow the posture:

  • central experience with distributed execution
  • provider-local reconcilers
  • replicated source and artefacts
  • independent recovery paths
  • local emergency authority

Central human identity is also a shared dependency.

Higher resilience postures may require provider-local emergency roles, existing-session behaviour and tested identity recovery.

Active-active remains exceptional

Active operation across several clouds introduces:

  • global traffic management
  • concurrent writes
  • duplicate processing
  • capacity management
  • latency
  • egress cost
  • incident coordination

Ordinary service calls should usually remain inside the chosen operating boundary unless cross-cloud communication is a deliberate product requirement.

Multi-cloud maturity is not measured by the number of active arrows crossing the diagram.

Operate one product model with several native implementations

One platform does not require one universal implementation repository.

The organisation may share:

  • API definitions
  • policy intent
  • journey tests
  • SLO definitions
  • evidence schemas
  • documentation structure

Provider implementations may remain separate.

platform/
    api/
    contracts/
    policies/
    tests/
    journeys/

aws/
    organisation/
    identity/
    network/
    capabilities/

azure/
    organisation/
    identity/
    network/
    capabilities/

gcp/
    organisation/
    identity/
    network/
    capabilities/

Crossplane or another control plane can select provider-specific compositions.

The compositions do not need identical resource graphs.

They need to satisfy the same contract.

A useful status can expose both:

Platform condition:
    Ready

Provider implementation:
    Azure storage capability

Native reference:
    available to authorised operators

The abstraction serves the developer.

The native implementation remains observable.

Responsibilities should remain clear

APPLICATION TEAM

uses the platform capability


PLATFORM PRODUCT TEAM

owns the common contract


PROVIDER IMPLEMENTATION TEAM

owns native architecture,
operations and conformance

These may be roles within one team.

The responsibilities still need to exist.

The shared platform does not subtract the native layers.

It adds coordination above them.

Each provider adds identity, networking, quotas, billing, support, observability and incident models.

That operating cost should be explicit.

A bfstore application example

Suppose the review service needs production deployment.

The request declares constraints and capability needs.

apiVersion: platform.bfstore.dev/v1alpha1
kind: Application
metadata:
  name: review-service
spec:
  runtime: go
  protocol: grpc
  exposure: internal

  placement:
    residency: uk
    posture: portable-placement

  database:
    contract: transactional-mysql-v3

  messaging:
    consumes:
      - order.completed
    publishes:
      - review.submitted

The placement system selects AWS.

Selected provider:
    AWS

Reason:
    UK residency
    transactional-mysql-v3 generally available
    existing order-service dependency
    production recovery evidence current

The shared contract promises:

  • private service exposure
  • temporary workload identity
  • encrypted database
  • durable messaging semantics
  • standard telemetry
  • tested backup and recovery
  • common status and SLOs

The AWS implementation fulfils those outcomes through AWS-native identity, networking and data services.

An Azure implementation may use a different native graph.

Application CONTRACT
        │
        ├── AWS implementation
        │     └── conformant
        │
        ├── Azure implementation
        │     └── pilot
        │
        └── Google Cloud implementation
              └── unsupported

The status preserves both layers.

Platform capability:
    Ready

Provider:
    AWS

Contract:
    application-v4

Database contract:
    transactional-mysql-v3

Native references:
    available to platform operators

Portability posture:
    portable placement

Migration evidence:
    application deployment tested
    data migration not promised

This is an honest abstraction.

The front door is coherent.

The buildings behind it do not need identical plumbing.

Questions I now ask

Purpose

Which business problem
and operating posture are required?

Portability

Which parts of the service
must move, and within what time?

Contract

Which versioned capability contract
must remain consistent?

Native value

Which provider strengths
and couplings are deliberate?

State

How will data, identity
and dependencies move or recover?

Independence

Which shared systems reconnect
the provider failure boundaries?

Evidence

Which test proves conformance,
migration or failover?

Ownership

Who owns each native implementation
and the common contract?

These questions make multi-cloud an architectural choice rather than a provider-counting exercise.

The mental model I am keeping

My earlier model was:

MULTI-CLOUD

build the same architecture
three times

The stronger model is:

                       BUSINESS REQUIREMENT
                                │
                                ▼
                        OPERATING POSTURE
                                │
                                ▼
                  VERSIONED CAPABILITY CONTRACT
                                │
              ┌─────────────────┼─────────────────┐
              │                 │                 │
              ▼                 ▼                 ▼
             AWS             AZURE        GOOGLE CLOUD
              │                 │                 │
              ▼                 ▼                 ▼
           NATIVE            NATIVE            NATIVE
        IMPLEMENTATION    IMPLEMENTATION    IMPLEMENTATION
              │                 │                 │
              └─────────────────┼─────────────────┘
                                ▼
                       CONFORMANCE EVIDENCE
                                │
                                ▼
                    STATUS, SLOs AND OWNERSHIP
                                │
                                ▼
                       TESTED MOVEMENT OR RECOVERY

The business requirement answers:

Why are several clouds needed?

The operating posture answers:

Is the promise placement,
migration, recovery or active service?

The capability contract answers:

Which useful outcome
must remain consistent?

Native implementation answers:

How can this provider
deliver the outcome well?

Conformance answers:

Has the implementation proved
the same semantics and evidence?

Portability testing answers:

Can the promised movement
actually happen within its target?

Independence testing answers:

Will the service survive
the failure that was named?

And ownership answers:

Who understands each cloud
when the abstraction leaks?

Multi-cloud architecture does not become stronger by reducing every provider to the small set of features they happen to share.

That may produce portable syntax while discarding useful identity, network, security and managed-service capabilities.

The better abstraction sits higher.

It standardises:

  • organisational intent
  • developer journeys
  • versioned capability contracts
  • security outcomes
  • operating evidence
  • recovery expectations

It allows implementation to remain cloud native.

The goal is not to make AWS, Azure and Google Cloud look identical. It is to make the organisation’s expectations precise enough that each cloud can meet them without losing its own strengths.

Some workloads will use portfolio placement.

Some will support portable deployment.

Some will have tested migration or recovery paths.

Some will deliberately use provider-specific capabilities.

Some will never justify the cost of moving.

That is not architectural inconsistency.

It is an honest portfolio of different requirements.

Lowest-common-denominator architecture asks:

What is the smallest feature set
all providers can imitate?

A stronger multi-cloud platform asks:

Which posture is required?

Which contract must remain consistent?

Which native differences are valuable?

Which movement or recovery claims
have actually been proved?

The first question creates a weaker imaginary cloud.

The second creates an operating model for several real ones.