Custom domain name with customer-managed CDN

Learn how to add a custom domain name to an AEM as a Cloud Service web site that uses a customer-managed CDN.

In this tutorial, the branding of the sample AEM WKND site is enhanced by adding an HTTPS-addressable custom domain name wkndviaawscdn.enablementadobe.com with Transport Layer Security (TLS) using a customer-managed CDN. In this tutorial, AWS CloudFront is used as the customer-managed CDN, however any CDN provider should be compatible with AEM as a Cloud Service.

The high-level steps are:

Custom Domain Name with Customer CDN {width="800" modal="regular"}

Prerequisites

Transcript
Before we dive in, make sure you have the following tools and services or collaborate with your IT teams to ensure a seamless setup. Ensure you have OpenSSL and DIG installed on your local machine. Access to a certificate authority service like DigiCert to request the signed certificate for your site domain. Access to your CDN vendor service to add SSL certificates and domain details. Access to DNS hosting services like Azure DNS or Route 53 to add DNS records for your custom domain. Access to Cloud Manager to run the pipelines after config changes are made in your AM project code.
  • OpenSSL and dig are installed on your local machine.

  • Access to third-party services:

    • Certificate Authority (CA) - to request the signed certificate for your site domain, like DigitCert
    • Customer CDN - to set up the customer CDN and add SSL certificates and domain details, like AWS CloudFront, Azure CDN, or Akamai.
    • Domain Name System (DNS) hosting service - to add DNS records for your custom domain, like Azure DNS, or AWS Route 53.
  • Access to Adobe Cloud Manager to deploy HTTP Header validation CDN rule to the AEM as a Cloud Service environment.

  • Sample AEM WKND site is deployed to the AEM as a Cloud Service environment of production program type.

If you do not have access to third-party services, collaborate with your security or hosting team to complete the steps.

Generate SSL certificate

You have two options:

  1. Using openssl command-line tool - you can generate a private key and a Certificate Signing Request (CSR) for your site domain. To request a signed certificate, submit the CSR to a Certificate Authority (CA).
  2. Your hosting team provides the required private key and signed certificate for your site.

Let’s review the steps for the first option.

To generate a private key and a CSR, run the following commands and provide the required information when prompted:

# Generate a private key and a CSR
$ openssl req -newkey rsa:2048 -keyout <YOUR-SITE-NAME>.key -out <YOUR-SITE-NAME>.csr -nodes

To request a signed certificate, provide the generated CSR to the CA by following their documentation. Once the CA signs the CSR, you receive the signed certificate file.

Review signed certificate

Reviewing the signed certificate before adding it to the Cloud Manager is a good practice. You can review the certificate details using the following command:

# Review the certificate details
$ openssl crl2pkcs7 -nocrl -certfile <YOUR-SIGNED-CERT>.crt | openssl pkcs7 -print_certs -noout

The signed certificate may contain the certificate chain, which includes the root and intermediate certificates along with the end-entity certificate.

The Adobe Cloud Manager accepts the end-entity certificate and the certificate chain in separate form fields, so you must extract the end-entity certificate and the certificate chain from the signed certificate.

In this tutorial, the DigitCert signed certificate issued against *.enablementadobe.com domain is used as an example. The end-entity and certificate chain is extracted by opening the signed certificate in a text editor and copying the content between the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- markers.

Set up customer-managed CDN

Set up the customer CDN, like AWS CloudFront, Azure CDN, or Akamai, and add the SSL certificate and domain details. In this tutorial, AWS CloudFront is used as an example. However, depending on your CDN vendor, the steps may vary. The key callouts are:

  • Add the SSL certificate to the CDN.
  • Add the custom domain name to the CDN.
  • Configure the CDN to cache the content, like images, CSS, and JavaScript files.
  • Add the X-Forwarded-Host HTTP header to the CDN settings so that your CDN includes this header in all requests it sends to the AEMCD origin.
  • Make sure the Host header value is set to the default AEM as a Cloud Service domain containing the program and environment ID and ending with adobeaemcloud.com. The HTTP host header value passed from the customer CDN to the Adobe CDN must be the default AEM as a Cloud Service domain, any other value result in an error state.

Configure DNS records

Transcript
Moving on, the next step is configuring DNS records. For this, you will need a DNS hosting service. In this demo, I’m using Azure DNS zone. However, work closely with your organization hosting team to ensure a smooth process, as you may be using a different DNS hosting service. I will now head over to the Azure DNS zone to add the CNAME record. In my case, the CNAME is weekend-via-aws-cdn.enablement-adobe.com and the target is the AWS CloudFront distribution domain name, which typically ends with .cloudfront.net. DNS propagation takes some time, so I’ll wait for a few minutes and pause the recording. My wait is over. Let’s verify the weekend site on this newly added custom domain.
It’s working as expected, with all pages and hyperlinks rendering correctly and the response header indicating cache hits or misses from the CloudFront. The custom domain setup for our weekend site is working. However, at the beginning of the video, I mentioned a crucial security step, how to pass HTTP headers from the customer CDN to the Adobe CDN. But first, let’s understand why and how this custom domain setup works.

To configure the DNS record for your custom domain follow these steps,

  1. Add a CNAME record for the custom domain pointing to the CDN domain name.

This tutorial adds a CNAME record to Azure DNS for the custom domain wkndviaawscdn.enablementadobe.com and points it to the AWS CloudFront distribution domain name.

Site verification

Verify the custom domain name by accessing the site using the custom domain name.
It may or may not work depending on the vhhost configuration in the AEM as a Cloud Service environment.

A crucial security step is to deploy the HTTP Header validation CDN rule to the AEM as a Cloud Service environment. The rule ensures that the request is coming from the customer CDN and not from any other source.

Current working state without HTTP Header validation CDN rule

Transcript
The sample vcan vhost file has a wildcard server alias in the virtual host configuration, allowing any domain to match. This setup is suitable for development purposes but not recommended for production. In a production environment, it’s essential to explicitly define which domains your server should handle to maintain control and mitigate security risk. In the current setup, if we print the request headers received by AEM using custom servlet code, you will not see the x-forwarded host header and the host header value will be the default AMIS Cloud service domain. This means that even if I change the virtual host configuration to explicitly match the vcan via aws-cedian.enablement-adobe.com domain name, it will not work. To pass the correct host header value to AEM, you must configure and deploy an HTTP header validation CDN rule in AEM as a cloud service. Once this rule is successfully deployed and validated, Adobe CDN will transform the host header value to the value of the x-forwarded host received from the customer CDN. Let’s do that.

Without the HTTP Header validation CDN rule, the Host header value is set to the default AEM as a Cloud Service domain containing the program and environment ID and ending with adobeaemcloud.com. Adobe CDN transforms the Host header value to the value of the X-Forwarded-Host received from the customer CDN only if the HTTP Header validation CDN rule is deployed. Otherwise, the Host header value is passed as is to the AEM as a Cloud Service environment and the X-Forwarded-Host header is not used.

Sample servlet code to print the Host header value

The following servlet code prints the Host, X-Forwarded-*, Referer and Via HTTP header values in the JSON response.

package com.adobe.aem.guides.wknd.core.servlets;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.Servlet;
import javax.servlet.ServletException;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.ServletResolverConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

@Component(service = Servlet.class, property = {
        ServletResolverConstants.SLING_SERVLET_PATHS + "=/bin/verify-headers",
        ServletResolverConstants.SLING_SERVLET_METHODS + "=" + HttpConstants.METHOD_GET
})
public class VerifyHeadersServlet extends SlingSafeMethodsServlet {

    @Reference
    private ResourceResolverFactory resourceResolverFactory;

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        // Create JSON response
        StringBuilder jsonResponse = new StringBuilder();
        jsonResponse.append("{");

        Enumeration<String> headerNames = request.getHeaderNames();
        boolean firstHeader = true;

        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();

            if (headerName.startsWith("X-Forwarded-") || headerName.startsWith("Host")
                    || headerName.startsWith("Referer") || headerName.startsWith("Via")) {
                if (!firstHeader) {
                    jsonResponse.append(",");
                }
                jsonResponse.append("\"").append(headerName).append("\": \"").append(request.getHeader(headerName))
                        .append("\"");
                firstHeader = false;
            }
        }

        jsonResponse.append("}");

        response.getWriter().write(jsonResponse.toString());
    }
}

To test the servlet, update the ../dispatcher/src/conf.dispatcher.d/filters/filters.any file with the following configuration. Also make sure that the CDN is configured to NOT cache the /bin/* path.

# Testing purpose bin
/0300 { /type "allow" /extension "json" /path "/bin/*"}
/0301 { /type "allow" /path "/bin/*"}
/0302 { /type "allow" /url "/bin/*"}

Configure and deploy HTTP Header validation CDN rule

To configure and deploy the HTTP Header validation CDN rule, follow these steps:

  • Add HTTP Header validation CDN rule in the cdn.yaml file, an example is provided below.

    code language-yaml
    kind: "CDN"
    version: "1"
    metadata:
    envTypes: ["prod"]
    data:
    authentication:
        authenticators:
        - name: edge-auth
            type: edge
            edgeKey1: ${{CDN_EDGEKEY_080124}}
            edgeKey2: ${{CDN_EDGEKEY_110124}}
        rules:
        - name: edge-auth-rule
            when: { reqProperty: tier, equals: "publish" }
            action:
            type: authenticate
            authenticator: edge-auth
    
  • Create secret-type environment variables (CDN_EDGEKEY_080124, CDN_EDGEKEY_110124) using the Cloud Manager UI.

  • Deploy the HTTP Header validation CDN rule to the AEM as a Cloud Service environment using the Cloud Manager pipeline.

Pass secret in the X-AEM-Edge-Key HTTP Header

Update the customer CDN to pass the secret in the X-AEM-Edge-Key HTTP Header. The secret is used by the Adobe CDN to validate the request is coming from the customer CDN and transform the Host header value to the value of the X-Forwarded-Host received from the customer CDN.

End to end video

You can also watch the end-to-end video that demonstrates the above steps to add a custom domain name with a customer-managed CDN to an AEM as a Cloud Service-hosted site.

Transcript
In this video, you will learn how to add a custom domain to an AMS Cloud Service hosted site using a Customer Managed CDN, commonly referred as Bring Your Own CDN or BIO CDN for short. Examples of Customer Managed CDN include Akamai, AWS CloudFront, and Azure Front Door. While AMS Cloud Service provides Adobe CDN to reduce latency and improve performance, there are situations where you might need to use a Customer Managed CDN due to corporate policies or pre-existing vendor contracts. Regardless of your reasons for using Customer Managed CDN, this tutorial will help you set up the custom domain name through the self-service feature, including managing the SSL certificate, domain name, and DNS configurations. The logical request flow after the setup is shown on the screen. In this step-by-step guide, I will demonstrate how to add a custom domain name to the sample weekend site deployed on my AMS Cloud Service environment using AWS CloudFront as the Customer Managed CDN and Azure DNS for managing custom domain name records. By leveraging these two prominent cloud service providers, you can see how the setup can be managed across different vendors, though it is also possible to manage everything within a single vendor if preferred. Note that your configuration steps might vary depending on your CDN and DNS vendor, but you will learn where to manage key details like SSL certificate, domain, and DNS records. Towards the end, we will cover a crucial security step, how to pass HTTP headers from the Customer CDN to the Adobe CDN. This is needed so that the Adobe CDN can validate the source of the request to avoid random CDN entities pointing to your own content. Before we dive in, make sure you have the following tools and services or collaborate with your IT teams to ensure a seamless setup. Ensure you have OpenSSL and DIG installed on your local machine. Access to a certificate authority service like DigiCert to request the signed certificate for your site domain. Access to your CDN vendor service to add SSL certificates and domain details. Access to DNS hosting services like Azure DNS or Route 53 to add DNS records for your custom domain. Access to Cloud Manager to run the pipelines after config changes are made in your AEM project code. The initial step in setting up a custom domain is generating a private key and certificate signing request or CSR for short. You can accomplish this by running OpenSSL commands on your local machine. Alternatively, your security team can provide you with the final products, the private key, and signed certificate for your site. In my case, I use OpenSSL to generate both the private key and CSR for the star.enablement.adobe.com domain. It’s important to emphasize the ownership of the private key and its secure handling. Please consult your company specific policies. The next step involves submitting the CSR file to the certificate authority service to obtain the signed certificate. In my case, I use the DigiCert service to obtain a valid certificate for my star.enablement.adobe.com domain. Now, let’s quickly review the signed certificate details using the OpenSSL command. As you can see, it contains multiple certificates like route, intermediate, and end-entity certificates, also known as certificate chain. Alright, I have the private key and signed SSL certificate. The next step is setting up the customer CDN, also known as BYO CDN. Since I’m using AWS CloudFront as the customer CDN, I have logged into the AWS console. First, I will use AWS certificate manager to upload the SSL certificate. In the import certificate form, copy the details from the signed certificate and private key files. Click import certificate to complete the process.
Next, navigate to the CloudFront service and create a distribution. In the create distribution form, enter the origin details. The origin domain value is your default AMSACloudService domain containing the program and environment ID and ending with the adobe amcloud.com. Also, add the x-forwarded host custom header so that CloudFront includes this header in all requests it sends to the AM origin.
Next, enter the default cache behavior details. For demo purposes, I’ll keep them simple. However, collaborate with your AWS or CDN expert for a production quality setup. An important note, while selecting the value for the origin request policy option, make sure to select all viewers except host header option or any option that doesn’t send the host header to the origin. In other words, Adobe CDN expects the host header value to be the default AMSACloudService domain containing the program and environment ID and ending with adobe amcloud.com. The most important part of this setup is adding the custom domain and associating the SSL certificate. In my case, I’m using the weekend-via-aws-cdn.enablement-adobe.com domain name.
Since my SSL certificate is issued for STAR or any domain of enablement-adobe.com, it should work seamlessly. Finally, click Create Distribution to complete the process. It should get deployed in a few minutes. This completes the customer CDN setup. Note that the above steps will differ based on your CDN vendor. An important takeaway is adding the x-forwarded host header and ensuring the host value sent to the origin is the default AMSACloudService domain. Moving on, the next step is configuring DNS records. For this, you will need a DNS hosting service. In this demo, I’m using Azure DNS zone. However, work closely with your organization hosting team to ensure a smooth process, as you may be using a different DNS hosting service. I will now head over to the Azure DNS zone to add the CNAME record.
In my case, the CNAME is weekend-via-aws-cdn.enablement-adobe.com and the target is the AWS CloudFront distribution domain name, which typically ends with .cloudfront.net. DNS propagation takes some time, so I’ll wait for a few minutes and pause the recording. My wait is over. Let’s verify the weekend site on this newly added custom domain.
It’s working as expected, with all pages and hyperlinks rendering correctly and the response header indicating cache hits or misses from the CloudFront. The custom domain setup for our weekend site is working. However, at the beginning of the video, I mentioned a crucial security step, how to pass HTTP headers from the customer CDN to the Adobe CDN. But first, let’s understand why and how this custom domain setup works.
The sample weekend vhost file has a wildcard server alias in the virtual host configuration, allowing any domain to match. This setup is suitable for development purposes but not recommended for production. In a production environment, it’s essential to explicitly define which domains your server should handle to maintain control and mitigate security risk. In the current setup, if we print the request headers received by AEM using custom servlet code, you will not see the x-forwarded host header and the host header value will be the default AMIS Cloud service domain. This means that even if I change the virtual host configuration to explicitly match the weekend via AWS CDN.enablement.adobe.com domain name, it will not work. To pass the correct host header value to AEM, you must configure and deploy an HTTP header validation CDN rule in AMIS Cloud service. Once this rule is successfully deployed and validated, Adobe CDN will transform the host header value to the value of the x-forwarded host received from the customer CDN. Let’s do that. I have cloned this sample weekend site locally. From the main config folder, open the CDN.yaml file and add the authentication rule.
Let’s review the rule details. The main authentication property includes two key sections. Authenticators and Rules. Under the authenticators section, we have defined an authenticator named edgeAuth of type Edge. This section includes two edge keys. Edge key 1 is referenced by the Cloud Manager’s secret type environment variable name. The variable name follows a convention indicating that this is a CDN related secret used for edge authentication and the date it was added. Edge key 2 is used for the rotation of secrets without any interruptions. Next, we have the rules section which contains a rule named edgeAuthRule. This rule specifies a condition. It activates when the request property TS equals publish. It has an action 2. The action for this rule is of type authenticate utilizing the edgeAuth authenticator defined earlier. Alright, let me commit these rule changes and push my code to the Adobe upstream repository.
Using Cloud Manager pipeline, I should deploy this rule to my AMIS Cloud service environment. Please note, I have already created the CDN config prod weekend pipeline that deploys only config files.
However, before triggering the deployment, I need to create secret type environment variables using the Cloud Manager UI. Open the configurations tab of the environment. Add two new secrets in the environment configuration model. For the first secret, enter the necessary details. Ensure the variable name matches the authentication rule edge key values. Choose a strong value for the secret. However, I’m keeping simple for demo purposes. In the service applied dropdown, select the all option. In the type dropdown, select the secret option. Finally, click add. Repeat these steps to add the second variable, which is used for the rotation of secrets without any interruptions.
Next, run the pipeline to deploy the authentication rule. This should be completed in a few minutes. Now that we have deployed the HTTP header validation rule, the next step is to pass the secret value in the HTTP header from the customer CDN to the Adobe CDN. The secret value must be passed in the x-am-edge-key header. Let’s head over to the AWS console and update the AWS CloudFront distribution to add the x-am-edge-key header with the secret value. Click on the ID of your distribution to open its details page. Then select the origins tab. Select and edit the AMCS origin where you want to add the header. In the edit origin form, click the add header button. In the header name field, enter x-am-edge-key and in the value field, enter the secret value. Save your changes.
With the header added, we can verify our custom domain to ensure everything is set up correctly.
Let’s print the request headers received by AM using the custom servlet code. You should see the correct host header value this time. Adobe CDN is transforming the host header value to the value of the x-forwarded host received from the customer CDN. Everything should be working as expected with the custom domain fully functional and secured by the HTTP header validation. Congratulations! Using the self-service feature of AM as a cloud service, we have successfully completed the setup of a custom domain for our weekend AM site. Using AWS CloudFront as the customer-managed CDN and Azure DNS for managing custom domain records. We have also implemented crucial security measures to ensure our setup is robust and secure. Thank you for following along.
recommendation-more-help
4859a77c-7971-4ac9-8f5c-4260823c6f69