Last active
January 1, 2023 18:29
-
-
Save jdalley/076b4e78545efc570eb30d2f6f250bda to your computer and use it in GitHub Desktop.
AWS CLI - blue/green deployment via swapping DNS aliases and SSL certificates between two Elastic Beanstalk environments.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This script gets the DNSNames of two defined Route53 domains (one is a subdomain of the other), | |
# and swaps the aliases to perform a blue/green deployment. Or for whatever other reason you can imagine. | |
# Note: If you were doing this for two different non-subdomain domains; you'd have two Hosted Zone Ids here: | |
$hostedZoneId = '<some-hosted-zone-id>' | |
$stagingDNSAlias = aws route53 list-resource-record-sets ` | |
--hosted-zone-id $hostedZoneId ` | |
--query "ResourceRecordSets[?Name == 'staging.yoursite.com.'].AliasTarget.DNSName" ` | |
--output text | |
$prodDNSAlias = aws route53 list-resource-record-sets ` | |
--hosted-zone-id $hostedZoneId ` | |
--query "ResourceRecordSets[?Name == 'www.yoursite.com.'].AliasTarget.DNSName" ` | |
--output text | |
if ([string]::IsNullOrEmpty($stagingDNSAlias) -or [string]::IsNullOrEmpty($prodDNSAlias)) { | |
Write-Host "Didn't get expected result from AWS, exiting..." | |
Exit | |
} | |
Write-Host "Current EC2 server aliases: `n Staging: $stagingDNSAlias `n Prod: $prodDNSAlias" | |
# Change batch: | |
# Notes: | |
# - HostedZoneId for this change should be the public ElasticBeanstalk zone id for your AWS environment: | |
# http://docs.aws.amazon.com/general/latest/gr/rande.html#elasticbeanstalk_region | |
# - Z38NKT9BP95V3O is the us-west-2 ElasticBeanstalk Hosted Zone Id. | |
$changeBatch = @" | |
{ | |
\"Comment\": \"Swap Web domain aliases for staging.yoursite.com and www.yoursite.com\", | |
\"Changes\": [ | |
{ | |
\"Action\": \"UPSERT\", | |
\"ResourceRecordSet\": { | |
\"Name\": \"staging.yoursite.com.\", | |
\"Type\": \"A\", | |
\"AliasTarget\": { | |
\"HostedZoneId\": \"Z38NKT9BP95V3O\", | |
\"EvaluateTargetHealth\": false, | |
\"DNSName\": \"$($prodDNSAlias)\" | |
} | |
} | |
}, | |
{ | |
\"Action\": \"UPSERT\", | |
\"ResourceRecordSet\": { | |
\"Name\": \"www.yoursite.com.\", | |
\"Type\": \"A\", | |
\"AliasTarget\": { | |
\"HostedZoneId\": \"Z38NKT9BP95V3O\", | |
\"EvaluateTargetHealth\": false, | |
\"DNSName\": \"$($stagingDNSAlias)\" | |
} | |
} | |
} | |
] | |
} | |
"@ | |
Write-Host "Change batch we're sending to aws route53 change-resource-record-sets: `n$changeBatch`n" | |
# Swap DNS Aliases: | |
Write-Host "AWS Route53 change-resource-record-sets response: `n" | |
$changeResponse = aws route53 change-resource-record-sets ` | |
--hosted-zone-id $hostedZoneId ` | |
--change-batch $changeBatch | ConvertFrom-Json | |
Write-Host "Status: $($changeResponse.ChangeInfo.Status)" | |
Write-Host "Comment: $($changeResponse.ChangeInfo.Comment)" | |
Write-Host "SubmittedAt: $($changeResponse.ChangeInfo.SubmittedAt)" | |
Write-Host "Id: $($changeResponse.ChangeInfo.Id)`n" | |
# Check for Status to move from PENDING to INSYNC before continuing: | |
$changeCheckDelay = 2 # Seconds | |
$changeCheckTimeout = 5 # Minutes | |
$startTime = Get-Date | |
$done = $null | |
Write-Host "Checking change status every $changeCheckDelay seconds until INSYNC..." | |
do { | |
$statusResponse = aws route53 get-change --id $changeResponse.ChangeInfo.Id | ConvertFrom-Json | |
Write-Host "Change status: $($statusResponse.ChangeInfo.Status)" | |
if ($statusResponse.ChangeInfo.Status -eq "INSYNC") { | |
$done = $true | |
Write-Host "Change INSYNC. DNS Aliases swapped. Continuing..." | |
} | |
else { | |
Start-Sleep -Seconds $changeCheckDelay | |
} | |
} while ($done -eq $null -and $startTime.AddMinutes($changeCheckTimeout) -gt (Get-Date)) | |
if ($done -eq $null) { | |
Write-Host "Didn't get an INSYNC status response within $changeCheckTimeout minutes, exiting without swapping SSL Certs." | |
Exit | |
} | |
Write-Host "`nPreparing to swap SSL Certificates between my-eb-environment-a and my-eb-environment-b..." | |
# This gets the current SSLCertificateId from my-eb-environment-a and my-eb-environment-b | |
# ElasticBeanstalk environment configurations, and swaps them. | |
# Get Environment Ids for my-eb-environment-a and my-eb-environment-b, used in update command below: | |
$envIdA = aws elasticbeanstalk describe-environments ` | |
--environment-names "my-eb-environment-a" ` | |
--output text ` | |
--query "Environments[0].EnvironmentId" | |
$envIdB = aws elasticbeanstalk describe-environments ` | |
--environment-names "my-eb-environment-b" ` | |
--output text ` | |
--query "Environments[0].EnvironmentId" | |
Write-Host "EnvironmentId for my-eb-environment-a: $envIdA" | |
Write-Host "EnvironmentId for my-eb-environment-b: $envIdB" | |
# Get the current SSL Certificate ARN for both environments: | |
$sslArnA = aws elasticbeanstalk describe-configuration-settings ` | |
--application-name "my-application-name" ` | |
--environment-name "my-eb-environment-a" ` | |
--query "ConfigurationSettings[0].OptionSettings[?OptionName=='SSLCertificateId' && Namespace=='aws:elb:loadbalancer'].Value" ` | |
--output text | |
$sslArnB = aws elasticbeanstalk describe-configuration-settings ` | |
--application-name "my-application-name" ` | |
--environment-name "my-eb-environment-b" ` | |
--query "ConfigurationSettings[0].OptionSettings[?OptionName=='SSLCertificateId' && Namespace=='aws:elb:loadbalancer'].Value" ` | |
--output text | |
Write-Host "Current SSL Cert ARN for my-eb-environment-a: $sslArnA" | |
Write-Host "Current SSL Cert ARN for my-eb-environment-b: $sslArnB" | |
# Swap the SSL Certificates between the ElasticBeanstalk environments: | |
Write-Host "Updating environment for my-eb-environment-a..." | |
aws elasticbeanstalk update-environment ` | |
--environment-id $envIdA ` | |
--option-settings "Namespace=aws:elb:loadbalancer,OptionName=SSLCertificateId,Value=$sslArnB" | |
Write-Host "Environment updated." | |
Write-Host "Updating environment for my-eb-environment-b..." | |
aws elasticbeanstalk update-environment ` | |
--environment-id $envIdB ` | |
--option-settings "Namespace=aws:elb:loadbalancer,OptionName=SSLCertificateId,Value=$sslArnA" | |
Write-Host "Environment updated." | |
Write-Host "`nSSL Certificate swap complete." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment