Note: If you're renewing a custom domain certificate, check out this accompanying blog post.
Renewing Your Custom Domain Certificate For Multi-Target Applications
While there are a couple of other great posts for configuring custom domains in cloud foundry,
Demystifying SAP Cloud Platform Custom Domains
Fun and Games with SAP Cloud Domains
... and with all the emphasis on creating multitenant SaaS solutions that integrate with SAP's cloud offerings (read, make money), I wanted to make sure I could put together an example of all that's needed to support this exact scenario. The following is the set of steps I took to accomplish this exact task for a sample project I'm working on(
conciletime.com). I didn't take to time to generalize the domain name in this example so you'll need to refactor it for your purposes. For the most part, a simple search/replace exercise in the project which can be found
here is all that should be needed.
I'll try to explain where this scenario is a bit more complicated than that for a single hostname, but most of this post will be screen shots and command line usage.
How multitenant apps work in the context of SAP Cloud Foundry.
Before we get started, it's important to understand a bit of how these types of applications exist in our cloud foundry environment. Cloud Foundry application execution is in a SHARED namespace environment even when the app itself runs in it's own isolated environment(container). As such some things need to be unique within the whole cloud foundry landscape. A multitenant app lives within a space within a subaccount within a master account on the landscape. It's designed in a way that it can field subscription/unsubscription requests and be registered to do so. When a client subscribes to your multitenant application, they get a unique hostname that's based on your custom domain. That way when your client's users access their tenant(subscription) they can be indentified as belonging to that client. I'm using client here to mean the client of the SaaS solution that you(likely a SAP partner/customer) have built and not you the customer of SAP. Each client will be given their own subaccount of your master account so that they can connect to their own identity provider(and manage their own users). Each subaccount has it's own subdomain which is an identifier used in the authentication mechanism and must be unique within the lanscape. It is this subdomain name concatenated with your custom domain name that forms the client's hostname for their subscription. Again, I'll use my sample project to illustrate.
Developing Multitenant Business Applications in the Cloud FoundryEnvironment
www.conciletime.com = Main web entry point for static content.
conciletime.conciletime.com = Hostname for administrative use of the application.(the subdomain conciletime is used for the main subaccount where the actual application lives. It happens to be the same as the domain.com name, but doesn't have to be)
client1.conciletime.com = A subscriber client that has a subaccount with the subdomain name client1. Note again that this subdomain name must be unique within the entire landscape so once claimed nobody else can use it. For this reason, don't be surprised if client1 is already taken. This is likely to occur if your client has subscribed to any other multitenant app on the landscape.
ct-client2.conciletime.com = A more reasonable convention to use when signing up subscribers to your multitenant application. By prefixing the client with "ct-" makes it more likely that the subdomain won't already be taken, but doesn't guarantee it. You'll need to keep this in mind as well.
By this point you should realize that you're going to need to support *.conciletime.com because you can't know ahead of time what subdomains will be available for your clients. This is important when it comes to purchasing the SSL certificate you'll need to protect your application.
Official docs.
Creating Custom Domains with TLS/SSL Server Authentication
Buy custom domain quota
In order to create a custom domain in Cloud Foundry you need a quota for doing so. Depending on your account you might be able to do this yourself(CPEA) but more likely you'll have to purchase this from your SAP salesperson.
Buy the domain
We'll assume you've already done this and have access to the DNS administrative tool or access to the IT person who does. There are plenty of domain registrars out there, I used
GoDaddy.
Create the custom domain
If you're scared of command line tools you'll need to stop here because there seems to be currently no way to do this through the cloud cockpit UI. If you don't have the cf cli got get it for your platform.
Getting Started with SAP Cloud Platform Cloud Foundry Environment
- Download and install the Cloud Foundry CLI
IMPORTANT: Dowload and install the custom domain CF CLI Plugin.
- Custom Domain Self-service - Manage TLS server certificates and client authentication trust for custom domains
Follow the
documentation for details.
Once you've got things installed, get connected to your account landscape's api endpoint and login.
Target the organization where you'll create your custom domain (don't forget you need a quota, look above for info).
cf t -o ConcileTime
Now create your domain name in your organization.
cf create-domain ConcileTime conciletime.com
Creating domain conciletime.com for org ConcileTime as andrew.lunde@sap.com...
OK
Check that your domain got created properly.
Generate private key and CSR
Now you need to create a special domain key. This is an encryption key that will be used to create your Certificate Signing Request(CSR). You'll need to supply some details and list the domain names you'll use with the resultant certificate. "C=US, ST=State, O=ConcileTime, CN=
*.conciletime.com" Be sure that the CN value contains an asterix(*) or the certificate won't work for all possible hostnames generated for your domain name.
cf custom-domain-create-key ComodoConcileTimeKey "C=US, ST=State, O=ConcileTime, CN=*.conciletime.com" conciletime.com --verbose
Command: custom-domain-create-key
Organisation: ConcileTime (4d641712-8d17-45c6-adca-65c4f61e4202)
API Endpoint: https://api.cf.us10.hana.ondemand.com/
Default API Server: https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/
Key:ComodoConcileTimeKey
Subject: C=US, ST=State, O=ConcileTime, CN=*.conciletime.com
Domain Names:
Host Names: conciletime.com
Are you sure to generate this key in the system? (y/N)
y
DEBUG:2019/07/30 14:22:07 client.go:100: POST to https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/api/v1/organizations/4d641712-8d17-...
DEBUG:2019/07/30 14:22:07 client.go:105: Request: [{ ComodoConcileTimeKey C=US, ST=State, O=ConcileTime, CN=*.conciletime.com [conciletime.com] }]
DEBUG:2019/07/30 14:22:14 client.go:129: HTTP Status: 202
DEBUG:2019/07/30 14:22:14 client.go:130: Response: [{"guid":"173006fd-5f0d-4ac4-a3e7-980c8739bfd6","alias":"ComodoConcileTimeKey","subject":"C=US, ST=State, O=ConcileTime, CN=*.conciletime.com","dns":["conciletime.com"]}]
Successfully created key request with name: ComodoConcileTimeKey
The private key will be generated in the system. This operation will take some time!
Call custom-domain-get-csr now to get the corresponding certificate signing request
cf custom-domain-get-csr ComodoConcileTimeKey csr.pem
Download the CSR
Now get the CSR with the following command. Save the certificate text somewhere safe as you'll need it later.
cf custom-domain-get-csr ComodoConcileTimeKey comodo_conciletime_csr.pem
Command: custom-domain-get-csr
Organisation: ConcileTime (4d641712-8d17-45c6-adca-65c4f61e4202)
API Endpoint: https://api.cf.us10.hana.ondemand.com/
Default API Server: https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/
-----BEGIN CERTIFICATE REQUEST-----
MIIC1DCCAbwCAQAwTzELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVN0YXRlMRQwEgYD
VQQKEwtDb25jaWxlVGltZTEaMBgGA1UEAwwRKi5jb25jaWxldGltZS5jb20wggEi
...
UrrQ4Wo0y3VW41u4o7YGSVJlWQ5GNxQOVbfdlzLJoLCIpb7nQgWb0NnWhC0ap5Qb
n8BbI37SEow=
-----END CERTIFICATE REQUEST-----
Send the CSR to get signed
Purchasing a wildcard SSL certificate.
I'm going to assume you already have a domain name that you can use for this purpose. If you need to you can have your DNS administrator create a new subdomain on your domain name (ex. sapcloud.conciletime.com) but to keep things as clear as possible, I'll create a wildcard certificate for a single level of domain matching on my domain name. It is possible to create a SSL wildcard certificate for multiple levels of subdomain(ex. *.*.conciletime.com) but let's keep it simple.
You'll need to grab your manager's credit card for the following. While it's possible to create SSL certificates using your own custom certificate authority, that's beyond the scope of this post and requires that every system that accesses your application install and trust your certificate authority(something IT admins are reluctant to do). Anyway, the point it to look like a legitimate business. Here's the link to official docs.
Creating Custom Domains with TLS/SSL Server Authentication
https://comodosslstore.com
You're looking for the Positive SSL Wildcard certificate.
Add it to your cart.
Put in your Billing Address and Credit Card Detail (Omitted). Confirm and Complete the Order.
You'll be prompted to set a password for your account with Comodo.
Next generate your certificate. Click
GENERATE CERT NOW
Select Order Type.
I used the CNAME method for authentication. Basically they want you to prove that you are creating a certificate for a domain name that you actually own and not someone else's.
Now take the plaintext of the CSR you generated above and paste it here in Step #4.
Select a couple other options and select OTHER as the server type. Click Continue.
Continue with the process.
MAKE SURE THAT THE DOMAIN NAME HAS AN ASTERIX * !
Continue looking over the form and verify that everything is correct.
If all looks correct, Click Continue.
You've now completed the request.
Pay special attention to the instructions for creating a DNS CNAME entry. This is needed to confirm that you are authorized to makes requests for your domain name.
Log into or ask your IT admin to make a CNAME record in your domain administration tool. Again, I'll use GoDaddy since that's where I registered my domain.
You may have to wait a bit for the DNS change to trickle through the Internet. Then you can test to be sure the changes took.
dig _0A75XXXXXXXXXXXXXXXXXXB2E2932182.conciletime.com
; <<>> DiG 9.10.6 <<>> _0A75XXXXXXXXXXXXXXXXXXB2E2932182.conciletime.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 28823
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;_0A75XXXXXXXXXXXXXXXXXXB2E2932182.conciletime.com. IN A
;; ANSWER SECTION:
_0A75XXXXXXXXXXXXXXXXXXB2E2932182.conciletime.com. 1800 IN CNAME xxxxx8fca937722e2ac4165f165fbcd0.xxxxx620f65fc3a390f19560c9816f30.xxxxxptoo9pw50e59ka5.comodoca.com.
;; AUTHORITY SECTION:
comodoca.com. 600 IN SOA ns1.as48447.net. hostmaster.comodoca.com. 2019070802 1800 1200 1814400 5400
;; Query time: 117 msec
;; SERVER: 192.168.1.254#53(192.168.1.254)
;; WHEN: Tue Jul 30 13:44:51 EDT 2019
;; MSG SIZE rcvd: 250
After a few minute, check your email box. You should get an email with an attachment containing your certificate,
From: Sectigo Certification Authority <noreply@notifications.sectigo.com>
Date: Tuesday, July 30, 2019 at 1:48 PM
To: "Lunde, Andrew" <andrew.lunde@sap.com>
Subject: ORDER #25500XXXX - Your PositiveSSL Wildcard Certificate for *.conciletime.com
|
Your PositiveSSL Wildcard Certificate for *.conciletime.com is attached! |
Dear andrew.lunde@sap.com,
Thank you for placing your order. We are pleased to announce that your PositiveSSL Wildcard Certificate for *.conciletime.com has been issued.
To help reduce domain name mismatch warnings, we have also included the domain name conciletime.com in your certificate.
We strongly recommend that you click here for instructions to ensure that your certificate is installed and your webserver is configured correctly.
Attached to this email you should find a .zip file containing:
- Root CA Certificate - AddTrustExternalCARoot.crt
- Intermediate CA Certificate - USERTrustRSAAddTrustCA.crt
- Intermediate CA Certificate - SectigoRSADomainValidationSecureServerCA.crt
- Your PositiveSSL Wildcard Certificate - STAR_conciletime_com.crt
You can also find your PositiveSSL Wildcard Certificate for *.conciletime.com in text format at the bottom of this email.
Should you have any questions or issues you would like to discuss, please do not hesitate to contact us.
Thank you for being a valued Sectigo customer.
visit our website
get support
Copyright Ⓒ Sectigo Limited, All rights reserved.
Your PositiveSSL Wildcard Certificate for *.conciletime.com in text format (if required):
-----BEGIN CERTIFICATE-----
MIIGBzCCBO+gAwIBAgIRAOu8RmSkyiweALyVCVENPugwDQYJKoZIhvcNAQELBQAw
gY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
...
EarDqD2umMD244ohsoWTgnJdj3F5nl03TzU/QOVXfB8ESQyDoNgvppOO052Nxbo4
viaxq3C4zkNZH5o=
-----END CERTIFICATE----- |
|
Download and unzip the files locally. You should see the 4 crt files mentioned in the email.
You'll need to concatenate these files together before uploading them.
cat STAR_conciletime_com/AddTrustExternalCARoot.crt > comodo-conciletime-certchain.pem
cat STAR_conciletime_com/USERTrustRSAAddTrustCA.crt >> comodo-conciletime-certchain.pem
cat STAR_conciletime_com/SectigoRSADomainValidationSecureServerCA.crt >> comodo-conciletime-certchain.pem
cat STAR_conciletime_com/STAR_conciletime_com.crt >> comodo-conciletime-certchain.pem
Upload certificate
Use the cf upload command to upload the composite certificate bundle you just created.
cf custom-domain-upload-certificate-chain ConcileTimeDomainKey comodo-conciletime-certchain.pem
Command: custom-domain-upload-certificate-chain
Organisation: ConcileTime (4d641712-8d17-45c6-adca-65c4f61e4202)
API Endpoint: https://api.cf.us10.hana.ondemand.com/
Default API Server: https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/
Key: ComodoConcileTimeKey
Subject:CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE
Issuer:CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE
Validity:valid
Not Before:Tue May 30 10:48:38 UTC 2000
Not After:Sat May 30 10:48:38 UTC 2020
-----BEGIN CERTIFICATE-----
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
...
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----
Subject:CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US
Issuer:CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE
Validity:valid
Not Before:Tue May 30 10:48:38 UTC 2000
Not After:Sat May 30 10:48:38 UTC 2020
-----BEGIN CERTIFICATE-----
MIIFdzCCBF+gAwIBAgIQE+oocFv07O0MNmMJgGFDNjANBgkqhkiG9w0BAQwFADBv
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
...
lQ9ew4IcH9Z35zyKwKoJ8OkLJvHgwmp1ocd5yblSYMgpEg7wrQPWCcR23+WmgZWn
RtqCV6mVksW2jwMibDN3wXsyF24HzloUQToFJBv2FAY7qCUkDrvMKnXduXBBP3zQ
YzYhBx9G/2CkkeFnvN4ffhkUyWNnkepnB2u0j4vAbkN9w6GAbLIevFOFfdyQoaS8
Le9Gclc1Bb+7RrtubTeZtv8jkpHGbkD4jylW6l/VXxRTrPBPYer3IsynVgviuDQf
Jtl7GQVoP7o81DgGotPmjw7jtHFtQELFhLRAlSv0ZaBIefYdgWOWnU914Ph85I6p
0fKtirOMxyHNwu8=
-----END CERTIFICATE-----
Subject:CN=Sectigo RSA Domain Validation Secure Server CA,O=Sectigo Limited,L=Salford,ST=Greater Manchester,C=GB
Issuer:CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US
Validity:valid
Not Before:Fri Nov 2 00:00:00 UTC 2018
Not After:Tue Dec 31 23:59:59 UTC 2030
-----BEGIN CERTIFICATE-----
MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
...
LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5
yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K
00u/I5sUKUErmgQfky3xxzlIPK1aEn8=
-----END CERTIFICATE-----
Subject: CN=*.conciletime.com,OU=DomainControl Validated+OU=PositiveSSL Wildcard
Subject Alternative Names:
DNSName: *.conciletime.com
DNSName: conciletime.com
Issuer:CN=Sectigo RSA Domain Validation Secure Server CA,O=Sectigo Limited,L=Salford,ST=Greater Manchester,C=GB
Validity:valid
Not Before:Tue Jul 30 00:00:00 UTC 2019
Not After:Wed Jul 29 23:59:59 UTC 2020
-----BEGIN CERTIFICATE-----
MIIGBTCCBO2gAwIBAgIRANVR1hWyMasqKrOMc28GWOQwDQYJKoZIhvcNAQELBQAw
gY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE3MDUGA1UE
...
wwMFLeAxS6MYivKclw3oOz2GU3n1IK2cXlTeC6JO+zsl5l4l1AUYz4ykNKihnW+n
IHnmckbC1GIAfN19OvaIE/CssI7VNdZQ4fGc3WKNDcYjseVEZpDaigMPTxDt8vIt
DvzjLzuyws2zlLzw0oeJuml1YqC2MKo1u2wTlVhQMrd3rTQWi9GQhfJypqXac0Zm
diGqTzgO96vxZwIHsYXQMLz5Eps7Yo8rLcfNnCxYzNhQM4rvCqRkg6klvOgmncue
z6iP+ouzZAYm
-----END CERTIFICATE-----
Are you sure to import this certificate chain into the system? (y/N)
y
OK
Server certificate is still not activated: First activate your server certificate with custom-domain-activate
Activate the certificate
cf custom-domain-activate ComodoConcileTimeKey conciletime.com --verbose
Command: custom-domain-activate
Organisation: ConcileTime (4d641712-8d17-45c6-adca-65c4f61e4202)
API Endpoint: https://api.cf.us10.hana.ondemand.com/
Default API Server: https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/
Key alias: ComodoConcileTimeKey
Domain Names: conciletime.com
DEBUG:2019/07/30 15:15:18 client.go:81: GET to https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/api/v1/organizations/4d641712-8d17-...
DEBUG:2019/07/30 15:15:23 client.go:95: RESPONSE: [{"guid":"aa316360-c14a-4f9e-8830-ca3662c89f9f","alias":"ComodoConcileTimeKey","subject":"C=US, ST=State, O=ConcileTime, CN=*.conciletime.com","dns":["conciletime.com","*.conciletime.com"],"chain":"-----BEGIN CERTIFICATE-----\nMIIGBTCCBO2gAwIBAgIRANVR1hWyMasqKrOMc28GWOQwDQYJKoZIhvcNAQELBQAw\ngY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\nBgNVBAcTB...
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----
}]
DEBUG:2019/07/30 15:15:23 client.go:324: IDENTITY FOUND: aa316360-c14a-4f9e-8830-ca3662c89f9f
DEBUG:2019/07/30 15:15:23 client.go:100: POST to https://custom-domain-certificates-api.cf.us10.hana.ondemand.com/api/v1/organizations/4d641712-8d17-...
DEBUG:2019/07/30 15:15:23 client.go:105: Request: [{ conciletime.com {aa316360-c14a-4f9e-8830-ca3662c89f9f} {} []}]
DEBUG:2019/07/30 15:15:25 client.go:129: HTTP Status: 200
DEBUG:2019/07/30 15:15:25 client.go:130: Response: [{"guid":"fa572e0e-f900-4c49-bf47-61ee3e1f78eb","name":"conciletime.com","state":"inprogress","tlsConfig":{"identityGuid":"aa316360-c14a-4f9e-8830-ca3662c89f9f"},"tlsClientTrustConfig":{}}]
OK
Activating conciletime.comin progress
This operation can take some time. Use custom-domain-list to track the status
Create a CNAME mapping
First, double check that Cloud Foundry understands when to use your custom domain certificate. Run this cf command and verify that the Domain name with wildcard is listed and activated(
in green).
cf custom-domain-list
Command: custom-domain-list
Organisation: ConcileTime (4d641712-8d17-45c6-adca-65c4f61e4202)
API Endpoint: https://api.cf.us10.hana.ondemand.com
Default API Server: https://custom-domain-certificates-api.cf.us10.hana.ondemand.com
Activated Certificates: 1
Activated Certificates Quota: 2
Domain Name: conciletime.com
Key: ComodoConcileTimeKey
Key Status: created, certificate chain uploaded
Certificate Status: valid
Client Authentication: disabled
Custom Domain Status: activated
Domain Name: *.conciletime.com
From an external request mapping standpoint, you need to make sure that requests are all mapped to the Cloud Foundry API endpoint for the landscape where your application is deployed. Again, I use GoDaddy for DNS management, so I'll illustrate what creating a CNAME mapping looks like. You may have to enlist your IT department to make CNAME additions to domains your company owns.
Notice that this DNS entry is of type CNAME and the targeted host is the wildcard "
*". Most critically the target of this entry is to the api endpoint of YOUR deployment landscape. In this case it's us10 with api.cf.us10.hana.ondemand.com but yours may be eu10(AWS Europe) instead of us10 or otherwise. This change may take a while to propagate throughout the Internet. After some time, verify that DNS resolution is correct. I use the Linux dig utility for this but you might use named or other tool.
dig www.conciletime.com
$ dig www.conciletime.com
; <<>> DiG 9.10.6 <<>> www.conciletime.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14920
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 9
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.conciletime.com. IN A
;; ANSWER SECTION:
www.conciletime.com. 3600 IN CNAME api.cf.us10.hana.ondemand.com.
api.cf.us10.hana.ondemand.com. 9915 IN CNAME cf-proxy-hcp-live-us10-2030508056.us-east-1.elb.amazonaws.com.
cf-proxy-hcp-live-us10-2030508056.us-east-1.elb.amazonaws.com. 6 IN A 54.209.228.56
cf-proxy-hcp-live-us10-2030508056.us-east-1.elb.amazonaws.com. 6 IN A 52.7.38.158
cf-proxy-hcp-live-us10-2030508056.us-east-1.elb.amazonaws.com. 6 IN A 52.4.61.78
Be sure to try a few other hostnames. You need to be sure ANY domain name maps to the api endpoint.
dig abc.conciletime.com
$ dig abc.conciletime.com
; <<>> DiG 9.10.6 <<>> abc.conciletime.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5664
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 9
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;abc.conciletime.com. IN A
;; ANSWER SECTION:
abc.conciletime.com. 3600 IN CNAME api.cf.us10.hana.ondemand.com.
dig whatever-hostname.conciletime.com
...
;; ANSWER SECTION:
whatever-hostname.conciletime.com. 3600 IN CNAME api.cf.us10.hana.ondemand.com.
Once you're confident external mapping is set and that you're not looking at any cached DNS results and the target is always the api endpoint, you can continue with configuring the internal route mapping.
Map domain to application
Once you have your application deployed into your space, the urls will all point to the hana.ondemand.com domain. This is the default behavior when deploying. What you want to do now is to create a new http route to your application so that requests coming in on your custom domain will be forwarded to your application.
Here's what it looks like before adding a route.
cf a
Getting apps in org ConcileTime / space dev as andrew.lunde@sap.com...
OK
name requested state instances memory disk urls
concile_app_v0 started 1/1 512M 256M conciletime-app.cfapps.us10.hana.ondemand.com
concile_web_v0 started 1/1 512M 256M conciletime.cfapps.us10.hana.ondemand.com
concile_utl_v0 started 1/1 512M 256M conciletime-utl.cfapps.us10.hana.ondemand.com
concile_srv_v0 started 1/1 512M 256M conciletime-srv.cfapps.us10.hana.ondemand.com
concile_db_v0 stopped 0/1 256M 256M
Now let's map a route that will cover all possible hostnames for your domain. We'll use the asterix here as well as the hostname. Since the * has meaning on our command line shell we need to put it in single quotes so that the shell doesn't try to expand it.
cf map-route concile_web_v0 conciletime.com --hostname '*'
Creating route *.conciletime.com for org ConcileTime / space dev as andrew.lunde@sap.com...
OK
Route *.conciletime.com is created
Adding route *.conciletime.com to app concile_web_v0 in org ConcileTime / space dev as andrew.lunde@sap.com...
OK
Now we can check again, this time I'll just check the app-router component of my application.
cf app concile_web_v0
Showing health and status for app concile_web_v0 in org ConcileTime / space dev as andrew.lunde@sap.com...
name: concile_web_v0
requested state: started
instances: 1/1
usage: 512M x 1 instances
routes: conciletime.cfapps.us10.hana.ondemand.com, *.conciletime.com
last uploaded: Thu 01 Aug 17:23:06 EDT 2019
stack: cflinuxfs3
buildpack: nodejs
state since cpu memory disk details
#0 running 2019-08-01T21:23:57Z 0.0% 47.1M of 512M 104.7M of 256M
Notice that in routes:
*.conciletime.com also appears.
We can now browse to
www.conciletime.com, or
abc.conciletime.com, or
xyz.conciletime.com and get the same application. Again, this is important in order to support multitenant application subscriptions.
You browser should also be completely happy and not show any certificate errors whatsoever.
!Critical configuration!
When your MTA application is deployed, the uaa service instance needs to be passed additional information so that the authentication mechanism can validate the relay destination upon the user's authentication. This is a kind of whitelist and while you don't have to do this if you're not using custom domains, if you do (like we are here) then it's mandatory.
Maker sure your project's mta.yaml file is configured to pick up an xs-security.json file in your project.
resources:
...
- name: conciletime-uaa
type: org.cloudfoundry.managed-service
parameters:
path: xs-security.json
service-name: CONCILETIME_UAA
service-plan: default
service: xsuaa
config:
xsappname: conciletime-${space}
tenant-mode: dedicated
Now in your xs-security.json file, make sure that you have an oauth2-configuration section.
"oauth2-configuration": {
"redirect-uris":
[
"http*://*.conciletime.com/**"
]
}
Notice that the
redirect-uris contains a uri with wildcard matching of the protocol type, the hostname, and any path that follows. This is pretty broad matching so you might want to restrict it to known login paths, but it's vital that the hostname wildcard matching be in place in order to support subscriptions of clients as we've discussed above.
Full docs for
Application Security Descriptor Configuration Syntax
Philip has put together an extensive collection of videos with all the particulars of building multitenant apps.
https://www.youtube.com/playlist?list=PLkzo92owKnVx3Sh0nemX8GoSNzJGfsWJM
Wow, this post got quite long. If you're still with me, congratulations! Let me know how your efforts at using custom domains in your mutitenant apps go or leave me a question below.
If I've missed any detail, take a look at this project where I've implemented everything I mention here.
https://github.com/alundesap/conciletime/tree/post01
-Andrew