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
readymeans - 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:
- build the target artefact
- provision the target environment
- recreate identity
- transfer or restore data
- stop or coordinate source writes
- move traffic
- verify user journeys
- measure elapsed time
- test rollback criteria
- reconcile writes if rollback occurs
- record provider-specific changes
- 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.