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

# Single port custom DNS
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 @@ -40,16 +40,25 @@ public class SinglePortLabelsProvisioner implements ConfigurationProvisioner {
private final String internalIpOfContainers;
private final String externalIpOfContainers;
private final String dockerNetwork;
private final String cheHostProtocol;
private final Boolean singleportWildcardIPless;
private final String singleportWildcardDomainHost;

@Inject
public SinglePortLabelsProvisioner(
@Nullable @Named("che.docker.ip") String internalIpOfContainers,
@Nullable @Named("che.docker.ip.external") String externalIpOfContainers,
@Nullable @Named("che.docker.network") String dockerNetwork,
@Nullable @Named("che.host.protocol") String cheHostProtocol,
@Nullable @Named("che.singleport.wildcard_domain.ipless") Boolean singleportWildcardIPless,
@Nullable @Named("che.singleport.wildcard_domain.host") String singleportWildcardDomainHost,
Provider<SinglePortHostnameBuilder> hostnameBuilderProvider) {
this.hostnameBuilderProvider = hostnameBuilderProvider;
this.internalIpOfContainers = internalIpOfContainers;
this.externalIpOfContainers = externalIpOfContainers;
this.singleportWildcardIPless = singleportWildcardIPless;
this.cheHostProtocol = cheHostProtocol;
this.singleportWildcardDomainHost = singleportWildcardDomainHost;
this.dockerNetwork = dockerNetwork;
}

Expand Down Expand Up @@ -98,6 +107,11 @@ private String getServiceName(String host) {
(externalIpOfContainers != null && host.contains(externalIpOfContainers))
? host.indexOf(externalIpOfContainers)
: host.indexOf(internalIpOfContainers);
return host.substring(0, idx - 1).replaceAll("\\.", "-");
if (idx > 1) {
return host.substring(0, idx - 1).replaceAll("\\.", "-");
Copy link
Contributor

Choose a reason for hiding this comment

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

Please, review logic here again. We dont need to replace dots anymore. Only cut until first dot and throw out any optional IP and wildcard domain.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point!

} else {
// the hostname does not contain the external or internal IPs
return host.replaceAll("\\.", "-");
}
}
}
Expand Up @@ -39,6 +39,7 @@ public class SinglePortHostnameBuilder {

public SinglePortHostnameBuilder(
String externalAddress, String internalAddress, String wildcardHost) {

this.wildcardDomain =
externalAddress != null
? getWildcardDomain(externalAddress, wildcardHost)
Expand All @@ -54,7 +55,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,8 +65,8 @@ public String build(String serverName, String machineName, String workspaceID) {
if (workspaceID != null) {
joiner.add(normalize(workspaceID));
}
joiner.add(wildcardDomain);
return joiner.toString();
// joiner.add(wildcardDomain);
return joiner.toString() + "." + wildcardDomain;
}

/**
Expand All @@ -74,8 +75,14 @@ public String build(String serverName, String machineName, String workspaceID) {
* @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 {
// custom dns
return wildcardHost;
}
}

private String getExternalIp(String localAddress) {
Expand Down