Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable single-level DNS domains (*.domain.tld) in SINGLE_PORT mode to simplify HTTPS setup #8983

Merged
Expand Up @@ -453,3 +453,6 @@ che.infra.openshift.tls_enabled=false
# Single port mode wildcard domain host & port. nip.io is used by default
che.singleport.wildcard_domain.host=NULL
che.singleport.wildcard_domain.port=NULL

# Enable single port custom DNS without inserting the IP
che.singleport.wildcard_domain.ipless=false
4 changes: 4 additions & 0 deletions dockerfiles/init/manifests/che.env
Expand Up @@ -249,6 +249,10 @@ CHE_SINGLE_PORT=false
#CHE_SINGLEPORT_WILDCARD__DOMAIN_HOST=NULL
#CHE_SINGLEPORT_WILDCARD__DOMAIN_PORT=NULL

# IP-less wildcard dns in single mode. This needs a *.domain.tld DNS entry. (Use it instead of
# nip.io)
#CHE_SINGLEPORT_WILDCARD__DOMAIN_IPLESS=false

# Default rewriter for URLs in links.
# This variable is automatically overridden in single port mode.
#CHE_INFRA_DOCKER_URL__REWRITER=DEFAULT
Expand Down
2 changes: 2 additions & 0 deletions dockerfiles/init/manifests/che.pp
Expand Up @@ -40,6 +40,7 @@
#
$che_single_port = getValue("CHE_SINGLE_PORT","false")
$che_single_port_wildcard_domain_host = getValue("CHE_SINGLEPORT_WILDCARD__DOMAIN_HOST","nip.io")
$che_single_port_wildcard_domain_ipless = getValue("CHE_SINGLEPORT_WILDCARD__DOMAIN_IPLESS","false")

###############################
# Che multiuser
Expand All @@ -66,6 +67,7 @@
$system_super_privileged_mode=getValue("SYSTEM_SUPER__PRIVILEGED__MODE", "false")

$che_keycloak_admin_require_update_password=getValue("CHE_KEYCLOAK_ADMIN_REQUIRE_UPDATE_PASSWORD", "true")
$che_keycloak_auth__server__url=getValue("CHE_KEYCLOAK_AUTH__SERVER__URL","")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see where $che_keycloak_auth__server__url is used, do we need that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i think this is a leftover


###############################
# Include base module
Expand Down
4 changes: 3 additions & 1 deletion dockerfiles/init/modules/che/templates/che.env.erb
Expand Up @@ -93,7 +93,9 @@ CHE_WORKSPACE_HTTP__PROXY__JAVA__OPTIONS=<% if ! @http_proxy_for_che_workspaces.
CHE_INFRA_DOCKER_URL__REWRITER=singleport

<% if scope.lookupvar('che::che_multiuser') == 'true' -%>
<% if ! @che_docker_ip_external.empty? -%>
<% if scope.lookupvar('che::che_single_port') == 'true' and scope.lookupvar('che::che_single_port_wildcard_domain_ipless') == 'true' -%>
CHE_KEYCLOAK_AUTH__SERVER__URL=http://keycloak.<%= scope.lookupvar('che::che_single_port_wildcard_domain_host') -%>/auth
<% elsif ! @che_docker_ip_external.empty? -%>
CHE_KEYCLOAK_AUTH__SERVER__URL=http://keycloak.<%= scope.lookupvar('che::che_docker_ip_external') -%>.<%= scope.lookupvar('che::che_single_port_wildcard_domain_host') -%>:<%= scope.lookupvar('che::che_port') -%>/auth
<% else -%>
CHE_KEYCLOAK_AUTH__SERVER__URL=http://keycloak.<%= scope.lookupvar('che::docker_ip') -%>.<%= scope.lookupvar('che::che_single_port_wildcard_domain_host') -%>:<%= scope.lookupvar('che::che_port') -%>/auth
Expand Down
Expand Up @@ -98,7 +98,7 @@ services:
<% end -%>
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- '<%= scope.lookupvar('che::che_instance') -%>/config/traefik/traefik.toml:/etc/traefik/traefik.toml'
- '<%= scope.lookupvar('che::che_instance') -%>/config/traefik:/etc/traefik'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is needed to place https certifactes in the config/traefik folder. not strictly necessary for single-level-subdomains

restart: always
<% end -%>

Expand Down Expand Up @@ -162,7 +162,9 @@ services:
labels:
traefik.keycloak.frontend.entryPoints: "http"
traefik.keycloak.port: "8080"
<% if ! @che_docker_ip_external.empty? -%>
<% if scope.lookupvar('che::che_single_port') == 'true' and scope.lookupvar('che::che_single_port_wildcard_domain_ipless') == 'true' -%>
traefik.keycloak.frontend.rule: "Host:keycloak.<%= scope.lookupvar('che::che_single_port_wildcard_domain_host') -%>"
<% elsif ! @che_docker_ip_external.empty? -%>
traefik.keycloak.frontend.rule: "Host:keycloak.<%= scope.lookupvar('che::che_docker_ip_external') -%>.<%= scope.lookupvar('che::che_single_port_wildcard_domain_host') -%>"
<% else -%>
traefik.keycloak.frontend.rule: "Host:keycloak.<%= scope.lookupvar('che::docker_ip') -%>.<%= scope.lookupvar('che::che_single_port_wildcard_domain_host') -%>"
Expand Down
Expand Up @@ -91,13 +91,15 @@ public void provision(DockerEnvironment internalEnv, RuntimeIdentity identity)
/**
* Constructs unique traefik service name - contains server, machine names and workspace ID. Dots
* is not allowed and replaced by dashes. Result is like:
* exec-agent-http-dev-machine-workspaceao6k83hkdav975g5
* exec-agent-http_dev-machine_workspaceao6k83hkdav975g5
*/
private String getServiceName(String host) {
int idx =
(externalIpOfContainers != null && host.contains(externalIpOfContainers))
? host.indexOf(externalIpOfContainers)
: host.indexOf(internalIpOfContainers);
return host.substring(0, idx - 1).replaceAll("\\.", "-");
int idx = host.indexOf(".");
if (idx > 1) {
return host.substring(0, idx - 1);
} else {
// the hostname does not contain the external or internal IPs (or in general any dots)
return host;
}
}
}
Expand Up @@ -22,7 +22,7 @@

/**
* Produces host names in form:
* [serverName].[machineName].[workspaceId].<external_or_internal_address>.<wildcardNipDomain> If
* [serverName]_[machineName]_[workspaceId].<external_or_internal_address>.<wildcardNipDomain> If
* some of the server name or machine name or workspace id is null, they will be not included.
*
* @author Max Shaposhnik (mshaposh@redhat.com)
Expand Down Expand Up @@ -54,7 +54,7 @@ public SinglePortHostnameBuilder(
* @return composite hostname
*/
public String build(String serverName, String machineName, String workspaceID) {
StringJoiner joiner = new StringJoiner(".");
StringJoiner joiner = new StringJoiner("_");
if (serverName != null) {
joiner.add(normalize(serverName));
}
Expand All @@ -64,18 +64,24 @@ public String build(String serverName, String machineName, String workspaceID) {
if (workspaceID != null) {
joiner.add(normalize(workspaceID));
}
joiner.add(wildcardDomain);
return joiner.toString();
return joiner.toString() + "." + wildcardDomain;
}

/**
* Gets a Wildcard domain based on the ip using an external provider like nip.io
* Gets a Wildcard domain based on the ip using an external provider like nip.io or by providing
* an IP-less DNS yourself
*
* @return wildcard domain
*/
private String getWildcardDomain(String localAddress, String wildcardHost) {
return String.format(
"%s.%s", getExternalIp(localAddress), wildcardHost == null ? "nip.io" : wildcardHost);
if (wildcardHost == null) {
return String.format("%s.%s", getExternalIp(localAddress), "nip.io");
} else if (wildcardHost.contains("nip.io") || wildcardHost.contains("xip.io")) {
return String.format("%s.%s", getExternalIp(localAddress), wildcardHost);
} else {
// IP-less DNS
return wildcardHost;
}
}

private String getExternalIp(String localAddress) {
Expand Down