Skip to content

Instantly share code, notes, and snippets.

@filipeandre
Last active November 19, 2024 13:21
Show Gist options
  • Save filipeandre/d95b3e187c7e80f76bf8a28afdac94bf to your computer and use it in GitHub Desktop.
Save filipeandre/d95b3e187c7e80f76bf8a28afdac94bf to your computer and use it in GitHub Desktop.
Deploys a solution that redirects multiple domains to a new domain using bucket redirect
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
RedirectDomain:
Type: String
Default: 'https://sapo.pt'
Description: 'The target domain for the redirect.'
DomainsToRedirect:
Type: CommaDelimitedList
Default: 'www.google.pt,google.pt'
Description: 'A comma-separated list of domain names to redirect.'
HostedZoneIds:
Type: CommaDelimitedList
Default: 'Z1A2B3C4D5E6Z7,Z1A2B3C4D5E6Z8' # Replace with the actual hosted zone IDs for google.pt and www.google.pt
Description: 'A comma-separated list of hosted zone IDs corresponding to each domain in DomainsToRedirect.'
Resources:
# ACM SSL certificate for the redirect domain
SSLCertificate:
Type: 'AWS::CertificateManager::Certificate'
Properties:
DomainName: !Ref RedirectDomain
ValidationMethod: DNS
SubjectAlternativeNames:
- !Ref RedirectDomain
Tags:
- Key: 'Name'
Value: 'RedirectDomainCertificate'
# CloudFront distribution to handle HTTPS redirect
CloudFrontDistribution:
Type: 'AWS::CloudFront::Distribution'
Properties:
DistributionConfig:
Comment: "HTTPS Redirect for domains"
Enabled: true
Origins:
- DomainName: !Sub "${RedirectDomain}"
Id: RedirectDomainOrigin
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: "https-only"
OriginSSLProtocols:
- "TLSv1.2"
DefaultCacheBehavior:
ViewerProtocolPolicy: "redirect-to-https"
TargetOriginId: RedirectDomainOrigin
ForwardedValues:
QueryString: false
Cookies:
Forward: none
ViewerCertificate:
AcmCertificateArn: !Ref SSLCertificate
SslSupportMethod: sni-only
# Inline Lambda function to create S3 buckets and Route 53 records
S3RedirectFunction:
Type: 'AWS::Lambda::Function'
Properties:
Handler: 'index.handler'
Role: !GetAtt LambdaExecutionRole.Arn
FunctionName: 'S3RedirectFunction'
Code:
ZipFile: |
import json
import boto3
s3 = boto3.client('s3')
route53 = boto3.client('route53')
def handler(event, context):
domains = event['DomainsToRedirect']
redirect_domain = event['RedirectDomain']
hosted_zone_ids = event['HostedZoneIds']
request_type = event['RequestType'] # "Create", "Update", or "Delete"
responses = []
# Iterate over each domain and hosted zone ID pair
for i, domain in enumerate(domains):
hosted_zone_id = hosted_zone_ids[i]
try:
if request_type == 'Create' or request_type == 'Update':
# Create or update S3 bucket for redirection
s3.create_bucket(Bucket=domain)
s3.put_bucket_website(
Bucket=domain,
WebsiteConfiguration={
'RedirectAllRequestsTo': {
'HostName': redirect_domain,
'Protocol': 'https'
}
}
)
# Create or update Route 53 record to point to CloudFront
route53.change_resource_record_sets(
HostedZoneId=hosted_zone_id,
ChangeBatch={
'Changes': [
{
'Action': 'UPSERT', # Use UPSERT for both create and update
'ResourceRecordSet': {
'Name': domain,
'Type': 'A',
'AliasTarget': {
'HostedZoneId': 'Z2FDTNDATAQYW2', # CloudFront hosted zone ID
'DNSName': event['CloudFrontDistributionDomainName'],
'EvaluateTargetHealth': False
}
}
}
]
}
)
responses.append(f"Successfully created/updated redirect for {domain} with Hosted Zone ID {hosted_zone_id}")
elif request_type == 'Delete':
# Delete the S3 bucket website configuration
s3.delete_bucket_website(Bucket=domain)
# Delete Route 53 record
route53.change_resource_record_sets(
HostedZoneId=hosted_zone_id,
ChangeBatch={
'Changes': [
{
'Action': 'DELETE',
'ResourceRecordSet': {
'Name': domain,
'Type': 'A',
'AliasTarget': {
'HostedZoneId': 'Z2FDTNDATAQYW2', # CloudFront hosted zone ID
'DNSName': event['CloudFrontDistributionDomainName'],
'EvaluateTargetHealth': False
}
}
}
]
}
)
# Delete the S3 bucket
s3.delete_bucket(Bucket=domain)
responses.append(f"Successfully deleted redirect for {domain} with Hosted Zone ID {hosted_zone_id}")
except Exception as e:
responses.append(f"Failed to process redirect for {domain}: {str(e)}")
return {
'statusCode': 200,
'body': json.dumps(responses)
}
Runtime: 'python3.13'
# IAM Role for Lambda execution
LambdaExecutionRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service: 'lambda.amazonaws.com'
Action: 'sts:AssumeRole'
Policies:
- PolicyName: 'LambdaS3Route53Policy'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Action:
- 's3:CreateBucket'
- 's3:PutBucketWebsite'
- 'route53:ChangeResourceRecordSets'
- 'acm:RequestCertificate'
- 'acm:DescribeCertificate'
Resource: '*'
# Custom Resource to invoke the Lambda function
S3RedirectResource:
Type: 'Custom::S3Redirect'
Properties:
ServiceToken: !GetAtt S3RedirectFunction.Arn
DomainsToRedirect: !Ref DomainsToRedirect
RedirectDomain: !Ref RedirectDomain
HostedZoneIds: !Ref HostedZoneIds
Outputs:
RedirectedDomains:
Value:
Fn::Join:
- ", "
- Ref: DomainsToRedirect
Description: "List of domains that will be redirected."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment