Back to Blog Cloud Migration

Secure Cloud Migration: How to Migrate Between Cloud Providers Safely

18 min read

Migrating between cloud providers - whether from AWS to Azure, GCP to AWS, or implementing a multi-cloud strategy - introduces significant security risks. This guide covers the essential security practices for protecting your data and maintaining compliance throughout the migration process.

Why Cloud Migrations Are Security-Critical

Cloud migrations are high-risk periods because:

  • Data in transit: Sensitive data moves across networks, potentially exposed
  • Dual environments: You're securing two clouds simultaneously
  • Configuration drift: Security controls may not translate directly between providers
  • Access sprawl: Temporary elevated permissions often become permanent
  • Compliance gaps: Regulations may have different requirements per provider

Phase 1: Pre-Migration Security Assessment

Inventory and Classify Your Data

Before moving anything, understand what you're migrating:

# Example data classification framework
CLASSIFICATION_LEVELS = {
    "public": {
        "encryption": "optional",
        "transfer": "standard",
        "compliance": []
    },
    "internal": {
        "encryption": "required_in_transit",
        "transfer": "encrypted_channel",
        "compliance": ["SOC2"]
    },
    "confidential": {
        "encryption": "required_at_rest_and_transit",
        "transfer": "dedicated_connection",
        "compliance": ["SOC2", "GDPR"]
    },
    "restricted": {
        "encryption": "customer_managed_keys",
        "transfer": "private_link_only",
        "compliance": ["SOC2", "GDPR", "PCI-DSS", "HIPAA"]
    }
}

Security Baseline Documentation

Document your current security posture:

  • All IAM roles, policies, and service accounts
  • Network security groups and firewall rules
  • Encryption keys and their rotation schedules
  • Compliance certifications and audit requirements
  • Security monitoring and alerting configurations

Map Security Controls Between Providers

Security Control AWS Azure GCP
Identity Provider IAM, IAM Identity Center Azure AD, Entra ID Cloud Identity, IAM
Secret Management Secrets Manager Key Vault Secret Manager
Key Management KMS Key Vault Cloud KMS
Network Firewall Security Groups, NACLs NSGs, Azure Firewall Firewall Rules, Cloud Armor
Threat Detection GuardDuty Defender for Cloud Security Command Center

Phase 2: Secure Data Transfer

Establish Private Connectivity

Never transfer sensitive data over the public internet:

Option 1: Direct Connect / ExpressRoute / Dedicated Interconnect

For large-scale migrations, establish dedicated private connections:

# AWS Direct Connect + Azure ExpressRoute peering
# Requires physical cross-connect at a colocation facility

# Alternative: Use cloud-to-cloud VPN
# AWS to Azure VPN example
aws ec2 create-vpn-gateway --type ipsec.1 --amazon-side-asn 65000
# Then configure Azure Virtual Network Gateway to connect

Option 2: Cloud-Native Transfer Services

# AWS to GCP: Use Storage Transfer Service
gcloud transfer jobs create \
    --source-agent-pool=aws-pool \
    --destination=gs://my-gcp-bucket \
    --source-creds-file=aws-credentials.json

# Azure to AWS: Use AWS DataSync
aws datasync create-location-azure-blob \
    --agent-arns arn:aws:datasync:region:account:agent/agent-id \
    --container-url "https://account.blob.core.windows.net/container" \
    --authentication-type SAS

Encrypt Data in Transit

Always use TLS 1.2+ for data transfer:

# Verify TLS version in transfer
openssl s_client -connect target-endpoint:443 -tls1_2

# For database migrations, use SSL connections
# PostgreSQL example
psql "host=target-db.region.rds.amazonaws.com \
      dbname=mydb \
      user=admin \
      sslmode=verify-full \
      sslrootcert=rds-ca-cert.pem"

Re-encrypt Data with Target Cloud Keys

Don't transfer encryption keys between clouds. Re-encrypt data with the target cloud's KMS:

# Step 1: Decrypt with source cloud key
aws kms decrypt \
    --ciphertext-blob fileb://encrypted-data \
    --output text --query Plaintext | base64 --decode > decrypted-data

# Step 2: Re-encrypt with target cloud key
gcloud kms encrypt \
    --location=us-central1 \
    --keyring=migration-keyring \
    --key=data-key \
    --plaintext-file=decrypted-data \
    --ciphertext-file=reencrypted-data

# Step 3: Securely delete plaintext
shred -vfz -n 5 decrypted-data

Phase 3: Identity and Access Migration

Federate Identity Across Clouds

Use a single identity provider for both clouds during migration:

# Configure AWS to trust Azure AD
# In AWS IAM Identity Provider:
{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Principal": {
            "Federated": "arn:aws:iam::ACCOUNT:saml-provider/AzureAD"
        },
        "Action": "sts:AssumeRoleWithSAML",
        "Condition": {
            "StringEquals": {
                "SAML:aud": "https://signin.aws.amazon.com/saml"
            }
        }
    }]
}

Implement Just-in-Time Access

Migration requires elevated access, but limit its scope and duration:

# Use temporary credentials with expiration
# AWS STS example
aws sts assume-role \
    --role-arn arn:aws:iam::ACCOUNT:role/MigrationRole \
    --role-session-name migration-session \
    --duration-seconds 3600

# Azure PIM - activate role for limited time
az rest --method POST \
    --uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignmentScheduleRequests" \
    --body '{
        "action": "selfActivate",
        "justification": "Cloud migration task",
        "scheduleInfo": {
            "expiration": {
                "type": "afterDuration",
                "duration": "PT4H"
            }
        }
    }'

Audit and Remove Temporary Access

# Script to find and flag migration-related IAM entities
# Run weekly during migration

# AWS - Find roles with "migration" in name
aws iam list-roles --query "Roles[?contains(RoleName, 'migration')]"

# Azure - Find migration-related role assignments
az role assignment list --query "[?contains(roleDefinitionName, 'migration')]"

# GCP - Find migration service accounts
gcloud iam service-accounts list --filter="email:migration"

Phase 4: Application Migration Security

Secrets Migration

Never copy secrets directly. Rotate and recreate in the target environment:

# 1. Create new secrets in target cloud
gcloud secrets create db-password --data-file=-

# 2. Update application to use new secret reference

# 3. Rotate the secret in source cloud to invalidate old value
aws secretsmanager rotate-secret --secret-id old-db-password

# 4. After verification, delete from source
aws secretsmanager delete-secret --secret-id old-db-password --force-delete-without-recovery

Container Image Migration

# Scan images before migration
trivy image my-registry/my-app:latest

# Sign images for the target registry
cosign sign --key gcpkms://projects/PROJECT/locations/LOCATION/keyRings/KEYRING/cryptoKeys/KEY \
    gcr.io/target-project/my-app:latest

# Verify signature in target environment
cosign verify --key gcpkms://... gcr.io/target-project/my-app:latest

Database Migration Security

# Use SSL/TLS for database migration
# AWS DMS with SSL
aws dms create-endpoint \
    --endpoint-identifier source-db \
    --endpoint-type source \
    --engine-name postgres \
    --ssl-mode verify-full \
    --certificate-arn arn:aws:dms:region:account:cert:cert-id

# Verify no sensitive data in logs
# Disable query logging during migration
ALTER SYSTEM SET log_statement = 'none';
SELECT pg_reload_conf();

Phase 5: Network Security During Migration

Temporary Network Architecture

# Create isolated migration network segment
# AWS VPC for migration
aws ec2 create-vpc --cidr-block 10.200.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=migration-vpc}]'

# Strict security group - only allow migration traffic
aws ec2 create-security-group \
    --group-name migration-sg \
    --description "Migration traffic only" \
    --vpc-id vpc-migration

aws ec2 authorize-security-group-ingress \
    --group-id sg-migration \
    --protocol tcp \
    --port 443 \
    --source-group sg-source-apps

Monitor Cross-Cloud Traffic

# Enable VPC Flow Logs on migration subnets
aws ec2 create-flow-logs \
    --resource-type VPC \
    --resource-ids vpc-migration \
    --traffic-type ALL \
    --log-destination-type cloud-watch-logs \
    --log-group-name /migration/flow-logs

# Alert on unexpected destinations
# CloudWatch Logs Insights query
fields @timestamp, srcAddr, dstAddr, bytes
| filter dstAddr not like /^10\./ and dstAddr not like /^172\.16\./
| stats sum(bytes) as totalBytes by dstAddr
| sort totalBytes desc
| limit 20

Phase 6: Compliance and Audit

Maintain Audit Trail

Document every action during migration for compliance:

# Centralize logs from both clouds
# Send to a SIEM or log aggregator

# AWS CloudTrail to S3
aws cloudtrail create-trail \
    --name migration-audit-trail \
    --s3-bucket-name central-audit-logs \
    --include-global-service-events \
    --is-multi-region-trail

# Azure Activity Logs to same destination
az monitor diagnostic-settings create \
    --name migration-audit \
    --resource /subscriptions/SUB_ID \
    --storage-account /subscriptions/SUB_ID/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/centrallogs

Compliance Validation Checklist

  • Data residency requirements met in target cloud
  • Encryption standards maintained (AES-256, TLS 1.2+)
  • Access controls replicated and tested
  • Audit logging enabled and retained per policy
  • Penetration test scheduled for post-migration
  • Compliance certifications verified for target services

Phase 7: Post-Migration Security

Cleanup Checklist

# 1. Remove temporary IAM roles and permissions
aws iam delete-role --role-name MigrationAdminRole

# 2. Delete temporary network connections
aws ec2 delete-vpc-peering-connection --vpc-peering-connection-id pcx-migration

# 3. Revoke temporary credentials
aws iam delete-access-key --user-name migration-user --access-key-id AKIA...

# 4. Remove migration security groups
aws ec2 delete-security-group --group-id sg-migration

# 5. Verify source environment decommissioning
# Run security scan to find orphaned resources

Security Validation

# Run security assessment on target environment
# Using cloud-native tools

# AWS Security Hub
aws securityhub get-findings --filters '{"GeneratorId":[{"Value":"security-control","Comparison":"PREFIX"}]}'

# Azure Defender
az security assessment list --query "[?status.code=='Unhealthy']"

# GCP Security Command Center
gcloud scc findings list organizations/ORG_ID --filter="state=\"ACTIVE\""

Migration Security Checklist

  • Pre-Migration:
    • Data classified and documented
    • Security controls mapped between clouds
    • Compliance requirements identified
    • Private connectivity established
  • During Migration:
    • All data encrypted in transit
    • Temporary access time-limited
    • Audit logging enabled on both clouds
    • Network traffic monitored
  • Post-Migration:
    • Temporary resources deleted
    • Access permissions audited
    • Security assessment completed
    • Source environment decommissioned securely

Next Steps

Cloud migration security requires careful planning and execution. The temporary nature of migrations often leads to security shortcuts that become permanent vulnerabilities. Treat your migration as a security-critical project with proper oversight and validation at every phase.

Need help with a secure cloud migration? Contact us for expert guidance and implementation support.