github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/design/https-acme/README.md (about)

     1  ### Story
     2  As a Heeus user I want my application to be requested using HTTPS
     3  
     4  ### Terms
     5  - HTTPS hypertext protocol which uses TLS encryption protocol to encypt communications
     6  - TLS - Transport Level Security
     7  - SSL - Secure Sockets Layer. TLS was known as SSL a time ago. Currently `SSL` term is used instead of `TLS`
     8  
     9  ### Solution principles
    10  - Request is always sent to a certain cluster (e.g. Main Cluster)
    11  - Each cluster has its own domain
    12  - We do NOT use Federation Domain/GEO-DNS
    13  - ACME provider ([Let's Encrypt](https://letsencrypt.org/)) is used to get HTTPS certificates
    14    - Let's Encrypt currently does not support wildcard certficates (DNS records SOA)
    15    - one certificate covers all sites (DNS records A and CNAME) of the domain
    16    - certificate for `localhost` can not be issued
    17    - ACME v2 protocol version is used
    18  - Certificate is obtained for each domain name. No wildcard certificates.
    19  
    20  ### Concepts
    21  - Register a domain name for each cluster
    22  - Open ports 443 and 80
    23  - Launch `ce server --ihttp.Port=443 --ihttp.ACME=true --ihttp.ClusterDomainBase="<cluster domain name base>"`, e.g. `example.com`
    24    - `--ihttp.ClusterDomainBase` should contain the minimum accepted cluster domain name part. e.g. `example.com` specified -> `example.com`, `www.example.com`, `cluster1.example.com` etc are accepted
    25    - `--ihttp.ClusterDomainBase` is needed to Let's Encrypt's HTTP01 challenge only
    26    - `--ihttp.ACME=true` -> Let's Encrypt provider will be used. `--ihttp.Port` is 443 by default
    27    - `--ihttp.ACME=true` -> `--ihttp.Port` must not be 80 (since it will be used to handle ACME protocol)
    28    - `--ihttp.ACME` is not specified or `false` -> HTTP will be used instead of HTTPS, `--ihttp.Port` could be any: 80, 443 etc
    29  
    30  ### Subdomains vs subdirectories
    31  - Google idexing algorhithms treats subdomains as standalone sites. Content of a subdomains is not taken is account when ranking the root domain.
    32  - practical impact on the SEO should be checked to choose between subdomains and subfolders
    33  - want web search over entites of your business be more relevant -> use subfolders
    34  - have completely different parts of a business not related to each other (e.g. 2 enterprises in one main domain) -> use subdomains
    35  - want technically spread features of the site over different machines -> use subdomains, each feature in own subdomain, e.g. blog.example.com, shop.example.com
    36  - there are no technical restrictions, legal restrictions in different countries, etc. -> use subfolders
    37  
    38  ### Components
    39  ```mermaid
    40  erDiagram
    41  IHTTPProcessor ||..|| httpProcessor : "implemented by"
    42  ihttpimpl_New ||..|| httpProcessor : "creates and returns"
    43  ihttpimpl_New ||..|| certManager : "creates *autocert.Manager{}"
    44  ihttpimpl_New ||..|| clusterName : "accepts string"
    45  httpProcessor ||..|| server : "has *http.Server{}"
    46  httpProcessor ||..|| serverACME : "has *http.Server{}"
    47  certStorage ||..|| routerAppStorage  : "Get()/Put()"
    48  routerAppStorage ||..|| istorage_IAppStorage : is
    49  ihttpimpl_New ||..|| certStorage : "accepts *autocert.Cache interface"
    50  serverACME ||..|| HTTPHandler : "uses"
    51  TLSConfig ||..|| GetCertificate : "uses"
    52  server ||..|| TLSConfig : "has *crypto/tls.Config{}"
    53  certManager ||..|| HTTPHandler : "has method"
    54  certManager ||..|| GetCertificate : "has method"
    55  certManager ||..|| Cache : "has *autocert.Cache field"
    56  certManager ||..|| HostPolicy :"has func field"
    57  Cache ||..|| certStorage : "implemented by"
    58  GetCertificate ||..|| Cache : "writes ACME token"
    59  HostPolicy ||..|| HostWhiteList: "implemented by autocert.HostWhiteList"
    60  HostWhiteList ||..|| clusterName : "uses"
    61  HTTPHandler ||..|| Cache : "reads ACME token"
    62  ```
    63  
    64  ### Establishing the HTTPS communication
    65  - A user opens a web page using https:// scheme
    66  - Request is got by one of Heeus CE instances by its http server on a port number 443
    67  - HTTP server obtains a certificate to encrypt the communication
    68    - Already has a certificate in the storage - use it
    69    - Missing\expired\broken etc certificate -> obtain a new certificate from Let's Encrypt
    70      - `autocert` library sends a request to Let's Encrypt server to issue a new certificate
    71      - Let's Encrypt sends request to the Cluster Domain on port 80 (handled by `autocert` library) to check if the server actually controls the domain
    72      - Reply from `autocert` is matched the initial request -> Let's Encrypt issues and returns a new certificate
    73      - Cetificate is written to the storage
    74  - Further communication between client and Heeus CE is encrypted using the certificate
    75  ```mermaid
    76  sequenceDiagram
    77  	participant b as browser
    78  	participant s as server(Heeus)
    79  	participant m as certManager(autocert)
    80  	participant c as certStorage(Heeus)
    81  	participant h as HTTPHandler(autocert)
    82  	participant sACME as serverACME(Heeus)
    83  	participant l as Let's Encrypt server
    84  	Note over s,sACME: httpProcessor
    85  	b->>s: https://example.com
    86  	activate s
    87  	s->>m: http.Server.TLSConfig.GetCertificate()
    88  	activate m
    89  	m->>c: Get()
    90  	activate c
    91  	c->>m: certificate or nil
    92  	deactivate c
    93  	opt certificate is nil
    94  		m->>c: Put(ACME token)
    95  		m->>l: send ACME token + request a new certificate for domain example.com
    96  		activate l
    97  		l->>sACME: if the request chained to you?
    98  		activate sACME
    99  		Note over l,sACME: http://example.com
   100  		sACME->>h: calls HTTPHandler()
   101  		activate h
   102  		h->>c: Get()
   103  		activate c
   104  		c->>h: ACME token
   105  		deactivate c
   106  		h->>l: send challenge response
   107  		deactivate h
   108  		deactivate sACME
   109  		l->>m: certificate
   110  		m->>c: Put(certificate)
   111  		deactivate l
   112  	end
   113  	m->>s: certificate
   114  	s->b: encrypted communication
   115  	deactivate m
   116  	deactivate s
   117  
   118  ```