Allowing users to point their domain names to my service - amazon-web-services

I am giving my services to my users via client.example.com and there are pages like
client.mysite.com/blog
client.mysite.com/blog/content/
client.mysite.com/docs/
etc.
I want to allow users to allow their domains to point to this subdomain.
so they can choose between any of the 1 option below :
client.com -> client.example.com
sub.client.com -> client.example.com
client.com/sub/ -> client.example.com
and pages should work automatically like
client.com/blog -> client.example.com/blog
sub.client.com/blog -> client.example.com/blog
client.com/sub/blog -> client.example.com/blog
Also, I use Elastic Beanstalk in Amazon to deploy my React application with nginx (Docker image ). Before I start I want to know if this is possible.I also don't want to give fixed IP address to my clients, just in case if I lose that IP. How are the big players like blogger.com, wordpress.com etc doing it?
As far as I researched I know cname is possible to allow clients subdomains and we need IP address for named domain. nowhere it mentioned about the folder. And for SSL, I can use LetsEncrypt.
I am OK with anything like CloudFlare / Route53 method.

Cloudflare for SaaS is designed for this use case. You would just go to Cloudflare Dashboard > You Domain (example.com) -> SSL -> Custom Hostnames. Add a fallback hostname to which you client will link to, e.g. ssl.example.com.
Then client then would need to add his or her custom hostname in your app, then link and verify his custom domain by adding a CNAME (pointing to ssl.example.com) and TXT record via his own DNS provider. The verification and issuing a new SSL would take a few minutes, completely handled by Cloudflare and from there on, your clients may access your service via custom hostname (e.g. client.com, sub.client.com, client.com/blog etc.)
If you need to manipulate the HTTP response as it goes through the customer's hostname, it's also possible to route these request through a CLoudflare Worker script (linked to */* — all hostnames/URLs).
Here is an example, of how to create a custom hostname programmatically:
import * as Cloudlfare from "cloudflare-client";
// Initialize custom hostnames client for Cloudlfare
const customHostnames = Cloudflare.customHostnames({
zoneId: process.env.CLOUDFLARE_ZONE_ID,
accessToken: process.env.CLOUDFLARE_API_TOKEN,
});
// Add the client's custom hostname record to Cloudflare
const record = await customHostnames.create(
hostname: "www.client.com",
ssl: {
method: "txt",
type: "dv",
settings: {
min_tls_version: "1.0",
},
}
);
// Fetch the status of the custom hostname
const status = await customHostnames.get(record.id);
// => { id: "xxx", status: "pending", ... } including TXT records
Pricing
CF for SaaS is free for 100 hostnames and $0.10/hostname/mo after (source).
Path-based URL forwarding
If you need to forward HTTP traffic to different endpoints, e.g. www.client.com/* (customer domain) to web.example.com (SaaS endpoint); www.client.com/blog/* to blog.example.com, etc.
You can achieve that by creating a Cloudfalre Worker script with a route handling */* requests (all customer hostnames, and all URL paths), that would look similar to this:
export default {
fetch(req, env, ctx) {
const url = new URL(req.url);
const { pathname, search } = url;
if (url.pathname === "/blog" || url.pathname.startsWith("/blog/")) {
return fetch(`https://blog.example.com${pathname}${search}`, req);
}
return fetch(`https://web.example.com${pathname}${search}`;
}
}
References
https://developers.cloudflare.com/cloudflare-for-saas/
https://github.com/kriasoft/cloudflare-client
https://github.com/kriasoft/cloudflare-starter-kit

The simplest approach to this, which I’ve implemented at scale (10,000+ clients), is to:
DNS
Have your clients create a CNAME record to either a specific client.example.com or general clients.example.com. This applies to both root (set the ALIAS record instead) and subdomains—an IP address is not required, nor recommended as it does not scale.
Create a database entry that registers/links that explicitly links their domain/subdomain to their account.
Have logic in the backend controller will that associates the hostname in the request to a specific client (security measure) to serve relevant content.
The above fulfills the first two use cases—it allows the client to link a root domain or subdomain to your service.
To achieve the third use case, you could allow the client to specify an arbitrary root path for your service to run within. If the client chooses this, you also need to handle redirects to other services that they have on their domain. This is a lot of responsibility for your app, however.
You could just leverage their registrar, most registrars have the ability to do path redirects—this is the simplest approach that requires the least amount of responsibility/maintenance on your end.
I also recommend having an option for redirecting all entry points (ie: root domain, subdomain, root domain+path, subdomain+path) to a primary entry point (ie: root domain + path), for SEO purposes.
Note: You may also use a service, such as wwwizer, that redirects to the www specified if the ALIAS option on the root domain of your client isn't available.
SSL
I recommend using Let's Encrypt's ACMEv2 API to enable SSL for any domain that is setup on your service. There are libraries available that you should be able.
What is worth mentioning is the challenge — which can occur via DNS or HTTP. When the library you decide on makes a request for a new certificate Let's Encrypt will respond by making a request to ensure that you control the domain (by checking DNS record for a predetermined unique hash) or that you control the server it points to (by checking HTTP path for a predetermined unique hash). What that means is that you need to ensure that your client either includes a hash in their DNS that you specify or you expose a route that adheres to the ACME v2 challenge response protocol (handled by the library you choose).
Here is an example library that you could use if the service you are building is based on python, which supports all features mentioned above and also includes a cli: https://github.com/komuw/sewer .
References
https://help.ns1.com/hc/en-us/articles/360017511293-What-is-the-difference-between-CNAME-and-ALIAS-records-
https://letsencrypt.org/docs/client-options/
https://datatracker.ietf.org/doc/html/rfc8555
http://wwwizer.com

I think what you are asking is how to have the client have their own domain, which they own, have a subdomain which points to your website, with a matching certificate somehow. But just from a security standpoint there is no safe way to do this IMO. Here are the ways off the top of my head you can do this:
You Manage DNS of Subdomain
Your customer could create a NS record to a public Route53 distribution which you own. Then that subdomain would effectively be yours, and you can create DNS records in their subdomain, and certificates in ACM which you can use in a Cloudfront Distribution. You can have multiple FQDN in the one certificate so you won't have to have multiple distributions. You will need to add the domains to the aliases in your distribution as well.
Client Manages own DNS but you tell them what to do
I'm not sure this works as I haven't tried it, but in the DNS validation of a ACM certificate you can see the records you need to create, you would tell the client the CNAME record which they need to create for AWS to issue a certificate for the given domain i.e. sub.client.com, and they would also need to create CNAMEs to point to your website. This way the client still manages their own DNS.
Import Certificate
You could get your client to create a cert for you can then you could import it. They would also need to create the CNAME records to point to your website. And again they would need to create a CNAME to point to your site. Probably least secure, and certs will require manual rotation.
Cloudfront
Your client can use your website as an origin in their own Cloudfront Distribution, bit hacky but would work. I don't think this scales with growing customers.
Summary
IMO I don't like any of those solutions, they are all messy, most likely non-compliant with security standards, and hard to automate if at all. Not to say there aren't situations where you might do this. I would suggest you create subdomains for your own domain, or otherwise consider yourself a hosting company and then you would own/manage your client's domains on their behalf then this easier. But IMO it does not make sense to own a domain, and then give out control to it, or transfer certificates. You'll run into trouble with customers who need to hold certain certifications, or need you to hold those, such as SOC2 for example.

Related

How to resolve "Domain's DNS record could not be retrieved" in GitHub page creation process?

I am trying to create a GitHub page for a repository. But when I gave the custom domain name, it shows the following message "Domain's DNS record could not be retrieved. For more information"
As I am new to GitHub I am not getting the information what is documented in GitHub pages. Could anyone help me to resolve this problem?
If you've recently changed or removed your custom domain and can't access the new URL in your browser, you may need to clear your browser's cache to reach the new custom domain. For more information on clearing your cache, see your browser's help site.
In order to serve the Page, your DNS records must point to GitHub's server. To confirm that your custom domain points to GitHub's servers, use the dig command with your custom domain. The dig command shows you where your custom domain points. For example:
$ dig example.com +nostats +nocomments +nocmd
example.com. 3600 IN A 185.199.108.153
In the example above, example.com points to the IP address 185.199.108.153.
If you configured A records through your DNS provider, your A records must point your custom domain to the following IP addresses:
185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
You may see a different IP address, since we serve Pages with a global Content Delivery Network. Use dig username.github.io to see the full resolution path. Note that DNS caching may cause a delay.
If you're using an A record that points to 192.30.252.153 or 192.30.252.154, you'll need to update your DNS settings for your site to be available over HTTPS or served with a Content Delivery Network. For more information, see "HTTPS errors."
If you're using an A record that points to 207.97.227.245 or 204.232.175.78, you'll need to update your DNS settings, as we no longer serve Pages directly from those servers.
Source: https://help.github.com/en/articles/troubleshooting-custom-domains

Akamai CDN - Whitelist service by Request header or User agent

We are using Akamai CDN as our load balancer and it also servers as a gatekeeper for requests.
We usually consume 3rd party services and in those cases whitelist their IP to be accessed in our servers. The service we are currently using cannot share IP since it is on cloud and keeps changing. They can either provide host name or Custom request header or a user agent.
I tried adding host entry but that did not work. Any idea how to add custom request header or user agent?
Depending on the product you're using to deliver with Akamai, the solution is to add a "Modify Outgoing Request Header" behavior.
This is what the "Add Behavior" tool looks like when you filter behaviors on "header".
By default, this allows you to specify a User-Agent header to go to your origin with the request. You can also specify a custom header name and value using that Behavior.
If you make it part of your Default Rule, then every single request that goes through that property will have the custom header.

Postman and multiple Client Certificates for a single domain?

I've been using Fiddler for a couple of weeks to test an API but we're moving to Postman.
Our APIs workflow is that a device must register by using a common cert and as a response to a successful registration a private cert is issued to that device. All requests the device makes after that uses the private cert.
I'm trying to test multiple devices which means I need Postman to use 5 or 6 certs for a single domain. In Fiddler I could modify the fiddlerscript so I had an array of all the certs I intended to use. If I wanted to switch certs I opened the script and used a different index of my cert array. I'd set oSession["https-Client-Certificate"] and the request would use that cert.
In postman, I see that I can set a client cert for a particular domain. I've been able to get that to work for the global cert and running a /register request successfully. I can then change the cert and keep going. It's an annoying process if I want to change this cert after every request as I emulate multiple devices each with their own cert.
I see there's a Pre-Request Script tab. Is there a way to change the client cert in this script? If not with a Pre-Request Script, is there any other place where I can have multiple certs for a single domain and easily switch between them between requests?
I don't think that's possible, but maybe you can trick it by updating your local hosts file by creating fake local domains
104.244.42.130 cert1.api.twitter.com
104.244.42.130 cert2.api.twitter.com
104.244.42.130 cert3.api.twitter.com
104.244.42.130 cert4.api.twitter.com
104.244.42.130 cert5.api.twitter.com
Then map each local domain in postman to each certificate
cert1.api.twitter.com
cert2.api.twitter.com
cert3.api.twitter.com
cert4.api.twitter.com
cert5.api.twitter.com
and create an environment for each certificate and update the url of each request to include the {{cert}} environment. Then by switching environments you should be switching the certificate at the same time.

Third party code on subdomain

As the owner of domain example.com with many content what security risks arising from providing subdomain to third party company. We don't want to share any of the content and the third company would have complete control over the application and machine hosting the subdomain site.
I'm concerned mainly about:
Shared cookies
We have cookies .example.com, so there will be sent also in the requests to subdomain. Is it possible for us to point A record to reverse proxy where we strip the cookies and send the request to third party provider without them?
Content loading from main domain
Is it possible to set document.domain to example.com and do XMLHttpRequest to the example.com?
Cross site scripting
I guess that it would be no problem because of the same origin policy. Subdomain is treated as separate domain?
Any other security issues?
We have cookies .example.com, so there will be sent also in the
requests to subdomain. Is it possible for us to point A record to
reverse proxy where we strip the cookies and send the request to third
party provider without them?
Great idea, you could do this yes, however you will also need to set the HttpOnly flag, otherwise they would be able to retrieve them with JavaScript.
Is it possible to set document.domain to example.com and do
XMLHttpRequest to the example.com?
No, subdomains for Ajax are treated as a different Origin. See this answer.
I guess that it would be no problem because of the same origin policy.
Subdomain is treated as separate domain?
JavaScript code could interact with each other subdomains - but only with the cooperation of your site. You would also need to also set document.domain = 'example.com'; If you do not do this, you are secure against this threat.
See here:
When using document.domain to allow a subdomain to access its parent
securely, you need to set document.domain to the same value in both
the parent domain and the subdomain. This is necessary even if doing
so is simply setting the parent domain back to its original value.
Failure to do this may result in permission errors.
Any other security issues?
You need to be aware of cookie poisoning. If evil.example.com sets a non host-only cookie at .example.com that your domain believes it has set itself, then the evil cookie may be used for your site.
For example, if you display the contents of the cookie as HTML, then this may introduce XSS. Also, if you're using the double submit cookies CSRF prevention method an evil domain may be able to set their own cookie value to achieve CSRF. See this answer.

DNS hosting public and web application on different hosts

Here is my setup.
Public site hosted by squarespace.com (www.example-domain.com)
Web application (AWS EC2/ELB), i would like to be available via the same domain. (my.example-domain.com)
Custom profile pages available as www.example-domain.com/username
My question is how can i setup the DNS to achieve this? If can't do it just through DNS, any suggestions? The problem i am facing is that if squarespace.com is handling the www.example-domain.com traffic how can i have it only partially handle it for certain urls. Maybe i am going about this in the wrong was all together though.
The two first are ok. As you mention, (1) is not compatible with (3) for a pure DNS config as www of example-domain.com has to be configured to a single end-point.
Some ideas of non-DNS workaround:
Having the squarespace.com domain on sqsp.example-domain.com and configure your www domain to a custom web server on which you configure the root (/) to redirect (HTTP 300) to sqsp.example-domain.com. It will be quite transparent for the user, except in his browser address.
The same but setting on / a full page HTML iframe containing sqsp.example-domain.com.
The iframe approach is a "less clean", Google the solutions to build your opinion.
EDIT:
As #mike-ryan mentioned, there is the proxy solution as well where you configure you web server to request another server to get the content to return to your user. If you are already using AWS, a smart way to do this is to use CloudFront: you can setup CloudFront to proxy one server on one URL and proxy another server on other URL. Actually, this is maybe the faster to way to implement you need. Of course, a proxy is one more "hop", so it may add more delay.
If you really want to have content served from different servers while only using a single domain name, you'll need to set up a proxy server to handle the request routing for you. I am assuming your custom profile pages must be served from your EC2 instance.
Nginx will receive all requests, and will then decide whether they should be sent to Square Space or your web app. Requests will be reverse proxied to Square Space or to your app, depending on the URL.
This is similar to #smad's answer, except it will all be invisible to the users which IMHO is better than redirecting the user to a new domain name.
Example steps:
Set up an Nginx server, create two virtual hosts - one for my.example.com, and one for www.example.com
Create two upstreams in your Nginx config - one for Square Space, and one for your app
Configure the www.example.com virtual host to reverse proxy connections to the Square Space upstream, if the URL is "/". Otherwise, traffic should be proxied to your app upstream [0]
Configure the my.example.com virtual host to proxy all traffic to your app upstream
[0] how to reverse proxy via nginx a specific url?