Last active
November 19, 2024 13:21
-
-
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
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
| 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