diff --git a/content/blog/unified-multi-cloud-infrastructure-management/index.md b/content/blog/unified-multi-cloud-infrastructure-management/index.md new file mode 100644 index 000000000000..45856e1ce652 --- /dev/null +++ b/content/blog/unified-multi-cloud-infrastructure-management/index.md @@ -0,0 +1,875 @@ +--- +title: "Unified Multi-Cloud Infrastructure Management Guide" +date: "2025-09-01" +meta_desc: "Manage AWS, Azure, and GCP infrastructure with Pulumi's unified approach. Code examples in Python and TypeScript." +authors: ["asaf-ashirov"] +tags: ["Multi-Cloud", "AWS", "Azure", "GCP", "Infrastructure as Code", "Cloud Management", "DevOps", "Platform Engineering"] +--- + +Managing infrastructure across AWS, Azure, and Google Cloud Platform presents unique challenges for modern engineering teams. As organizations adopt multi-cloud strategies for resilience, compliance, and best-of-breed services, the complexity of managing disparate cloud platforms can become overwhelming. This comprehensive guide explores how Pulumi provides a unified, developer-first solution for multi-cloud infrastructure management. + + + +## The Multi-Cloud Reality: Why Organizations Need Unified Management + +Organizations increasingly operate across multiple cloud providers to: + +- Avoid vendor lock-in and maintain negotiating leverage +- Meet regional compliance and data sovereignty requirements +- Leverage best-in-class services from each provider +- Ensure business continuity through geographic distribution +- Optimize costs by utilizing competitive pricing across clouds + +Traditional approaches using cloud-specific tools like CloudFormation, ARM Templates, and Deployment Manager create silos that hinder collaboration and increase operational overhead. + +## Pulumi's Unified Multi-Cloud Approach + +Unlike tools that treat each cloud as a separate entity, Pulumi provides a consistent developer experience across all major cloud providers. Write infrastructure code once in your preferred programming language—Python, TypeScript, Go, C#, Java, or YAML—and deploy consistently across AWS, Azure, and GCP. + +### Key Advantages of Pulumi for Multi-Cloud Management + +1. **Single Programming Model**: Use the same languages, patterns, and tools across all clouds +2. **Native Cloud Support**: Access to 100% of each cloud's services and features +3. **Built-in State Management**: Automatic tracking of resource relationships across clouds +4. **Policy as Code**: Enforce compliance and governance consistently across providers +5. **Secrets Management**: Unified handling of sensitive data across environments + +## Real-World Example: Deploying a Multi-Cloud Application + +Let's explore a practical example of deploying a distributed application across AWS, Azure, and GCP using Pulumi. + +### Python Implementation + +```python +import pulumi +import pulumi_aws as aws +import pulumi_azure_native as azure +import pulumi_gcp as gcp + +# Configuration +config = pulumi.Config() +app_name = config.require("appName") + +# AWS: Deploy application backend +aws_provider = aws.Provider("aws-provider", region="us-east-1") + +aws_vpc = aws.ec2.Vpc( + "app-vpc", + cidr_block="10.0.0.0/16", + enable_dns_hostnames=True, + opts=pulumi.ResourceOptions(provider=aws_provider) +) + +aws_subnet = aws.ec2.Subnet( + "app-subnet", + vpc_id=aws_vpc.id, + cidr_block="10.0.1.0/24", + availability_zone="us-east-1a", + opts=pulumi.ResourceOptions(provider=aws_provider) +) + +# Deploy AWS Lambda for serverless compute +lambda_role = aws.iam.Role( + "lambda-role", + assume_role_policy=json.dumps({ + "Version": "2012-10-17", + "Statement": [{ + "Effect": "Allow", + "Principal": {"Service": "lambda.amazonaws.com"}, + "Action": "sts:AssumeRole" + }] + }), + opts=pulumi.ResourceOptions(provider=aws_provider) +) + +aws_function = aws.lambda_.Function( + "backend-processor", + runtime="python3.9", + handler="index.handler", + role=lambda_role.arn, + code=pulumi.AssetArchive({ + ".": pulumi.FileArchive("./backend") + }), + environment=aws.lambda_.FunctionEnvironmentArgs( + variables={ + "APP_NAME": app_name + } + ), + opts=pulumi.ResourceOptions(provider=aws_provider) +) + +# Azure: Deploy frontend and CDN +azure_resource_group = azure.resources.ResourceGroup( + "app-rg", + location="eastus" +) + +azure_storage = azure.storage.StorageAccount( + "appstorage", + resource_group_name=azure_resource_group.name, + sku=azure.storage.SkuArgs(name="Standard_LRS"), + kind="StorageV2", + static_website=azure.storage.StaticWebsiteArgs( + index_document="index.html", + error404_document="404.html" + ) +) + +# Azure CDN for global distribution +azure_cdn_profile = azure.cdn.Profile( + "app-cdn", + resource_group_name=azure_resource_group.name, + sku=azure.cdn.SkuArgs(name="Standard_Microsoft") +) + +azure_cdn_endpoint = azure.cdn.Endpoint( + "app-endpoint", + resource_group_name=azure_resource_group.name, + profile_name=azure_cdn_profile.name, + origin_host_header=azure_storage.primary_web_host, + origins=[azure.cdn.DeepCreatedOriginArgs( + name="storage-origin", + host_name=azure_storage.primary_web_host + )] +) + +# GCP: Deploy data analytics pipeline +gcp_project = gcp.organizations.get_project() + +gcp_bucket = gcp.storage.Bucket( + "analytics-data", + location="US", + uniform_bucket_level_access=gcp.storage.BucketUniformBucketLevelAccessArgs( + enabled=True + ) +) + +gcp_dataset = gcp.bigquery.Dataset( + "analytics_dataset", + dataset_id=f"{app_name}_analytics", + location="US", + description="Multi-cloud application analytics" +) + +gcp_dataflow_job = gcp.dataflow.Job( + "analytics-pipeline", + template_gcs_path="gs://dataflow-templates/latest/Stream_GCS_to_BigQuery", + temp_gcs_location=pulumi.Output.concat("gs://", gcp_bucket.name, "/temp"), + parameters={ + "inputFilePattern": pulumi.Output.concat("gs://", gcp_bucket.name, "/data/*.json"), + "outputTable": pulumi.Output.concat(gcp_project.project, ":", gcp_dataset.dataset_id, ".events"), + "javascriptTextTransformFunctionName": "transform", + "javascriptTextTransformGcsPath": pulumi.Output.concat("gs://", gcp_bucket.name, "/transform.js") + } +) + +# Cross-cloud networking with VPN connections +aws_to_azure_vpn = aws.ec2.VpnConnection( + "aws-azure-vpn", + type="ipsec.1", + static_routes_only=True, + customer_gateway_id=aws_customer_gateway.id, + vpn_gateway_id=aws_vpn_gateway.id, + opts=pulumi.ResourceOptions(provider=aws_provider) +) + +# Export endpoints for application access +pulumi.export("aws_function_url", aws_function.invoke_arn) +pulumi.export("azure_cdn_endpoint", azure_cdn_endpoint.host_name) +pulumi.export("gcp_analytics_dataset", gcp_dataset.dataset_id) +``` + +### TypeScript Implementation + +```typescript +import * as pulumi from "@pulumi/pulumi"; +import * as aws from "@pulumi/aws"; +import * as azure from "@pulumi/azure-native"; +import * as gcp from "@pulumi/gcp"; + +const config = new pulumi.Config(); +const appName = config.require("appName"); + +// AWS: Deploy microservices on EKS +const awsProvider = new aws.Provider("aws-provider", { + region: "us-west-2", +}); + +const eksCluster = new aws.eks.Cluster("app-cluster", { + desiredCapacity: 3, + minSize: 2, + maxSize: 5, + instanceType: "t3.medium", + providerCredentialOpts: { + profileName: "aws-profile", + }, +}, { provider: awsProvider }); + +// Deploy Kubernetes application to EKS +const k8sProvider = new k8s.Provider("k8s-provider", { + kubeconfig: eksCluster.kubeconfig, +}); + +const appNamespace = new k8s.core.v1.Namespace("app-namespace", { + metadata: { name: appName }, +}, { provider: k8sProvider }); + +const appDeployment = new k8s.apps.v1.Deployment("app-deployment", { + metadata: { + namespace: appNamespace.metadata.name, + }, + spec: { + replicas: 3, + selector: { + matchLabels: { app: appName }, + }, + template: { + metadata: { + labels: { app: appName }, + }, + spec: { + containers: [{ + name: "app", + image: "myregistry/myapp:latest", + ports: [{ containerPort: 8080 }], + env: [ + { name: "CLOUD_PROVIDER", value: "AWS" }, + { name: "REGION", value: "us-west-2" }, + ], + }], + }, + }, + }, +}, { provider: k8sProvider }); + +// Azure: Machine Learning workspace +const azureResourceGroup = new azure.resources.ResourceGroup("ml-rg", { + location: "westus2", +}); + +const azureMLWorkspace = new azure.machinelearningservices.Workspace("ml-workspace", { + resourceGroupName: azureResourceGroup.name, + location: azureResourceGroup.location, + sku: { + name: "Basic", + }, + identity: { + type: "SystemAssigned", + }, +}); + +// GCP: API Gateway and Cloud Functions +const gcpProject = gcp.organizations.getProject(); + +const gcpApiGateway = new gcp.apigateway.Api("app-api", { + apiId: `${appName}-api`, +}); + +const gcpFunction = new gcp.cloudfunctions.Function("api-handler", { + runtime: "nodejs18", + entryPoint: "handleRequest", + sourceArchiveBucket: gcpBucket.name, + sourceArchiveObject: codeArchive.name, + trigger: { + eventType: "providers/cloud.firestore/eventTypes/document.write", + resource: "projects/${gcpProject.project}/databases/(default)/documents/items/{item}", + }, + environmentVariables: { + APP_NAME: appName, + ANALYTICS_DATASET: gcpDataset.datasetId, + }, +}); + +// Multi-cloud monitoring with unified dashboard +const monitoringDashboard = new aws.cloudwatch.Dashboard("unified-dashboard", { + dashboardName: `${appName}-multi-cloud`, + dashboardBody: JSON.stringify({ + widgets: [ + { + type: "metric", + properties: { + metrics: [ + ["AWS/Lambda", "Invocations", { stat: "Sum" }], + ["AWS/Lambda", "Errors", { stat: "Sum" }], + ["AWS/Lambda", "Duration", { stat: "Average" }], + ], + period: 300, + stat: "Average", + region: "us-west-2", + title: "AWS Lambda Metrics", + }, + }, + { + type: "text", + properties: { + markdown: `## Multi-Cloud Application Status + +- **AWS EKS Cluster**: ${eksCluster.name} +- **Azure ML Workspace**: ${azureMLWorkspace.name} +- **GCP API Gateway**: ${gcpApiGateway.name}`, + }, + }, + ], + }), +}, { provider: awsProvider }); + +// Export multi-cloud endpoints +export const awsClusterEndpoint = eksCluster.endpoint; +export const azureMLEndpoint = azureMLWorkspace.discoveryUrl; +export const gcpApiEndpoint = gcpApiGateway.defaultHostname; +``` + +## Advanced Multi-Cloud Patterns with Pulumi + +### 1. Cross-Cloud Service Mesh + +Deploy a service mesh that spans multiple clouds for seamless communication: + +```python +# Deploy Istio across clouds +istio_control_plane = kubernetes.helm.v3.Chart( + "istio-control", + kubernetes.helm.v3.ChartArgs( + chart="istiod", + fetch_opts=kubernetes.helm.v3.FetchArgs( + repo="https://istio-release.storage.googleapis.com/charts" + ), + values={ + "pilot": { + "env": { + "PILOT_ENABLE_WORKLOAD_ENTRY_AUTOREGISTRATION": True, + "PILOT_ENABLE_CROSS_CLUSTER_WORKLOAD_ENTRY": True, + } + }, + "global": { + "meshID": "multi-cloud-mesh", + "multiCluster": { + "clusterName": "aws-cluster", + }, + "network": "aws-network", + } + } + ) +) +``` + +### 2. Unified Policy Enforcement + +Implement consistent governance across all clouds: + +```typescript +import * as policy from "@pulumi/policy"; + +const multiCloudPolicies = new policy.PolicyPack("multi-cloud-compliance", { + policies: [ + { + name: "required-tags", + description: "Ensure all resources have required tags", + enforcementLevel: "mandatory", + validateResource: (args, reportViolation) => { + const requiredTags = ["Environment", "Owner", "CostCenter", "Project"]; + const tags = args.props.tags || {}; + + for (const tag of requiredTags) { + if (!tags[tag]) { + reportViolation(`Missing required tag: ${tag}`); + } + } + }, + }, + { + name: "encryption-at-rest", + description: "Ensure all storage resources use encryption", + enforcementLevel: "mandatory", + validateResource: (args, reportViolation) => { + // Check AWS S3 buckets + if (args.type === "aws:s3/bucket:Bucket") { + if (!args.props.serverSideEncryptionConfiguration) { + reportViolation("S3 bucket must have encryption enabled"); + } + } + // Check Azure Storage + if (args.type === "azure-native:storage:StorageAccount") { + if (!args.props.encryption?.services?.blob?.enabled) { + reportViolation("Azure storage must have encryption enabled"); + } + } + // Check GCP Storage + if (args.type === "gcp:storage/bucket:Bucket") { + if (!args.props.encryption) { + reportViolation("GCS bucket must have encryption enabled"); + } + } + }, + }, + ], +}); +``` + +### 3. Disaster Recovery and Failover + +Implement automated failover between clouds: + +```python +class MultiCloudFailover(pulumi.ComponentResource): + def __init__(self, name, args, opts=None): + super().__init__("custom:multicloud:Failover", name, opts) + + # Primary region (AWS) + self.primary_alb = aws.lb.LoadBalancer( + f"{name}-primary-alb", + load_balancer_type="application", + subnets=args["aws_subnets"], + enable_cross_zone_load_balancing=True, + opts=pulumi.ResourceOptions(parent=self) + ) + + # Secondary region (Azure) + self.secondary_lb = azure.network.LoadBalancer( + f"{name}-secondary-lb", + resource_group_name=args["azure_resource_group"], + location=args["azure_location"], + sku=azure.network.LoadBalancerSkuArgs( + name="Standard", + tier="Regional" + ), + opts=pulumi.ResourceOptions(parent=self) + ) + + # Health checks and failover logic + self.health_check = aws.route53.HealthCheck( + f"{name}-health-check", + fqdn=self.primary_alb.dns_name, + port=443, + type="HTTPS", + resource_path="/health", + failure_threshold=3, + request_interval=30, + opts=pulumi.ResourceOptions(parent=self) + ) + + # DNS failover configuration + self.primary_record = aws.route53.Record( + f"{name}-primary-dns", + zone_id=args["route53_zone_id"], + name=args["domain_name"], + type="A", + alias=aws.route53.RecordAliasArgs( + name=self.primary_alb.dns_name, + zone_id=self.primary_alb.zone_id, + evaluate_target_health=True, + ), + set_identifier="Primary", + failover_routing_policies=[ + aws.route53.RecordFailoverRoutingPolicyArgs( + type="PRIMARY", + ) + ], + opts=pulumi.ResourceOptions(parent=self) + ) + + self.secondary_record = aws.route53.Record( + f"{name}-secondary-dns", + zone_id=args["route53_zone_id"], + name=args["domain_name"], + type="CNAME", + records=[self.secondary_lb.frontend_ip_configurations[0].public_ip_address.fqdn], + ttl=60, + set_identifier="Secondary", + failover_routing_policies=[ + aws.route53.RecordFailoverRoutingPolicyArgs( + type="SECONDARY", + ) + ], + opts=pulumi.ResourceOptions(parent=self) + ) +``` + +## Multi-Cloud Cost Optimization + +Pulumi enables intelligent resource placement based on cost: + +```typescript +interface CloudPricing { + aws: number; + azure: number; + gcp: number; +} + +function selectOptimalCloud( + workloadType: string, + region: string, + requirements: WorkloadRequirements +): string { + const pricing: CloudPricing = getCostEstimates(workloadType, region, requirements); + + // Select cloud based on cost and requirements + const clouds = [ + { name: "aws", cost: pricing.aws, score: calculateScore("aws", requirements) }, + { name: "azure", cost: pricing.azure, score: calculateScore("azure", requirements) }, + { name: "gcp", cost: pricing.gcp, score: calculateScore("gcp", requirements) }, + ]; + + // Weighted decision based on cost (60%) and feature score (40%) + clouds.sort((a, b) => { + const aWeight = (a.cost * 0.6) + ((100 - a.score) * 0.4); + const bWeight = (b.cost * 0.6) + ((100 - b.score) * 0.4); + return aWeight - bWeight; + }); + + return clouds[0].name; +} + +// Deploy workload to optimal cloud +const optimalCloud = selectOptimalCloud("compute", "us-west", { + cpu: 8, + memory: 32, + storage: 500, + networkBandwidth: "high", +}); + +switch (optimalCloud) { + case "aws": + deployToAWS(workloadConfig); + break; + case "azure": + deployToAzure(workloadConfig); + break; + case "gcp": + deployToGCP(workloadConfig); + break; +} +``` + +## Security and Compliance Across Clouds + +### Unified Secrets Management + +```python +import pulumi_vault as vault + +# Central vault for multi-cloud secrets +vault_provider = vault.Provider("vault", address="https://vault.company.com") + +# Store cloud credentials securely +aws_creds = vault.generic.Secret( + "aws-credentials", + path="secret/cloud/aws", + data_json=json.dumps({ + "access_key": aws_access_key, + "secret_key": aws_secret_key, + }), + opts=pulumi.ResourceOptions(provider=vault_provider) +) + +azure_creds = vault.generic.Secret( + "azure-credentials", + path="secret/cloud/azure", + data_json=json.dumps({ + "client_id": azure_client_id, + "client_secret": azure_client_secret, + "tenant_id": azure_tenant_id, + }), + opts=pulumi.ResourceOptions(provider=vault_provider) +) + +gcp_creds = vault.generic.Secret( + "gcp-credentials", + path="secret/cloud/gcp", + data_json=gcp_service_account_key, + opts=pulumi.ResourceOptions(provider=vault_provider) +) + +# Use secrets in deployments +aws_deployment = deploy_aws_resources( + credentials=vault.get_secret("secret/cloud/aws") +) +``` + +### Compliance Automation + +```typescript +// Automated compliance checks +const complianceRules = { + hipaa: [ + "encryption-at-rest", + "encryption-in-transit", + "access-logging", + "audit-trails", + ], + pciDss: [ + "network-segmentation", + "access-controls", + "encryption", + "monitoring", + ], + gdpr: [ + "data-residency", + "encryption", + "access-controls", + "data-retention", + ], +}; + +function enforceCompliance( + standard: string, + resources: pulumi.Resource[] +): ComplianceReport { + const rules = complianceRules[standard]; + const violations: Violation[] = []; + + for (const resource of resources) { + for (const rule of rules) { + if (!checkRule(rule, resource)) { + violations.push({ + resource: resource.urn, + rule: rule, + severity: "high", + }); + } + } + } + + return { + standard, + passed: violations.length === 0, + violations, + timestamp: new Date(), + }; +} +``` + +## Multi-Cloud Networking and Connectivity + +### Establishing Cross-Cloud VPN Connections + +```python +# AWS to Azure VPN Connection +aws_vpn_gateway = aws.ec2.VpnGateway( + "aws-vpn-gw", + vpc_id=aws_vpc.id, + tags={"Name": "AWS-Azure-VPN"} +) + +azure_vpn_gateway = azure.network.VirtualNetworkGateway( + "azure-vpn-gw", + resource_group_name=azure_resource_group.name, + location=azure_resource_group.location, + gateway_type="Vpn", + vpn_type="RouteBased", + sku=azure.network.VirtualNetworkGatewaySkuArgs( + name="VpnGw1", + tier="VpnGw1" + ), + ip_configurations=[ + azure.network.VirtualNetworkGatewayIpConfigurationArgs( + name="vnet-gw-config", + public_ip_address_id=azure_public_ip.id, + subnet_id=gateway_subnet.id + ) + ] +) + +# Establish connection +vpn_connection = azure.network.VirtualNetworkGatewayConnection( + "azure-aws-connection", + resource_group_name=azure_resource_group.name, + virtual_network_gateway1_id=azure_vpn_gateway.id, + connection_type="IPsec", + shared_key=pulumi.Config().require_secret("vpn_shared_key") +) +``` + +## Monitoring and Observability + +### Unified Monitoring Dashboard + +```typescript +// Aggregate metrics from all clouds +const unifiedMetrics = new DatadogDashboard("multi-cloud-dashboard", { + title: "Multi-Cloud Infrastructure Overview", + widgets: [ + // AWS Metrics + { + definition: { + type: "timeseries", + requests: [{ + q: "avg:aws.ec2.cpuutilization{*} by {instance-id}", + display_type: "line", + }], + title: "AWS EC2 CPU Utilization", + }, + }, + // Azure Metrics + { + definition: { + type: "timeseries", + requests: [{ + q: "avg:azure.vm.percentage_cpu{*} by {vm_name}", + display_type: "line", + }], + title: "Azure VM CPU Percentage", + }, + }, + // GCP Metrics + { + definition: { + type: "timeseries", + requests: [{ + q: "avg:gcp.compute.instance.cpu.utilization{*} by {instance_name}", + display_type: "line", + }], + title: "GCP Compute CPU Utilization", + }, + }, + // Cross-cloud cost tracking + { + definition: { + type: "query_value", + requests: [{ + q: "sum:cloud.cost.daily{*}", + aggregator: "sum", + }], + title: "Total Daily Cloud Spend", + }, + }, + ], +}); +``` + +## Best Practices for Multi-Cloud Success + +### 1. Standardize Development Workflows + +- Use consistent naming conventions across clouds +- Implement shared component libraries +- Maintain unified CI/CD pipelines + +### 2. Implement Strong Governance + +- Enforce tagging policies for cost allocation +- Use policy as code for compliance +- Regular security audits across all clouds + +### 3. Optimize for Performance + +- Leverage cloud-native services where appropriate +- Implement intelligent workload placement +- Use content delivery networks for global reach + +### 4. Plan for Resilience + +- Design for failure across cloud boundaries +- Implement automated backup and recovery +- Regular disaster recovery testing + +### 5. Monitor Holistically + +- Aggregate logs and metrics centrally +- Set up cross-cloud alerting +- Track costs across all providers + +## Frequently Asked Questions + +### Q: How does Pulumi handle state management across multiple clouds? + +Pulumi maintains a unified state file that tracks all resources across all clouds. This state can be stored in Pulumi Cloud (default), AWS S3, Azure Blob Storage, Google Cloud Storage, or self-managed backends. The state file maintains relationships between resources, even across cloud boundaries, enabling features like automatic dependency resolution and safe updates. + +### Q: Can I migrate existing cloud resources to Pulumi? + +Yes, Pulumi provides multiple migration paths: + +- **Import existing resources**: Use `pulumi import` to bring existing cloud resources under Pulumi management +- **Convert Terraform code**: Use `pulumi convert` to transform Terraform HCL to Pulumi programs +- **Generate code from existing infrastructure**: Use `pulumi import` with code generation to create Pulumi code from existing resources + +### Q: How does Pulumi compare to cloud-specific tools? + +While cloud-specific tools like AWS CloudFormation, Azure Resource Manager, and Google Cloud Deployment Manager offer deep integration with their respective platforms, Pulumi provides: + +- **Multi-cloud support**: Single tool for all clouds +- **Real programming languages**: Full power of Python, TypeScript, Go, etc. +- **Superior IDE support**: Code completion, refactoring, testing +- **Reusable components**: Share infrastructure patterns across teams +- **Advanced workflows**: Automation API for custom deployment scenarios + +### Q: What about Kubernetes deployments across clouds? + +Pulumi excels at multi-cloud Kubernetes deployments: + +- Deploy managed Kubernetes (EKS, AKS, GKE) with consistent APIs +- Manage Kubernetes resources alongside cloud infrastructure +- Use the same language for infrastructure and application deployment +- Implement cross-cloud service mesh and networking + +### Q: How do I handle different authentication methods across clouds? + +Pulumi supports multiple authentication methods: + +```python +# AWS +aws_provider = aws.Provider("aws", + region="us-west-2", + profile="production" # or access_key/secret_key +) + +# Azure +azure_provider = azure.Provider("azure", + subscription_id=azure_subscription, + client_id=azure_client_id, + client_secret=azure_client_secret, + tenant_id=azure_tenant_id +) + +# GCP +gcp_provider = gcp.Provider("gcp", + project=gcp_project, + credentials=gcp_service_account_key +) +``` + +## Getting Started with Pulumi Multi-Cloud + +1. **Install Pulumi**: + +```bash +curl -fsSL https://get.pulumi.com | sh +``` + +1. **Create a new multi-cloud project**: + +```bash +pulumi new python # or typescript, go, etc. +``` + +1. **Add cloud provider dependencies**: + +```bash +# Python +pip install pulumi-aws pulumi-azure-native pulumi-gcp + +# TypeScript +npm install @pulumi/aws @pulumi/azure-native @pulumi/gcp +``` + +1. **Configure cloud credentials**: + +```bash +pulumi config set aws:region us-west-2 +pulumi config set azure-native:location westus2 +pulumi config set gcp:project my-project-id +``` + +1. **Deploy your infrastructure**: + +```bash +pulumi up +``` + +## Conclusion + +Managing infrastructure across AWS, Azure, and GCP doesn't have to be complex. Pulumi's unified programming model brings consistency, automation, and developer productivity to multi-cloud deployments. By leveraging familiar programming languages and modern software engineering practices, teams can build, deploy, and manage sophisticated multi-cloud architectures with confidence. + +Whether you're implementing disaster recovery, optimizing costs across providers, or leveraging best-of-breed services from each cloud, Pulumi provides the tools and flexibility needed for successful multi-cloud infrastructure management. + +Ready to simplify your multi-cloud infrastructure? [Get started with Pulumi today](https://www.pulumi.com/docs/get-started/) or explore our [multi-cloud examples](https://github.com/pulumi/examples#multi-cloud) to see these patterns in action.